OSDN Git Service

6e5ac8a47b6fc91c3232cc0586af8f966ba895b9
[android-x86/frameworks-base.git] / tests / net / java / com / android / server / ConnectivityServiceTest.java
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
17 package com.android.server;
18
19 import static android.net.ConnectivityManager.CONNECTIVITY_ACTION;
20 import static android.net.ConnectivityManager.TYPE_ETHERNET;
21 import static android.net.ConnectivityManager.TYPE_MOBILE;
22 import static android.net.ConnectivityManager.TYPE_WIFI;
23 import static android.net.ConnectivityManager.getNetworkTypeName;
24 import static android.net.NetworkCapabilities.*;
25
26 import static org.mockito.Mockito.anyBoolean;
27 import static org.mockito.Mockito.anyInt;
28 import static org.mockito.Mockito.eq;
29 import static org.mockito.Mockito.mock;
30 import static org.mockito.Mockito.spy;
31 import static org.mockito.Mockito.when;
32
33 import android.app.NotificationManager;
34 import android.app.PendingIntent;
35 import android.content.BroadcastReceiver;
36 import android.content.ContentResolver;
37 import android.content.Context;
38 import android.content.ContextWrapper;
39 import android.content.Intent;
40 import android.content.IntentFilter;
41 import android.content.res.Resources;
42 import android.net.CaptivePortal;
43 import android.net.ConnectivityManager;
44 import android.net.ConnectivityManager.NetworkCallback;
45 import android.net.ConnectivityManager.PacketKeepalive;
46 import android.net.ConnectivityManager.PacketKeepaliveCallback;
47 import android.net.INetworkPolicyManager;
48 import android.net.INetworkStatsService;
49 import android.net.IpPrefix;
50 import android.net.LinkAddress;
51 import android.net.LinkProperties;
52 import android.net.MatchAllNetworkSpecifier;
53 import android.net.Network;
54 import android.net.NetworkAgent;
55 import android.net.NetworkCapabilities;
56 import android.net.NetworkConfig;
57 import android.net.NetworkFactory;
58 import android.net.NetworkInfo;
59 import android.net.NetworkInfo.DetailedState;
60 import android.net.NetworkMisc;
61 import android.net.NetworkRequest;
62 import android.net.NetworkSpecifier;
63 import android.net.RouteInfo;
64 import android.net.StringNetworkSpecifier;
65 import android.net.metrics.IpConnectivityLog;
66 import android.net.util.MultinetworkPolicyTracker;
67 import android.os.ConditionVariable;
68 import android.os.Handler;
69 import android.os.HandlerThread;
70 import android.os.IBinder;
71 import android.os.INetworkManagementService;
72 import android.os.Looper;
73 import android.os.Message;
74 import android.os.MessageQueue;
75 import android.os.Messenger;
76 import android.os.MessageQueue.IdleHandler;
77 import android.os.Parcel;
78 import android.os.Parcelable;
79 import android.os.Process;
80 import android.os.SystemClock;
81 import android.os.UserHandle;
82 import android.provider.Settings;
83 import android.test.AndroidTestCase;
84 import android.test.mock.MockContentResolver;
85 import android.test.suitebuilder.annotation.SmallTest;
86 import android.text.TextUtils;
87 import android.util.Log;
88 import android.util.LogPrinter;
89
90 import com.android.internal.util.WakeupMessage;
91 import com.android.internal.util.test.BroadcastInterceptingContext;
92 import com.android.internal.util.test.FakeSettingsProvider;
93 import com.android.server.connectivity.MockableSystemProperties;
94 import com.android.server.connectivity.NetworkAgentInfo;
95 import com.android.server.connectivity.NetworkMonitor;
96 import com.android.server.connectivity.NetworkMonitor.CaptivePortalProbeResult;
97 import com.android.server.net.NetworkPinner;
98 import com.android.server.net.NetworkPolicyManagerInternal;
99
100 import org.mockito.Mock;
101 import org.mockito.MockitoAnnotations;
102 import org.mockito.Spy;
103
104 import java.net.InetAddress;
105 import java.util.ArrayList;
106 import java.util.Arrays;
107 import java.util.Objects;
108 import java.util.concurrent.CountDownLatch;
109 import java.util.concurrent.LinkedBlockingQueue;
110 import java.util.concurrent.TimeUnit;
111 import java.util.concurrent.atomic.AtomicBoolean;
112 import 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  */
120 public 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 }