1/*
2 * Copyright (C) 2012 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.server;
18
19import static android.net.ConnectivityManager.CONNECTIVITY_ACTION;
20import static android.net.ConnectivityManager.TYPE_ETHERNET;
21import static android.net.ConnectivityManager.TYPE_MOBILE;
22import static android.net.ConnectivityManager.TYPE_WIFI;
23import static android.net.ConnectivityManager.getNetworkTypeName;
24import static android.net.NetworkCapabilities.*;
25
26import static org.mockito.Mockito.anyBoolean;
27import static org.mockito.Mockito.anyInt;
28import static org.mockito.Mockito.eq;
29import static org.mockito.Mockito.mock;
30import static org.mockito.Mockito.spy;
31import static org.mockito.Mockito.when;
32
33import android.app.NotificationManager;
34import android.app.PendingIntent;
35import android.content.BroadcastReceiver;
36import android.content.ContentResolver;
37import android.content.Context;
38import android.content.ContextWrapper;
39import android.content.Intent;
40import android.content.IntentFilter;
41import android.content.res.Resources;
42import android.net.CaptivePortal;
43import android.net.ConnectivityManager;
44import android.net.ConnectivityManager.NetworkCallback;
45import android.net.ConnectivityManager.PacketKeepalive;
46import android.net.ConnectivityManager.PacketKeepaliveCallback;
47import android.net.INetworkPolicyManager;
48import android.net.INetworkStatsService;
49import android.net.IpPrefix;
50import android.net.LinkAddress;
51import android.net.LinkProperties;
52import android.net.MatchAllNetworkSpecifier;
53import android.net.Network;
54import android.net.NetworkAgent;
55import android.net.NetworkCapabilities;
56import android.net.NetworkConfig;
57import android.net.NetworkFactory;
58import android.net.NetworkInfo;
59import android.net.NetworkInfo.DetailedState;
60import android.net.NetworkMisc;
61import android.net.NetworkRequest;
62import android.net.NetworkSpecifier;
63import android.net.RouteInfo;
64import android.net.StringNetworkSpecifier;
65import android.net.metrics.IpConnectivityLog;
66import android.net.util.MultinetworkPolicyTracker;
67import android.os.ConditionVariable;
68import android.os.Handler;
69import android.os.HandlerThread;
70import android.os.IBinder;
71import android.os.INetworkManagementService;
72import android.os.Looper;
73import android.os.Message;
74import android.os.MessageQueue;
75import android.os.Messenger;
76import android.os.MessageQueue.IdleHandler;
77import android.os.Parcel;
78import android.os.Parcelable;
79import android.os.Process;
80import android.os.SystemClock;
81import android.os.UserHandle;
82import android.provider.Settings;
83import android.test.AndroidTestCase;
84import android.test.mock.MockContentResolver;
85import android.test.suitebuilder.annotation.SmallTest;
86import android.text.TextUtils;
87import android.util.Log;
88import android.util.LogPrinter;
89
90import com.android.internal.util.WakeupMessage;
91import com.android.internal.util.test.BroadcastInterceptingContext;
92import com.android.internal.util.test.FakeSettingsProvider;
93import com.android.server.connectivity.MockableSystemProperties;
94import com.android.server.connectivity.NetworkAgentInfo;
95import com.android.server.connectivity.NetworkMonitor;
96import com.android.server.connectivity.NetworkMonitor.CaptivePortalProbeResult;
97import com.android.server.net.NetworkPinner;
98import com.android.server.net.NetworkPolicyManagerInternal;
99
100import org.mockito.Mock;
101import org.mockito.MockitoAnnotations;
102import org.mockito.Spy;
103
104import java.net.InetAddress;
105import java.util.ArrayList;
106import java.util.Arrays;
107import java.util.Objects;
108import java.util.concurrent.CountDownLatch;
109import java.util.concurrent.LinkedBlockingQueue;
110import java.util.concurrent.TimeUnit;
111import java.util.concurrent.atomic.AtomicBoolean;
112import java.util.function.BooleanSupplier;
113
114/**
115 * Tests for {@link ConnectivityService}.
116 *
117 * Build, install and run with:
118 *  runtest frameworks-services -c com.android.server.ConnectivityServiceTest
119 */
120public class ConnectivityServiceTest extends AndroidTestCase {
121    private static final String TAG = "ConnectivityServiceTest";
122
123    private static final int TIMEOUT_MS = 500;
124    private static final int TEST_LINGER_DELAY_MS = 120;
125
126    private MockContext mServiceContext;
127    private WrappedConnectivityService mService;
128    private WrappedConnectivityManager mCm;
129    private MockNetworkAgent mWiFiNetworkAgent;
130    private MockNetworkAgent mCellNetworkAgent;
131    private MockNetworkAgent mEthernetNetworkAgent;
132
133    // This class exists to test bindProcessToNetwork and getBoundNetworkForProcess. These methods
134    // do not go through ConnectivityService but talk to netd directly, so they don't automatically
135    // reflect the state of our test ConnectivityService.
136    private class WrappedConnectivityManager extends ConnectivityManager {
137        private Network mFakeBoundNetwork;
138
139        public synchronized boolean bindProcessToNetwork(Network network) {
140            mFakeBoundNetwork = network;
141            return true;
142        }
143
144        public synchronized Network getBoundNetworkForProcess() {
145            return mFakeBoundNetwork;
146        }
147
148        public WrappedConnectivityManager(Context context, ConnectivityService service) {
149            super(context, service);
150        }
151    }
152
153    private class MockContext extends BroadcastInterceptingContext {
154        private final MockContentResolver mContentResolver;
155
156        @Spy private Resources mResources;
157        private final LinkedBlockingQueue<Intent> mStartedActivities = new LinkedBlockingQueue<>();
158
159        MockContext(Context base) {
160            super(base);
161
162            mResources = spy(base.getResources());
163            when(mResources.getStringArray(com.android.internal.R.array.networkAttributes)).
164                    thenReturn(new String[] {
165                            "wifi,1,1,1,-1,true",
166                            "mobile,0,0,0,-1,true",
167                            "mobile_mms,2,0,2,60000,true",
168                    });
169
170            mContentResolver = new MockContentResolver();
171            mContentResolver.addProvider(Settings.AUTHORITY, new FakeSettingsProvider());
172        }
173
174        @Override
175        public void startActivityAsUser(Intent intent, UserHandle handle) {
176            mStartedActivities.offer(intent);
177        }
178
179        public Intent expectStartActivityIntent(int timeoutMs) {
180            Intent intent = null;
181            try {
182                intent = mStartedActivities.poll(timeoutMs, TimeUnit.MILLISECONDS);
183            } catch (InterruptedException e) {}
184            assertNotNull("Did not receive sign-in intent after " + timeoutMs + "ms", intent);
185            return intent;
186        }
187
188        public void expectNoStartActivityIntent(int timeoutMs) {
189            try {
190                assertNull("Received unexpected Intent to start activity",
191                        mStartedActivities.poll(timeoutMs, TimeUnit.MILLISECONDS));
192            } catch (InterruptedException e) {}
193        }
194
195        @Override
196        public Object getSystemService(String name) {
197            if (Context.CONNECTIVITY_SERVICE.equals(name)) return mCm;
198            if (Context.NOTIFICATION_SERVICE.equals(name)) return mock(NotificationManager.class);
199            return super.getSystemService(name);
200        }
201
202        @Override
203        public ContentResolver getContentResolver() {
204            return mContentResolver;
205        }
206
207        @Override
208        public Resources getResources() {
209            return mResources;
210        }
211    }
212
213    /**
214     * Block until the given handler becomes idle, or until timeoutMs has passed.
215     */
216    private static void waitForIdleHandler(HandlerThread handlerThread, int timeoutMs) {
217        final ConditionVariable cv = new ConditionVariable();
218        final Handler handler = new Handler(handlerThread.getLooper());
219        handler.post(() -> cv.open());
220        if (!cv.block(timeoutMs)) {
221            fail("HandlerThread " + handlerThread.getName() +
222                    " did not become idle after " + timeoutMs + " ms");
223        }
224    }
225
226    @SmallTest
227    public void testWaitForIdle() {
228        final int attempts = 50;  // Causes the test to take about 200ms on bullhead-eng.
229
230        // Tests that waitForIdle returns immediately if the service is already idle.
231        for (int i = 0; i < attempts; i++) {
232            mService.waitForIdle();
233        }
234
235        // Bring up a network that we can use to send messages to ConnectivityService.
236        ConditionVariable cv = waitForConnectivityBroadcasts(1);
237        mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
238        mWiFiNetworkAgent.connect(false);
239        waitFor(cv);
240        Network n = mWiFiNetworkAgent.getNetwork();
241        assertNotNull(n);
242
243        // Tests that calling waitForIdle waits for messages to be processed.
244        for (int i = 0; i < attempts; i++) {
245            mWiFiNetworkAgent.setSignalStrength(i);
246            mService.waitForIdle();
247            assertEquals(i, mCm.getNetworkCapabilities(n).getSignalStrength());
248        }
249    }
250
251    // This test has an inherent race condition in it, and cannot be enabled for continuous testing
252    // or presubmit tests. It is kept for manual runs and documentation purposes.
253    public void verifyThatNotWaitingForIdleCausesRaceConditions() {
254        // Bring up a network that we can use to send messages to ConnectivityService.
255        ConditionVariable cv = waitForConnectivityBroadcasts(1);
256        mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
257        mWiFiNetworkAgent.connect(false);
258        waitFor(cv);
259        Network n = mWiFiNetworkAgent.getNetwork();
260        assertNotNull(n);
261
262        // Ensure that not calling waitForIdle causes a race condition.
263        final int attempts = 50;  // Causes the test to take about 200ms on bullhead-eng.
264        for (int i = 0; i < attempts; i++) {
265            mWiFiNetworkAgent.setSignalStrength(i);
266            if (i != mCm.getNetworkCapabilities(n).getSignalStrength()) {
267                // We hit a race condition, as expected. Pass the test.
268                return;
269            }
270        }
271
272        // No race? There is a bug in this test.
273        fail("expected race condition at least once in " + attempts + " attempts");
274    }
275
276    private class MockNetworkAgent {
277        private final WrappedNetworkMonitor mWrappedNetworkMonitor;
278        private final NetworkInfo mNetworkInfo;
279        private final NetworkCapabilities mNetworkCapabilities;
280        private final HandlerThread mHandlerThread;
281        private final ConditionVariable mDisconnected = new ConditionVariable();
282        private final ConditionVariable mNetworkStatusReceived = new ConditionVariable();
283        private final ConditionVariable mPreventReconnectReceived = new ConditionVariable();
284        private int mScore;
285        private NetworkAgent mNetworkAgent;
286        private int mStartKeepaliveError = PacketKeepalive.ERROR_HARDWARE_UNSUPPORTED;
287        private int mStopKeepaliveError = PacketKeepalive.NO_KEEPALIVE;
288        private Integer mExpectedKeepaliveSlot = null;
289        // Contains the redirectUrl from networkStatus(). Before reading, wait for
290        // mNetworkStatusReceived.
291        private String mRedirectUrl;
292
293        MockNetworkAgent(int transport) {
294            final int type = transportToLegacyType(transport);
295            final String typeName = ConnectivityManager.getNetworkTypeName(type);
296            mNetworkInfo = new NetworkInfo(type, 0, typeName, "Mock");
297            mNetworkCapabilities = new NetworkCapabilities();
298            mNetworkCapabilities.addTransportType(transport);
299            switch (transport) {
300                case TRANSPORT_ETHERNET:
301                    mScore = 70;
302                    break;
303                case TRANSPORT_WIFI:
304                    mScore = 60;
305                    break;
306                case TRANSPORT_CELLULAR:
307                    mScore = 50;
308                    break;
309                default:
310                    throw new UnsupportedOperationException("unimplemented network type");
311            }
312            mHandlerThread = new HandlerThread("Mock-" + typeName);
313            mHandlerThread.start();
314            mNetworkAgent = new NetworkAgent(mHandlerThread.getLooper(), mServiceContext,
315                    "Mock-" + typeName, mNetworkInfo, mNetworkCapabilities,
316                    new LinkProperties(), mScore, new NetworkMisc()) {
317                @Override
318                public void unwanted() { mDisconnected.open(); }
319
320                @Override
321                public void startPacketKeepalive(Message msg) {
322                    int slot = msg.arg1;
323                    if (mExpectedKeepaliveSlot != null) {
324                        assertEquals((int) mExpectedKeepaliveSlot, slot);
325                    }
326                    onPacketKeepaliveEvent(slot, mStartKeepaliveError);
327                }
328
329                @Override
330                public void stopPacketKeepalive(Message msg) {
331                    onPacketKeepaliveEvent(msg.arg1, mStopKeepaliveError);
332                }
333
334                @Override
335                public void networkStatus(int status, String redirectUrl) {
336                    mRedirectUrl = redirectUrl;
337                    mNetworkStatusReceived.open();
338                }
339
340                @Override
341                protected void preventAutomaticReconnect() {
342                    mPreventReconnectReceived.open();
343                }
344            };
345            // Waits for the NetworkAgent to be registered, which includes the creation of the
346            // NetworkMonitor.
347            mService.waitForIdle();
348            mWrappedNetworkMonitor = mService.getLastCreatedWrappedNetworkMonitor();
349        }
350
351        public void waitForIdle(int timeoutMs) {
352            waitForIdleHandler(mHandlerThread, timeoutMs);
353        }
354
355        public void waitForIdle() {
356            waitForIdle(TIMEOUT_MS);
357        }
358
359        public void adjustScore(int change) {
360            mScore += change;
361            mNetworkAgent.sendNetworkScore(mScore);
362        }
363
364        public void addCapability(int capability) {
365            mNetworkCapabilities.addCapability(capability);
366            mNetworkAgent.sendNetworkCapabilities(mNetworkCapabilities);
367        }
368
369        public void removeCapability(int capability) {
370            mNetworkCapabilities.removeCapability(capability);
371            mNetworkAgent.sendNetworkCapabilities(mNetworkCapabilities);
372        }
373
374        public void setSignalStrength(int signalStrength) {
375            mNetworkCapabilities.setSignalStrength(signalStrength);
376            mNetworkAgent.sendNetworkCapabilities(mNetworkCapabilities);
377        }
378
379        public void setNetworkSpecifier(NetworkSpecifier networkSpecifier) {
380            mNetworkCapabilities.setNetworkSpecifier(networkSpecifier);
381            mNetworkAgent.sendNetworkCapabilities(mNetworkCapabilities);
382        }
383
384        public void connectWithoutInternet() {
385            mNetworkInfo.setDetailedState(DetailedState.CONNECTED, null, null);
386            mNetworkAgent.sendNetworkInfo(mNetworkInfo);
387        }
388
389        /**
390         * Transition this NetworkAgent to CONNECTED state with NET_CAPABILITY_INTERNET.
391         * @param validated Indicate if network should pretend to be validated.
392         */
393        public void connect(boolean validated) {
394            assertEquals("MockNetworkAgents can only be connected once",
395                    mNetworkInfo.getDetailedState(), DetailedState.IDLE);
396            assertFalse(mNetworkCapabilities.hasCapability(NET_CAPABILITY_INTERNET));
397
398            NetworkCallback callback = null;
399            final ConditionVariable validatedCv = new ConditionVariable();
400            if (validated) {
401                mWrappedNetworkMonitor.gen204ProbeResult = 204;
402                NetworkRequest request = new NetworkRequest.Builder()
403                        .addTransportType(mNetworkCapabilities.getTransportTypes()[0])
404                        .build();
405                callback = new NetworkCallback() {
406                    public void onCapabilitiesChanged(Network network,
407                            NetworkCapabilities networkCapabilities) {
408                        if (network.equals(getNetwork()) &&
409                            networkCapabilities.hasCapability(NET_CAPABILITY_VALIDATED)) {
410                            validatedCv.open();
411                        }
412                    }
413                };
414                mCm.registerNetworkCallback(request, callback);
415            }
416            addCapability(NET_CAPABILITY_INTERNET);
417
418            connectWithoutInternet();
419
420            if (validated) {
421                // Wait for network to validate.
422                waitFor(validatedCv);
423                mWrappedNetworkMonitor.gen204ProbeResult = 500;
424            }
425
426            if (callback != null) mCm.unregisterNetworkCallback(callback);
427        }
428
429        public void connectWithCaptivePortal(String redirectUrl) {
430            mWrappedNetworkMonitor.gen204ProbeResult = 200;
431            mWrappedNetworkMonitor.gen204ProbeRedirectUrl = redirectUrl;
432            connect(false);
433        }
434
435        public void suspend() {
436            mNetworkInfo.setDetailedState(DetailedState.SUSPENDED, null, null);
437            mNetworkAgent.sendNetworkInfo(mNetworkInfo);
438        }
439
440        public void disconnect() {
441            mNetworkInfo.setDetailedState(DetailedState.DISCONNECTED, null, null);
442            mNetworkAgent.sendNetworkInfo(mNetworkInfo);
443        }
444
445        public Network getNetwork() {
446            return new Network(mNetworkAgent.netId);
447        }
448
449        public ConditionVariable getPreventReconnectReceived() {
450            return mPreventReconnectReceived;
451        }
452
453        public ConditionVariable getDisconnectedCV() {
454            return mDisconnected;
455        }
456
457        public WrappedNetworkMonitor getWrappedNetworkMonitor() {
458            return mWrappedNetworkMonitor;
459        }
460
461        public void sendLinkProperties(LinkProperties lp) {
462            mNetworkAgent.sendLinkProperties(lp);
463        }
464
465        public void setStartKeepaliveError(int error) {
466            mStartKeepaliveError = error;
467        }
468
469        public void setStopKeepaliveError(int error) {
470            mStopKeepaliveError = error;
471        }
472
473        public void setExpectedKeepaliveSlot(Integer slot) {
474            mExpectedKeepaliveSlot = slot;
475        }
476
477        public String waitForRedirectUrl() {
478            assertTrue(mNetworkStatusReceived.block(TIMEOUT_MS));
479            return mRedirectUrl;
480        }
481    }
482
483    /**
484     * A NetworkFactory that allows tests to wait until any in-flight NetworkRequest add or remove
485     * operations have been processed. Before ConnectivityService can add or remove any requests,
486     * the factory must be told to expect those operations by calling expectAddRequests or
487     * expectRemoveRequests.
488     */
489    private static class MockNetworkFactory extends NetworkFactory {
490        private final ConditionVariable mNetworkStartedCV = new ConditionVariable();
491        private final ConditionVariable mNetworkStoppedCV = new ConditionVariable();
492        private final AtomicBoolean mNetworkStarted = new AtomicBoolean(false);
493
494        // Used to expect that requests be removed or added on a separate thread, without sleeping.
495        // Callers can call either expectAddRequests() or expectRemoveRequests() exactly once, then
496        // cause some other thread to add or remove requests, then call waitForRequests(). We can
497        // either expect requests to be added or removed, but not both, because CountDownLatch can
498        // only count in one direction.
499        private CountDownLatch mExpectations;
500
501        // Whether we are currently expecting requests to be added or removed. Valid only if
502        // mExpectations is non-null.
503        private boolean mExpectingAdditions;
504
505        public MockNetworkFactory(Looper looper, Context context, String logTag,
506                NetworkCapabilities filter) {
507            super(looper, context, logTag, filter);
508        }
509
510        public int getMyRequestCount() {
511            return getRequestCount();
512        }
513
514        protected void startNetwork() {
515            mNetworkStarted.set(true);
516            mNetworkStartedCV.open();
517        }
518
519        protected void stopNetwork() {
520            mNetworkStarted.set(false);
521            mNetworkStoppedCV.open();
522        }
523
524        public boolean getMyStartRequested() {
525            return mNetworkStarted.get();
526        }
527
528        public ConditionVariable getNetworkStartedCV() {
529            mNetworkStartedCV.close();
530            return mNetworkStartedCV;
531        }
532
533        public ConditionVariable getNetworkStoppedCV() {
534            mNetworkStoppedCV.close();
535            return mNetworkStoppedCV;
536        }
537
538        @Override
539        protected void handleAddRequest(NetworkRequest request, int score) {
540            // If we're expecting anything, we must be expecting additions.
541            if (mExpectations != null && !mExpectingAdditions) {
542                fail("Can't add requests while expecting requests to be removed");
543            }
544
545            // Add the request.
546            super.handleAddRequest(request, score);
547
548            // Reduce the number of request additions we're waiting for.
549            if (mExpectingAdditions) {
550                assertTrue("Added more requests than expected", mExpectations.getCount() > 0);
551                mExpectations.countDown();
552            }
553        }
554
555        @Override
556        protected void handleRemoveRequest(NetworkRequest request) {
557            // If we're expecting anything, we must be expecting removals.
558            if (mExpectations != null && mExpectingAdditions) {
559                fail("Can't remove requests while expecting requests to be added");
560            }
561
562            // Remove the request.
563            super.handleRemoveRequest(request);
564
565            // Reduce the number of request removals we're waiting for.
566            if (!mExpectingAdditions) {
567                assertTrue("Removed more requests than expected", mExpectations.getCount() > 0);
568                mExpectations.countDown();
569            }
570        }
571
572        private void assertNoExpectations() {
573            if (mExpectations != null) {
574                fail("Can't add expectation, " + mExpectations.getCount() + " already pending");
575            }
576        }
577
578        // Expects that count requests will be added.
579        public void expectAddRequests(final int count) {
580            assertNoExpectations();
581            mExpectingAdditions = true;
582            mExpectations = new CountDownLatch(count);
583        }
584
585        // Expects that count requests will be removed.
586        public void expectRemoveRequests(final int count) {
587            assertNoExpectations();
588            mExpectingAdditions = false;
589            mExpectations = new CountDownLatch(count);
590        }
591
592        // Waits for the expected request additions or removals to happen within a timeout.
593        public void waitForRequests() throws InterruptedException {
594            assertNotNull("Nothing to wait for", mExpectations);
595            mExpectations.await(TIMEOUT_MS, TimeUnit.MILLISECONDS);
596            final long count = mExpectations.getCount();
597            final String msg = count + " requests still not " +
598                    (mExpectingAdditions ? "added" : "removed") +
599                    " after " + TIMEOUT_MS + " ms";
600            assertEquals(msg, 0, count);
601            mExpectations = null;
602        }
603
604        public void waitForNetworkRequests(final int count) throws InterruptedException {
605            waitForRequests();
606            assertEquals(count, getMyRequestCount());
607        }
608    }
609
610    private class FakeWakeupMessage extends WakeupMessage {
611        private static final int UNREASONABLY_LONG_WAIT = 1000;
612
613        public FakeWakeupMessage(Context context, Handler handler, String cmdName, int cmd) {
614            super(context, handler, cmdName, cmd);
615        }
616
617        public FakeWakeupMessage(Context context, Handler handler, String cmdName, int cmd,
618                int arg1, int arg2, Object obj) {
619            super(context, handler, cmdName, cmd, arg1, arg2, obj);
620        }
621
622        @Override
623        public void schedule(long when) {
624            long delayMs = when - SystemClock.elapsedRealtime();
625            if (delayMs < 0) delayMs = 0;
626            if (delayMs > UNREASONABLY_LONG_WAIT) {
627                fail("Attempting to send msg more than " + UNREASONABLY_LONG_WAIT +
628                        "ms into the future: " + delayMs);
629            }
630            Message msg = mHandler.obtainMessage(mCmd, mArg1, mArg2, mObj);
631            mHandler.sendMessageDelayed(msg, delayMs);
632        }
633
634        @Override
635        public void cancel() {
636            mHandler.removeMessages(mCmd, mObj);
637        }
638
639        @Override
640        public void onAlarm() {
641            throw new AssertionError("Should never happen. Update this fake.");
642        }
643    }
644
645    // NetworkMonitor implementation allowing overriding of Internet connectivity probe result.
646    private class WrappedNetworkMonitor extends NetworkMonitor {
647        // HTTP response code fed back to NetworkMonitor for Internet connectivity probe.
648        public int gen204ProbeResult = 500;
649        public String gen204ProbeRedirectUrl = null;
650
651        public WrappedNetworkMonitor(Context context, Handler handler,
652                NetworkAgentInfo networkAgentInfo, NetworkRequest defaultRequest,
653                IpConnectivityLog log) {
654            super(context, handler, networkAgentInfo, defaultRequest, log);
655        }
656
657        @Override
658        protected CaptivePortalProbeResult isCaptivePortal() {
659            if (!mIsCaptivePortalCheckEnabled) { return new CaptivePortalProbeResult(204); }
660            return new CaptivePortalProbeResult(gen204ProbeResult, gen204ProbeRedirectUrl, null);
661        }
662    }
663
664    private class WrappedMultinetworkPolicyTracker extends MultinetworkPolicyTracker {
665        public volatile boolean configRestrictsAvoidBadWifi;
666        public volatile int configMeteredMultipathPreference;
667
668        public WrappedMultinetworkPolicyTracker(Context c, Handler h, Runnable r) {
669            super(c, h, r);
670        }
671
672        @Override
673        public boolean configRestrictsAvoidBadWifi() {
674            return configRestrictsAvoidBadWifi;
675        }
676
677        @Override
678        public int configMeteredMultipathPreference() {
679            return configMeteredMultipathPreference;
680        }
681    }
682
683    private class WrappedConnectivityService extends ConnectivityService {
684        public WrappedMultinetworkPolicyTracker wrappedMultinetworkPolicyTracker;
685        private WrappedNetworkMonitor mLastCreatedNetworkMonitor;
686        private MockableSystemProperties mSystemProperties;
687
688        public WrappedConnectivityService(Context context, INetworkManagementService netManager,
689                INetworkStatsService statsService, INetworkPolicyManager policyManager,
690                IpConnectivityLog log) {
691            super(context, netManager, statsService, policyManager, log);
692            mLingerDelayMs = TEST_LINGER_DELAY_MS;
693        }
694
695        @Override
696        protected MockableSystemProperties getSystemProperties() {
697            // Minimal approach to overriding system properties: let most calls fall through to real
698            // device values, and only override ones values that are important to this test.
699            mSystemProperties = spy(new MockableSystemProperties());
700            when(mSystemProperties.getInt("net.tcp.default_init_rwnd", 0)).thenReturn(0);
701            when(mSystemProperties.getBoolean("ro.radio.noril", false)).thenReturn(false);
702            return mSystemProperties;
703        }
704
705        @Override
706        protected int reserveNetId() {
707            while (true) {
708                final int netId = super.reserveNetId();
709
710                // Don't overlap test NetIDs with real NetIDs as binding sockets to real networks
711                // can have odd side-effects, like network validations succeeding.
712                final Network[] networks = ConnectivityManager.from(getContext()).getAllNetworks();
713                boolean overlaps = false;
714                for (Network network : networks) {
715                    if (netId == network.netId) {
716                        overlaps = true;
717                        break;
718                    }
719                }
720                if (overlaps) continue;
721
722                return netId;
723            }
724        }
725
726        @Override
727        public NetworkMonitor createNetworkMonitor(Context context, Handler handler,
728                NetworkAgentInfo nai, NetworkRequest defaultRequest) {
729            final WrappedNetworkMonitor monitor = new WrappedNetworkMonitor(
730                    context, handler, nai, defaultRequest, mock(IpConnectivityLog.class));
731            mLastCreatedNetworkMonitor = monitor;
732            return monitor;
733        }
734
735        @Override
736        public MultinetworkPolicyTracker createMultinetworkPolicyTracker(
737                Context c, Handler h, Runnable r) {
738            final WrappedMultinetworkPolicyTracker tracker = new WrappedMultinetworkPolicyTracker(c, h, r);
739            return tracker;
740        }
741
742        public WrappedMultinetworkPolicyTracker getMultinetworkPolicyTracker() {
743            return (WrappedMultinetworkPolicyTracker) mMultinetworkPolicyTracker;
744        }
745
746        @Override
747        public WakeupMessage makeWakeupMessage(
748                Context context, Handler handler, String cmdName, int cmd, Object obj) {
749            return new FakeWakeupMessage(context, handler, cmdName, cmd, 0, 0, obj);
750        }
751
752        public WrappedNetworkMonitor getLastCreatedWrappedNetworkMonitor() {
753            return mLastCreatedNetworkMonitor;
754        }
755
756        public void waitForIdle(int timeoutMs) {
757            waitForIdleHandler(mHandlerThread, timeoutMs);
758        }
759
760        public void waitForIdle() {
761            waitForIdle(TIMEOUT_MS);
762        }
763    }
764
765    /**
766     * Wait up to TIMEOUT_MS for {@code conditionVariable} to open.
767     * Fails if TIMEOUT_MS goes by before {@code conditionVariable} opens.
768     */
769    static private void waitFor(ConditionVariable conditionVariable) {
770        assertTrue(conditionVariable.block(TIMEOUT_MS));
771    }
772
773    @Override
774    public void setUp() throws Exception {
775        super.setUp();
776
777        // InstrumentationTestRunner prepares a looper, but AndroidJUnitRunner does not.
778        // http://b/25897652 .
779        if (Looper.myLooper() == null) {
780            Looper.prepare();
781        }
782
783        mServiceContext = new MockContext(getContext());
784        LocalServices.removeServiceForTest(NetworkPolicyManagerInternal.class);
785        LocalServices.addService(
786                NetworkPolicyManagerInternal.class, mock(NetworkPolicyManagerInternal.class));
787        mService = new WrappedConnectivityService(mServiceContext,
788                mock(INetworkManagementService.class),
789                mock(INetworkStatsService.class),
790                mock(INetworkPolicyManager.class),
791                mock(IpConnectivityLog.class));
792
793        mService.systemReady();
794        mCm = new WrappedConnectivityManager(getContext(), mService);
795        mCm.bindProcessToNetwork(null);
796
797        // Ensure that the default setting for Captive Portals is used for most tests
798        setCaptivePortalMode(Settings.Global.CAPTIVE_PORTAL_MODE_PROMPT);
799    }
800
801    public void tearDown() throws Exception {
802        setMobileDataAlwaysOn(false);
803        if (mCellNetworkAgent != null) { mCellNetworkAgent.disconnect(); }
804        if (mWiFiNetworkAgent != null) { mWiFiNetworkAgent.disconnect(); }
805        mCellNetworkAgent = mWiFiNetworkAgent = null;
806        super.tearDown();
807    }
808
809    private int transportToLegacyType(int transport) {
810        switch (transport) {
811            case TRANSPORT_ETHERNET:
812                return TYPE_ETHERNET;
813            case TRANSPORT_WIFI:
814                return TYPE_WIFI;
815            case TRANSPORT_CELLULAR:
816                return TYPE_MOBILE;
817            default:
818                throw new IllegalStateException("Unknown transport " + transport);
819        }
820    }
821
822    private void verifyActiveNetwork(int transport) {
823        // Test getActiveNetworkInfo()
824        assertNotNull(mCm.getActiveNetworkInfo());
825        assertEquals(transportToLegacyType(transport), mCm.getActiveNetworkInfo().getType());
826        // Test getActiveNetwork()
827        assertNotNull(mCm.getActiveNetwork());
828        assertEquals(mCm.getActiveNetwork(), mCm.getActiveNetworkForUid(Process.myUid()));
829        switch (transport) {
830            case TRANSPORT_WIFI:
831                assertEquals(mCm.getActiveNetwork(), mWiFiNetworkAgent.getNetwork());
832                break;
833            case TRANSPORT_CELLULAR:
834                assertEquals(mCm.getActiveNetwork(), mCellNetworkAgent.getNetwork());
835                break;
836            default:
837                throw new IllegalStateException("Unknown transport" + transport);
838        }
839        // Test getNetworkInfo(Network)
840        assertNotNull(mCm.getNetworkInfo(mCm.getActiveNetwork()));
841        assertEquals(transportToLegacyType(transport), mCm.getNetworkInfo(mCm.getActiveNetwork()).getType());
842        // Test getNetworkCapabilities(Network)
843        assertNotNull(mCm.getNetworkCapabilities(mCm.getActiveNetwork()));
844        assertTrue(mCm.getNetworkCapabilities(mCm.getActiveNetwork()).hasTransport(transport));
845    }
846
847    private void verifyNoNetwork() {
848        // Test getActiveNetworkInfo()
849        assertNull(mCm.getActiveNetworkInfo());
850        // Test getActiveNetwork()
851        assertNull(mCm.getActiveNetwork());
852        assertNull(mCm.getActiveNetworkForUid(Process.myUid()));
853        // Test getAllNetworks()
854        assertEquals(0, mCm.getAllNetworks().length);
855    }
856
857    /**
858     * Return a ConditionVariable that opens when {@code count} numbers of CONNECTIVITY_ACTION
859     * broadcasts are received.
860     */
861    private ConditionVariable waitForConnectivityBroadcasts(final int count) {
862        final ConditionVariable cv = new ConditionVariable();
863        mServiceContext.registerReceiver(new BroadcastReceiver() {
864                    private int remaining = count;
865                    public void onReceive(Context context, Intent intent) {
866                        if (--remaining == 0) {
867                            cv.open();
868                            mServiceContext.unregisterReceiver(this);
869                        }
870                    }
871                }, new IntentFilter(CONNECTIVITY_ACTION));
872        return cv;
873    }
874
875    public void testNetworkTypes() {
876        // Ensure that our mocks for the networkAttributes config variable work as expected. If they
877        // don't, then tests that depend on CONNECTIVITY_ACTION broadcasts for these network types
878        // will fail. Failing here is much easier to debug.
879        assertTrue(mCm.isNetworkSupported(TYPE_WIFI));
880        assertTrue(mCm.isNetworkSupported(TYPE_MOBILE));
881    }
882
883    @SmallTest
884    public void testLingering() throws Exception {
885        verifyNoNetwork();
886        mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
887        mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
888        assertNull(mCm.getActiveNetworkInfo());
889        assertNull(mCm.getActiveNetwork());
890        // Test bringing up validated cellular.
891        ConditionVariable cv = waitForConnectivityBroadcasts(1);
892        mCellNetworkAgent.connect(true);
893        waitFor(cv);
894        verifyActiveNetwork(TRANSPORT_CELLULAR);
895        assertEquals(2, mCm.getAllNetworks().length);
896        assertTrue(mCm.getAllNetworks()[0].equals(mCm.getActiveNetwork()) ||
897                mCm.getAllNetworks()[1].equals(mCm.getActiveNetwork()));
898        assertTrue(mCm.getAllNetworks()[0].equals(mWiFiNetworkAgent.getNetwork()) ||
899                mCm.getAllNetworks()[1].equals(mWiFiNetworkAgent.getNetwork()));
900        // Test bringing up validated WiFi.
901        cv = waitForConnectivityBroadcasts(2);
902        mWiFiNetworkAgent.connect(true);
903        waitFor(cv);
904        verifyActiveNetwork(TRANSPORT_WIFI);
905        assertEquals(2, mCm.getAllNetworks().length);
906        assertTrue(mCm.getAllNetworks()[0].equals(mCm.getActiveNetwork()) ||
907                mCm.getAllNetworks()[1].equals(mCm.getActiveNetwork()));
908        assertTrue(mCm.getAllNetworks()[0].equals(mCellNetworkAgent.getNetwork()) ||
909                mCm.getAllNetworks()[1].equals(mCellNetworkAgent.getNetwork()));
910        // Test cellular linger timeout.
911        waitFor(mCellNetworkAgent.getDisconnectedCV());
912        mService.waitForIdle();
913        assertEquals(1, mCm.getAllNetworks().length);
914        verifyActiveNetwork(TRANSPORT_WIFI);
915        assertEquals(1, mCm.getAllNetworks().length);
916        assertEquals(mCm.getAllNetworks()[0], mCm.getActiveNetwork());
917        // Test WiFi disconnect.
918        cv = waitForConnectivityBroadcasts(1);
919        mWiFiNetworkAgent.disconnect();
920        waitFor(cv);
921        verifyNoNetwork();
922    }
923
924    @SmallTest
925    public void testValidatedCellularOutscoresUnvalidatedWiFi() throws Exception {
926        // Test bringing up unvalidated WiFi
927        mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
928        ConditionVariable cv = waitForConnectivityBroadcasts(1);
929        mWiFiNetworkAgent.connect(false);
930        waitFor(cv);
931        verifyActiveNetwork(TRANSPORT_WIFI);
932        // Test bringing up unvalidated cellular
933        mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
934        mCellNetworkAgent.connect(false);
935        mService.waitForIdle();
936        verifyActiveNetwork(TRANSPORT_WIFI);
937        // Test cellular disconnect.
938        mCellNetworkAgent.disconnect();
939        mService.waitForIdle();
940        verifyActiveNetwork(TRANSPORT_WIFI);
941        // Test bringing up validated cellular
942        mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
943        cv = waitForConnectivityBroadcasts(2);
944        mCellNetworkAgent.connect(true);
945        waitFor(cv);
946        verifyActiveNetwork(TRANSPORT_CELLULAR);
947        // Test cellular disconnect.
948        cv = waitForConnectivityBroadcasts(2);
949        mCellNetworkAgent.disconnect();
950        waitFor(cv);
951        verifyActiveNetwork(TRANSPORT_WIFI);
952        // Test WiFi disconnect.
953        cv = waitForConnectivityBroadcasts(1);
954        mWiFiNetworkAgent.disconnect();
955        waitFor(cv);
956        verifyNoNetwork();
957    }
958
959    @SmallTest
960    public void testUnvalidatedWifiOutscoresUnvalidatedCellular() throws Exception {
961        // Test bringing up unvalidated cellular.
962        mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
963        ConditionVariable cv = waitForConnectivityBroadcasts(1);
964        mCellNetworkAgent.connect(false);
965        waitFor(cv);
966        verifyActiveNetwork(TRANSPORT_CELLULAR);
967        // Test bringing up unvalidated WiFi.
968        mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
969        cv = waitForConnectivityBroadcasts(2);
970        mWiFiNetworkAgent.connect(false);
971        waitFor(cv);
972        verifyActiveNetwork(TRANSPORT_WIFI);
973        // Test WiFi disconnect.
974        cv = waitForConnectivityBroadcasts(2);
975        mWiFiNetworkAgent.disconnect();
976        waitFor(cv);
977        verifyActiveNetwork(TRANSPORT_CELLULAR);
978        // Test cellular disconnect.
979        cv = waitForConnectivityBroadcasts(1);
980        mCellNetworkAgent.disconnect();
981        waitFor(cv);
982        verifyNoNetwork();
983    }
984
985    @SmallTest
986    public void testUnlingeringDoesNotValidate() throws Exception {
987        // Test bringing up unvalidated WiFi.
988        mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
989        ConditionVariable cv = waitForConnectivityBroadcasts(1);
990        mWiFiNetworkAgent.connect(false);
991        waitFor(cv);
992        verifyActiveNetwork(TRANSPORT_WIFI);
993        assertFalse(mCm.getNetworkCapabilities(mWiFiNetworkAgent.getNetwork()).hasCapability(
994                NET_CAPABILITY_VALIDATED));
995        // Test bringing up validated cellular.
996        mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
997        cv = waitForConnectivityBroadcasts(2);
998        mCellNetworkAgent.connect(true);
999        waitFor(cv);
1000        verifyActiveNetwork(TRANSPORT_CELLULAR);
1001        assertFalse(mCm.getNetworkCapabilities(mWiFiNetworkAgent.getNetwork()).hasCapability(
1002                NET_CAPABILITY_VALIDATED));
1003        // Test cellular disconnect.
1004        cv = waitForConnectivityBroadcasts(2);
1005        mCellNetworkAgent.disconnect();
1006        waitFor(cv);
1007        verifyActiveNetwork(TRANSPORT_WIFI);
1008        // Unlingering a network should not cause it to be marked as validated.
1009        assertFalse(mCm.getNetworkCapabilities(mWiFiNetworkAgent.getNetwork()).hasCapability(
1010                NET_CAPABILITY_VALIDATED));
1011    }
1012
1013    @SmallTest
1014    public void testCellularOutscoresWeakWifi() throws Exception {
1015        // Test bringing up validated cellular.
1016        mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
1017        ConditionVariable cv = waitForConnectivityBroadcasts(1);
1018        mCellNetworkAgent.connect(true);
1019        waitFor(cv);
1020        verifyActiveNetwork(TRANSPORT_CELLULAR);
1021        // Test bringing up validated WiFi.
1022        mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
1023        cv = waitForConnectivityBroadcasts(2);
1024        mWiFiNetworkAgent.connect(true);
1025        waitFor(cv);
1026        verifyActiveNetwork(TRANSPORT_WIFI);
1027        // Test WiFi getting really weak.
1028        cv = waitForConnectivityBroadcasts(2);
1029        mWiFiNetworkAgent.adjustScore(-11);
1030        waitFor(cv);
1031        verifyActiveNetwork(TRANSPORT_CELLULAR);
1032        // Test WiFi restoring signal strength.
1033        cv = waitForConnectivityBroadcasts(2);
1034        mWiFiNetworkAgent.adjustScore(11);
1035        waitFor(cv);
1036        verifyActiveNetwork(TRANSPORT_WIFI);
1037    }
1038
1039    @SmallTest
1040    public void testReapingNetwork() throws Exception {
1041        // Test bringing up WiFi without NET_CAPABILITY_INTERNET.
1042        // Expect it to be torn down immediately because it satisfies no requests.
1043        mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
1044        ConditionVariable cv = mWiFiNetworkAgent.getDisconnectedCV();
1045        mWiFiNetworkAgent.connectWithoutInternet();
1046        waitFor(cv);
1047        // Test bringing up cellular without NET_CAPABILITY_INTERNET.
1048        // Expect it to be torn down immediately because it satisfies no requests.
1049        mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
1050        cv = mCellNetworkAgent.getDisconnectedCV();
1051        mCellNetworkAgent.connectWithoutInternet();
1052        waitFor(cv);
1053        // Test bringing up validated WiFi.
1054        mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
1055        cv = waitForConnectivityBroadcasts(1);
1056        mWiFiNetworkAgent.connect(true);
1057        waitFor(cv);
1058        verifyActiveNetwork(TRANSPORT_WIFI);
1059        // Test bringing up unvalidated cellular.
1060        // Expect it to be torn down because it could never be the highest scoring network
1061        // satisfying the default request even if it validated.
1062        mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
1063        cv = mCellNetworkAgent.getDisconnectedCV();
1064        mCellNetworkAgent.connect(false);
1065        waitFor(cv);
1066        verifyActiveNetwork(TRANSPORT_WIFI);
1067        cv = mWiFiNetworkAgent.getDisconnectedCV();
1068        mWiFiNetworkAgent.disconnect();
1069        waitFor(cv);
1070    }
1071
1072    @SmallTest
1073    public void testCellularFallback() throws Exception {
1074        // Test bringing up validated cellular.
1075        mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
1076        ConditionVariable cv = waitForConnectivityBroadcasts(1);
1077        mCellNetworkAgent.connect(true);
1078        waitFor(cv);
1079        verifyActiveNetwork(TRANSPORT_CELLULAR);
1080        // Test bringing up validated WiFi.
1081        mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
1082        cv = waitForConnectivityBroadcasts(2);
1083        mWiFiNetworkAgent.connect(true);
1084        waitFor(cv);
1085        verifyActiveNetwork(TRANSPORT_WIFI);
1086        // Reevaluate WiFi (it'll instantly fail DNS).
1087        cv = waitForConnectivityBroadcasts(2);
1088        assertTrue(mCm.getNetworkCapabilities(mWiFiNetworkAgent.getNetwork()).hasCapability(
1089                NET_CAPABILITY_VALIDATED));
1090        mCm.reportBadNetwork(mWiFiNetworkAgent.getNetwork());
1091        // Should quickly fall back to Cellular.
1092        waitFor(cv);
1093        assertFalse(mCm.getNetworkCapabilities(mWiFiNetworkAgent.getNetwork()).hasCapability(
1094                NET_CAPABILITY_VALIDATED));
1095        verifyActiveNetwork(TRANSPORT_CELLULAR);
1096        // Reevaluate cellular (it'll instantly fail DNS).
1097        cv = waitForConnectivityBroadcasts(2);
1098        assertTrue(mCm.getNetworkCapabilities(mCellNetworkAgent.getNetwork()).hasCapability(
1099                NET_CAPABILITY_VALIDATED));
1100        mCm.reportBadNetwork(mCellNetworkAgent.getNetwork());
1101        // Should quickly fall back to WiFi.
1102        waitFor(cv);
1103        assertFalse(mCm.getNetworkCapabilities(mCellNetworkAgent.getNetwork()).hasCapability(
1104                NET_CAPABILITY_VALIDATED));
1105        assertFalse(mCm.getNetworkCapabilities(mWiFiNetworkAgent.getNetwork()).hasCapability(
1106                NET_CAPABILITY_VALIDATED));
1107        verifyActiveNetwork(TRANSPORT_WIFI);
1108    }
1109
1110    @SmallTest
1111    public void testWiFiFallback() throws Exception {
1112        // Test bringing up unvalidated WiFi.
1113        mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
1114        ConditionVariable cv = waitForConnectivityBroadcasts(1);
1115        mWiFiNetworkAgent.connect(false);
1116        waitFor(cv);
1117        verifyActiveNetwork(TRANSPORT_WIFI);
1118        // Test bringing up validated cellular.
1119        mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
1120        cv = waitForConnectivityBroadcasts(2);
1121        mCellNetworkAgent.connect(true);
1122        waitFor(cv);
1123        verifyActiveNetwork(TRANSPORT_CELLULAR);
1124        // Reevaluate cellular (it'll instantly fail DNS).
1125        cv = waitForConnectivityBroadcasts(2);
1126        assertTrue(mCm.getNetworkCapabilities(mCellNetworkAgent.getNetwork()).hasCapability(
1127                NET_CAPABILITY_VALIDATED));
1128        mCm.reportBadNetwork(mCellNetworkAgent.getNetwork());
1129        // Should quickly fall back to WiFi.
1130        waitFor(cv);
1131        assertFalse(mCm.getNetworkCapabilities(mCellNetworkAgent.getNetwork()).hasCapability(
1132                NET_CAPABILITY_VALIDATED));
1133        verifyActiveNetwork(TRANSPORT_WIFI);
1134    }
1135
1136    enum CallbackState {
1137        NONE,
1138        AVAILABLE,
1139        NETWORK_CAPABILITIES,
1140        LINK_PROPERTIES,
1141        SUSPENDED,
1142        LOSING,
1143        LOST,
1144        UNAVAILABLE
1145    }
1146
1147    private static class CallbackInfo {
1148        public final CallbackState state;
1149        public final Network network;
1150        public final Object arg;
1151        public CallbackInfo(CallbackState s, Network n, Object o) {
1152            state = s; network = n; arg = o;
1153        }
1154        public String toString() {
1155            return String.format("%s (%s) (%s)", state, network, arg);
1156        }
1157        @Override
1158        public boolean equals(Object o) {
1159            if (!(o instanceof CallbackInfo)) return false;
1160            // Ignore timeMs, since it's unpredictable.
1161            CallbackInfo other = (CallbackInfo) o;
1162            return (state == other.state) && Objects.equals(network, other.network);
1163        }
1164        @Override
1165        public int hashCode() {
1166            return Objects.hash(state, network);
1167        }
1168    }
1169
1170    /**
1171     * Utility NetworkCallback for testing. The caller must explicitly test for all the callbacks
1172     * this class receives, by calling expectCallback() exactly once each time a callback is
1173     * received. assertNoCallback may be called at any time.
1174     */
1175    private class TestNetworkCallback extends NetworkCallback {
1176        // Chosen to be much less than the linger timeout. This ensures that we can distinguish
1177        // between a LOST callback that arrives immediately and a LOST callback that arrives after
1178        // the linger timeout.
1179        private final static int TIMEOUT_MS = 100;
1180
1181        private final LinkedBlockingQueue<CallbackInfo> mCallbacks = new LinkedBlockingQueue<>();
1182
1183        protected void setLastCallback(CallbackState state, Network network, Object o) {
1184            mCallbacks.offer(new CallbackInfo(state, network, o));
1185        }
1186
1187        @Override
1188        public void onAvailable(Network network) {
1189            setLastCallback(CallbackState.AVAILABLE, network, null);
1190        }
1191
1192        @Override
1193        public void onCapabilitiesChanged(Network network, NetworkCapabilities netCap) {
1194            setLastCallback(CallbackState.NETWORK_CAPABILITIES, network, netCap);
1195        }
1196
1197        @Override
1198        public void onLinkPropertiesChanged(Network network, LinkProperties linkProp) {
1199            setLastCallback(CallbackState.LINK_PROPERTIES, network, linkProp);
1200        }
1201
1202        @Override
1203        public void onUnavailable() {
1204            setLastCallback(CallbackState.UNAVAILABLE, null, null);
1205        }
1206
1207        @Override
1208        public void onNetworkSuspended(Network network) {
1209            setLastCallback(CallbackState.SUSPENDED, network, null);
1210        }
1211
1212        @Override
1213        public void onLosing(Network network, int maxMsToLive) {
1214            setLastCallback(CallbackState.LOSING, network, maxMsToLive /* autoboxed int */);
1215        }
1216
1217        @Override
1218        public void onLost(Network network) {
1219            setLastCallback(CallbackState.LOST, network, null);
1220        }
1221
1222        CallbackInfo nextCallback(int timeoutMs) {
1223            CallbackInfo cb = null;
1224            try {
1225                cb = mCallbacks.poll(timeoutMs, TimeUnit.MILLISECONDS);
1226            } catch (InterruptedException e) {
1227            }
1228            if (cb == null) {
1229                // LinkedBlockingQueue.poll() returns null if it timeouts.
1230                fail("Did not receive callback after " + timeoutMs + "ms");
1231            }
1232            return cb;
1233        }
1234
1235        CallbackInfo expectCallback(CallbackState state, MockNetworkAgent agent, int timeoutMs) {
1236            final Network expectedNetwork = (agent != null) ? agent.getNetwork() : null;
1237            CallbackInfo expected = new CallbackInfo(state, expectedNetwork, 0);
1238            CallbackInfo actual = nextCallback(timeoutMs);
1239            assertEquals("Unexpected callback:", expected, actual);
1240
1241            if (state == CallbackState.LOSING) {
1242                String msg = String.format(
1243                        "Invalid linger time value %d, must be between %d and %d",
1244                        actual.arg, 0, TEST_LINGER_DELAY_MS);
1245                int maxMsToLive = (Integer) actual.arg;
1246                assertTrue(msg, 0 <= maxMsToLive && maxMsToLive <= TEST_LINGER_DELAY_MS);
1247            }
1248
1249            return actual;
1250        }
1251
1252        CallbackInfo expectCallback(CallbackState state, MockNetworkAgent agent) {
1253            return expectCallback(state, agent, TIMEOUT_MS);
1254        }
1255
1256        void expectAvailableCallbacks(MockNetworkAgent agent, boolean expectSuspended, int timeoutMs) {
1257            expectCallback(CallbackState.AVAILABLE, agent, timeoutMs);
1258            if (expectSuspended) {
1259                expectCallback(CallbackState.SUSPENDED, agent, timeoutMs);
1260            }
1261            expectCallback(CallbackState.NETWORK_CAPABILITIES, agent, timeoutMs);
1262            expectCallback(CallbackState.LINK_PROPERTIES, agent, timeoutMs);
1263        }
1264
1265        void expectAvailableCallbacks(MockNetworkAgent agent) {
1266            expectAvailableCallbacks(agent, false, TIMEOUT_MS);
1267        }
1268
1269        void expectAvailableAndSuspendedCallbacks(MockNetworkAgent agent) {
1270            expectAvailableCallbacks(agent, true, TIMEOUT_MS);
1271        }
1272
1273        void expectAvailableAndValidatedCallbacks(MockNetworkAgent agent) {
1274            expectAvailableCallbacks(agent, false, TIMEOUT_MS);
1275            expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, agent);
1276        }
1277
1278        void expectCapabilitiesWith(int capability, MockNetworkAgent agent) {
1279            CallbackInfo cbi = expectCallback(CallbackState.NETWORK_CAPABILITIES, agent);
1280            NetworkCapabilities nc = (NetworkCapabilities) cbi.arg;
1281            assertTrue(nc.hasCapability(capability));
1282        }
1283
1284        void expectCapabilitiesWithout(int capability, MockNetworkAgent agent) {
1285            CallbackInfo cbi = expectCallback(CallbackState.NETWORK_CAPABILITIES, agent);
1286            NetworkCapabilities nc = (NetworkCapabilities) cbi.arg;
1287            assertFalse(nc.hasCapability(capability));
1288        }
1289
1290        void assertNoCallback() {
1291            mService.waitForIdle();
1292            CallbackInfo c = mCallbacks.peek();
1293            assertNull("Unexpected callback: " + c, c);
1294        }
1295    }
1296
1297    // Can't be part of TestNetworkCallback because "cannot be declared static; static methods can
1298    // only be declared in a static or top level type".
1299    static void assertNoCallbacks(TestNetworkCallback ... callbacks) {
1300        for (TestNetworkCallback c : callbacks) {
1301            c.assertNoCallback();
1302        }
1303    }
1304
1305    @SmallTest
1306    public void testStateChangeNetworkCallbacks() throws Exception {
1307        final TestNetworkCallback genericNetworkCallback = new TestNetworkCallback();
1308        final TestNetworkCallback wifiNetworkCallback = new TestNetworkCallback();
1309        final TestNetworkCallback cellNetworkCallback = new TestNetworkCallback();
1310        final NetworkRequest genericRequest = new NetworkRequest.Builder()
1311                .clearCapabilities().build();
1312        final NetworkRequest wifiRequest = new NetworkRequest.Builder()
1313                .addTransportType(TRANSPORT_WIFI).build();
1314        final NetworkRequest cellRequest = new NetworkRequest.Builder()
1315                .addTransportType(TRANSPORT_CELLULAR).build();
1316        mCm.registerNetworkCallback(genericRequest, genericNetworkCallback);
1317        mCm.registerNetworkCallback(wifiRequest, wifiNetworkCallback);
1318        mCm.registerNetworkCallback(cellRequest, cellNetworkCallback);
1319
1320        // Test unvalidated networks
1321        ConditionVariable cv = waitForConnectivityBroadcasts(1);
1322        mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
1323        mCellNetworkAgent.connect(false);
1324        genericNetworkCallback.expectAvailableCallbacks(mCellNetworkAgent);
1325        cellNetworkCallback.expectAvailableCallbacks(mCellNetworkAgent);
1326        assertEquals(mCellNetworkAgent.getNetwork(), mCm.getActiveNetwork());
1327        waitFor(cv);
1328        assertNoCallbacks(genericNetworkCallback, wifiNetworkCallback, cellNetworkCallback);
1329
1330        // This should not trigger spurious onAvailable() callbacks, b/21762680.
1331        mCellNetworkAgent.adjustScore(-1);
1332        mService.waitForIdle();
1333        assertNoCallbacks(genericNetworkCallback, wifiNetworkCallback, cellNetworkCallback);
1334        assertEquals(mCellNetworkAgent.getNetwork(), mCm.getActiveNetwork());
1335
1336        cv = waitForConnectivityBroadcasts(2);
1337        mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
1338        mWiFiNetworkAgent.connect(false);
1339        genericNetworkCallback.expectAvailableCallbacks(mWiFiNetworkAgent);
1340        wifiNetworkCallback.expectAvailableCallbacks(mWiFiNetworkAgent);
1341        assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetwork());
1342        waitFor(cv);
1343        assertNoCallbacks(genericNetworkCallback, wifiNetworkCallback, cellNetworkCallback);
1344
1345        cv = waitForConnectivityBroadcasts(2);
1346        mWiFiNetworkAgent.disconnect();
1347        genericNetworkCallback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
1348        wifiNetworkCallback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
1349        cellNetworkCallback.assertNoCallback();
1350        waitFor(cv);
1351        assertNoCallbacks(genericNetworkCallback, wifiNetworkCallback, cellNetworkCallback);
1352
1353        cv = waitForConnectivityBroadcasts(1);
1354        mCellNetworkAgent.disconnect();
1355        genericNetworkCallback.expectCallback(CallbackState.LOST, mCellNetworkAgent);
1356        cellNetworkCallback.expectCallback(CallbackState.LOST, mCellNetworkAgent);
1357        waitFor(cv);
1358        assertNoCallbacks(genericNetworkCallback, wifiNetworkCallback, cellNetworkCallback);
1359
1360        // Test validated networks
1361        mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
1362        mCellNetworkAgent.connect(true);
1363        genericNetworkCallback.expectAvailableAndValidatedCallbacks(mCellNetworkAgent);
1364        cellNetworkCallback.expectAvailableAndValidatedCallbacks(mCellNetworkAgent);
1365        assertEquals(mCellNetworkAgent.getNetwork(), mCm.getActiveNetwork());
1366        assertNoCallbacks(genericNetworkCallback, wifiNetworkCallback, cellNetworkCallback);
1367
1368        // This should not trigger spurious onAvailable() callbacks, b/21762680.
1369        mCellNetworkAgent.adjustScore(-1);
1370        mService.waitForIdle();
1371        assertNoCallbacks(genericNetworkCallback, wifiNetworkCallback, cellNetworkCallback);
1372        assertEquals(mCellNetworkAgent.getNetwork(), mCm.getActiveNetwork());
1373
1374        mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
1375        mWiFiNetworkAgent.connect(true);
1376        genericNetworkCallback.expectAvailableCallbacks(mWiFiNetworkAgent);
1377        genericNetworkCallback.expectCallback(CallbackState.LOSING, mCellNetworkAgent);
1378        genericNetworkCallback.expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, mWiFiNetworkAgent);
1379        wifiNetworkCallback.expectAvailableAndValidatedCallbacks(mWiFiNetworkAgent);
1380        cellNetworkCallback.expectCallback(CallbackState.LOSING, mCellNetworkAgent);
1381        assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetwork());
1382        assertNoCallbacks(genericNetworkCallback, wifiNetworkCallback, cellNetworkCallback);
1383
1384        mWiFiNetworkAgent.disconnect();
1385        genericNetworkCallback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
1386        wifiNetworkCallback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
1387        assertNoCallbacks(genericNetworkCallback, wifiNetworkCallback, cellNetworkCallback);
1388
1389        mCellNetworkAgent.disconnect();
1390        genericNetworkCallback.expectCallback(CallbackState.LOST, mCellNetworkAgent);
1391        cellNetworkCallback.expectCallback(CallbackState.LOST, mCellNetworkAgent);
1392        assertNoCallbacks(genericNetworkCallback, wifiNetworkCallback, cellNetworkCallback);
1393    }
1394
1395    @SmallTest
1396    public void testMultipleLingering() {
1397        NetworkRequest request = new NetworkRequest.Builder()
1398                .clearCapabilities().addCapability(NET_CAPABILITY_NOT_METERED)
1399                .build();
1400        TestNetworkCallback callback = new TestNetworkCallback();
1401        mCm.registerNetworkCallback(request, callback);
1402
1403        TestNetworkCallback defaultCallback = new TestNetworkCallback();
1404        mCm.registerDefaultNetworkCallback(defaultCallback);
1405
1406        mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
1407        mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
1408        mEthernetNetworkAgent = new MockNetworkAgent(TRANSPORT_ETHERNET);
1409
1410        mCellNetworkAgent.addCapability(NET_CAPABILITY_NOT_METERED);
1411        mWiFiNetworkAgent.addCapability(NET_CAPABILITY_NOT_METERED);
1412        mEthernetNetworkAgent.addCapability(NET_CAPABILITY_NOT_METERED);
1413
1414        mCellNetworkAgent.connect(true);
1415        callback.expectAvailableAndValidatedCallbacks(mCellNetworkAgent);
1416        defaultCallback.expectAvailableAndValidatedCallbacks(mCellNetworkAgent);
1417        assertEquals(mCellNetworkAgent.getNetwork(), mCm.getActiveNetwork());
1418
1419        mWiFiNetworkAgent.connect(true);
1420        // We get AVAILABLE on wifi when wifi connects and satisfies our unmetered request.
1421        // We then get LOSING when wifi validates and cell is outscored.
1422        callback.expectAvailableCallbacks(mWiFiNetworkAgent);
1423        // TODO: Investigate sending validated before losing.
1424        callback.expectCallback(CallbackState.LOSING, mCellNetworkAgent);
1425        callback.expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, mWiFiNetworkAgent);
1426        defaultCallback.expectAvailableAndValidatedCallbacks(mWiFiNetworkAgent);
1427        assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetwork());
1428
1429        mEthernetNetworkAgent.connect(true);
1430        callback.expectAvailableCallbacks(mEthernetNetworkAgent);
1431        // TODO: Investigate sending validated before losing.
1432        callback.expectCallback(CallbackState.LOSING, mWiFiNetworkAgent);
1433        callback.expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, mEthernetNetworkAgent);
1434        defaultCallback.expectAvailableAndValidatedCallbacks(mEthernetNetworkAgent);
1435        assertEquals(mEthernetNetworkAgent.getNetwork(), mCm.getActiveNetwork());
1436
1437        mEthernetNetworkAgent.disconnect();
1438        callback.expectCallback(CallbackState.LOST, mEthernetNetworkAgent);
1439        defaultCallback.expectCallback(CallbackState.LOST, mEthernetNetworkAgent);
1440        defaultCallback.expectAvailableCallbacks(mWiFiNetworkAgent);
1441
1442        for (int i = 0; i < 4; i++) {
1443            MockNetworkAgent oldNetwork, newNetwork;
1444            if (i % 2 == 0) {
1445                mWiFiNetworkAgent.adjustScore(-15);
1446                oldNetwork = mWiFiNetworkAgent;
1447                newNetwork = mCellNetworkAgent;
1448            } else {
1449                mWiFiNetworkAgent.adjustScore(15);
1450                oldNetwork = mCellNetworkAgent;
1451                newNetwork = mWiFiNetworkAgent;
1452
1453            }
1454            callback.expectCallback(CallbackState.LOSING, oldNetwork);
1455            // TODO: should we send an AVAILABLE callback to newNetwork, to indicate that it is no
1456            // longer lingering?
1457            defaultCallback.expectAvailableCallbacks(newNetwork);
1458            assertEquals(newNetwork.getNetwork(), mCm.getActiveNetwork());
1459        }
1460        assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetwork());
1461
1462        // Verify that if a network no longer satisfies a request, we send LOST and not LOSING, even
1463        // if the network is still up.
1464        mWiFiNetworkAgent.removeCapability(NET_CAPABILITY_NOT_METERED);
1465        // We expect a notification about the capabilities change, and nothing else.
1466        defaultCallback.expectCapabilitiesWithout(NET_CAPABILITY_NOT_METERED, mWiFiNetworkAgent);
1467        defaultCallback.assertNoCallback();
1468        callback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
1469
1470        // Wifi no longer satisfies our listen, which is for an unmetered network.
1471        // But because its score is 55, it's still up (and the default network).
1472        assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetwork());
1473
1474        // Disconnect our test networks.
1475        mWiFiNetworkAgent.disconnect();
1476        defaultCallback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
1477        defaultCallback.expectAvailableCallbacks(mCellNetworkAgent);
1478        mCellNetworkAgent.disconnect();
1479        defaultCallback.expectCallback(CallbackState.LOST, mCellNetworkAgent);
1480
1481        mCm.unregisterNetworkCallback(callback);
1482        mService.waitForIdle();
1483
1484        // Check that a network is only lingered or torn down if it would not satisfy a request even
1485        // if it validated.
1486        request = new NetworkRequest.Builder().clearCapabilities().build();
1487        callback = new TestNetworkCallback();
1488
1489        mCm.registerNetworkCallback(request, callback);
1490
1491        mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
1492        mCellNetworkAgent.connect(false);   // Score: 10
1493        callback.expectAvailableCallbacks(mCellNetworkAgent);
1494        defaultCallback.expectAvailableCallbacks(mCellNetworkAgent);
1495        assertEquals(mCellNetworkAgent.getNetwork(), mCm.getActiveNetwork());
1496
1497        // Bring up wifi with a score of 20.
1498        // Cell stays up because it would satisfy the default request if it validated.
1499        mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
1500        mWiFiNetworkAgent.connect(false);   // Score: 20
1501        callback.expectAvailableCallbacks(mWiFiNetworkAgent);
1502        defaultCallback.expectAvailableCallbacks(mWiFiNetworkAgent);
1503        assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetwork());
1504
1505        mWiFiNetworkAgent.disconnect();
1506        callback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
1507        defaultCallback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
1508        defaultCallback.expectAvailableCallbacks(mCellNetworkAgent);
1509        assertEquals(mCellNetworkAgent.getNetwork(), mCm.getActiveNetwork());
1510
1511        // Bring up wifi with a score of 70.
1512        // Cell is lingered because it would not satisfy any request, even if it validated.
1513        mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
1514        mWiFiNetworkAgent.adjustScore(50);
1515        mWiFiNetworkAgent.connect(false);   // Score: 70
1516        callback.expectAvailableCallbacks(mWiFiNetworkAgent);
1517        callback.expectCallback(CallbackState.LOSING, mCellNetworkAgent);
1518        defaultCallback.expectAvailableCallbacks(mWiFiNetworkAgent);
1519        assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetwork());
1520
1521        // Tear down wifi.
1522        mWiFiNetworkAgent.disconnect();
1523        callback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
1524        defaultCallback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
1525        defaultCallback.expectAvailableCallbacks(mCellNetworkAgent);
1526        assertEquals(mCellNetworkAgent.getNetwork(), mCm.getActiveNetwork());
1527
1528        // Bring up wifi, then validate it. Previous versions would immediately tear down cell, but
1529        // it's arguably correct to linger it, since it was the default network before it validated.
1530        mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
1531        mWiFiNetworkAgent.connect(true);
1532        callback.expectAvailableCallbacks(mWiFiNetworkAgent);
1533        // TODO: Investigate sending validated before losing.
1534        callback.expectCallback(CallbackState.LOSING, mCellNetworkAgent);
1535        callback.expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, mWiFiNetworkAgent);
1536        defaultCallback.expectAvailableAndValidatedCallbacks(mWiFiNetworkAgent);
1537        assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetwork());
1538
1539        mWiFiNetworkAgent.disconnect();
1540        callback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
1541        defaultCallback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
1542        defaultCallback.expectAvailableCallbacks(mCellNetworkAgent);
1543        mCellNetworkAgent.disconnect();
1544        callback.expectCallback(CallbackState.LOST, mCellNetworkAgent);
1545        defaultCallback.expectCallback(CallbackState.LOST, mCellNetworkAgent);
1546
1547        // If a network is lingering, and we add and remove a request from it, resume lingering.
1548        mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
1549        mCellNetworkAgent.connect(true);
1550        callback.expectAvailableAndValidatedCallbacks(mCellNetworkAgent);
1551        defaultCallback.expectAvailableAndValidatedCallbacks(mCellNetworkAgent);
1552        mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
1553        mWiFiNetworkAgent.connect(true);
1554        defaultCallback.expectAvailableAndValidatedCallbacks(mWiFiNetworkAgent);
1555        callback.expectAvailableCallbacks(mWiFiNetworkAgent);
1556        // TODO: Investigate sending validated before losing.
1557        callback.expectCallback(CallbackState.LOSING, mCellNetworkAgent);
1558        callback.expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, mWiFiNetworkAgent);
1559
1560        NetworkRequest cellRequest = new NetworkRequest.Builder()
1561                .addTransportType(TRANSPORT_CELLULAR).build();
1562        NetworkCallback noopCallback = new NetworkCallback();
1563        mCm.requestNetwork(cellRequest, noopCallback);
1564        // TODO: should this cause an AVAILABLE callback, to indicate that the network is no longer
1565        // lingering?
1566        mCm.unregisterNetworkCallback(noopCallback);
1567        callback.expectCallback(CallbackState.LOSING, mCellNetworkAgent);
1568
1569        // Similar to the above: lingering can start even after the lingered request is removed.
1570        // Disconnect wifi and switch to cell.
1571        mWiFiNetworkAgent.disconnect();
1572        callback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
1573        defaultCallback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
1574        defaultCallback.expectAvailableCallbacks(mCellNetworkAgent);
1575
1576        // Cell is now the default network. Pin it with a cell-specific request.
1577        noopCallback = new NetworkCallback();  // Can't reuse NetworkCallbacks. http://b/20701525
1578        mCm.requestNetwork(cellRequest, noopCallback);
1579
1580        // Now connect wifi, and expect it to become the default network.
1581        mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
1582        mWiFiNetworkAgent.connect(true);
1583        callback.expectAvailableAndValidatedCallbacks(mWiFiNetworkAgent);
1584        defaultCallback.expectAvailableAndValidatedCallbacks(mWiFiNetworkAgent);
1585        // The default request is lingering on cell, but nothing happens to cell, and we send no
1586        // callbacks for it, because it's kept up by cellRequest.
1587        callback.assertNoCallback();
1588        // Now unregister cellRequest and expect cell to start lingering.
1589        mCm.unregisterNetworkCallback(noopCallback);
1590        callback.expectCallback(CallbackState.LOSING, mCellNetworkAgent);
1591
1592        // Let linger run its course.
1593        callback.assertNoCallback();
1594        final int lingerTimeoutMs = TEST_LINGER_DELAY_MS + TEST_LINGER_DELAY_MS / 4;
1595        callback.expectCallback(CallbackState.LOST, mCellNetworkAgent, lingerTimeoutMs);
1596
1597        // Clean up.
1598        mWiFiNetworkAgent.disconnect();
1599        callback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
1600        defaultCallback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
1601
1602        mCm.unregisterNetworkCallback(callback);
1603        mCm.unregisterNetworkCallback(defaultCallback);
1604    }
1605
1606    private void tryNetworkFactoryRequests(int capability) throws Exception {
1607        // Verify NOT_RESTRICTED is set appropriately
1608        final NetworkCapabilities nc = new NetworkRequest.Builder().addCapability(capability)
1609                .build().networkCapabilities;
1610        if (capability == NET_CAPABILITY_CBS || capability == NET_CAPABILITY_DUN ||
1611                capability == NET_CAPABILITY_EIMS || capability == NET_CAPABILITY_FOTA ||
1612                capability == NET_CAPABILITY_IA || capability == NET_CAPABILITY_IMS ||
1613                capability == NET_CAPABILITY_RCS || capability == NET_CAPABILITY_XCAP) {
1614            assertFalse(nc.hasCapability(NET_CAPABILITY_NOT_RESTRICTED));
1615        } else {
1616            assertTrue(nc.hasCapability(NET_CAPABILITY_NOT_RESTRICTED));
1617        }
1618
1619        NetworkCapabilities filter = new NetworkCapabilities();
1620        filter.addCapability(capability);
1621        final HandlerThread handlerThread = new HandlerThread("testNetworkFactoryRequests");
1622        handlerThread.start();
1623        final MockNetworkFactory testFactory = new MockNetworkFactory(handlerThread.getLooper(),
1624                mServiceContext, "testFactory", filter);
1625        testFactory.setScoreFilter(40);
1626        ConditionVariable cv = testFactory.getNetworkStartedCV();
1627        testFactory.expectAddRequests(1);
1628        testFactory.register();
1629        testFactory.waitForNetworkRequests(1);
1630        int expectedRequestCount = 1;
1631        NetworkCallback networkCallback = null;
1632        // For non-INTERNET capabilities we cannot rely on the default request being present, so
1633        // add one.
1634        if (capability != NET_CAPABILITY_INTERNET) {
1635            assertFalse(testFactory.getMyStartRequested());
1636            NetworkRequest request = new NetworkRequest.Builder().addCapability(capability).build();
1637            networkCallback = new NetworkCallback();
1638            testFactory.expectAddRequests(1);
1639            mCm.requestNetwork(request, networkCallback);
1640            expectedRequestCount++;
1641            testFactory.waitForNetworkRequests(expectedRequestCount);
1642        }
1643        waitFor(cv);
1644        assertEquals(expectedRequestCount, testFactory.getMyRequestCount());
1645        assertTrue(testFactory.getMyStartRequested());
1646
1647        // Now bring in a higher scored network.
1648        MockNetworkAgent testAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
1649        // Rather than create a validated network which complicates things by registering it's
1650        // own NetworkRequest during startup, just bump up the score to cancel out the
1651        // unvalidated penalty.
1652        testAgent.adjustScore(40);
1653        cv = testFactory.getNetworkStoppedCV();
1654
1655        // When testAgent connects, ConnectivityService will re-send us all current requests with
1656        // the new score. There are expectedRequestCount such requests, and we must wait for all of
1657        // them.
1658        testFactory.expectAddRequests(expectedRequestCount);
1659        testAgent.connect(false);
1660        testAgent.addCapability(capability);
1661        waitFor(cv);
1662        testFactory.waitForNetworkRequests(expectedRequestCount);
1663        assertFalse(testFactory.getMyStartRequested());
1664
1665        // Bring in a bunch of requests.
1666        testFactory.expectAddRequests(10);
1667        assertEquals(expectedRequestCount, testFactory.getMyRequestCount());
1668        ConnectivityManager.NetworkCallback[] networkCallbacks =
1669                new ConnectivityManager.NetworkCallback[10];
1670        for (int i = 0; i< networkCallbacks.length; i++) {
1671            networkCallbacks[i] = new ConnectivityManager.NetworkCallback();
1672            NetworkRequest.Builder builder = new NetworkRequest.Builder();
1673            builder.addCapability(capability);
1674            mCm.requestNetwork(builder.build(), networkCallbacks[i]);
1675        }
1676        testFactory.waitForNetworkRequests(10 + expectedRequestCount);
1677        assertFalse(testFactory.getMyStartRequested());
1678
1679        // Remove the requests.
1680        testFactory.expectRemoveRequests(10);
1681        for (int i = 0; i < networkCallbacks.length; i++) {
1682            mCm.unregisterNetworkCallback(networkCallbacks[i]);
1683        }
1684        testFactory.waitForNetworkRequests(expectedRequestCount);
1685        assertFalse(testFactory.getMyStartRequested());
1686
1687        // Drop the higher scored network.
1688        cv = testFactory.getNetworkStartedCV();
1689        testAgent.disconnect();
1690        waitFor(cv);
1691        assertEquals(expectedRequestCount, testFactory.getMyRequestCount());
1692        assertTrue(testFactory.getMyStartRequested());
1693
1694        testFactory.unregister();
1695        if (networkCallback != null) mCm.unregisterNetworkCallback(networkCallback);
1696        handlerThread.quit();
1697    }
1698
1699    @SmallTest
1700    public void testNetworkFactoryRequests() throws Exception {
1701        tryNetworkFactoryRequests(NET_CAPABILITY_MMS);
1702        tryNetworkFactoryRequests(NET_CAPABILITY_SUPL);
1703        tryNetworkFactoryRequests(NET_CAPABILITY_DUN);
1704        tryNetworkFactoryRequests(NET_CAPABILITY_FOTA);
1705        tryNetworkFactoryRequests(NET_CAPABILITY_IMS);
1706        tryNetworkFactoryRequests(NET_CAPABILITY_CBS);
1707        tryNetworkFactoryRequests(NET_CAPABILITY_WIFI_P2P);
1708        tryNetworkFactoryRequests(NET_CAPABILITY_IA);
1709        tryNetworkFactoryRequests(NET_CAPABILITY_RCS);
1710        tryNetworkFactoryRequests(NET_CAPABILITY_XCAP);
1711        tryNetworkFactoryRequests(NET_CAPABILITY_EIMS);
1712        tryNetworkFactoryRequests(NET_CAPABILITY_NOT_METERED);
1713        tryNetworkFactoryRequests(NET_CAPABILITY_INTERNET);
1714        tryNetworkFactoryRequests(NET_CAPABILITY_TRUSTED);
1715        tryNetworkFactoryRequests(NET_CAPABILITY_NOT_VPN);
1716        // Skipping VALIDATED and CAPTIVE_PORTAL as they're disallowed.
1717    }
1718
1719    @SmallTest
1720    public void testNoMutableNetworkRequests() throws Exception {
1721        PendingIntent pendingIntent = PendingIntent.getBroadcast(mContext, 0, new Intent("a"), 0);
1722        NetworkRequest.Builder builder = new NetworkRequest.Builder();
1723        builder.addCapability(NET_CAPABILITY_VALIDATED);
1724        try {
1725            mCm.requestNetwork(builder.build(), new NetworkCallback());
1726            fail();
1727        } catch (IllegalArgumentException expected) {}
1728        try {
1729            mCm.requestNetwork(builder.build(), pendingIntent);
1730            fail();
1731        } catch (IllegalArgumentException expected) {}
1732        builder = new NetworkRequest.Builder();
1733        builder.addCapability(NET_CAPABILITY_CAPTIVE_PORTAL);
1734        try {
1735            mCm.requestNetwork(builder.build(), new NetworkCallback());
1736            fail();
1737        } catch (IllegalArgumentException expected) {}
1738        try {
1739            mCm.requestNetwork(builder.build(), pendingIntent);
1740            fail();
1741        } catch (IllegalArgumentException expected) {}
1742    }
1743
1744    @SmallTest
1745    public void testMMSonWiFi() throws Exception {
1746        // Test bringing up cellular without MMS NetworkRequest gets reaped
1747        mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
1748        mCellNetworkAgent.addCapability(NET_CAPABILITY_MMS);
1749        ConditionVariable cv = mCellNetworkAgent.getDisconnectedCV();
1750        mCellNetworkAgent.connectWithoutInternet();
1751        waitFor(cv);
1752        mService.waitForIdle();
1753        assertEquals(0, mCm.getAllNetworks().length);
1754        verifyNoNetwork();
1755        // Test bringing up validated WiFi.
1756        mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
1757        cv = waitForConnectivityBroadcasts(1);
1758        mWiFiNetworkAgent.connect(true);
1759        waitFor(cv);
1760        verifyActiveNetwork(TRANSPORT_WIFI);
1761        // Register MMS NetworkRequest
1762        NetworkRequest.Builder builder = new NetworkRequest.Builder();
1763        builder.addCapability(NetworkCapabilities.NET_CAPABILITY_MMS);
1764        final TestNetworkCallback networkCallback = new TestNetworkCallback();
1765        mCm.requestNetwork(builder.build(), networkCallback);
1766        // Test bringing up unvalidated cellular with MMS
1767        mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
1768        mCellNetworkAgent.addCapability(NET_CAPABILITY_MMS);
1769        mCellNetworkAgent.connectWithoutInternet();
1770        networkCallback.expectAvailableCallbacks(mCellNetworkAgent);
1771        verifyActiveNetwork(TRANSPORT_WIFI);
1772        // Test releasing NetworkRequest disconnects cellular with MMS
1773        cv = mCellNetworkAgent.getDisconnectedCV();
1774        mCm.unregisterNetworkCallback(networkCallback);
1775        waitFor(cv);
1776        verifyActiveNetwork(TRANSPORT_WIFI);
1777    }
1778
1779    @SmallTest
1780    public void testMMSonCell() throws Exception {
1781        // Test bringing up cellular without MMS
1782        mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
1783        ConditionVariable cv = waitForConnectivityBroadcasts(1);
1784        mCellNetworkAgent.connect(false);
1785        waitFor(cv);
1786        verifyActiveNetwork(TRANSPORT_CELLULAR);
1787        // Register MMS NetworkRequest
1788        NetworkRequest.Builder builder = new NetworkRequest.Builder();
1789        builder.addCapability(NetworkCapabilities.NET_CAPABILITY_MMS);
1790        final TestNetworkCallback networkCallback = new TestNetworkCallback();
1791        mCm.requestNetwork(builder.build(), networkCallback);
1792        // Test bringing up MMS cellular network
1793        MockNetworkAgent mmsNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
1794        mmsNetworkAgent.addCapability(NET_CAPABILITY_MMS);
1795        mmsNetworkAgent.connectWithoutInternet();
1796        networkCallback.expectAvailableCallbacks(mmsNetworkAgent);
1797        verifyActiveNetwork(TRANSPORT_CELLULAR);
1798        // Test releasing MMS NetworkRequest does not disconnect main cellular NetworkAgent
1799        cv = mmsNetworkAgent.getDisconnectedCV();
1800        mCm.unregisterNetworkCallback(networkCallback);
1801        waitFor(cv);
1802        verifyActiveNetwork(TRANSPORT_CELLULAR);
1803    }
1804
1805    @SmallTest
1806    public void testCaptivePortal() {
1807        final TestNetworkCallback captivePortalCallback = new TestNetworkCallback();
1808        final NetworkRequest captivePortalRequest = new NetworkRequest.Builder()
1809                .addCapability(NET_CAPABILITY_CAPTIVE_PORTAL).build();
1810        mCm.registerNetworkCallback(captivePortalRequest, captivePortalCallback);
1811
1812        final TestNetworkCallback validatedCallback = new TestNetworkCallback();
1813        final NetworkRequest validatedRequest = new NetworkRequest.Builder()
1814                .addCapability(NET_CAPABILITY_VALIDATED).build();
1815        mCm.registerNetworkCallback(validatedRequest, validatedCallback);
1816
1817        // Bring up a network with a captive portal.
1818        // Expect onAvailable callback of listen for NET_CAPABILITY_CAPTIVE_PORTAL.
1819        mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
1820        String firstRedirectUrl = "http://example.com/firstPath";
1821        mWiFiNetworkAgent.connectWithCaptivePortal(firstRedirectUrl);
1822        captivePortalCallback.expectAvailableCallbacks(mWiFiNetworkAgent);
1823        assertEquals(mWiFiNetworkAgent.waitForRedirectUrl(), firstRedirectUrl);
1824
1825        // Take down network.
1826        // Expect onLost callback.
1827        mWiFiNetworkAgent.disconnect();
1828        captivePortalCallback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
1829
1830        // Bring up a network with a captive portal.
1831        // Expect onAvailable callback of listen for NET_CAPABILITY_CAPTIVE_PORTAL.
1832        mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
1833        String secondRedirectUrl = "http://example.com/secondPath";
1834        mWiFiNetworkAgent.connectWithCaptivePortal(secondRedirectUrl);
1835        captivePortalCallback.expectAvailableCallbacks(mWiFiNetworkAgent);
1836        assertEquals(mWiFiNetworkAgent.waitForRedirectUrl(), secondRedirectUrl);
1837
1838        // Make captive portal disappear then revalidate.
1839        // Expect onLost callback because network no longer provides NET_CAPABILITY_CAPTIVE_PORTAL.
1840        mWiFiNetworkAgent.getWrappedNetworkMonitor().gen204ProbeResult = 204;
1841        mCm.reportNetworkConnectivity(mWiFiNetworkAgent.getNetwork(), true);
1842        captivePortalCallback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
1843
1844        // Expect NET_CAPABILITY_VALIDATED onAvailable callback.
1845        validatedCallback.expectAvailableCallbacks(mWiFiNetworkAgent);
1846        // TODO: Investigate only sending available callbacks.
1847        validatedCallback.expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, mWiFiNetworkAgent);
1848
1849        // Break network connectivity.
1850        // Expect NET_CAPABILITY_VALIDATED onLost callback.
1851        mWiFiNetworkAgent.getWrappedNetworkMonitor().gen204ProbeResult = 500;
1852        mCm.reportNetworkConnectivity(mWiFiNetworkAgent.getNetwork(), false);
1853        validatedCallback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
1854    }
1855
1856    @SmallTest
1857    public void testCaptivePortalApp() {
1858        final TestNetworkCallback captivePortalCallback = new TestNetworkCallback();
1859        final NetworkRequest captivePortalRequest = new NetworkRequest.Builder()
1860                .addCapability(NET_CAPABILITY_CAPTIVE_PORTAL).build();
1861        mCm.registerNetworkCallback(captivePortalRequest, captivePortalCallback);
1862
1863        final TestNetworkCallback validatedCallback = new TestNetworkCallback();
1864        final NetworkRequest validatedRequest = new NetworkRequest.Builder()
1865                .addCapability(NET_CAPABILITY_VALIDATED).build();
1866        mCm.registerNetworkCallback(validatedRequest, validatedCallback);
1867
1868        // Bring up wifi.
1869        mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
1870        mWiFiNetworkAgent.connect(true);
1871        validatedCallback.expectAvailableAndValidatedCallbacks(mWiFiNetworkAgent);
1872        Network wifiNetwork = mWiFiNetworkAgent.getNetwork();
1873
1874        // Check that calling startCaptivePortalApp does nothing.
1875        final int fastTimeoutMs = 100;
1876        mCm.startCaptivePortalApp(wifiNetwork);
1877        mServiceContext.expectNoStartActivityIntent(fastTimeoutMs);
1878
1879        // Turn into a captive portal.
1880        mWiFiNetworkAgent.getWrappedNetworkMonitor().gen204ProbeResult = 302;
1881        mCm.reportNetworkConnectivity(wifiNetwork, false);
1882        captivePortalCallback.expectAvailableCallbacks(mWiFiNetworkAgent);
1883        validatedCallback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
1884
1885        // Check that startCaptivePortalApp sends the expected intent.
1886        mCm.startCaptivePortalApp(wifiNetwork);
1887        Intent intent = mServiceContext.expectStartActivityIntent(TIMEOUT_MS);
1888        assertEquals(ConnectivityManager.ACTION_CAPTIVE_PORTAL_SIGN_IN, intent.getAction());
1889        assertEquals(wifiNetwork, intent.getExtra(ConnectivityManager.EXTRA_NETWORK));
1890
1891        // Have the app report that the captive portal is dismissed, and check that we revalidate.
1892        mWiFiNetworkAgent.getWrappedNetworkMonitor().gen204ProbeResult = 204;
1893        CaptivePortal c = (CaptivePortal) intent.getExtra(ConnectivityManager.EXTRA_CAPTIVE_PORTAL);
1894        c.reportCaptivePortalDismissed();
1895        validatedCallback.expectAvailableCallbacks(mWiFiNetworkAgent);
1896        captivePortalCallback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
1897
1898        mCm.unregisterNetworkCallback(validatedCallback);
1899        mCm.unregisterNetworkCallback(captivePortalCallback);
1900    }
1901
1902    @SmallTest
1903    public void testAvoidOrIgnoreCaptivePortals() {
1904        final TestNetworkCallback captivePortalCallback = new TestNetworkCallback();
1905        final NetworkRequest captivePortalRequest = new NetworkRequest.Builder()
1906                .addCapability(NET_CAPABILITY_CAPTIVE_PORTAL).build();
1907        mCm.registerNetworkCallback(captivePortalRequest, captivePortalCallback);
1908
1909        final TestNetworkCallback validatedCallback = new TestNetworkCallback();
1910        final NetworkRequest validatedRequest = new NetworkRequest.Builder()
1911                .addCapability(NET_CAPABILITY_VALIDATED).build();
1912        mCm.registerNetworkCallback(validatedRequest, validatedCallback);
1913
1914        setCaptivePortalMode(Settings.Global.CAPTIVE_PORTAL_MODE_AVOID);
1915        // Bring up a network with a captive portal.
1916        // Expect it to fail to connect and not result in any callbacks.
1917        mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
1918        String firstRedirectUrl = "http://example.com/firstPath";
1919
1920        ConditionVariable disconnectCv = mWiFiNetworkAgent.getDisconnectedCV();
1921        ConditionVariable avoidCv = mWiFiNetworkAgent.getPreventReconnectReceived();
1922        mWiFiNetworkAgent.connectWithCaptivePortal(firstRedirectUrl);
1923        waitFor(disconnectCv);
1924        waitFor(avoidCv);
1925
1926        assertNoCallbacks(captivePortalCallback, validatedCallback);
1927
1928        // Now test ignore mode.
1929        setCaptivePortalMode(Settings.Global.CAPTIVE_PORTAL_MODE_IGNORE);
1930
1931        // Bring up a network with a captive portal.
1932        // Since we're ignoring captive portals, the network will validate.
1933        mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
1934        String secondRedirectUrl = "http://example.com/secondPath";
1935        mWiFiNetworkAgent.connectWithCaptivePortal(secondRedirectUrl);
1936
1937        // Expect NET_CAPABILITY_VALIDATED onAvailable callback.
1938        validatedCallback.expectAvailableCallbacks(mWiFiNetworkAgent);
1939        // But there should be no CaptivePortal callback.
1940        captivePortalCallback.assertNoCallback();
1941    }
1942
1943    private NetworkRequest.Builder newWifiRequestBuilder() {
1944        return new NetworkRequest.Builder().addTransportType(TRANSPORT_WIFI);
1945    }
1946
1947    @SmallTest
1948    public void testNetworkSpecifier() {
1949        NetworkRequest rEmpty1 = newWifiRequestBuilder().build();
1950        NetworkRequest rEmpty2 = newWifiRequestBuilder().setNetworkSpecifier((String) null).build();
1951        NetworkRequest rEmpty3 = newWifiRequestBuilder().setNetworkSpecifier("").build();
1952        NetworkRequest rEmpty4 = newWifiRequestBuilder().setNetworkSpecifier(
1953            (NetworkSpecifier) null).build();
1954        NetworkRequest rFoo = newWifiRequestBuilder().setNetworkSpecifier("foo").build();
1955        NetworkRequest rBar = newWifiRequestBuilder().setNetworkSpecifier(
1956                new StringNetworkSpecifier("bar")).build();
1957
1958        TestNetworkCallback cEmpty1 = new TestNetworkCallback();
1959        TestNetworkCallback cEmpty2 = new TestNetworkCallback();
1960        TestNetworkCallback cEmpty3 = new TestNetworkCallback();
1961        TestNetworkCallback cEmpty4 = new TestNetworkCallback();
1962        TestNetworkCallback cFoo = new TestNetworkCallback();
1963        TestNetworkCallback cBar = new TestNetworkCallback();
1964        TestNetworkCallback[] emptyCallbacks = new TestNetworkCallback[] {
1965                cEmpty1, cEmpty2, cEmpty3 };
1966
1967        mCm.registerNetworkCallback(rEmpty1, cEmpty1);
1968        mCm.registerNetworkCallback(rEmpty2, cEmpty2);
1969        mCm.registerNetworkCallback(rEmpty3, cEmpty3);
1970        mCm.registerNetworkCallback(rEmpty4, cEmpty4);
1971        mCm.registerNetworkCallback(rFoo, cFoo);
1972        mCm.registerNetworkCallback(rBar, cBar);
1973
1974        mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
1975        mWiFiNetworkAgent.connect(false);
1976        cEmpty1.expectAvailableCallbacks(mWiFiNetworkAgent);
1977        cEmpty2.expectAvailableCallbacks(mWiFiNetworkAgent);
1978        cEmpty3.expectAvailableCallbacks(mWiFiNetworkAgent);
1979        cEmpty4.expectAvailableCallbacks(mWiFiNetworkAgent);
1980        assertNoCallbacks(cFoo, cBar);
1981
1982        mWiFiNetworkAgent.setNetworkSpecifier(new StringNetworkSpecifier("foo"));
1983        cFoo.expectAvailableCallbacks(mWiFiNetworkAgent);
1984        for (TestNetworkCallback c: emptyCallbacks) {
1985            c.expectCallback(CallbackState.NETWORK_CAPABILITIES, mWiFiNetworkAgent);
1986        }
1987        cFoo.expectCallback(CallbackState.NETWORK_CAPABILITIES, mWiFiNetworkAgent);
1988        cFoo.assertNoCallback();
1989
1990        mWiFiNetworkAgent.setNetworkSpecifier(new StringNetworkSpecifier("bar"));
1991        cFoo.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
1992        cBar.expectAvailableCallbacks(mWiFiNetworkAgent);
1993        for (TestNetworkCallback c: emptyCallbacks) {
1994            c.expectCallback(CallbackState.NETWORK_CAPABILITIES, mWiFiNetworkAgent);
1995        }
1996        cBar.expectCallback(CallbackState.NETWORK_CAPABILITIES, mWiFiNetworkAgent);
1997        cBar.assertNoCallback();
1998
1999        mWiFiNetworkAgent.setNetworkSpecifier(null);
2000        cBar.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
2001        for (TestNetworkCallback c: emptyCallbacks) {
2002            c.expectCallback(CallbackState.NETWORK_CAPABILITIES, mWiFiNetworkAgent);
2003        }
2004
2005        assertNoCallbacks(cEmpty1, cEmpty2, cEmpty3, cFoo, cBar);
2006    }
2007
2008    @SmallTest
2009    public void testInvalidNetworkSpecifier() {
2010        try {
2011            NetworkRequest.Builder builder = new NetworkRequest.Builder();
2012            builder.setNetworkSpecifier(new MatchAllNetworkSpecifier());
2013            fail("NetworkRequest builder with MatchAllNetworkSpecifier");
2014        } catch (IllegalArgumentException expected) {
2015            // expected
2016        }
2017
2018        try {
2019            NetworkCapabilities networkCapabilities = new NetworkCapabilities();
2020            networkCapabilities.addTransportType(TRANSPORT_WIFI)
2021                    .setNetworkSpecifier(new MatchAllNetworkSpecifier());
2022            mService.requestNetwork(networkCapabilities, null, 0, null,
2023                    ConnectivityManager.TYPE_WIFI);
2024            fail("ConnectivityService requestNetwork with MatchAllNetworkSpecifier");
2025        } catch (IllegalArgumentException expected) {
2026            // expected
2027        }
2028
2029        class NonParcelableSpecifier extends NetworkSpecifier {
2030            public boolean satisfiedBy(NetworkSpecifier other) { return false; }
2031        };
2032        class ParcelableSpecifier extends NonParcelableSpecifier implements Parcelable {
2033            @Override public int describeContents() { return 0; }
2034            @Override public void writeToParcel(Parcel p, int flags) {}
2035        }
2036        NetworkRequest.Builder builder;
2037
2038        builder = new NetworkRequest.Builder().addTransportType(TRANSPORT_ETHERNET);
2039        try {
2040            builder.setNetworkSpecifier(new NonParcelableSpecifier());
2041            Parcel parcelW = Parcel.obtain();
2042            builder.build().writeToParcel(parcelW, 0);
2043            fail("Parceling a non-parcelable specifier did not throw an exception");
2044        } catch (Exception e) {
2045            // expected
2046        }
2047
2048        builder = new NetworkRequest.Builder().addTransportType(TRANSPORT_ETHERNET);
2049        builder.setNetworkSpecifier(new ParcelableSpecifier());
2050        NetworkRequest nr = builder.build();
2051        assertNotNull(nr);
2052
2053        try {
2054            Parcel parcelW = Parcel.obtain();
2055            nr.writeToParcel(parcelW, 0);
2056            byte[] bytes = parcelW.marshall();
2057            parcelW.recycle();
2058
2059            Parcel parcelR = Parcel.obtain();
2060            parcelR.unmarshall(bytes, 0, bytes.length);
2061            parcelR.setDataPosition(0);
2062            NetworkRequest rereadNr = NetworkRequest.CREATOR.createFromParcel(parcelR);
2063            fail("Unparceling a non-framework NetworkSpecifier did not throw an exception");
2064        } catch (Exception e) {
2065            // expected
2066        }
2067    }
2068
2069    @SmallTest
2070    public void testRegisterDefaultNetworkCallback() throws Exception {
2071        final TestNetworkCallback defaultNetworkCallback = new TestNetworkCallback();
2072        mCm.registerDefaultNetworkCallback(defaultNetworkCallback);
2073        defaultNetworkCallback.assertNoCallback();
2074
2075        // Create a TRANSPORT_CELLULAR request to keep the mobile interface up
2076        // whenever Wi-Fi is up. Without this, the mobile network agent is
2077        // reaped before any other activity can take place.
2078        final TestNetworkCallback cellNetworkCallback = new TestNetworkCallback();
2079        final NetworkRequest cellRequest = new NetworkRequest.Builder()
2080                .addTransportType(TRANSPORT_CELLULAR).build();
2081        mCm.requestNetwork(cellRequest, cellNetworkCallback);
2082        cellNetworkCallback.assertNoCallback();
2083
2084        // Bring up cell and expect CALLBACK_AVAILABLE.
2085        mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
2086        mCellNetworkAgent.connect(true);
2087        cellNetworkCallback.expectAvailableAndValidatedCallbacks(mCellNetworkAgent);
2088        defaultNetworkCallback.expectAvailableAndValidatedCallbacks(mCellNetworkAgent);
2089
2090        // Bring up wifi and expect CALLBACK_AVAILABLE.
2091        mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
2092        mWiFiNetworkAgent.connect(true);
2093        cellNetworkCallback.assertNoCallback();
2094        defaultNetworkCallback.expectAvailableAndValidatedCallbacks(mWiFiNetworkAgent);
2095
2096        // Bring down cell. Expect no default network callback, since it wasn't the default.
2097        mCellNetworkAgent.disconnect();
2098        cellNetworkCallback.expectCallback(CallbackState.LOST, mCellNetworkAgent);
2099        defaultNetworkCallback.assertNoCallback();
2100
2101        // Bring up cell. Expect no default network callback, since it won't be the default.
2102        mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
2103        mCellNetworkAgent.connect(true);
2104        cellNetworkCallback.expectAvailableAndValidatedCallbacks(mCellNetworkAgent);
2105        defaultNetworkCallback.assertNoCallback();
2106
2107        // Bring down wifi. Expect the default network callback to notified of LOST wifi
2108        // followed by AVAILABLE cell.
2109        mWiFiNetworkAgent.disconnect();
2110        cellNetworkCallback.assertNoCallback();
2111        defaultNetworkCallback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
2112        defaultNetworkCallback.expectAvailableCallbacks(mCellNetworkAgent);
2113        mCellNetworkAgent.disconnect();
2114        cellNetworkCallback.expectCallback(CallbackState.LOST, mCellNetworkAgent);
2115        defaultNetworkCallback.expectCallback(CallbackState.LOST, mCellNetworkAgent);
2116    }
2117
2118    @SmallTest
2119    public void testAdditionalStateCallbacks() throws Exception {
2120        // File a network request for mobile.
2121        final TestNetworkCallback cellNetworkCallback = new TestNetworkCallback();
2122        final NetworkRequest cellRequest = new NetworkRequest.Builder()
2123                .addTransportType(TRANSPORT_CELLULAR).build();
2124        mCm.requestNetwork(cellRequest, cellNetworkCallback);
2125
2126        // Bring up the mobile network.
2127        mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
2128        mCellNetworkAgent.connect(true);
2129
2130        // We should get onAvailable(), onCapabilitiesChanged(), and
2131        // onLinkPropertiesChanged() in rapid succession. Additionally, we
2132        // should get onCapabilitiesChanged() when the mobile network validates.
2133        cellNetworkCallback.expectAvailableAndValidatedCallbacks(mCellNetworkAgent);
2134        cellNetworkCallback.assertNoCallback();
2135
2136        // Update LinkProperties.
2137        final LinkProperties lp = new LinkProperties();
2138        lp.setInterfaceName("foonet_data0");
2139        mCellNetworkAgent.sendLinkProperties(lp);
2140        // We should get onLinkPropertiesChanged().
2141        cellNetworkCallback.expectCallback(CallbackState.LINK_PROPERTIES, mCellNetworkAgent);
2142        cellNetworkCallback.assertNoCallback();
2143
2144        // Suspend the network.
2145        mCellNetworkAgent.suspend();
2146        cellNetworkCallback.expectCallback(CallbackState.SUSPENDED, mCellNetworkAgent);
2147        cellNetworkCallback.assertNoCallback();
2148
2149        // Register a garden variety default network request.
2150        final TestNetworkCallback dfltNetworkCallback = new TestNetworkCallback();
2151        mCm.registerDefaultNetworkCallback(dfltNetworkCallback);
2152        // We should get onAvailable(), onCapabilitiesChanged(), onLinkPropertiesChanged(),
2153        // as well as onNetworkSuspended() in rapid succession.
2154        dfltNetworkCallback.expectAvailableAndSuspendedCallbacks(mCellNetworkAgent);
2155        dfltNetworkCallback.assertNoCallback();
2156
2157        mCm.unregisterNetworkCallback(dfltNetworkCallback);
2158        mCm.unregisterNetworkCallback(cellNetworkCallback);
2159    }
2160
2161    private void setCaptivePortalMode(int mode) {
2162        ContentResolver cr = mServiceContext.getContentResolver();
2163        Settings.Global.putInt(cr, Settings.Global.CAPTIVE_PORTAL_MODE, mode);
2164    }
2165
2166    private void setMobileDataAlwaysOn(boolean enable) {
2167        ContentResolver cr = mServiceContext.getContentResolver();
2168        Settings.Global.putInt(cr, Settings.Global.MOBILE_DATA_ALWAYS_ON, enable ? 1 : 0);
2169        mService.updateMobileDataAlwaysOn();
2170        mService.waitForIdle();
2171    }
2172
2173    private boolean isForegroundNetwork(MockNetworkAgent network) {
2174        NetworkCapabilities nc = mCm.getNetworkCapabilities(network.getNetwork());
2175        assertNotNull(nc);
2176        return nc.hasCapability(NET_CAPABILITY_FOREGROUND);
2177    }
2178
2179    @SmallTest
2180    public void testBackgroundNetworks() throws Exception {
2181        // Create a background request. We can't do this ourselves because ConnectivityService
2182        // doesn't have an API for it. So just turn on mobile data always on.
2183        setMobileDataAlwaysOn(true);
2184        final NetworkRequest request = new NetworkRequest.Builder().build();
2185        final NetworkRequest fgRequest = new NetworkRequest.Builder()
2186                .addCapability(NET_CAPABILITY_FOREGROUND).build();
2187        final TestNetworkCallback callback = new TestNetworkCallback();
2188        final TestNetworkCallback fgCallback = new TestNetworkCallback();
2189        mCm.registerNetworkCallback(request, callback);
2190        mCm.registerNetworkCallback(fgRequest, fgCallback);
2191
2192        mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
2193        mCellNetworkAgent.connect(true);
2194        callback.expectAvailableAndValidatedCallbacks(mCellNetworkAgent);
2195        fgCallback.expectAvailableAndValidatedCallbacks(mCellNetworkAgent);
2196        assertTrue(isForegroundNetwork(mCellNetworkAgent));
2197
2198        mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
2199        mWiFiNetworkAgent.connect(true);
2200
2201        // When wifi connects, cell lingers.
2202        callback.expectAvailableCallbacks(mWiFiNetworkAgent);
2203        callback.expectCallback(CallbackState.LOSING, mCellNetworkAgent);
2204        callback.expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, mWiFiNetworkAgent);
2205        fgCallback.expectAvailableCallbacks(mWiFiNetworkAgent);
2206        fgCallback.expectCallback(CallbackState.LOSING, mCellNetworkAgent);
2207        fgCallback.expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, mWiFiNetworkAgent);
2208        assertTrue(isForegroundNetwork(mCellNetworkAgent));
2209        assertTrue(isForegroundNetwork(mWiFiNetworkAgent));
2210
2211        // When lingering is complete, cell is still there but is now in the background.
2212        mService.waitForIdle();
2213        int timeoutMs = TEST_LINGER_DELAY_MS + TEST_LINGER_DELAY_MS / 4;
2214        fgCallback.expectCallback(CallbackState.LOST, mCellNetworkAgent, timeoutMs);
2215        // Expect a network capabilities update sans FOREGROUND.
2216        callback.expectCapabilitiesWithout(NET_CAPABILITY_FOREGROUND, mCellNetworkAgent);
2217        assertFalse(isForegroundNetwork(mCellNetworkAgent));
2218        assertTrue(isForegroundNetwork(mWiFiNetworkAgent));
2219
2220        // File a cell request and check that cell comes into the foreground.
2221        final NetworkRequest cellRequest = new NetworkRequest.Builder()
2222                .addTransportType(TRANSPORT_CELLULAR).build();
2223        final TestNetworkCallback cellCallback = new TestNetworkCallback();
2224        mCm.requestNetwork(cellRequest, cellCallback);
2225        // NOTE: This request causes the network's capabilities to change. This
2226        // is currently delivered before the onAvailable() callbacks.
2227        // TODO: Fix this.
2228        cellCallback.expectCapabilitiesWith(NET_CAPABILITY_FOREGROUND, mCellNetworkAgent);
2229        cellCallback.expectAvailableCallbacks(mCellNetworkAgent);
2230        fgCallback.expectAvailableCallbacks(mCellNetworkAgent);
2231        // Expect a network capabilities update with FOREGROUND, because the most recent
2232        // request causes its state to change.
2233        callback.expectCapabilitiesWith(NET_CAPABILITY_FOREGROUND, mCellNetworkAgent);
2234        assertTrue(isForegroundNetwork(mCellNetworkAgent));
2235        assertTrue(isForegroundNetwork(mWiFiNetworkAgent));
2236
2237        // Release the request. The network immediately goes into the background, since it was not
2238        // lingering.
2239        mCm.unregisterNetworkCallback(cellCallback);
2240        fgCallback.expectCallback(CallbackState.LOST, mCellNetworkAgent);
2241        // Expect a network capabilities update sans FOREGROUND.
2242        callback.expectCapabilitiesWithout(NET_CAPABILITY_FOREGROUND, mCellNetworkAgent);
2243        assertFalse(isForegroundNetwork(mCellNetworkAgent));
2244        assertTrue(isForegroundNetwork(mWiFiNetworkAgent));
2245
2246        // Disconnect wifi and check that cell is foreground again.
2247        mWiFiNetworkAgent.disconnect();
2248        callback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
2249        fgCallback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
2250        fgCallback.expectAvailableCallbacks(mCellNetworkAgent);
2251        assertTrue(isForegroundNetwork(mCellNetworkAgent));
2252
2253        mCm.unregisterNetworkCallback(callback);
2254        mCm.unregisterNetworkCallback(fgCallback);
2255    }
2256
2257    @SmallTest
2258    public void testRequestBenchmark() throws Exception {
2259        // TODO: turn this unit test into a real benchmarking test.
2260        // Benchmarks connecting and switching performance in the presence of a large number of
2261        // NetworkRequests.
2262        // 1. File NUM_REQUESTS requests.
2263        // 2. Have a network connect. Wait for NUM_REQUESTS onAvailable callbacks to fire.
2264        // 3. Have a new network connect and outscore the previous. Wait for NUM_REQUESTS onLosing
2265        //    and NUM_REQUESTS onAvailable callbacks to fire.
2266        // See how long it took.
2267        final int NUM_REQUESTS = 90;
2268        final NetworkRequest request = new NetworkRequest.Builder().clearCapabilities().build();
2269        final NetworkCallback[] callbacks = new NetworkCallback[NUM_REQUESTS];
2270        final CountDownLatch availableLatch = new CountDownLatch(NUM_REQUESTS);
2271        final CountDownLatch losingLatch = new CountDownLatch(NUM_REQUESTS);
2272
2273        for (int i = 0; i < NUM_REQUESTS; i++) {
2274            callbacks[i] = new NetworkCallback() {
2275                @Override public void onAvailable(Network n) { availableLatch.countDown(); }
2276                @Override public void onLosing(Network n, int t) { losingLatch.countDown(); }
2277            };
2278        }
2279
2280        final int REGISTER_TIME_LIMIT_MS = 180;
2281        assertTimeLimit("Registering callbacks", REGISTER_TIME_LIMIT_MS, () -> {
2282            for (NetworkCallback cb : callbacks) {
2283                mCm.registerNetworkCallback(request, cb);
2284            }
2285        });
2286
2287        final int CONNECT_TIME_LIMIT_MS = 40;
2288        mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
2289        // Don't request that the network validate, because otherwise connect() will block until
2290        // the network gets NET_CAPABILITY_VALIDATED, after all the callbacks below have fired,
2291        // and we won't actually measure anything.
2292        mCellNetworkAgent.connect(false);
2293
2294        long onAvailableDispatchingDuration = durationOf(() -> {
2295            if (!awaitLatch(availableLatch, CONNECT_TIME_LIMIT_MS)) {
2296                fail(String.format("Only dispatched %d/%d onAvailable callbacks in %dms",
2297                        NUM_REQUESTS - availableLatch.getCount(), NUM_REQUESTS,
2298                        CONNECT_TIME_LIMIT_MS));
2299            }
2300        });
2301        Log.d(TAG, String.format("Connect, %d callbacks: %dms, acceptable %dms",
2302                NUM_REQUESTS, onAvailableDispatchingDuration, CONNECT_TIME_LIMIT_MS));
2303
2304        final int SWITCH_TIME_LIMIT_MS = 40;
2305        mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
2306        // Give wifi a high enough score that we'll linger cell when wifi comes up.
2307        mWiFiNetworkAgent.adjustScore(40);
2308        mWiFiNetworkAgent.connect(false);
2309
2310        long onLostDispatchingDuration = durationOf(() -> {
2311            if (!awaitLatch(losingLatch, SWITCH_TIME_LIMIT_MS)) {
2312                fail(String.format("Only dispatched %d/%d onLosing callbacks in %dms",
2313                        NUM_REQUESTS - losingLatch.getCount(), NUM_REQUESTS, SWITCH_TIME_LIMIT_MS));
2314            }
2315        });
2316        Log.d(TAG, String.format("Linger, %d callbacks: %dms, acceptable %dms",
2317                NUM_REQUESTS, onLostDispatchingDuration, SWITCH_TIME_LIMIT_MS));
2318
2319        final int UNREGISTER_TIME_LIMIT_MS = 10;
2320        assertTimeLimit("Unregistering callbacks", UNREGISTER_TIME_LIMIT_MS, () -> {
2321            for (NetworkCallback cb : callbacks) {
2322                mCm.unregisterNetworkCallback(cb);
2323            }
2324        });
2325    }
2326
2327    private long durationOf(Runnable fn) {
2328        long startTime = SystemClock.elapsedRealtime();
2329        fn.run();
2330        return SystemClock.elapsedRealtime() - startTime;
2331    }
2332
2333    private void assertTimeLimit(String descr, long timeLimit, Runnable fn) {
2334        long timeTaken = durationOf(fn);
2335        String msg = String.format("%s: took %dms, limit was %dms", descr, timeTaken, timeLimit);
2336        Log.d(TAG, msg);
2337        assertTrue(msg, timeTaken <= timeLimit);
2338    }
2339
2340    private boolean awaitLatch(CountDownLatch l, long timeoutMs) {
2341        try {
2342            if (l.await(timeoutMs, TimeUnit.MILLISECONDS)) {
2343                return true;
2344            }
2345        } catch (InterruptedException e) {}
2346        return false;
2347    }
2348
2349    @SmallTest
2350    public void testMobileDataAlwaysOn() throws Exception {
2351        final TestNetworkCallback cellNetworkCallback = new TestNetworkCallback();
2352        final NetworkRequest cellRequest = new NetworkRequest.Builder()
2353                .addTransportType(TRANSPORT_CELLULAR).build();
2354        mCm.registerNetworkCallback(cellRequest, cellNetworkCallback);
2355
2356        final HandlerThread handlerThread = new HandlerThread("MobileDataAlwaysOnFactory");
2357        handlerThread.start();
2358        NetworkCapabilities filter = new NetworkCapabilities()
2359                .addTransportType(TRANSPORT_CELLULAR)
2360                .addCapability(NET_CAPABILITY_INTERNET);
2361        final MockNetworkFactory testFactory = new MockNetworkFactory(handlerThread.getLooper(),
2362                mServiceContext, "testFactory", filter);
2363        testFactory.setScoreFilter(40);
2364
2365        // Register the factory and expect it to start looking for a network.
2366        testFactory.expectAddRequests(1);
2367        testFactory.register();
2368        testFactory.waitForNetworkRequests(1);
2369        assertTrue(testFactory.getMyStartRequested());
2370
2371        // Bring up wifi. The factory stops looking for a network.
2372        mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
2373        testFactory.expectAddRequests(2);  // Because the default request changes score twice.
2374        mWiFiNetworkAgent.connect(true);
2375        testFactory.waitForNetworkRequests(1);
2376        assertFalse(testFactory.getMyStartRequested());
2377
2378        ContentResolver cr = mServiceContext.getContentResolver();
2379
2380        // Turn on mobile data always on. The factory starts looking again.
2381        testFactory.expectAddRequests(1);
2382        setMobileDataAlwaysOn(true);
2383        testFactory.waitForNetworkRequests(2);
2384        assertTrue(testFactory.getMyStartRequested());
2385
2386        // Bring up cell data and check that the factory stops looking.
2387        assertEquals(1, mCm.getAllNetworks().length);
2388        mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
2389        testFactory.expectAddRequests(2);  // Because the cell request changes score twice.
2390        mCellNetworkAgent.connect(true);
2391        cellNetworkCallback.expectAvailableAndValidatedCallbacks(mCellNetworkAgent);
2392        testFactory.waitForNetworkRequests(2);
2393        assertFalse(testFactory.getMyStartRequested());  // Because the cell network outscores us.
2394
2395        // Check that cell data stays up.
2396        mService.waitForIdle();
2397        verifyActiveNetwork(TRANSPORT_WIFI);
2398        assertEquals(2, mCm.getAllNetworks().length);
2399
2400        // Turn off mobile data always on and expect the request to disappear...
2401        testFactory.expectRemoveRequests(1);
2402        setMobileDataAlwaysOn(false);
2403        testFactory.waitForNetworkRequests(1);
2404
2405        // ...  and cell data to be torn down.
2406        cellNetworkCallback.expectCallback(CallbackState.LOST, mCellNetworkAgent);
2407        assertEquals(1, mCm.getAllNetworks().length);
2408
2409        testFactory.unregister();
2410        mCm.unregisterNetworkCallback(cellNetworkCallback);
2411        handlerThread.quit();
2412    }
2413
2414    @SmallTest
2415    public void testAvoidBadWifiSetting() throws Exception {
2416        final ContentResolver cr = mServiceContext.getContentResolver();
2417        final WrappedMultinetworkPolicyTracker tracker = mService.getMultinetworkPolicyTracker();
2418        final String settingName = Settings.Global.NETWORK_AVOID_BAD_WIFI;
2419
2420        tracker.configRestrictsAvoidBadWifi = false;
2421        String[] values = new String[] {null, "0", "1"};
2422        for (int i = 0; i < values.length; i++) {
2423            Settings.Global.putInt(cr, settingName, 1);
2424            tracker.reevaluate();
2425            mService.waitForIdle();
2426            String msg = String.format("config=false, setting=%s", values[i]);
2427            assertTrue(mService.avoidBadWifi());
2428            assertFalse(msg, tracker.shouldNotifyWifiUnvalidated());
2429        }
2430
2431        tracker.configRestrictsAvoidBadWifi = true;
2432
2433        Settings.Global.putInt(cr, settingName, 0);
2434        tracker.reevaluate();
2435        mService.waitForIdle();
2436        assertFalse(mService.avoidBadWifi());
2437        assertFalse(tracker.shouldNotifyWifiUnvalidated());
2438
2439        Settings.Global.putInt(cr, settingName, 1);
2440        tracker.reevaluate();
2441        mService.waitForIdle();
2442        assertTrue(mService.avoidBadWifi());
2443        assertFalse(tracker.shouldNotifyWifiUnvalidated());
2444
2445        Settings.Global.putString(cr, settingName, null);
2446        tracker.reevaluate();
2447        mService.waitForIdle();
2448        assertFalse(mService.avoidBadWifi());
2449        assertTrue(tracker.shouldNotifyWifiUnvalidated());
2450    }
2451
2452    @SmallTest
2453    public void testAvoidBadWifi() throws Exception {
2454        final ContentResolver cr = mServiceContext.getContentResolver();
2455        final WrappedMultinetworkPolicyTracker tracker = mService.getMultinetworkPolicyTracker();
2456
2457        // Pretend we're on a carrier that restricts switching away from bad wifi.
2458        tracker.configRestrictsAvoidBadWifi = true;
2459
2460        // File a request for cell to ensure it doesn't go down.
2461        final TestNetworkCallback cellNetworkCallback = new TestNetworkCallback();
2462        final NetworkRequest cellRequest = new NetworkRequest.Builder()
2463                .addTransportType(TRANSPORT_CELLULAR).build();
2464        mCm.requestNetwork(cellRequest, cellNetworkCallback);
2465
2466        TestNetworkCallback defaultCallback = new TestNetworkCallback();
2467        mCm.registerDefaultNetworkCallback(defaultCallback);
2468
2469        NetworkRequest validatedWifiRequest = new NetworkRequest.Builder()
2470                .addTransportType(TRANSPORT_WIFI)
2471                .addCapability(NET_CAPABILITY_VALIDATED)
2472                .build();
2473        TestNetworkCallback validatedWifiCallback = new TestNetworkCallback();
2474        mCm.registerNetworkCallback(validatedWifiRequest, validatedWifiCallback);
2475
2476        Settings.Global.putInt(cr, Settings.Global.NETWORK_AVOID_BAD_WIFI, 0);
2477        tracker.reevaluate();
2478
2479        // Bring up validated cell.
2480        mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
2481        mCellNetworkAgent.connect(true);
2482        cellNetworkCallback.expectAvailableAndValidatedCallbacks(mCellNetworkAgent);
2483        defaultCallback.expectAvailableAndValidatedCallbacks(mCellNetworkAgent);
2484        Network cellNetwork = mCellNetworkAgent.getNetwork();
2485
2486        // Bring up validated wifi.
2487        mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
2488        mWiFiNetworkAgent.connect(true);
2489        defaultCallback.expectAvailableAndValidatedCallbacks(mWiFiNetworkAgent);
2490        validatedWifiCallback.expectAvailableCallbacks(mWiFiNetworkAgent);
2491        validatedWifiCallback.expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, mWiFiNetworkAgent);
2492        Network wifiNetwork = mWiFiNetworkAgent.getNetwork();
2493
2494        // Fail validation on wifi.
2495        mWiFiNetworkAgent.getWrappedNetworkMonitor().gen204ProbeResult = 599;
2496        mCm.reportNetworkConnectivity(wifiNetwork, false);
2497        defaultCallback.expectCapabilitiesWithout(NET_CAPABILITY_VALIDATED, mWiFiNetworkAgent);
2498        validatedWifiCallback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
2499
2500        // Because avoid bad wifi is off, we don't switch to cellular.
2501        defaultCallback.assertNoCallback();
2502        assertFalse(mCm.getNetworkCapabilities(wifiNetwork).hasCapability(
2503                NET_CAPABILITY_VALIDATED));
2504        assertTrue(mCm.getNetworkCapabilities(cellNetwork).hasCapability(
2505                NET_CAPABILITY_VALIDATED));
2506        assertEquals(mCm.getActiveNetwork(), wifiNetwork);
2507
2508        // Simulate switching to a carrier that does not restrict avoiding bad wifi, and expect
2509        // that we switch back to cell.
2510        tracker.configRestrictsAvoidBadWifi = false;
2511        tracker.reevaluate();
2512        defaultCallback.expectAvailableCallbacks(mCellNetworkAgent);
2513        assertEquals(mCm.getActiveNetwork(), cellNetwork);
2514
2515        // Switch back to a restrictive carrier.
2516        tracker.configRestrictsAvoidBadWifi = true;
2517        tracker.reevaluate();
2518        defaultCallback.expectAvailableCallbacks(mWiFiNetworkAgent);
2519        assertEquals(mCm.getActiveNetwork(), wifiNetwork);
2520
2521        // Simulate the user selecting "switch" on the dialog, and check that we switch to cell.
2522        mCm.setAvoidUnvalidated(wifiNetwork);
2523        defaultCallback.expectAvailableCallbacks(mCellNetworkAgent);
2524        assertFalse(mCm.getNetworkCapabilities(wifiNetwork).hasCapability(
2525                NET_CAPABILITY_VALIDATED));
2526        assertTrue(mCm.getNetworkCapabilities(cellNetwork).hasCapability(
2527                NET_CAPABILITY_VALIDATED));
2528        assertEquals(mCm.getActiveNetwork(), cellNetwork);
2529
2530        // Disconnect and reconnect wifi to clear the one-time switch above.
2531        mWiFiNetworkAgent.disconnect();
2532        mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
2533        mWiFiNetworkAgent.connect(true);
2534        defaultCallback.expectAvailableAndValidatedCallbacks(mWiFiNetworkAgent);
2535        validatedWifiCallback.expectAvailableCallbacks(mWiFiNetworkAgent);
2536        validatedWifiCallback.expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, mWiFiNetworkAgent);
2537        wifiNetwork = mWiFiNetworkAgent.getNetwork();
2538
2539        // Fail validation on wifi and expect the dialog to appear.
2540        mWiFiNetworkAgent.getWrappedNetworkMonitor().gen204ProbeResult = 599;
2541        mCm.reportNetworkConnectivity(wifiNetwork, false);
2542        defaultCallback.expectCapabilitiesWithout(NET_CAPABILITY_VALIDATED, mWiFiNetworkAgent);
2543        validatedWifiCallback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
2544
2545        // Simulate the user selecting "switch" and checking the don't ask again checkbox.
2546        Settings.Global.putInt(cr, Settings.Global.NETWORK_AVOID_BAD_WIFI, 1);
2547        tracker.reevaluate();
2548
2549        // We now switch to cell.
2550        defaultCallback.expectAvailableCallbacks(mCellNetworkAgent);
2551        assertFalse(mCm.getNetworkCapabilities(wifiNetwork).hasCapability(
2552                NET_CAPABILITY_VALIDATED));
2553        assertTrue(mCm.getNetworkCapabilities(cellNetwork).hasCapability(
2554                NET_CAPABILITY_VALIDATED));
2555        assertEquals(mCm.getActiveNetwork(), cellNetwork);
2556
2557        // Simulate the user turning the cellular fallback setting off and then on.
2558        // We switch to wifi and then to cell.
2559        Settings.Global.putString(cr, Settings.Global.NETWORK_AVOID_BAD_WIFI, null);
2560        tracker.reevaluate();
2561        defaultCallback.expectAvailableCallbacks(mWiFiNetworkAgent);
2562        assertEquals(mCm.getActiveNetwork(), wifiNetwork);
2563        Settings.Global.putInt(cr, Settings.Global.NETWORK_AVOID_BAD_WIFI, 1);
2564        tracker.reevaluate();
2565        defaultCallback.expectAvailableCallbacks(mCellNetworkAgent);
2566        assertEquals(mCm.getActiveNetwork(), cellNetwork);
2567
2568        // If cell goes down, we switch to wifi.
2569        mCellNetworkAgent.disconnect();
2570        defaultCallback.expectCallback(CallbackState.LOST, mCellNetworkAgent);
2571        defaultCallback.expectAvailableCallbacks(mWiFiNetworkAgent);
2572        validatedWifiCallback.assertNoCallback();
2573
2574        mCm.unregisterNetworkCallback(cellNetworkCallback);
2575        mCm.unregisterNetworkCallback(validatedWifiCallback);
2576        mCm.unregisterNetworkCallback(defaultCallback);
2577    }
2578
2579    @SmallTest
2580    public void testMeteredMultipathPreferenceSetting() throws Exception {
2581        final ContentResolver cr = mServiceContext.getContentResolver();
2582        final WrappedMultinetworkPolicyTracker tracker = mService.getMultinetworkPolicyTracker();
2583        final String settingName = Settings.Global.NETWORK_METERED_MULTIPATH_PREFERENCE;
2584
2585        for (int config : Arrays.asList(0, 3, 2)) {
2586            for (String setting: Arrays.asList(null, "0", "2", "1")) {
2587                tracker.configMeteredMultipathPreference = config;
2588                Settings.Global.putString(cr, settingName, setting);
2589                tracker.reevaluate();
2590                mService.waitForIdle();
2591
2592                final int expected = (setting != null) ? Integer.parseInt(setting) : config;
2593                String msg = String.format("config=%d, setting=%s", config, setting);
2594                assertEquals(msg, expected, mCm.getMultipathPreference(null));
2595            }
2596        }
2597    }
2598
2599    /**
2600     * Validate that a satisfied network request does not trigger onUnavailable() once the
2601     * time-out period expires.
2602     */
2603    @SmallTest
2604    public void testSatisfiedNetworkRequestDoesNotTriggerOnUnavailable() {
2605        NetworkRequest nr = new NetworkRequest.Builder().addTransportType(
2606                NetworkCapabilities.TRANSPORT_WIFI).build();
2607        final TestNetworkCallback networkCallback = new TestNetworkCallback();
2608        final int timeoutMs = 150;
2609        mCm.requestNetwork(nr, networkCallback, timeoutMs);
2610
2611        mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
2612        mWiFiNetworkAgent.connect(false);
2613        networkCallback.expectAvailableCallbacks(mWiFiNetworkAgent, false, timeoutMs);
2614
2615        // pass timeout and validate that UNAVAILABLE is not called
2616        networkCallback.assertNoCallback();
2617    }
2618
2619    /**
2620     * Validate that a satisfied network request followed by a disconnected (lost) network does
2621     * not trigger onUnavailable() once the time-out period expires.
2622     */
2623    @SmallTest
2624    public void testSatisfiedThenLostNetworkRequestDoesNotTriggerOnUnavailable() {
2625        NetworkRequest nr = new NetworkRequest.Builder().addTransportType(
2626                NetworkCapabilities.TRANSPORT_WIFI).build();
2627        final TestNetworkCallback networkCallback = new TestNetworkCallback();
2628        final int requestTimeoutMs = 100;
2629        mCm.requestNetwork(nr, networkCallback, requestTimeoutMs);
2630
2631        mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
2632        mWiFiNetworkAgent.connect(false);
2633        final int assertTimeoutMs = 150;
2634        networkCallback.expectAvailableCallbacks(mWiFiNetworkAgent, false, assertTimeoutMs);
2635        sleepFor(20);
2636        mWiFiNetworkAgent.disconnect();
2637        networkCallback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
2638
2639        // pass timeout and validate that UNAVAILABLE is not called
2640        sleepFor(100);
2641        networkCallback.assertNoCallback();
2642    }
2643
2644    /**
2645     * Validate that when a time-out is specified for a network request the onUnavailable()
2646     * callback is called when time-out expires. Then validate that if network request is
2647     * (somehow) satisfied - the callback isn't called later.
2648     */
2649    @SmallTest
2650    public void testTimedoutNetworkRequest() {
2651        NetworkRequest nr = new NetworkRequest.Builder().addTransportType(
2652                NetworkCapabilities.TRANSPORT_WIFI).build();
2653        final TestNetworkCallback networkCallback = new TestNetworkCallback();
2654        final int timeoutMs = 10;
2655        mCm.requestNetwork(nr, networkCallback, timeoutMs);
2656
2657        // pass timeout and validate that UNAVAILABLE is called
2658        networkCallback.expectCallback(CallbackState.UNAVAILABLE, null);
2659
2660        // create a network satisfying request - validate that request not triggered
2661        mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
2662        mWiFiNetworkAgent.connect(false);
2663        networkCallback.assertNoCallback();
2664    }
2665
2666    /**
2667     * Validate that when a network request is unregistered (cancelled) the time-out for that
2668     * request doesn't trigger the onUnavailable() callback.
2669     */
2670    @SmallTest
2671    public void testTimedoutAfterUnregisteredNetworkRequest() {
2672        NetworkRequest nr = new NetworkRequest.Builder().addTransportType(
2673                NetworkCapabilities.TRANSPORT_WIFI).build();
2674        final TestNetworkCallback networkCallback = new TestNetworkCallback();
2675        final int timeoutMs = 10;
2676        mCm.requestNetwork(nr, networkCallback, timeoutMs);
2677
2678        // remove request
2679        mCm.unregisterNetworkCallback(networkCallback);
2680
2681        // pass timeout and validate that no callbacks
2682        // Note: doesn't validate that nothing called from CS since even if called the CM already
2683        // unregisters the callback and won't pass it through!
2684        sleepFor(15);
2685        networkCallback.assertNoCallback();
2686
2687        // create a network satisfying request - validate that request not triggered
2688        mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
2689        mWiFiNetworkAgent.connect(false);
2690        networkCallback.assertNoCallback();
2691    }
2692
2693    private static class TestKeepaliveCallback extends PacketKeepaliveCallback {
2694
2695        public static enum CallbackType { ON_STARTED, ON_STOPPED, ON_ERROR };
2696
2697        private class CallbackValue {
2698            public CallbackType callbackType;
2699            public int error;
2700
2701            public CallbackValue(CallbackType type) {
2702                this.callbackType = type;
2703                this.error = PacketKeepalive.SUCCESS;
2704                assertTrue("onError callback must have error", type != CallbackType.ON_ERROR);
2705            }
2706
2707            public CallbackValue(CallbackType type, int error) {
2708                this.callbackType = type;
2709                this.error = error;
2710                assertEquals("error can only be set for onError", type, CallbackType.ON_ERROR);
2711            }
2712
2713            @Override
2714            public boolean equals(Object o) {
2715                return o instanceof CallbackValue &&
2716                        this.callbackType == ((CallbackValue) o).callbackType &&
2717                        this.error == ((CallbackValue) o).error;
2718            }
2719
2720            @Override
2721            public String toString() {
2722                return String.format("%s(%s, %d)", getClass().getSimpleName(), callbackType, error);
2723            }
2724        }
2725
2726        private LinkedBlockingQueue<CallbackValue> mCallbacks = new LinkedBlockingQueue<>();
2727
2728        @Override
2729        public void onStarted() {
2730            mCallbacks.add(new CallbackValue(CallbackType.ON_STARTED));
2731        }
2732
2733        @Override
2734        public void onStopped() {
2735            mCallbacks.add(new CallbackValue(CallbackType.ON_STOPPED));
2736        }
2737
2738        @Override
2739        public void onError(int error) {
2740            mCallbacks.add(new CallbackValue(CallbackType.ON_ERROR, error));
2741        }
2742
2743        private void expectCallback(CallbackValue callbackValue) {
2744            try {
2745                assertEquals(
2746                        callbackValue,
2747                        mCallbacks.poll(TIMEOUT_MS, TimeUnit.MILLISECONDS));
2748            } catch (InterruptedException e) {
2749                fail(callbackValue.callbackType + " callback not seen after " + TIMEOUT_MS + " ms");
2750            }
2751        }
2752
2753        public void expectStarted() {
2754            expectCallback(new CallbackValue(CallbackType.ON_STARTED));
2755        }
2756
2757        public void expectStopped() {
2758            expectCallback(new CallbackValue(CallbackType.ON_STOPPED));
2759        }
2760
2761        public void expectError(int error) {
2762            expectCallback(new CallbackValue(CallbackType.ON_ERROR, error));
2763        }
2764    }
2765
2766    private Network connectKeepaliveNetwork(LinkProperties lp) {
2767        // Ensure the network is disconnected before we do anything.
2768        if (mWiFiNetworkAgent != null) {
2769            assertNull(mCm.getNetworkCapabilities(mWiFiNetworkAgent.getNetwork()));
2770        }
2771
2772        mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
2773        ConditionVariable cv = waitForConnectivityBroadcasts(1);
2774        mWiFiNetworkAgent.connect(true);
2775        waitFor(cv);
2776        verifyActiveNetwork(TRANSPORT_WIFI);
2777        mWiFiNetworkAgent.sendLinkProperties(lp);
2778        mService.waitForIdle();
2779        return mWiFiNetworkAgent.getNetwork();
2780    }
2781
2782    @SmallTest
2783    public void testPacketKeepalives() throws Exception {
2784        InetAddress myIPv4 = InetAddress.getByName("192.0.2.129");
2785        InetAddress notMyIPv4 = InetAddress.getByName("192.0.2.35");
2786        InetAddress myIPv6 = InetAddress.getByName("2001:db8::1");
2787        InetAddress dstIPv4 = InetAddress.getByName("8.8.8.8");
2788        InetAddress dstIPv6 = InetAddress.getByName("2001:4860:4860::8888");
2789
2790        LinkProperties lp = new LinkProperties();
2791        lp.setInterfaceName("wlan12");
2792        lp.addLinkAddress(new LinkAddress(myIPv6, 64));
2793        lp.addLinkAddress(new LinkAddress(myIPv4, 25));
2794        lp.addRoute(new RouteInfo(InetAddress.getByName("fe80::1234")));
2795        lp.addRoute(new RouteInfo(InetAddress.getByName("192.0.2.254")));
2796
2797        Network notMyNet = new Network(61234);
2798        Network myNet = connectKeepaliveNetwork(lp);
2799
2800        TestKeepaliveCallback callback = new TestKeepaliveCallback();
2801        PacketKeepalive ka;
2802
2803        // Attempt to start keepalives with invalid parameters and check for errors.
2804        ka = mCm.startNattKeepalive(notMyNet, 25, callback, myIPv4, 1234, dstIPv4);
2805        callback.expectError(PacketKeepalive.ERROR_INVALID_NETWORK);
2806
2807        ka = mCm.startNattKeepalive(myNet, 19, callback, notMyIPv4, 1234, dstIPv4);
2808        callback.expectError(PacketKeepalive.ERROR_INVALID_INTERVAL);
2809
2810        ka = mCm.startNattKeepalive(myNet, 25, callback, myIPv4, 1234, dstIPv6);
2811        callback.expectError(PacketKeepalive.ERROR_INVALID_IP_ADDRESS);
2812
2813        ka = mCm.startNattKeepalive(myNet, 25, callback, myIPv6, 1234, dstIPv4);
2814        callback.expectError(PacketKeepalive.ERROR_INVALID_IP_ADDRESS);
2815
2816        ka = mCm.startNattKeepalive(myNet, 25, callback, myIPv6, 1234, dstIPv6);
2817        callback.expectError(PacketKeepalive.ERROR_INVALID_IP_ADDRESS);  // NAT-T is IPv4-only.
2818
2819        ka = mCm.startNattKeepalive(myNet, 25, callback, myIPv4, 123456, dstIPv4);
2820        callback.expectError(PacketKeepalive.ERROR_INVALID_PORT);
2821
2822        ka = mCm.startNattKeepalive(myNet, 25, callback, myIPv4, 123456, dstIPv4);
2823        callback.expectError(PacketKeepalive.ERROR_INVALID_PORT);
2824
2825        ka = mCm.startNattKeepalive(myNet, 25, callback, myIPv4, 12345, dstIPv4);
2826        callback.expectError(PacketKeepalive.ERROR_HARDWARE_UNSUPPORTED);
2827
2828        ka = mCm.startNattKeepalive(myNet, 25, callback, myIPv4, 12345, dstIPv4);
2829        callback.expectError(PacketKeepalive.ERROR_HARDWARE_UNSUPPORTED);
2830
2831        // Check that a started keepalive can be stopped.
2832        mWiFiNetworkAgent.setStartKeepaliveError(PacketKeepalive.SUCCESS);
2833        ka = mCm.startNattKeepalive(myNet, 25, callback, myIPv4, 12345, dstIPv4);
2834        callback.expectStarted();
2835        mWiFiNetworkAgent.setStopKeepaliveError(PacketKeepalive.SUCCESS);
2836        ka.stop();
2837        callback.expectStopped();
2838
2839        // Check that deleting the IP address stops the keepalive.
2840        LinkProperties bogusLp = new LinkProperties(lp);
2841        ka = mCm.startNattKeepalive(myNet, 25, callback, myIPv4, 12345, dstIPv4);
2842        callback.expectStarted();
2843        bogusLp.removeLinkAddress(new LinkAddress(myIPv4, 25));
2844        bogusLp.addLinkAddress(new LinkAddress(notMyIPv4, 25));
2845        mWiFiNetworkAgent.sendLinkProperties(bogusLp);
2846        callback.expectError(PacketKeepalive.ERROR_INVALID_IP_ADDRESS);
2847        mWiFiNetworkAgent.sendLinkProperties(lp);
2848
2849        // Check that a started keepalive is stopped correctly when the network disconnects.
2850        ka = mCm.startNattKeepalive(myNet, 25, callback, myIPv4, 12345, dstIPv4);
2851        callback.expectStarted();
2852        mWiFiNetworkAgent.disconnect();
2853        waitFor(mWiFiNetworkAgent.getDisconnectedCV());
2854        callback.expectError(PacketKeepalive.ERROR_INVALID_NETWORK);
2855
2856        // ... and that stopping it after that has no adverse effects.
2857        mService.waitForIdle();
2858        final Network myNetAlias = myNet;
2859        assertNull(mCm.getNetworkCapabilities(myNetAlias));
2860        ka.stop();
2861
2862        // Reconnect.
2863        myNet = connectKeepaliveNetwork(lp);
2864        mWiFiNetworkAgent.setStartKeepaliveError(PacketKeepalive.SUCCESS);
2865
2866        // Check things work as expected when the keepalive is stopped and the network disconnects.
2867        ka = mCm.startNattKeepalive(myNet, 25, callback, myIPv4, 12345, dstIPv4);
2868        callback.expectStarted();
2869        ka.stop();
2870        mWiFiNetworkAgent.disconnect();
2871        waitFor(mWiFiNetworkAgent.getDisconnectedCV());
2872        mService.waitForIdle();
2873        callback.expectStopped();
2874
2875        // Reconnect.
2876        myNet = connectKeepaliveNetwork(lp);
2877        mWiFiNetworkAgent.setStartKeepaliveError(PacketKeepalive.SUCCESS);
2878
2879        // Check that keepalive slots start from 1 and increment. The first one gets slot 1.
2880        mWiFiNetworkAgent.setExpectedKeepaliveSlot(1);
2881        ka = mCm.startNattKeepalive(myNet, 25, callback, myIPv4, 12345, dstIPv4);
2882        callback.expectStarted();
2883
2884        // The second one gets slot 2.
2885        mWiFiNetworkAgent.setExpectedKeepaliveSlot(2);
2886        TestKeepaliveCallback callback2 = new TestKeepaliveCallback();
2887        PacketKeepalive ka2 = mCm.startNattKeepalive(myNet, 25, callback2, myIPv4, 6789, dstIPv4);
2888        callback2.expectStarted();
2889
2890        // Now stop the first one and create a third. This also gets slot 1.
2891        ka.stop();
2892        callback.expectStopped();
2893
2894        mWiFiNetworkAgent.setExpectedKeepaliveSlot(1);
2895        TestKeepaliveCallback callback3 = new TestKeepaliveCallback();
2896        PacketKeepalive ka3 = mCm.startNattKeepalive(myNet, 25, callback3, myIPv4, 9876, dstIPv4);
2897        callback3.expectStarted();
2898
2899        ka2.stop();
2900        callback2.expectStopped();
2901
2902        ka3.stop();
2903        callback3.expectStopped();
2904    }
2905
2906    @SmallTest
2907    public void testGetCaptivePortalServerUrl() throws Exception {
2908        String url = mCm.getCaptivePortalServerUrl();
2909        assertEquals("http://connectivitycheck.gstatic.com/generate_204", url);
2910    }
2911
2912    private static class TestNetworkPinner extends NetworkPinner {
2913        public static boolean awaitPin(int timeoutMs) {
2914            synchronized(sLock) {
2915                if (sNetwork == null) {
2916                    try {
2917                        sLock.wait(timeoutMs);
2918                    } catch (InterruptedException e) {}
2919                }
2920                return sNetwork != null;
2921            }
2922        }
2923
2924        public static boolean awaitUnpin(int timeoutMs) {
2925            synchronized(sLock) {
2926                if (sNetwork != null) {
2927                    try {
2928                        sLock.wait(timeoutMs);
2929                    } catch (InterruptedException e) {}
2930                }
2931                return sNetwork == null;
2932            }
2933        }
2934    }
2935
2936    private void assertPinnedToWifiWithCellDefault() {
2937        assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getBoundNetworkForProcess());
2938        assertEquals(mCellNetworkAgent.getNetwork(), mCm.getActiveNetwork());
2939    }
2940
2941    private void assertPinnedToWifiWithWifiDefault() {
2942        assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getBoundNetworkForProcess());
2943        assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetwork());
2944    }
2945
2946    private void assertNotPinnedToWifi() {
2947        assertNull(mCm.getBoundNetworkForProcess());
2948        assertEquals(mCellNetworkAgent.getNetwork(), mCm.getActiveNetwork());
2949    }
2950
2951    @SmallTest
2952    public void testNetworkPinner() {
2953        NetworkRequest wifiRequest = new NetworkRequest.Builder()
2954                .addTransportType(TRANSPORT_WIFI)
2955                .build();
2956        assertNull(mCm.getBoundNetworkForProcess());
2957
2958        TestNetworkPinner.pin(mServiceContext, wifiRequest);
2959        assertNull(mCm.getBoundNetworkForProcess());
2960
2961        mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
2962        mCellNetworkAgent.connect(true);
2963        mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
2964        mWiFiNetworkAgent.connect(false);
2965
2966        // When wi-fi connects, expect to be pinned.
2967        assertTrue(TestNetworkPinner.awaitPin(100));
2968        assertPinnedToWifiWithCellDefault();
2969
2970        // Disconnect and expect the pin to drop.
2971        mWiFiNetworkAgent.disconnect();
2972        assertTrue(TestNetworkPinner.awaitUnpin(100));
2973        assertNotPinnedToWifi();
2974
2975        // Reconnecting does not cause the pin to come back.
2976        mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
2977        mWiFiNetworkAgent.connect(false);
2978        assertFalse(TestNetworkPinner.awaitPin(100));
2979        assertNotPinnedToWifi();
2980
2981        // Pinning while connected causes the pin to take effect immediately.
2982        TestNetworkPinner.pin(mServiceContext, wifiRequest);
2983        assertTrue(TestNetworkPinner.awaitPin(100));
2984        assertPinnedToWifiWithCellDefault();
2985
2986        // Explicitly unpin and expect to use the default network again.
2987        TestNetworkPinner.unpin();
2988        assertNotPinnedToWifi();
2989
2990        // Disconnect cell and wifi.
2991        ConditionVariable cv = waitForConnectivityBroadcasts(3);  // cell down, wifi up, wifi down.
2992        mCellNetworkAgent.disconnect();
2993        mWiFiNetworkAgent.disconnect();
2994        waitFor(cv);
2995
2996        // Pinning takes effect even if the pinned network is the default when the pin is set...
2997        TestNetworkPinner.pin(mServiceContext, wifiRequest);
2998        mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
2999        mWiFiNetworkAgent.connect(false);
3000        assertTrue(TestNetworkPinner.awaitPin(100));
3001        assertPinnedToWifiWithWifiDefault();
3002
3003        // ... and is maintained even when that network is no longer the default.
3004        cv = waitForConnectivityBroadcasts(1);
3005        mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
3006        mCellNetworkAgent.connect(true);
3007        waitFor(cv);
3008        assertPinnedToWifiWithCellDefault();
3009    }
3010
3011    @SmallTest
3012    public void testNetworkRequestMaximum() {
3013        final int MAX_REQUESTS = 100;
3014        // Test that the limit is enforced when MAX_REQUESTS simultaneous requests are added.
3015        NetworkRequest networkRequest = new NetworkRequest.Builder().build();
3016        ArrayList<NetworkCallback> networkCallbacks = new ArrayList<NetworkCallback>();
3017        try {
3018            for (int i = 0; i < MAX_REQUESTS; i++) {
3019                NetworkCallback networkCallback = new NetworkCallback();
3020                mCm.requestNetwork(networkRequest, networkCallback);
3021                networkCallbacks.add(networkCallback);
3022            }
3023            fail("Registering " + MAX_REQUESTS + " NetworkRequests did not throw exception");
3024        } catch (IllegalArgumentException expected) {}
3025        for (NetworkCallback networkCallback : networkCallbacks) {
3026            mCm.unregisterNetworkCallback(networkCallback);
3027        }
3028        networkCallbacks.clear();
3029
3030        try {
3031            for (int i = 0; i < MAX_REQUESTS; i++) {
3032                NetworkCallback networkCallback = new NetworkCallback();
3033                mCm.registerNetworkCallback(networkRequest, networkCallback);
3034                networkCallbacks.add(networkCallback);
3035            }
3036            fail("Registering " + MAX_REQUESTS + " NetworkCallbacks did not throw exception");
3037        } catch (IllegalArgumentException expected) {}
3038        for (NetworkCallback networkCallback : networkCallbacks) {
3039            mCm.unregisterNetworkCallback(networkCallback);
3040        }
3041        networkCallbacks.clear();
3042
3043        ArrayList<PendingIntent> pendingIntents = new ArrayList<PendingIntent>();
3044        try {
3045            for (int i = 0; i < MAX_REQUESTS + 1; i++) {
3046                PendingIntent pendingIntent =
3047                        PendingIntent.getBroadcast(mContext, 0, new Intent("a" + i), 0);
3048                mCm.requestNetwork(networkRequest, pendingIntent);
3049                pendingIntents.add(pendingIntent);
3050            }
3051            fail("Registering " + MAX_REQUESTS +
3052                    " PendingIntent NetworkRequests did not throw exception");
3053        } catch (IllegalArgumentException expected) {}
3054        for (PendingIntent pendingIntent : pendingIntents) {
3055            mCm.unregisterNetworkCallback(pendingIntent);
3056        }
3057        pendingIntents.clear();
3058
3059        try {
3060            for (int i = 0; i < MAX_REQUESTS + 1; i++) {
3061                PendingIntent pendingIntent =
3062                        PendingIntent.getBroadcast(mContext, 0, new Intent("a" + i), 0);
3063                mCm.registerNetworkCallback(networkRequest, pendingIntent);
3064                pendingIntents.add(pendingIntent);
3065            }
3066            fail("Registering " + MAX_REQUESTS +
3067                    " PendingIntent NetworkCallbacks did not throw exception");
3068        } catch (IllegalArgumentException expected) {}
3069        for (PendingIntent pendingIntent : pendingIntents) {
3070            mCm.unregisterNetworkCallback(pendingIntent);
3071        }
3072        pendingIntents.clear();
3073        mService.waitForIdle(5000);
3074
3075        // Test that the limit is not hit when MAX_REQUESTS requests are added and removed.
3076        for (int i = 0; i < MAX_REQUESTS; i++) {
3077            NetworkCallback networkCallback = new NetworkCallback();
3078            mCm.requestNetwork(networkRequest, networkCallback);
3079            mCm.unregisterNetworkCallback(networkCallback);
3080        }
3081        mService.waitForIdle();
3082        for (int i = 0; i < MAX_REQUESTS; i++) {
3083            NetworkCallback networkCallback = new NetworkCallback();
3084            mCm.registerNetworkCallback(networkRequest, networkCallback);
3085            mCm.unregisterNetworkCallback(networkCallback);
3086        }
3087        mService.waitForIdle();
3088        for (int i = 0; i < MAX_REQUESTS; i++) {
3089            PendingIntent pendingIntent =
3090                    PendingIntent.getBroadcast(mContext, 0, new Intent("b" + i), 0);
3091            mCm.requestNetwork(networkRequest, pendingIntent);
3092            mCm.unregisterNetworkCallback(pendingIntent);
3093        }
3094        mService.waitForIdle();
3095        for (int i = 0; i < MAX_REQUESTS; i++) {
3096            PendingIntent pendingIntent =
3097                    PendingIntent.getBroadcast(mContext, 0, new Intent("c" + i), 0);
3098            mCm.registerNetworkCallback(networkRequest, pendingIntent);
3099            mCm.unregisterNetworkCallback(pendingIntent);
3100        }
3101    }
3102
3103    /* test utilities */
3104    // TODO: eliminate all usages of sleepFor and replace by proper timeouts/waitForIdle.
3105    static private void sleepFor(int ms) {
3106        try {
3107            Thread.sleep(ms);
3108        } catch (InterruptedException e) {
3109        }
3110    }
3111}
3112