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 
bindProcessToNetwork(Network network)139         public synchronized boolean bindProcessToNetwork(Network network) {
140             mFakeBoundNetwork = network;
141             return true;
142         }
143 
getBoundNetworkForProcess()144         public synchronized Network getBoundNetworkForProcess() {
145             return mFakeBoundNetwork;
146         }
147 
WrappedConnectivityManager(Context context, ConnectivityService service)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 
MockContext(Context base)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
startActivityAsUser(Intent intent, UserHandle handle)175         public void startActivityAsUser(Intent intent, UserHandle handle) {
176             mStartedActivities.offer(intent);
177         }
178 
expectStartActivityIntent(int timeoutMs)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 
expectNoStartActivityIntent(int timeoutMs)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
getSystemService(String name)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
getContentResolver()203         public ContentResolver getContentResolver() {
204             return mContentResolver;
205         }
206 
207         @Override
getResources()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      */
waitForIdleHandler(HandlerThread handlerThread, int timeoutMs)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
testWaitForIdle()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.
verifyThatNotWaitingForIdleCausesRaceConditions()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 
MockNetworkAgent(int transport)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 
waitForIdle(int timeoutMs)351         public void waitForIdle(int timeoutMs) {
352             waitForIdleHandler(mHandlerThread, timeoutMs);
353         }
354 
waitForIdle()355         public void waitForIdle() {
356             waitForIdle(TIMEOUT_MS);
357         }
358 
adjustScore(int change)359         public void adjustScore(int change) {
360             mScore += change;
361             mNetworkAgent.sendNetworkScore(mScore);
362         }
363 
addCapability(int capability)364         public void addCapability(int capability) {
365             mNetworkCapabilities.addCapability(capability);
366             mNetworkAgent.sendNetworkCapabilities(mNetworkCapabilities);
367         }
368 
removeCapability(int capability)369         public void removeCapability(int capability) {
370             mNetworkCapabilities.removeCapability(capability);
371             mNetworkAgent.sendNetworkCapabilities(mNetworkCapabilities);
372         }
373 
setSignalStrength(int signalStrength)374         public void setSignalStrength(int signalStrength) {
375             mNetworkCapabilities.setSignalStrength(signalStrength);
376             mNetworkAgent.sendNetworkCapabilities(mNetworkCapabilities);
377         }
378 
setNetworkSpecifier(NetworkSpecifier networkSpecifier)379         public void setNetworkSpecifier(NetworkSpecifier networkSpecifier) {
380             mNetworkCapabilities.setNetworkSpecifier(networkSpecifier);
381             mNetworkAgent.sendNetworkCapabilities(mNetworkCapabilities);
382         }
383 
connectWithoutInternet()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          */
connect(boolean validated)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 
connectWithCaptivePortal(String redirectUrl)429         public void connectWithCaptivePortal(String redirectUrl) {
430             mWrappedNetworkMonitor.gen204ProbeResult = 200;
431             mWrappedNetworkMonitor.gen204ProbeRedirectUrl = redirectUrl;
432             connect(false);
433         }
434 
suspend()435         public void suspend() {
436             mNetworkInfo.setDetailedState(DetailedState.SUSPENDED, null, null);
437             mNetworkAgent.sendNetworkInfo(mNetworkInfo);
438         }
439 
disconnect()440         public void disconnect() {
441             mNetworkInfo.setDetailedState(DetailedState.DISCONNECTED, null, null);
442             mNetworkAgent.sendNetworkInfo(mNetworkInfo);
443         }
444 
getNetwork()445         public Network getNetwork() {
446             return new Network(mNetworkAgent.netId);
447         }
448 
getPreventReconnectReceived()449         public ConditionVariable getPreventReconnectReceived() {
450             return mPreventReconnectReceived;
451         }
452 
getDisconnectedCV()453         public ConditionVariable getDisconnectedCV() {
454             return mDisconnected;
455         }
456 
getWrappedNetworkMonitor()457         public WrappedNetworkMonitor getWrappedNetworkMonitor() {
458             return mWrappedNetworkMonitor;
459         }
460 
sendLinkProperties(LinkProperties lp)461         public void sendLinkProperties(LinkProperties lp) {
462             mNetworkAgent.sendLinkProperties(lp);
463         }
464 
setStartKeepaliveError(int error)465         public void setStartKeepaliveError(int error) {
466             mStartKeepaliveError = error;
467         }
468 
setStopKeepaliveError(int error)469         public void setStopKeepaliveError(int error) {
470             mStopKeepaliveError = error;
471         }
472 
setExpectedKeepaliveSlot(Integer slot)473         public void setExpectedKeepaliveSlot(Integer slot) {
474             mExpectedKeepaliveSlot = slot;
475         }
476 
waitForRedirectUrl()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 
MockNetworkFactory(Looper looper, Context context, String logTag, NetworkCapabilities filter)505         public MockNetworkFactory(Looper looper, Context context, String logTag,
506                 NetworkCapabilities filter) {
507             super(looper, context, logTag, filter);
508         }
509 
getMyRequestCount()510         public int getMyRequestCount() {
511             return getRequestCount();
512         }
513 
startNetwork()514         protected void startNetwork() {
515             mNetworkStarted.set(true);
516             mNetworkStartedCV.open();
517         }
518 
stopNetwork()519         protected void stopNetwork() {
520             mNetworkStarted.set(false);
521             mNetworkStoppedCV.open();
522         }
523 
getMyStartRequested()524         public boolean getMyStartRequested() {
525             return mNetworkStarted.get();
526         }
527 
getNetworkStartedCV()528         public ConditionVariable getNetworkStartedCV() {
529             mNetworkStartedCV.close();
530             return mNetworkStartedCV;
531         }
532 
getNetworkStoppedCV()533         public ConditionVariable getNetworkStoppedCV() {
534             mNetworkStoppedCV.close();
535             return mNetworkStoppedCV;
536         }
537 
538         @Override
handleAddRequest(NetworkRequest request, int score)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
handleRemoveRequest(NetworkRequest request)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 
assertNoExpectations()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.
expectAddRequests(final int count)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.
expectRemoveRequests(final int count)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.
waitForRequests()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 
waitForNetworkRequests(final int count)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 
FakeWakeupMessage(Context context, Handler handler, String cmdName, int cmd)613         public FakeWakeupMessage(Context context, Handler handler, String cmdName, int cmd) {
614             super(context, handler, cmdName, cmd);
615         }
616 
FakeWakeupMessage(Context context, Handler handler, String cmdName, int cmd, int arg1, int arg2, Object obj)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
schedule(long when)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
cancel()635         public void cancel() {
636             mHandler.removeMessages(mCmd, mObj);
637         }
638 
639         @Override
onAlarm()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 
WrappedNetworkMonitor(Context context, Handler handler, NetworkAgentInfo networkAgentInfo, NetworkRequest defaultRequest, IpConnectivityLog log)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
isCaptivePortal()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 
WrappedMultinetworkPolicyTracker(Context c, Handler h, Runnable r)668         public WrappedMultinetworkPolicyTracker(Context c, Handler h, Runnable r) {
669             super(c, h, r);
670         }
671 
672         @Override
configRestrictsAvoidBadWifi()673         public boolean configRestrictsAvoidBadWifi() {
674             return configRestrictsAvoidBadWifi;
675         }
676 
677         @Override
configMeteredMultipathPreference()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 
WrappedConnectivityService(Context context, INetworkManagementService netManager, INetworkStatsService statsService, INetworkPolicyManager policyManager, IpConnectivityLog log)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
getSystemProperties()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
reserveNetId()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
createNetworkMonitor(Context context, Handler handler, NetworkAgentInfo nai, NetworkRequest defaultRequest)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
createMultinetworkPolicyTracker( Context c, Handler h, Runnable r)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 
getMultinetworkPolicyTracker()742         public WrappedMultinetworkPolicyTracker getMultinetworkPolicyTracker() {
743             return (WrappedMultinetworkPolicyTracker) mMultinetworkPolicyTracker;
744         }
745 
746         @Override
makeWakeupMessage( Context context, Handler handler, String cmdName, int cmd, Object obj)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 
getLastCreatedWrappedNetworkMonitor()752         public WrappedNetworkMonitor getLastCreatedWrappedNetworkMonitor() {
753             return mLastCreatedNetworkMonitor;
754         }
755 
waitForIdle(int timeoutMs)756         public void waitForIdle(int timeoutMs) {
757             waitForIdleHandler(mHandlerThread, timeoutMs);
758         }
759 
waitForIdle()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      */
waitFor(ConditionVariable conditionVariable)769     static private void waitFor(ConditionVariable conditionVariable) {
770         assertTrue(conditionVariable.block(TIMEOUT_MS));
771     }
772 
773     @Override
setUp()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 
tearDown()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 
transportToLegacyType(int transport)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 
verifyActiveNetwork(int transport)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 
verifyNoNetwork()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      */
waitForConnectivityBroadcasts(final int count)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 
testNetworkTypes()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
testLingering()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
testValidatedCellularOutscoresUnvalidatedWiFi()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
testUnvalidatedWifiOutscoresUnvalidatedCellular()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
testUnlingeringDoesNotValidate()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
testCellularOutscoresWeakWifi()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
testReapingNetwork()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
testCellularFallback()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
testWiFiFallback()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;
CallbackInfo(CallbackState s, Network n, Object o)1151         public CallbackInfo(CallbackState s, Network n, Object o) {
1152             state = s; network = n; arg = o;
1153         }
toString()1154         public String toString() {
1155             return String.format("%s (%s) (%s)", state, network, arg);
1156         }
1157         @Override
equals(Object o)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
hashCode()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 
setLastCallback(CallbackState state, Network network, Object o)1183         protected void setLastCallback(CallbackState state, Network network, Object o) {
1184             mCallbacks.offer(new CallbackInfo(state, network, o));
1185         }
1186 
1187         @Override
onAvailable(Network network)1188         public void onAvailable(Network network) {
1189             setLastCallback(CallbackState.AVAILABLE, network, null);
1190         }
1191 
1192         @Override
onCapabilitiesChanged(Network network, NetworkCapabilities netCap)1193         public void onCapabilitiesChanged(Network network, NetworkCapabilities netCap) {
1194             setLastCallback(CallbackState.NETWORK_CAPABILITIES, network, netCap);
1195         }
1196 
1197         @Override
onLinkPropertiesChanged(Network network, LinkProperties linkProp)1198         public void onLinkPropertiesChanged(Network network, LinkProperties linkProp) {
1199             setLastCallback(CallbackState.LINK_PROPERTIES, network, linkProp);
1200         }
1201 
1202         @Override
onUnavailable()1203         public void onUnavailable() {
1204             setLastCallback(CallbackState.UNAVAILABLE, null, null);
1205         }
1206 
1207         @Override
onNetworkSuspended(Network network)1208         public void onNetworkSuspended(Network network) {
1209             setLastCallback(CallbackState.SUSPENDED, network, null);
1210         }
1211 
1212         @Override
onLosing(Network network, int maxMsToLive)1213         public void onLosing(Network network, int maxMsToLive) {
1214             setLastCallback(CallbackState.LOSING, network, maxMsToLive /* autoboxed int */);
1215         }
1216 
1217         @Override
onLost(Network network)1218         public void onLost(Network network) {
1219             setLastCallback(CallbackState.LOST, network, null);
1220         }
1221 
nextCallback(int timeoutMs)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 
expectCallback(CallbackState state, MockNetworkAgent agent, int timeoutMs)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 
expectCallback(CallbackState state, MockNetworkAgent agent)1252         CallbackInfo expectCallback(CallbackState state, MockNetworkAgent agent) {
1253             return expectCallback(state, agent, TIMEOUT_MS);
1254         }
1255 
expectAvailableCallbacks(MockNetworkAgent agent, boolean expectSuspended, int timeoutMs)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 
expectAvailableCallbacks(MockNetworkAgent agent)1265         void expectAvailableCallbacks(MockNetworkAgent agent) {
1266             expectAvailableCallbacks(agent, false, TIMEOUT_MS);
1267         }
1268 
expectAvailableAndSuspendedCallbacks(MockNetworkAgent agent)1269         void expectAvailableAndSuspendedCallbacks(MockNetworkAgent agent) {
1270             expectAvailableCallbacks(agent, true, TIMEOUT_MS);
1271         }
1272 
expectAvailableAndValidatedCallbacks(MockNetworkAgent agent)1273         void expectAvailableAndValidatedCallbacks(MockNetworkAgent agent) {
1274             expectAvailableCallbacks(agent, false, TIMEOUT_MS);
1275             expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, agent);
1276         }
1277 
expectCapabilitiesWith(int capability, MockNetworkAgent agent)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 
expectCapabilitiesWithout(int capability, MockNetworkAgent agent)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 
assertNoCallback()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".
assertNoCallbacks(TestNetworkCallback .... callbacks)1299     static void assertNoCallbacks(TestNetworkCallback ... callbacks) {
1300         for (TestNetworkCallback c : callbacks) {
1301             c.assertNoCallback();
1302         }
1303     }
1304 
1305     @SmallTest
testStateChangeNetworkCallbacks()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
testMultipleLingering()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 
tryNetworkFactoryRequests(int capability)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
testNetworkFactoryRequests()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
testNoMutableNetworkRequests()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
testMMSonWiFi()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
testMMSonCell()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
testCaptivePortal()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
testCaptivePortalApp()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
testAvoidOrIgnoreCaptivePortals()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 
newWifiRequestBuilder()1943     private NetworkRequest.Builder newWifiRequestBuilder() {
1944         return new NetworkRequest.Builder().addTransportType(TRANSPORT_WIFI);
1945     }
1946 
1947     @SmallTest
testNetworkSpecifier()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
testInvalidNetworkSpecifier()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
testRegisterDefaultNetworkCallback()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
testAdditionalStateCallbacks()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 
setCaptivePortalMode(int mode)2161     private void setCaptivePortalMode(int mode) {
2162         ContentResolver cr = mServiceContext.getContentResolver();
2163         Settings.Global.putInt(cr, Settings.Global.CAPTIVE_PORTAL_MODE, mode);
2164     }
2165 
setMobileDataAlwaysOn(boolean enable)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 
isForegroundNetwork(MockNetworkAgent network)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
testBackgroundNetworks()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
testRequestBenchmark()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 
durationOf(Runnable fn)2327     private long durationOf(Runnable fn) {
2328         long startTime = SystemClock.elapsedRealtime();
2329         fn.run();
2330         return SystemClock.elapsedRealtime() - startTime;
2331     }
2332 
assertTimeLimit(String descr, long timeLimit, Runnable fn)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 
awaitLatch(CountDownLatch l, long timeoutMs)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
testMobileDataAlwaysOn()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
testAvoidBadWifiSetting()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
testAvoidBadWifi()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
testMeteredMultipathPreferenceSetting()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
testSatisfiedNetworkRequestDoesNotTriggerOnUnavailable()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
testSatisfiedThenLostNetworkRequestDoesNotTriggerOnUnavailable()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
testTimedoutNetworkRequest()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
testTimedoutAfterUnregisteredNetworkRequest()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 
CallbackValue(CallbackType type)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 
CallbackValue(CallbackType type, int error)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
equals(Object o)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
toString()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
onStarted()2729         public void onStarted() {
2730             mCallbacks.add(new CallbackValue(CallbackType.ON_STARTED));
2731         }
2732 
2733         @Override
onStopped()2734         public void onStopped() {
2735             mCallbacks.add(new CallbackValue(CallbackType.ON_STOPPED));
2736         }
2737 
2738         @Override
onError(int error)2739         public void onError(int error) {
2740             mCallbacks.add(new CallbackValue(CallbackType.ON_ERROR, error));
2741         }
2742 
expectCallback(CallbackValue callbackValue)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 
expectStarted()2753         public void expectStarted() {
2754             expectCallback(new CallbackValue(CallbackType.ON_STARTED));
2755         }
2756 
expectStopped()2757         public void expectStopped() {
2758             expectCallback(new CallbackValue(CallbackType.ON_STOPPED));
2759         }
2760 
expectError(int error)2761         public void expectError(int error) {
2762             expectCallback(new CallbackValue(CallbackType.ON_ERROR, error));
2763         }
2764     }
2765 
connectKeepaliveNetwork(LinkProperties lp)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
testPacketKeepalives()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
testGetCaptivePortalServerUrl()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 {
awaitPin(int timeoutMs)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 
awaitUnpin(int timeoutMs)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 
assertPinnedToWifiWithCellDefault()2936     private void assertPinnedToWifiWithCellDefault() {
2937         assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getBoundNetworkForProcess());
2938         assertEquals(mCellNetworkAgent.getNetwork(), mCm.getActiveNetwork());
2939     }
2940 
assertPinnedToWifiWithWifiDefault()2941     private void assertPinnedToWifiWithWifiDefault() {
2942         assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getBoundNetworkForProcess());
2943         assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetwork());
2944     }
2945 
assertNotPinnedToWifi()2946     private void assertNotPinnedToWifi() {
2947         assertNull(mCm.getBoundNetworkForProcess());
2948         assertEquals(mCellNetworkAgent.getNetwork(), mCm.getActiveNetwork());
2949     }
2950 
2951     @SmallTest
testNetworkPinner()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
testNetworkRequestMaximum()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.
sleepFor(int ms)3105     static private void sleepFor(int ms) {
3106         try {
3107             Thread.sleep(ms);
3108         } catch (InterruptedException e) {
3109         }
3110     }
3111 }
3112