blob: 002953b714a2393b1a6404de898026477abbfdbb [file] [log] [blame]
Jeff Sharkeyfb878b62012-07-26 18:32:30 -07001/*
2 * Copyright (C) 2012 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.server;
18
Erik Klinef851d6d2015-04-20 16:03:48 +090019import static android.net.ConnectivityManager.CONNECTIVITY_ACTION;
Erik Kline79c6d052018-03-21 07:18:33 -070020import static android.net.ConnectivityManager.PRIVATE_DNS_MODE_OFF;
21import static android.net.ConnectivityManager.PRIVATE_DNS_MODE_OPPORTUNISTIC;
22import static android.net.ConnectivityManager.PRIVATE_DNS_MODE_PROVIDER_HOSTNAME;
Lorenzo Colitti7369d8d12016-06-28 21:28:28 +090023import static android.net.ConnectivityManager.TYPE_ETHERNET;
Jeff Sharkeyfb878b62012-07-26 18:32:30 -070024import static android.net.ConnectivityManager.TYPE_MOBILE;
Lorenzo Colitti7bbe3ee2017-08-24 22:35:10 +090025import static android.net.ConnectivityManager.TYPE_MOBILE_FOTA;
26import static android.net.ConnectivityManager.TYPE_MOBILE_MMS;
Hugo Benichi16f0a942017-06-20 14:07:59 +090027import static android.net.ConnectivityManager.TYPE_NONE;
Jeff Sharkeyfb878b62012-07-26 18:32:30 -070028import static android.net.ConnectivityManager.TYPE_WIFI;
Jeff Sharkey72f9c422017-10-27 17:22:59 -060029import static android.net.NetworkCapabilities.NET_CAPABILITY_CAPTIVE_PORTAL;
30import static android.net.NetworkCapabilities.NET_CAPABILITY_CBS;
31import static android.net.NetworkCapabilities.NET_CAPABILITY_DUN;
32import static android.net.NetworkCapabilities.NET_CAPABILITY_EIMS;
33import static android.net.NetworkCapabilities.NET_CAPABILITY_FOREGROUND;
34import static android.net.NetworkCapabilities.NET_CAPABILITY_FOTA;
35import static android.net.NetworkCapabilities.NET_CAPABILITY_IA;
36import static android.net.NetworkCapabilities.NET_CAPABILITY_IMS;
37import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET;
38import static android.net.NetworkCapabilities.NET_CAPABILITY_MMS;
39import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_METERED;
40import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED;
Chalard Jean804b8fb2018-01-30 22:41:41 +090041import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_SUSPENDED;
Jeff Sharkey72f9c422017-10-27 17:22:59 -060042import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VPN;
43import static android.net.NetworkCapabilities.NET_CAPABILITY_RCS;
44import static android.net.NetworkCapabilities.NET_CAPABILITY_SUPL;
45import static android.net.NetworkCapabilities.NET_CAPABILITY_TRUSTED;
46import static android.net.NetworkCapabilities.NET_CAPABILITY_VALIDATED;
47import static android.net.NetworkCapabilities.NET_CAPABILITY_WIFI_P2P;
48import static android.net.NetworkCapabilities.NET_CAPABILITY_XCAP;
49import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
50import static android.net.NetworkCapabilities.TRANSPORT_ETHERNET;
Chalard Jean0b214af2018-01-12 17:22:49 +090051import static android.net.NetworkCapabilities.TRANSPORT_VPN;
Jeff Sharkey72f9c422017-10-27 17:22:59 -060052import static android.net.NetworkCapabilities.TRANSPORT_WIFI;
53import static android.net.NetworkCapabilities.TRANSPORT_WIFI_AWARE;
54
55import static com.android.internal.util.TestUtils.waitForIdleHandler;
Chalard Jeanb72b62d2018-02-16 16:08:35 +090056import static com.android.internal.util.TestUtils.waitForIdleLooper;
Lorenzo Colitti83fa2582015-08-07 12:49:01 +090057
Hugo Benichi4a0c5d72017-10-11 11:26:25 +090058import static org.junit.Assert.assertEquals;
59import static org.junit.Assert.assertFalse;
junyulai4a192e22018-06-13 15:00:37 +080060import static org.junit.Assert.assertNotEquals;
Hugo Benichi4a0c5d72017-10-11 11:26:25 +090061import static org.junit.Assert.assertNotNull;
62import static org.junit.Assert.assertNull;
Jeff Sharkey72f9c422017-10-27 17:22:59 -060063import static org.junit.Assert.assertTrue;
Hugo Benichi4a0c5d72017-10-11 11:26:25 +090064import static org.junit.Assert.fail;
Erik Klinee89953b2018-01-11 16:11:10 +090065import static org.mockito.Matchers.anyInt;
Erik Klinee89953b2018-01-11 16:11:10 +090066import static org.mockito.Mockito.any;
Jeff Sharkey72f9c422017-10-27 17:22:59 -060067import static org.mockito.Mockito.atLeastOnce;
Erik Kline117e7f32018-03-04 21:01:01 +090068import static org.mockito.Mockito.eq;
Jeff Sharkey3671b1e2013-01-31 17:22:26 -080069import static org.mockito.Mockito.mock;
Jeff Sharkey72f9c422017-10-27 17:22:59 -060070import static org.mockito.Mockito.never;
71import static org.mockito.Mockito.reset;
Lorenzo Colitti42cdf572017-03-21 18:54:11 +090072import static org.mockito.Mockito.spy;
Erik Klinee89953b2018-01-11 16:11:10 +090073import static org.mockito.Mockito.times;
Jeff Sharkey72f9c422017-10-27 17:22:59 -060074import static org.mockito.Mockito.verify;
Erik Kline79c6d052018-03-21 07:18:33 -070075import static org.mockito.Mockito.verifyNoMoreInteractions;
Lorenzo Colitti42cdf572017-03-21 18:54:11 +090076import static org.mockito.Mockito.when;
Jeff Sharkeyfb878b62012-07-26 18:32:30 -070077
Erik Klinee89953b2018-01-11 16:11:10 +090078
Lorenzo Colitti73b209382016-09-15 22:18:09 +090079import android.app.NotificationManager;
Paul Jensenbb2e0e92015-06-16 15:11:58 -040080import android.app.PendingIntent;
Paul Jensend7b6ca92015-05-13 14:05:12 -040081import android.content.BroadcastReceiver;
Lorenzo Colitti6d553f62016-06-05 02:20:29 +090082import android.content.ContentResolver;
Jeff Sharkeyfb878b62012-07-26 18:32:30 -070083import android.content.Context;
Paul Jensend7b6ca92015-05-13 14:05:12 -040084import android.content.Intent;
85import android.content.IntentFilter;
Lorenzo Colitti42cdf572017-03-21 18:54:11 +090086import android.content.res.Resources;
Lorenzo Colitti4734cdb2017-04-27 14:30:21 +090087import android.net.CaptivePortal;
Paul Jensend7b6ca92015-05-13 14:05:12 -040088import android.net.ConnectivityManager;
89import android.net.ConnectivityManager.NetworkCallback;
Lorenzo Colitti7914ce52015-09-08 13:21:48 +090090import android.net.ConnectivityManager.PacketKeepalive;
91import android.net.ConnectivityManager.PacketKeepaliveCallback;
Hugo Benichicb883232017-05-11 13:16:17 +090092import android.net.ConnectivityManager.TooManyRequestsException;
Chalard Jeanb72b62d2018-02-16 16:08:35 +090093import android.net.ConnectivityThread;
Jeff Sharkeyfb878b62012-07-26 18:32:30 -070094import android.net.INetworkPolicyManager;
95import android.net.INetworkStatsService;
junyulai4a192e22018-06-13 15:00:37 +080096import android.net.InterfaceConfiguration;
Lorenzo Colitti7914ce52015-09-08 13:21:48 +090097import android.net.IpPrefix;
98import android.net.LinkAddress;
Jeff Sharkeyfb878b62012-07-26 18:32:30 -070099import android.net.LinkProperties;
Etan Cohena7434272017-04-03 12:17:51 -0700100import android.net.MatchAllNetworkSpecifier;
Paul Jensend7b6ca92015-05-13 14:05:12 -0400101import android.net.Network;
102import android.net.NetworkAgent;
103import android.net.NetworkCapabilities;
Robert Greenwalt348e98d2015-06-05 17:55:36 -0700104import android.net.NetworkFactory;
Jeff Sharkeyfb878b62012-07-26 18:32:30 -0700105import android.net.NetworkInfo;
106import android.net.NetworkInfo.DetailedState;
Paul Jensend7b6ca92015-05-13 14:05:12 -0400107import android.net.NetworkMisc;
108import android.net.NetworkRequest;
Etan Cohena7434272017-04-03 12:17:51 -0700109import android.net.NetworkSpecifier;
Rubin Xu1bb5c082017-09-05 18:40:49 +0100110import android.net.NetworkUtils;
Jeff Sharkeyfb878b62012-07-26 18:32:30 -0700111import android.net.RouteInfo;
Etan Cohena7434272017-04-03 12:17:51 -0700112import android.net.StringNetworkSpecifier;
Chalard Jean0b214af2018-01-12 17:22:49 +0900113import android.net.UidRange;
Remi NGUYEN VANd63c1192018-05-22 09:58:19 +0900114import android.net.captiveportal.CaptivePortalProbeResult;
Hugo Benichif9fdf872016-07-28 17:53:06 +0900115import android.net.metrics.IpConnectivityLog;
Lorenzo Colitti58ebe1c2017-01-24 09:41:36 +0900116import android.net.util.MultinetworkPolicyTracker;
Paul Jensend7b6ca92015-05-13 14:05:12 -0400117import android.os.ConditionVariable;
Jeff Sharkeyfb878b62012-07-26 18:32:30 -0700118import android.os.Handler;
Robert Greenwalt348e98d2015-06-05 17:55:36 -0700119import android.os.HandlerThread;
Jeff Sharkeyfb878b62012-07-26 18:32:30 -0700120import android.os.INetworkManagementService;
Lorenzo Colittie58961a2015-08-07 20:17:27 +0900121import android.os.Looper;
Lorenzo Colitti7914ce52015-09-08 13:21:48 +0900122import android.os.Message;
Etan Cohena7434272017-04-03 12:17:51 -0700123import android.os.Parcel;
124import android.os.Parcelable;
Robin Leed2baf792016-03-24 12:07:00 +0000125import android.os.Process;
junyulai4a192e22018-06-13 15:00:37 +0800126import android.os.RemoteException;
Lorenzo Colittibfecba22016-02-21 01:09:26 +0900127import android.os.SystemClock;
Lorenzo Colitti4734cdb2017-04-27 14:30:21 +0900128import android.os.UserHandle;
Lorenzo Colitti6d553f62016-06-05 02:20:29 +0900129import android.provider.Settings;
Hugo Benichi4a0c5d72017-10-11 11:26:25 +0900130import android.support.test.InstrumentationRegistry;
131import android.support.test.filters.SmallTest;
132import android.support.test.runner.AndroidJUnit4;
Lorenzo Colitti6d553f62016-06-05 02:20:29 +0900133import android.test.mock.MockContentResolver;
Rubin Xu1bb5c082017-09-05 18:40:49 +0100134import android.util.ArraySet;
Jeff Sharkeyfb878b62012-07-26 18:32:30 -0700135import android.util.Log;
Jeff Sharkeyfb878b62012-07-26 18:32:30 -0700136
Chalard Jeanf89e8da2018-05-18 21:47:45 +0900137import com.android.internal.net.VpnConfig;
Erik Klinee89953b2018-01-11 16:11:10 +0900138import com.android.internal.util.ArrayUtils;
Lorenzo Colittibfecba22016-02-21 01:09:26 +0900139import com.android.internal.util.WakeupMessage;
Lorenzo Colitti3c295b52016-10-28 12:56:03 +0900140import com.android.internal.util.test.BroadcastInterceptingContext;
Lorenzo Colittib8df76e42016-10-28 12:37:38 +0900141import com.android.internal.util.test.FakeSettingsProvider;
Chalard Jeandda156a2018-01-10 21:19:32 +0900142import com.android.server.connectivity.ConnectivityConstants;
Hugo Benichi64901e52017-10-19 14:42:40 +0900143import com.android.server.connectivity.DefaultNetworkMetrics;
Erik Kline117e7f32018-03-04 21:01:01 +0900144import com.android.server.connectivity.DnsManager;
Hugo Benichi64901e52017-10-19 14:42:40 +0900145import com.android.server.connectivity.IpConnectivityMetrics;
Lorenzo Colitti42cdf572017-03-21 18:54:11 +0900146import com.android.server.connectivity.MockableSystemProperties;
junyulai4a192e22018-06-13 15:00:37 +0800147import com.android.server.connectivity.Nat464Xlat;
Paul Jensencf4c2c62015-07-01 14:16:32 -0400148import com.android.server.connectivity.NetworkAgentInfo;
Paul Jensend7b6ca92015-05-13 14:05:12 -0400149import com.android.server.connectivity.NetworkMonitor;
Chalard Jeandda156a2018-01-10 21:19:32 +0900150import com.android.server.connectivity.Vpn;
Lorenzo Colitti531a3442016-03-01 12:55:58 +0900151import com.android.server.net.NetworkPinner;
Hugo Benichi938ab4f2017-02-11 17:04:43 +0900152import com.android.server.net.NetworkPolicyManagerInternal;
Paul Jensend7b6ca92015-05-13 14:05:12 -0400153
Hugo Benichi4a0c5d72017-10-11 11:26:25 +0900154import org.junit.After;
155import org.junit.Before;
Hugo Benichi849b81b2017-05-25 13:42:31 +0900156import org.junit.Ignore;
Hugo Benichi4a0c5d72017-10-11 11:26:25 +0900157import org.junit.Test;
158import org.junit.runner.RunWith;
Erik Klinee89953b2018-01-11 16:11:10 +0900159import org.mockito.ArgumentCaptor;
Lorenzo Colitti42cdf572017-03-21 18:54:11 +0900160import org.mockito.Mock;
161import org.mockito.MockitoAnnotations;
162import org.mockito.Spy;
163
junyulai4a192e22018-06-13 15:00:37 +0800164import java.net.Inet4Address;
Jeff Sharkeyfb878b62012-07-26 18:32:30 -0700165import java.net.InetAddress;
junyulai4a192e22018-06-13 15:00:37 +0800166import java.net.UnknownHostException;
Paul Jensen4e1d3fd2016-04-08 13:56:52 -0400167import java.util.ArrayList;
Lorenzo Colitti165c51c2016-09-19 01:00:19 +0900168import java.util.Arrays;
Rubin Xu1bb5c082017-09-05 18:40:49 +0100169import java.util.Collection;
junyulai4a192e22018-06-13 15:00:37 +0800170import java.util.Collections;
dalyk1fcb7392018-03-05 12:42:22 -0500171import java.util.HashSet;
Rubin Xu1bb5c082017-09-05 18:40:49 +0100172import java.util.List;
Lorenzo Colitti6ee0a922016-06-27 16:44:07 +0900173import java.util.Objects;
Rubin Xu1bb5c082017-09-05 18:40:49 +0100174import java.util.Set;
Lorenzo Colittiffa390b2015-08-08 01:55:44 +0900175import java.util.concurrent.CountDownLatch;
Lorenzo Colitti7914ce52015-09-08 13:21:48 +0900176import java.util.concurrent.LinkedBlockingQueue;
Lorenzo Colittiffa390b2015-08-08 01:55:44 +0900177import java.util.concurrent.TimeUnit;
Robert Greenwalt348e98d2015-06-05 17:55:36 -0700178import java.util.concurrent.atomic.AtomicBoolean;
Hugo Benichi16f0a942017-06-20 14:07:59 +0900179import java.util.function.Predicate;
Jeff Sharkeyfb878b62012-07-26 18:32:30 -0700180
Hugo Benichi4a0c5d72017-10-11 11:26:25 +0900181
Jeff Sharkeyfb878b62012-07-26 18:32:30 -0700182/**
183 * Tests for {@link ConnectivityService}.
Paul Jensend7b6ca92015-05-13 14:05:12 -0400184 *
185 * Build, install and run with:
Hugo Benichibb91c572017-05-22 10:44:02 +0900186 * runtest frameworks-net -c com.android.server.ConnectivityServiceTest
Jeff Sharkeyfb878b62012-07-26 18:32:30 -0700187 */
Hugo Benichi4a0c5d72017-10-11 11:26:25 +0900188@RunWith(AndroidJUnit4.class)
189@SmallTest
190public class ConnectivityServiceTest {
Jeff Sharkeyfb878b62012-07-26 18:32:30 -0700191 private static final String TAG = "ConnectivityServiceTest";
192
Lorenzo Colittiffa390b2015-08-08 01:55:44 +0900193 private static final int TIMEOUT_MS = 500;
Remi NGUYEN VANef8377d2018-07-26 16:39:45 +0900194 private static final int TEST_LINGER_DELAY_MS = 250;
195 // Chosen to be less than the linger timeout. This ensures that we can distinguish between a
196 // LOST callback that arrives immediately and a LOST callback that arrives after the linger
197 // timeout. For this, our assertions should run fast enough to leave less than
198 // (mService.mLingerDelayMs - TEST_CALLBACK_TIMEOUT_MS) between the time callbacks are
199 // supposedly fired, and the time we call expectCallback.
200 private final static int TEST_CALLBACK_TIMEOUT_MS = 200;
Lorenzo Colittiffa390b2015-08-08 01:55:44 +0900201
junyulai4a192e22018-06-13 15:00:37 +0800202 private static final String CLAT_PREFIX = "v4-";
Erik Kline79c6d052018-03-21 07:18:33 -0700203 private static final String MOBILE_IFNAME = "test_rmnet_data0";
204 private static final String WIFI_IFNAME = "test_wlan0";
205
Lorenzo Colitti4734cdb2017-04-27 14:30:21 +0900206 private MockContext mServiceContext;
Paul Jensencf4c2c62015-07-01 14:16:32 -0400207 private WrappedConnectivityService mService;
Lorenzo Colitti531a3442016-03-01 12:55:58 +0900208 private WrappedConnectivityManager mCm;
Paul Jensend7b6ca92015-05-13 14:05:12 -0400209 private MockNetworkAgent mWiFiNetworkAgent;
210 private MockNetworkAgent mCellNetworkAgent;
Lorenzo Colitti7369d8d12016-06-28 21:28:28 +0900211 private MockNetworkAgent mEthernetNetworkAgent;
Chalard Jeanf89e8da2018-05-18 21:47:45 +0900212 private MockVpn mMockVpn;
Hugo Benichi4a0c5d72017-10-11 11:26:25 +0900213 private Context mContext;
Jeff Sharkeyfb878b62012-07-26 18:32:30 -0700214
Hugo Benichi64901e52017-10-19 14:42:40 +0900215 @Mock IpConnectivityMetrics.Logger mMetricsService;
216 @Mock DefaultNetworkMetrics mDefaultNetworkMetrics;
Erik Klinee89953b2018-01-11 16:11:10 +0900217 @Mock INetworkManagementService mNetworkManagementService;
Jeff Sharkey72f9c422017-10-27 17:22:59 -0600218 @Mock INetworkStatsService mStatsService;
Hugo Benichi64901e52017-10-19 14:42:40 +0900219
Erik Klinee89953b2018-01-11 16:11:10 +0900220 private ArgumentCaptor<String[]> mStringArrayCaptor = ArgumentCaptor.forClass(String[].class);
221
Lorenzo Colitti531a3442016-03-01 12:55:58 +0900222 // This class exists to test bindProcessToNetwork and getBoundNetworkForProcess. These methods
223 // do not go through ConnectivityService but talk to netd directly, so they don't automatically
224 // reflect the state of our test ConnectivityService.
225 private class WrappedConnectivityManager extends ConnectivityManager {
226 private Network mFakeBoundNetwork;
227
228 public synchronized boolean bindProcessToNetwork(Network network) {
229 mFakeBoundNetwork = network;
230 return true;
231 }
232
233 public synchronized Network getBoundNetworkForProcess() {
234 return mFakeBoundNetwork;
235 }
236
237 public WrappedConnectivityManager(Context context, ConnectivityService service) {
238 super(context, service);
239 }
240 }
241
Paul Jensend7b6ca92015-05-13 14:05:12 -0400242 private class MockContext extends BroadcastInterceptingContext {
Lorenzo Colitti6d553f62016-06-05 02:20:29 +0900243 private final MockContentResolver mContentResolver;
244
Lorenzo Colitti42cdf572017-03-21 18:54:11 +0900245 @Spy private Resources mResources;
Lorenzo Colitti4734cdb2017-04-27 14:30:21 +0900246 private final LinkedBlockingQueue<Intent> mStartedActivities = new LinkedBlockingQueue<>();
Lorenzo Colitti42cdf572017-03-21 18:54:11 +0900247
Paul Jensend7b6ca92015-05-13 14:05:12 -0400248 MockContext(Context base) {
249 super(base);
Lorenzo Colitti42cdf572017-03-21 18:54:11 +0900250
251 mResources = spy(base.getResources());
252 when(mResources.getStringArray(com.android.internal.R.array.networkAttributes)).
253 thenReturn(new String[] {
254 "wifi,1,1,1,-1,true",
255 "mobile,0,0,0,-1,true",
256 "mobile_mms,2,0,2,60000,true",
257 });
258
Lorenzo Colitti6d553f62016-06-05 02:20:29 +0900259 mContentResolver = new MockContentResolver();
260 mContentResolver.addProvider(Settings.AUTHORITY, new FakeSettingsProvider());
Paul Jensend7b6ca92015-05-13 14:05:12 -0400261 }
262
263 @Override
Lorenzo Colitti4734cdb2017-04-27 14:30:21 +0900264 public void startActivityAsUser(Intent intent, UserHandle handle) {
265 mStartedActivities.offer(intent);
266 }
267
268 public Intent expectStartActivityIntent(int timeoutMs) {
269 Intent intent = null;
270 try {
271 intent = mStartedActivities.poll(timeoutMs, TimeUnit.MILLISECONDS);
272 } catch (InterruptedException e) {}
273 assertNotNull("Did not receive sign-in intent after " + timeoutMs + "ms", intent);
274 return intent;
275 }
276
277 public void expectNoStartActivityIntent(int timeoutMs) {
278 try {
279 assertNull("Received unexpected Intent to start activity",
280 mStartedActivities.poll(timeoutMs, TimeUnit.MILLISECONDS));
281 } catch (InterruptedException e) {}
282 }
283
284 @Override
Lorenzo Colitti6d553f62016-06-05 02:20:29 +0900285 public Object getSystemService(String name) {
Lorenzo Colitti73b209382016-09-15 22:18:09 +0900286 if (Context.CONNECTIVITY_SERVICE.equals(name)) return mCm;
287 if (Context.NOTIFICATION_SERVICE.equals(name)) return mock(NotificationManager.class);
Paul Jensend7b6ca92015-05-13 14:05:12 -0400288 return super.getSystemService(name);
289 }
Lorenzo Colitti6d553f62016-06-05 02:20:29 +0900290
291 @Override
292 public ContentResolver getContentResolver() {
293 return mContentResolver;
294 }
Lorenzo Colitti42cdf572017-03-21 18:54:11 +0900295
296 @Override
297 public Resources getResources() {
298 return mResources;
299 }
Paul Jensend7b6ca92015-05-13 14:05:12 -0400300 }
301
Hugo Benichi669f0232017-06-29 22:58:39 +0900302 public void waitForIdle(int timeoutMsAsInt) {
303 long timeoutMs = timeoutMsAsInt;
Hugo Benichibb91c572017-05-22 10:44:02 +0900304 waitForIdleHandler(mService.mHandlerThread, timeoutMs);
305 waitForIdle(mCellNetworkAgent, timeoutMs);
306 waitForIdle(mWiFiNetworkAgent, timeoutMs);
307 waitForIdle(mEthernetNetworkAgent, timeoutMs);
308 waitForIdleHandler(mService.mHandlerThread, timeoutMs);
Chalard Jeanb72b62d2018-02-16 16:08:35 +0900309 waitForIdleLooper(ConnectivityThread.getInstanceLooper(), timeoutMs);
Hugo Benichibb91c572017-05-22 10:44:02 +0900310 }
311
Hugo Benichi669f0232017-06-29 22:58:39 +0900312 public void waitForIdle(MockNetworkAgent agent, long timeoutMs) {
Hugo Benichibb91c572017-05-22 10:44:02 +0900313 if (agent == null) {
314 return;
315 }
316 waitForIdleHandler(agent.mHandlerThread, timeoutMs);
317 }
318
319 private void waitForIdle() {
320 waitForIdle(TIMEOUT_MS);
321 }
322
Hugo Benichi4a0c5d72017-10-11 11:26:25 +0900323 @Test
Hugo Benichiad4db4e2016-10-17 15:54:51 +0900324 public void testWaitForIdle() {
Lorenzo Colittie58961a2015-08-07 20:17:27 +0900325 final int attempts = 50; // Causes the test to take about 200ms on bullhead-eng.
326
327 // Tests that waitForIdle returns immediately if the service is already idle.
328 for (int i = 0; i < attempts; i++) {
Hugo Benichibb91c572017-05-22 10:44:02 +0900329 waitForIdle();
Lorenzo Colittie58961a2015-08-07 20:17:27 +0900330 }
331
332 // Bring up a network that we can use to send messages to ConnectivityService.
333 ConditionVariable cv = waitForConnectivityBroadcasts(1);
334 mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
335 mWiFiNetworkAgent.connect(false);
336 waitFor(cv);
337 Network n = mWiFiNetworkAgent.getNetwork();
338 assertNotNull(n);
339
340 // Tests that calling waitForIdle waits for messages to be processed.
341 for (int i = 0; i < attempts; i++) {
342 mWiFiNetworkAgent.setSignalStrength(i);
Hugo Benichibb91c572017-05-22 10:44:02 +0900343 waitForIdle();
Lorenzo Colittie58961a2015-08-07 20:17:27 +0900344 assertEquals(i, mCm.getNetworkCapabilities(n).getSignalStrength());
345 }
Hugo Benichi5d540d12016-10-17 15:54:51 +0900346 }
347
Hugo Benichiad4db4e2016-10-17 15:54:51 +0900348 // This test has an inherent race condition in it, and cannot be enabled for continuous testing
349 // or presubmit tests. It is kept for manual runs and documentation purposes.
Andreas Gampe35dbf352018-01-26 20:41:17 -0800350 @Ignore
Hugo Benichiad4db4e2016-10-17 15:54:51 +0900351 public void verifyThatNotWaitingForIdleCausesRaceConditions() {
Hugo Benichi5d540d12016-10-17 15:54:51 +0900352 // Bring up a network that we can use to send messages to ConnectivityService.
353 ConditionVariable cv = waitForConnectivityBroadcasts(1);
354 mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
355 mWiFiNetworkAgent.connect(false);
356 waitFor(cv);
357 Network n = mWiFiNetworkAgent.getNetwork();
358 assertNotNull(n);
Lorenzo Colittie58961a2015-08-07 20:17:27 +0900359
360 // Ensure that not calling waitForIdle causes a race condition.
Hugo Benichi5d540d12016-10-17 15:54:51 +0900361 final int attempts = 50; // Causes the test to take about 200ms on bullhead-eng.
Lorenzo Colittie58961a2015-08-07 20:17:27 +0900362 for (int i = 0; i < attempts; i++) {
363 mWiFiNetworkAgent.setSignalStrength(i);
364 if (i != mCm.getNetworkCapabilities(n).getSignalStrength()) {
365 // We hit a race condition, as expected. Pass the test.
366 return;
367 }
368 }
369
370 // No race? There is a bug in this test.
371 fail("expected race condition at least once in " + attempts + " attempts");
372 }
373
Paul Jensend7b6ca92015-05-13 14:05:12 -0400374 private class MockNetworkAgent {
Paul Jensencf4c2c62015-07-01 14:16:32 -0400375 private final WrappedNetworkMonitor mWrappedNetworkMonitor;
Paul Jensend7b6ca92015-05-13 14:05:12 -0400376 private final NetworkInfo mNetworkInfo;
377 private final NetworkCapabilities mNetworkCapabilities;
Hugo Benichiad4db4e2016-10-17 15:54:51 +0900378 private final HandlerThread mHandlerThread;
Paul Jensene0988542015-06-25 15:30:08 -0400379 private final ConditionVariable mDisconnected = new ConditionVariable();
Paul Jensen232437312016-04-06 09:51:26 -0400380 private final ConditionVariable mNetworkStatusReceived = new ConditionVariable();
Calvin On1f64f3f2016-10-11 15:10:46 -0700381 private final ConditionVariable mPreventReconnectReceived = new ConditionVariable();
Paul Jensen3d911462015-06-12 06:40:24 -0400382 private int mScore;
Paul Jensend7b6ca92015-05-13 14:05:12 -0400383 private NetworkAgent mNetworkAgent;
Lorenzo Colitti7914ce52015-09-08 13:21:48 +0900384 private int mStartKeepaliveError = PacketKeepalive.ERROR_HARDWARE_UNSUPPORTED;
385 private int mStopKeepaliveError = PacketKeepalive.NO_KEEPALIVE;
386 private Integer mExpectedKeepaliveSlot = null;
Paul Jensen232437312016-04-06 09:51:26 -0400387 // Contains the redirectUrl from networkStatus(). Before reading, wait for
388 // mNetworkStatusReceived.
389 private String mRedirectUrl;
Paul Jensend7b6ca92015-05-13 14:05:12 -0400390
391 MockNetworkAgent(int transport) {
Rubin Xu1bb5c082017-09-05 18:40:49 +0100392 this(transport, new LinkProperties());
393 }
394
395 MockNetworkAgent(int transport, LinkProperties linkProperties) {
Paul Jensend7b6ca92015-05-13 14:05:12 -0400396 final int type = transportToLegacyType(transport);
Chalard Jean0b214af2018-01-12 17:22:49 +0900397 final String typeName = ConnectivityManager.getNetworkTypeName(transport);
Paul Jensend7b6ca92015-05-13 14:05:12 -0400398 mNetworkInfo = new NetworkInfo(type, 0, typeName, "Mock");
399 mNetworkCapabilities = new NetworkCapabilities();
400 mNetworkCapabilities.addTransportType(transport);
Paul Jensend7b6ca92015-05-13 14:05:12 -0400401 switch (transport) {
Lorenzo Colitti7369d8d12016-06-28 21:28:28 +0900402 case TRANSPORT_ETHERNET:
403 mScore = 70;
404 break;
Paul Jensend7b6ca92015-05-13 14:05:12 -0400405 case TRANSPORT_WIFI:
Paul Jensen3d911462015-06-12 06:40:24 -0400406 mScore = 60;
Paul Jensend7b6ca92015-05-13 14:05:12 -0400407 break;
408 case TRANSPORT_CELLULAR:
Paul Jensen3d911462015-06-12 06:40:24 -0400409 mScore = 50;
Paul Jensend7b6ca92015-05-13 14:05:12 -0400410 break;
Hugo Benichi16f0a942017-06-20 14:07:59 +0900411 case TRANSPORT_WIFI_AWARE:
412 mScore = 20;
413 break;
Chalard Jean0b214af2018-01-12 17:22:49 +0900414 case TRANSPORT_VPN:
Chalard Jeanb552c462018-02-21 18:43:54 +0900415 mNetworkCapabilities.removeCapability(NET_CAPABILITY_NOT_VPN);
Chalard Jeandda156a2018-01-10 21:19:32 +0900416 mScore = ConnectivityConstants.VPN_DEFAULT_SCORE;
Chalard Jean0b214af2018-01-12 17:22:49 +0900417 break;
Paul Jensend7b6ca92015-05-13 14:05:12 -0400418 default:
419 throw new UnsupportedOperationException("unimplemented network type");
420 }
Hugo Benichiad4db4e2016-10-17 15:54:51 +0900421 mHandlerThread = new HandlerThread("Mock-" + typeName);
Lorenzo Colittie58961a2015-08-07 20:17:27 +0900422 mHandlerThread.start();
423 mNetworkAgent = new NetworkAgent(mHandlerThread.getLooper(), mServiceContext,
424 "Mock-" + typeName, mNetworkInfo, mNetworkCapabilities,
Rubin Xu1bb5c082017-09-05 18:40:49 +0100425 linkProperties, mScore, new NetworkMisc()) {
Lorenzo Colitti7914ce52015-09-08 13:21:48 +0900426 @Override
Lorenzo Colittie58961a2015-08-07 20:17:27 +0900427 public void unwanted() { mDisconnected.open(); }
Lorenzo Colitti7914ce52015-09-08 13:21:48 +0900428
429 @Override
430 public void startPacketKeepalive(Message msg) {
431 int slot = msg.arg1;
432 if (mExpectedKeepaliveSlot != null) {
433 assertEquals((int) mExpectedKeepaliveSlot, slot);
434 }
435 onPacketKeepaliveEvent(slot, mStartKeepaliveError);
436 }
437
438 @Override
439 public void stopPacketKeepalive(Message msg) {
440 onPacketKeepaliveEvent(msg.arg1, mStopKeepaliveError);
441 }
Paul Jensen232437312016-04-06 09:51:26 -0400442
443 @Override
444 public void networkStatus(int status, String redirectUrl) {
445 mRedirectUrl = redirectUrl;
446 mNetworkStatusReceived.open();
447 }
Calvin On1f64f3f2016-10-11 15:10:46 -0700448
449 @Override
450 protected void preventAutomaticReconnect() {
451 mPreventReconnectReceived.open();
452 }
Paul Jensend7b6ca92015-05-13 14:05:12 -0400453 };
Lorenzo Colittie58961a2015-08-07 20:17:27 +0900454 // Waits for the NetworkAgent to be registered, which includes the creation of the
455 // NetworkMonitor.
Hugo Benichibb91c572017-05-22 10:44:02 +0900456 waitForIdle();
Paul Jensencf4c2c62015-07-01 14:16:32 -0400457 mWrappedNetworkMonitor = mService.getLastCreatedWrappedNetworkMonitor();
Paul Jensen3d911462015-06-12 06:40:24 -0400458 }
459
460 public void adjustScore(int change) {
461 mScore += change;
462 mNetworkAgent.sendNetworkScore(mScore);
Paul Jensend7b6ca92015-05-13 14:05:12 -0400463 }
464
Lorenzo Colitti02cc8392017-05-17 01:28:09 +0900465 public void explicitlySelected(boolean acceptUnvalidated) {
466 mNetworkAgent.explicitlySelected(acceptUnvalidated);
467 }
468
Paul Jensen85cf78e2015-06-25 13:25:07 -0400469 public void addCapability(int capability) {
470 mNetworkCapabilities.addCapability(capability);
471 mNetworkAgent.sendNetworkCapabilities(mNetworkCapabilities);
472 }
473
Lorenzo Colitti7369d8d12016-06-28 21:28:28 +0900474 public void removeCapability(int capability) {
475 mNetworkCapabilities.removeCapability(capability);
476 mNetworkAgent.sendNetworkCapabilities(mNetworkCapabilities);
477 }
478
Chalard Jean0b214af2018-01-12 17:22:49 +0900479 public void setUids(Set<UidRange> uids) {
480 mNetworkCapabilities.setUids(uids);
481 mNetworkAgent.sendNetworkCapabilities(mNetworkCapabilities);
482 }
483
Lorenzo Colittie58961a2015-08-07 20:17:27 +0900484 public void setSignalStrength(int signalStrength) {
485 mNetworkCapabilities.setSignalStrength(signalStrength);
486 mNetworkAgent.sendNetworkCapabilities(mNetworkCapabilities);
487 }
488
Etan Cohena7434272017-04-03 12:17:51 -0700489 public void setNetworkSpecifier(NetworkSpecifier networkSpecifier) {
490 mNetworkCapabilities.setNetworkSpecifier(networkSpecifier);
Lorenzo Colitti6556a222017-04-03 17:46:35 +0900491 mNetworkAgent.sendNetworkCapabilities(mNetworkCapabilities);
492 }
493
Chalard Jeanf89e8da2018-05-18 21:47:45 +0900494 public void setNetworkCapabilities(NetworkCapabilities nc,
495 boolean sendToConnectivityService) {
496 mNetworkCapabilities.set(nc);
497 if (sendToConnectivityService) {
498 mNetworkAgent.sendNetworkCapabilities(mNetworkCapabilities);
499 }
500 }
501
Paul Jensene0988542015-06-25 15:30:08 -0400502 public void connectWithoutInternet() {
503 mNetworkInfo.setDetailedState(DetailedState.CONNECTED, null, null);
504 mNetworkAgent.sendNetworkInfo(mNetworkInfo);
505 }
506
Paul Jensend7b6ca92015-05-13 14:05:12 -0400507 /**
Paul Jensene0988542015-06-25 15:30:08 -0400508 * Transition this NetworkAgent to CONNECTED state with NET_CAPABILITY_INTERNET.
Paul Jensend7b6ca92015-05-13 14:05:12 -0400509 * @param validated Indicate if network should pretend to be validated.
510 */
511 public void connect(boolean validated) {
Hugo Benichi16f0a942017-06-20 14:07:59 +0900512 connect(validated, true);
513 }
514
515 /**
516 * Transition this NetworkAgent to CONNECTED state.
517 * @param validated Indicate if network should pretend to be validated.
518 * @param hasInternet Indicate if network should pretend to have NET_CAPABILITY_INTERNET.
519 */
520 public void connect(boolean validated, boolean hasInternet) {
Lorenzo Colittib57578ca2016-07-01 01:53:25 +0900521 assertEquals("MockNetworkAgents can only be connected once",
522 mNetworkInfo.getDetailedState(), DetailedState.IDLE);
Paul Jensend7b6ca92015-05-13 14:05:12 -0400523 assertFalse(mNetworkCapabilities.hasCapability(NET_CAPABILITY_INTERNET));
524
Paul Jensend7b6ca92015-05-13 14:05:12 -0400525 NetworkCallback callback = null;
526 final ConditionVariable validatedCv = new ConditionVariable();
527 if (validated) {
Paul Jensencf4c2c62015-07-01 14:16:32 -0400528 mWrappedNetworkMonitor.gen204ProbeResult = 204;
Paul Jensend7b6ca92015-05-13 14:05:12 -0400529 NetworkRequest request = new NetworkRequest.Builder()
530 .addTransportType(mNetworkCapabilities.getTransportTypes()[0])
Chalard Jeanfb0c87e2018-04-18 19:18:58 +0900531 .clearCapabilities()
Paul Jensend7b6ca92015-05-13 14:05:12 -0400532 .build();
533 callback = new NetworkCallback() {
534 public void onCapabilitiesChanged(Network network,
535 NetworkCapabilities networkCapabilities) {
Paul Jensencf4c2c62015-07-01 14:16:32 -0400536 if (network.equals(getNetwork()) &&
537 networkCapabilities.hasCapability(NET_CAPABILITY_VALIDATED)) {
Paul Jensend7b6ca92015-05-13 14:05:12 -0400538 validatedCv.open();
539 }
540 }
541 };
Paul Jensencf4c2c62015-07-01 14:16:32 -0400542 mCm.registerNetworkCallback(request, callback);
Paul Jensend7b6ca92015-05-13 14:05:12 -0400543 }
Hugo Benichi16f0a942017-06-20 14:07:59 +0900544 if (hasInternet) {
545 addCapability(NET_CAPABILITY_INTERNET);
546 }
Paul Jensend7b6ca92015-05-13 14:05:12 -0400547
Paul Jensene0988542015-06-25 15:30:08 -0400548 connectWithoutInternet();
Paul Jensend7b6ca92015-05-13 14:05:12 -0400549
550 if (validated) {
551 // Wait for network to validate.
Paul Jensen3d911462015-06-12 06:40:24 -0400552 waitFor(validatedCv);
Paul Jensencf4c2c62015-07-01 14:16:32 -0400553 mWrappedNetworkMonitor.gen204ProbeResult = 500;
Paul Jensend7b6ca92015-05-13 14:05:12 -0400554 }
555
556 if (callback != null) mCm.unregisterNetworkCallback(callback);
557 }
558
Paul Jensen232437312016-04-06 09:51:26 -0400559 public void connectWithCaptivePortal(String redirectUrl) {
Paul Jensencf4c2c62015-07-01 14:16:32 -0400560 mWrappedNetworkMonitor.gen204ProbeResult = 200;
Paul Jensen232437312016-04-06 09:51:26 -0400561 mWrappedNetworkMonitor.gen204ProbeRedirectUrl = redirectUrl;
Paul Jensencf4c2c62015-07-01 14:16:32 -0400562 connect(false);
Paul Jensencf4c2c62015-07-01 14:16:32 -0400563 }
564
Erik Kline1d3db322017-02-28 16:20:20 +0900565 public void suspend() {
566 mNetworkInfo.setDetailedState(DetailedState.SUSPENDED, null, null);
567 mNetworkAgent.sendNetworkInfo(mNetworkInfo);
568 }
569
Chalard Jean804b8fb2018-01-30 22:41:41 +0900570 public void resume() {
571 mNetworkInfo.setDetailedState(DetailedState.CONNECTED, null, null);
572 mNetworkAgent.sendNetworkInfo(mNetworkInfo);
573 }
574
Paul Jensend7b6ca92015-05-13 14:05:12 -0400575 public void disconnect() {
576 mNetworkInfo.setDetailedState(DetailedState.DISCONNECTED, null, null);
577 mNetworkAgent.sendNetworkInfo(mNetworkInfo);
578 }
579
580 public Network getNetwork() {
581 return new Network(mNetworkAgent.netId);
582 }
Paul Jensene0988542015-06-25 15:30:08 -0400583
Calvin On1f64f3f2016-10-11 15:10:46 -0700584 public ConditionVariable getPreventReconnectReceived() {
585 return mPreventReconnectReceived;
586 }
587
Paul Jensene0988542015-06-25 15:30:08 -0400588 public ConditionVariable getDisconnectedCV() {
589 return mDisconnected;
590 }
Paul Jensencf4c2c62015-07-01 14:16:32 -0400591
592 public WrappedNetworkMonitor getWrappedNetworkMonitor() {
593 return mWrappedNetworkMonitor;
594 }
Lorenzo Colitti7914ce52015-09-08 13:21:48 +0900595
596 public void sendLinkProperties(LinkProperties lp) {
597 mNetworkAgent.sendLinkProperties(lp);
598 }
599
600 public void setStartKeepaliveError(int error) {
601 mStartKeepaliveError = error;
602 }
603
604 public void setStopKeepaliveError(int error) {
605 mStopKeepaliveError = error;
606 }
607
608 public void setExpectedKeepaliveSlot(Integer slot) {
609 mExpectedKeepaliveSlot = slot;
610 }
Paul Jensen232437312016-04-06 09:51:26 -0400611
612 public String waitForRedirectUrl() {
613 assertTrue(mNetworkStatusReceived.block(TIMEOUT_MS));
614 return mRedirectUrl;
615 }
Chalard Jean804b8fb2018-01-30 22:41:41 +0900616
Chalard Jeanf89e8da2018-05-18 21:47:45 +0900617 public NetworkAgent getNetworkAgent() {
618 return mNetworkAgent;
619 }
620
Chalard Jean804b8fb2018-01-30 22:41:41 +0900621 public NetworkCapabilities getNetworkCapabilities() {
622 return mNetworkCapabilities;
623 }
Paul Jensend7b6ca92015-05-13 14:05:12 -0400624 }
625
Lorenzo Colittiffa390b2015-08-08 01:55:44 +0900626 /**
627 * A NetworkFactory that allows tests to wait until any in-flight NetworkRequest add or remove
628 * operations have been processed. Before ConnectivityService can add or remove any requests,
629 * the factory must be told to expect those operations by calling expectAddRequests or
630 * expectRemoveRequests.
631 */
Robert Greenwalt348e98d2015-06-05 17:55:36 -0700632 private static class MockNetworkFactory extends NetworkFactory {
Paul Jensencf4c2c62015-07-01 14:16:32 -0400633 private final ConditionVariable mNetworkStartedCV = new ConditionVariable();
634 private final ConditionVariable mNetworkStoppedCV = new ConditionVariable();
Paul Jensencf4c2c62015-07-01 14:16:32 -0400635 private final AtomicBoolean mNetworkStarted = new AtomicBoolean(false);
Robert Greenwalt348e98d2015-06-05 17:55:36 -0700636
Lorenzo Colittiffa390b2015-08-08 01:55:44 +0900637 // Used to expect that requests be removed or added on a separate thread, without sleeping.
638 // Callers can call either expectAddRequests() or expectRemoveRequests() exactly once, then
639 // cause some other thread to add or remove requests, then call waitForRequests(). We can
640 // either expect requests to be added or removed, but not both, because CountDownLatch can
641 // only count in one direction.
642 private CountDownLatch mExpectations;
643
644 // Whether we are currently expecting requests to be added or removed. Valid only if
645 // mExpectations is non-null.
646 private boolean mExpectingAdditions;
647
Robert Greenwalt348e98d2015-06-05 17:55:36 -0700648 public MockNetworkFactory(Looper looper, Context context, String logTag,
649 NetworkCapabilities filter) {
650 super(looper, context, logTag, filter);
651 }
652
653 public int getMyRequestCount() {
654 return getRequestCount();
655 }
656
657 protected void startNetwork() {
658 mNetworkStarted.set(true);
Paul Jensen0a2823e2015-06-12 10:31:09 -0400659 mNetworkStartedCV.open();
Robert Greenwalt348e98d2015-06-05 17:55:36 -0700660 }
661
662 protected void stopNetwork() {
663 mNetworkStarted.set(false);
Paul Jensen0a2823e2015-06-12 10:31:09 -0400664 mNetworkStoppedCV.open();
Robert Greenwalt348e98d2015-06-05 17:55:36 -0700665 }
666
667 public boolean getMyStartRequested() {
668 return mNetworkStarted.get();
669 }
Paul Jensen0a2823e2015-06-12 10:31:09 -0400670
671 public ConditionVariable getNetworkStartedCV() {
672 mNetworkStartedCV.close();
673 return mNetworkStartedCV;
674 }
675
676 public ConditionVariable getNetworkStoppedCV() {
677 mNetworkStoppedCV.close();
678 return mNetworkStoppedCV;
679 }
680
Lorenzo Colittiffa390b2015-08-08 01:55:44 +0900681 @Override
682 protected void handleAddRequest(NetworkRequest request, int score) {
683 // If we're expecting anything, we must be expecting additions.
684 if (mExpectations != null && !mExpectingAdditions) {
685 fail("Can't add requests while expecting requests to be removed");
686 }
687
688 // Add the request.
689 super.handleAddRequest(request, score);
690
691 // Reduce the number of request additions we're waiting for.
692 if (mExpectingAdditions) {
693 assertTrue("Added more requests than expected", mExpectations.getCount() > 0);
694 mExpectations.countDown();
695 }
Paul Jensen0a2823e2015-06-12 10:31:09 -0400696 }
697
Lorenzo Colittiffa390b2015-08-08 01:55:44 +0900698 @Override
699 protected void handleRemoveRequest(NetworkRequest request) {
700 // If we're expecting anything, we must be expecting removals.
701 if (mExpectations != null && mExpectingAdditions) {
702 fail("Can't remove requests while expecting requests to be added");
703 }
704
705 // Remove the request.
706 super.handleRemoveRequest(request);
707
708 // Reduce the number of request removals we're waiting for.
709 if (!mExpectingAdditions) {
710 assertTrue("Removed more requests than expected", mExpectations.getCount() > 0);
711 mExpectations.countDown();
712 }
Paul Jensen0a2823e2015-06-12 10:31:09 -0400713 }
714
Lorenzo Colittiffa390b2015-08-08 01:55:44 +0900715 private void assertNoExpectations() {
716 if (mExpectations != null) {
717 fail("Can't add expectation, " + mExpectations.getCount() + " already pending");
718 }
Paul Jensen0a2823e2015-06-12 10:31:09 -0400719 }
720
Lorenzo Colittiffa390b2015-08-08 01:55:44 +0900721 // Expects that count requests will be added.
722 public void expectAddRequests(final int count) {
723 assertNoExpectations();
724 mExpectingAdditions = true;
725 mExpectations = new CountDownLatch(count);
Paul Jensen0a2823e2015-06-12 10:31:09 -0400726 }
727
Lorenzo Colittiffa390b2015-08-08 01:55:44 +0900728 // Expects that count requests will be removed.
729 public void expectRemoveRequests(final int count) {
730 assertNoExpectations();
731 mExpectingAdditions = false;
732 mExpectations = new CountDownLatch(count);
733 }
734
735 // Waits for the expected request additions or removals to happen within a timeout.
736 public void waitForRequests() throws InterruptedException {
737 assertNotNull("Nothing to wait for", mExpectations);
738 mExpectations.await(TIMEOUT_MS, TimeUnit.MILLISECONDS);
739 final long count = mExpectations.getCount();
740 final String msg = count + " requests still not " +
741 (mExpectingAdditions ? "added" : "removed") +
742 " after " + TIMEOUT_MS + " ms";
743 assertEquals(msg, 0, count);
744 mExpectations = null;
745 }
746
747 public void waitForNetworkRequests(final int count) throws InterruptedException {
748 waitForRequests();
749 assertEquals(count, getMyRequestCount());
Paul Jensen0a2823e2015-06-12 10:31:09 -0400750 }
Robert Greenwalt348e98d2015-06-05 17:55:36 -0700751 }
752
Chalard Jeanf89e8da2018-05-18 21:47:45 +0900753 private static Looper startHandlerThreadAndReturnLooper() {
754 final HandlerThread handlerThread = new HandlerThread("MockVpnThread");
755 handlerThread.start();
756 return handlerThread.getLooper();
757 }
758
759 private class MockVpn extends Vpn {
760 // TODO : the interactions between this mock and the mock network agent are too
761 // hard to get right at this moment, because it's unclear in which case which
762 // target needs to get a method call or both, and in what order. It's because
763 // MockNetworkAgent wants to manage its own NetworkCapabilities, but the Vpn
764 // parent class of MockVpn agent wants that responsibility.
765 // That being said inside the test it should be possible to make the interactions
766 // harder to get wrong with precise speccing, judicious comments, helper methods
767 // and a few sprinkled assertions.
768
769 private boolean mConnected = false;
770 // Careful ! This is different from mNetworkAgent, because MockNetworkAgent does
771 // not inherit from NetworkAgent.
772 private MockNetworkAgent mMockNetworkAgent;
773
774 public MockVpn(int userId) {
775 super(startHandlerThreadAndReturnLooper(), mServiceContext, mNetworkManagementService,
776 userId);
777 }
778
779 public void setNetworkAgent(MockNetworkAgent agent) {
780 waitForIdle(agent, TIMEOUT_MS);
781 mMockNetworkAgent = agent;
782 mNetworkAgent = agent.getNetworkAgent();
783 mNetworkCapabilities.set(agent.getNetworkCapabilities());
784 }
785
786 public void setUids(Set<UidRange> uids) {
787 mNetworkCapabilities.setUids(uids);
788 updateCapabilities();
789 }
790
791 @Override
792 public int getNetId() {
793 return mMockNetworkAgent.getNetwork().netId;
794 }
795
796 @Override
797 public boolean appliesToUid(int uid) {
798 return mConnected; // Trickery to simplify testing.
799 }
800
801 @Override
802 protected boolean isCallerEstablishedOwnerLocked() {
803 return mConnected; // Similar trickery
804 }
805
806 public void connect() {
807 mNetworkCapabilities.set(mMockNetworkAgent.getNetworkCapabilities());
808 mConnected = true;
809 mConfig = new VpnConfig();
810 }
811
812 @Override
813 public void updateCapabilities() {
814 if (!mConnected) return;
815 super.updateCapabilities();
816 // Because super.updateCapabilities will update the capabilities of the agent but not
817 // the mock agent, the mock agent needs to know about them.
818 copyCapabilitiesToNetworkAgent();
819 }
820
821 private void copyCapabilitiesToNetworkAgent() {
822 if (null != mMockNetworkAgent) {
823 mMockNetworkAgent.setNetworkCapabilities(mNetworkCapabilities,
824 false /* sendToConnectivityService */);
825 }
826 }
827
828 public void disconnect() {
829 mConnected = false;
830 mConfig = null;
831 }
832 }
833
Lorenzo Colittibfecba22016-02-21 01:09:26 +0900834 private class FakeWakeupMessage extends WakeupMessage {
835 private static final int UNREASONABLY_LONG_WAIT = 1000;
836
837 public FakeWakeupMessage(Context context, Handler handler, String cmdName, int cmd) {
838 super(context, handler, cmdName, cmd);
839 }
840
Lorenzo Colittib57578ca2016-07-01 01:53:25 +0900841 public FakeWakeupMessage(Context context, Handler handler, String cmdName, int cmd,
842 int arg1, int arg2, Object obj) {
843 super(context, handler, cmdName, cmd, arg1, arg2, obj);
844 }
845
Lorenzo Colittibfecba22016-02-21 01:09:26 +0900846 @Override
847 public void schedule(long when) {
848 long delayMs = when - SystemClock.elapsedRealtime();
849 if (delayMs < 0) delayMs = 0;
850 if (delayMs > UNREASONABLY_LONG_WAIT) {
851 fail("Attempting to send msg more than " + UNREASONABLY_LONG_WAIT +
852 "ms into the future: " + delayMs);
853 }
Lorenzo Colittib57578ca2016-07-01 01:53:25 +0900854 Message msg = mHandler.obtainMessage(mCmd, mArg1, mArg2, mObj);
855 mHandler.sendMessageDelayed(msg, delayMs);
Lorenzo Colittibfecba22016-02-21 01:09:26 +0900856 }
857
858 @Override
859 public void cancel() {
Lorenzo Colittib57578ca2016-07-01 01:53:25 +0900860 mHandler.removeMessages(mCmd, mObj);
Lorenzo Colittibfecba22016-02-21 01:09:26 +0900861 }
862
863 @Override
864 public void onAlarm() {
865 throw new AssertionError("Should never happen. Update this fake.");
866 }
867 }
868
Paul Jensencf4c2c62015-07-01 14:16:32 -0400869 // NetworkMonitor implementation allowing overriding of Internet connectivity probe result.
870 private class WrappedNetworkMonitor extends NetworkMonitor {
Erik Kline79c6d052018-03-21 07:18:33 -0700871 public final Handler connectivityHandler;
Paul Jensencf4c2c62015-07-01 14:16:32 -0400872 // HTTP response code fed back to NetworkMonitor for Internet connectivity probe.
873 public int gen204ProbeResult = 500;
Paul Jensen232437312016-04-06 09:51:26 -0400874 public String gen204ProbeRedirectUrl = null;
Paul Jensencf4c2c62015-07-01 14:16:32 -0400875
876 public WrappedNetworkMonitor(Context context, Handler handler,
Hugo Benichif9fdf872016-07-28 17:53:06 +0900877 NetworkAgentInfo networkAgentInfo, NetworkRequest defaultRequest,
878 IpConnectivityLog log) {
Hugo Benichic894b122017-07-31 12:58:20 +0900879 super(context, handler, networkAgentInfo, defaultRequest, log,
880 NetworkMonitor.NetworkMonitorSettings.DEFAULT);
Erik Kline117e7f32018-03-04 21:01:01 +0900881 connectivityHandler = handler;
Paul Jensencf4c2c62015-07-01 14:16:32 -0400882 }
883
884 @Override
Paul Jensen232437312016-04-06 09:51:26 -0400885 protected CaptivePortalProbeResult isCaptivePortal() {
Calvin On1f64f3f2016-10-11 15:10:46 -0700886 if (!mIsCaptivePortalCheckEnabled) { return new CaptivePortalProbeResult(204); }
Hugo Benichid953bf82016-09-27 09:22:35 +0900887 return new CaptivePortalProbeResult(gen204ProbeResult, gen204ProbeRedirectUrl, null);
Paul Jensencf4c2c62015-07-01 14:16:32 -0400888 }
889 }
890
Lorenzo Colitti58ebe1c2017-01-24 09:41:36 +0900891 private class WrappedMultinetworkPolicyTracker extends MultinetworkPolicyTracker {
Hugo Benichi53d83d52016-11-15 13:42:34 +0900892 public volatile boolean configRestrictsAvoidBadWifi;
Lorenzo Colitti2de49252017-01-24 18:08:41 +0900893 public volatile int configMeteredMultipathPreference;
Paul Jensencf4c2c62015-07-01 14:16:32 -0400894
Lorenzo Colitti58ebe1c2017-01-24 09:41:36 +0900895 public WrappedMultinetworkPolicyTracker(Context c, Handler h, Runnable r) {
Erik Kline065ab6e2016-10-02 18:02:14 +0900896 super(c, h, r);
897 }
898
899 @Override
900 public boolean configRestrictsAvoidBadWifi() {
901 return configRestrictsAvoidBadWifi;
902 }
Lorenzo Colitti2de49252017-01-24 18:08:41 +0900903
904 @Override
905 public int configMeteredMultipathPreference() {
906 return configMeteredMultipathPreference;
907 }
Erik Kline065ab6e2016-10-02 18:02:14 +0900908 }
909
910 private class WrappedConnectivityService extends ConnectivityService {
Lorenzo Colitti58ebe1c2017-01-24 09:41:36 +0900911 public WrappedMultinetworkPolicyTracker wrappedMultinetworkPolicyTracker;
Erik Kline065ab6e2016-10-02 18:02:14 +0900912 private WrappedNetworkMonitor mLastCreatedNetworkMonitor;
Lorenzo Colitti42cdf572017-03-21 18:54:11 +0900913 private MockableSystemProperties mSystemProperties;
Erik Kline065ab6e2016-10-02 18:02:14 +0900914
Paul Jensend7b6ca92015-05-13 14:05:12 -0400915 public WrappedConnectivityService(Context context, INetworkManagementService netManager,
Hugo Benichif9fdf872016-07-28 17:53:06 +0900916 INetworkStatsService statsService, INetworkPolicyManager policyManager,
917 IpConnectivityLog log) {
918 super(context, netManager, statsService, policyManager, log);
Lorenzo Colittib57578ca2016-07-01 01:53:25 +0900919 mLingerDelayMs = TEST_LINGER_DELAY_MS;
Paul Jensend7b6ca92015-05-13 14:05:12 -0400920 }
921
922 @Override
Lorenzo Colitti42cdf572017-03-21 18:54:11 +0900923 protected MockableSystemProperties getSystemProperties() {
924 // Minimal approach to overriding system properties: let most calls fall through to real
925 // device values, and only override ones values that are important to this test.
926 mSystemProperties = spy(new MockableSystemProperties());
927 when(mSystemProperties.getInt("net.tcp.default_init_rwnd", 0)).thenReturn(0);
928 when(mSystemProperties.getBoolean("ro.radio.noril", false)).thenReturn(false);
929 return mSystemProperties;
Paul Jensend7b6ca92015-05-13 14:05:12 -0400930 }
Paul Jensen67b0b072015-06-10 11:22:17 -0400931
932 @Override
933 protected int reserveNetId() {
934 while (true) {
935 final int netId = super.reserveNetId();
936
937 // Don't overlap test NetIDs with real NetIDs as binding sockets to real networks
938 // can have odd side-effects, like network validations succeeding.
Hugo Benichi4a0c5d72017-10-11 11:26:25 +0900939 Context context = InstrumentationRegistry.getContext();
940 final Network[] networks = ConnectivityManager.from(context).getAllNetworks();
Paul Jensen67b0b072015-06-10 11:22:17 -0400941 boolean overlaps = false;
942 for (Network network : networks) {
943 if (netId == network.netId) {
944 overlaps = true;
945 break;
946 }
947 }
948 if (overlaps) continue;
949
950 return netId;
951 }
952 }
Paul Jensencf4c2c62015-07-01 14:16:32 -0400953
954 @Override
955 public NetworkMonitor createNetworkMonitor(Context context, Handler handler,
956 NetworkAgentInfo nai, NetworkRequest defaultRequest) {
Hugo Benichif9fdf872016-07-28 17:53:06 +0900957 final WrappedNetworkMonitor monitor = new WrappedNetworkMonitor(
958 context, handler, nai, defaultRequest, mock(IpConnectivityLog.class));
Paul Jensencf4c2c62015-07-01 14:16:32 -0400959 mLastCreatedNetworkMonitor = monitor;
Paul Jensencf4c2c62015-07-01 14:16:32 -0400960 return monitor;
961 }
962
junyulai4a192e22018-06-13 15:00:37 +0800963 public Nat464Xlat getNat464Xlat(MockNetworkAgent mna) {
964 return getNetworkAgentInfoForNetwork(mna.getNetwork()).clatd;
965 }
966
Lorenzo Colittib57578ca2016-07-01 01:53:25 +0900967 @Override
Lorenzo Colitti58ebe1c2017-01-24 09:41:36 +0900968 public MultinetworkPolicyTracker createMultinetworkPolicyTracker(
Erik Kline065ab6e2016-10-02 18:02:14 +0900969 Context c, Handler h, Runnable r) {
Lorenzo Colitti58ebe1c2017-01-24 09:41:36 +0900970 final WrappedMultinetworkPolicyTracker tracker = new WrappedMultinetworkPolicyTracker(c, h, r);
Erik Kline065ab6e2016-10-02 18:02:14 +0900971 return tracker;
972 }
973
Lorenzo Colitti58ebe1c2017-01-24 09:41:36 +0900974 public WrappedMultinetworkPolicyTracker getMultinetworkPolicyTracker() {
975 return (WrappedMultinetworkPolicyTracker) mMultinetworkPolicyTracker;
Lorenzo Colittib57578ca2016-07-01 01:53:25 +0900976 }
977
Lorenzo Colitti165c51c2016-09-19 01:00:19 +0900978 @Override
Erik Kline065ab6e2016-10-02 18:02:14 +0900979 public WakeupMessage makeWakeupMessage(
980 Context context, Handler handler, String cmdName, int cmd, Object obj) {
981 return new FakeWakeupMessage(context, handler, cmdName, cmd, 0, 0, obj);
Lorenzo Colitti165c51c2016-09-19 01:00:19 +0900982 }
983
Lorenzo Colitti7bbe3ee2017-08-24 22:35:10 +0900984 @Override
985 public boolean hasService(String name) {
986 // Currenty, the only relevant service that ConnectivityService checks for is
987 // ETHERNET_SERVICE.
988 return Context.ETHERNET_SERVICE.equals(name);
989 }
990
Hugo Benichi64901e52017-10-19 14:42:40 +0900991 @Override
992 protected IpConnectivityMetrics.Logger metricsLogger() {
993 return mMetricsService;
994 }
995
dalyk1fcb7392018-03-05 12:42:22 -0500996 @Override
997 protected void registerNetdEventCallback() {
998 }
999
Paul Jensencf4c2c62015-07-01 14:16:32 -04001000 public WrappedNetworkMonitor getLastCreatedWrappedNetworkMonitor() {
1001 return mLastCreatedNetworkMonitor;
1002 }
1003
Chalard Jeanfb0c87e2018-04-18 19:18:58 +09001004 public void mockVpn(int uid) {
1005 synchronized (mVpns) {
Chalard Jeanf89e8da2018-05-18 21:47:45 +09001006 int userId = UserHandle.getUserId(uid);
1007 mMockVpn = new MockVpn(userId);
Chalard Jeanfb0c87e2018-04-18 19:18:58 +09001008 // This has no effect unless the VPN is actually connected, because things like
1009 // getActiveNetworkForUidInternal call getNetworkAgentInfoForNetId on the VPN
1010 // netId, and check if that network is actually connected.
Chalard Jeanf89e8da2018-05-18 21:47:45 +09001011 mVpns.put(userId, mMockVpn);
Chalard Jeanfb0c87e2018-04-18 19:18:58 +09001012 }
1013 }
1014
Lorenzo Colittie58961a2015-08-07 20:17:27 +09001015 public void waitForIdle(int timeoutMs) {
Hugo Benichiad4db4e2016-10-17 15:54:51 +09001016 waitForIdleHandler(mHandlerThread, timeoutMs);
Paul Jensencf4c2c62015-07-01 14:16:32 -04001017 }
Lorenzo Colittie58961a2015-08-07 20:17:27 +09001018
1019 public void waitForIdle() {
Lorenzo Colittiffa390b2015-08-08 01:55:44 +09001020 waitForIdle(TIMEOUT_MS);
Lorenzo Colittie58961a2015-08-07 20:17:27 +09001021 }
Paul Jensend7b6ca92015-05-13 14:05:12 -04001022 }
1023
Paul Jensen3d911462015-06-12 06:40:24 -04001024 /**
Lorenzo Colittiffa390b2015-08-08 01:55:44 +09001025 * Wait up to TIMEOUT_MS for {@code conditionVariable} to open.
1026 * Fails if TIMEOUT_MS goes by before {@code conditionVariable} opens.
Paul Jensen3d911462015-06-12 06:40:24 -04001027 */
1028 static private void waitFor(ConditionVariable conditionVariable) {
Hugo Benichi16f0a942017-06-20 14:07:59 +09001029 if (conditionVariable.block(TIMEOUT_MS)) {
1030 return;
1031 }
1032 fail("ConditionVariable was blocked for more than " + TIMEOUT_MS + "ms");
Paul Jensen3d911462015-06-12 06:40:24 -04001033 }
1034
Hugo Benichi4a0c5d72017-10-11 11:26:25 +09001035 @Before
Paul Jensend7b6ca92015-05-13 14:05:12 -04001036 public void setUp() throws Exception {
Hugo Benichi4a0c5d72017-10-11 11:26:25 +09001037 mContext = InstrumentationRegistry.getContext();
Paul Jensend7b6ca92015-05-13 14:05:12 -04001038
Hugo Benichi64901e52017-10-19 14:42:40 +09001039 MockitoAnnotations.initMocks(this);
1040 when(mMetricsService.defaultNetworkMetrics()).thenReturn(mDefaultNetworkMetrics);
1041
Lorenzo Colitti2c1a2532015-11-27 10:52:10 +09001042 // InstrumentationTestRunner prepares a looper, but AndroidJUnitRunner does not.
1043 // http://b/25897652 .
1044 if (Looper.myLooper() == null) {
1045 Looper.prepare();
1046 }
1047
Hugo Benichi4a0c5d72017-10-11 11:26:25 +09001048 mServiceContext = new MockContext(InstrumentationRegistry.getContext());
Hugo Benichi938ab4f2017-02-11 17:04:43 +09001049 LocalServices.removeServiceForTest(NetworkPolicyManagerInternal.class);
1050 LocalServices.addService(
1051 NetworkPolicyManagerInternal.class, mock(NetworkPolicyManagerInternal.class));
Lorenzo Colitti83fa2582015-08-07 12:49:01 +09001052 mService = new WrappedConnectivityService(mServiceContext,
Erik Klinee89953b2018-01-11 16:11:10 +09001053 mNetworkManagementService,
Jeff Sharkey72f9c422017-10-27 17:22:59 -06001054 mStatsService,
Hugo Benichif9fdf872016-07-28 17:53:06 +09001055 mock(INetworkPolicyManager.class),
1056 mock(IpConnectivityLog.class));
Paul Jensend7b6ca92015-05-13 14:05:12 -04001057
Jeff Sharkeye0c29952018-02-20 17:24:55 -07001058 // Create local CM before sending system ready so that we can answer
1059 // getSystemService() correctly.
Hugo Benichi4a0c5d72017-10-11 11:26:25 +09001060 mCm = new WrappedConnectivityManager(InstrumentationRegistry.getContext(), mService);
Jeff Sharkeye0c29952018-02-20 17:24:55 -07001061 mService.systemReady();
Chalard Jeanfb0c87e2018-04-18 19:18:58 +09001062 mService.mockVpn(Process.myUid());
Lorenzo Colitti531a3442016-03-01 12:55:58 +09001063 mCm.bindProcessToNetwork(null);
Calvin On1f64f3f2016-10-11 15:10:46 -07001064
1065 // Ensure that the default setting for Captive Portals is used for most tests
1066 setCaptivePortalMode(Settings.Global.CAPTIVE_PORTAL_MODE_PROMPT);
Lorenzo Colitti02cc8392017-05-17 01:28:09 +09001067 setMobileDataAlwaysOn(false);
Erik Kline79c6d052018-03-21 07:18:33 -07001068 setPrivateDnsSettings(PRIVATE_DNS_MODE_OFF, "ignored.example.com");
Paul Jensend7b6ca92015-05-13 14:05:12 -04001069 }
1070
Hugo Benichi4a0c5d72017-10-11 11:26:25 +09001071 @After
Lorenzo Colitti6ee0a922016-06-27 16:44:07 +09001072 public void tearDown() throws Exception {
Lorenzo Colittie14d49a2016-07-20 21:35:19 +09001073 setMobileDataAlwaysOn(false);
Hugo Benichibb91c572017-05-22 10:44:02 +09001074 if (mCellNetworkAgent != null) {
1075 mCellNetworkAgent.disconnect();
1076 mCellNetworkAgent = null;
1077 }
1078 if (mWiFiNetworkAgent != null) {
1079 mWiFiNetworkAgent.disconnect();
1080 mWiFiNetworkAgent = null;
1081 }
1082 if (mEthernetNetworkAgent != null) {
1083 mEthernetNetworkAgent.disconnect();
1084 mEthernetNetworkAgent = null;
1085 }
Lorenzo Colitti6ee0a922016-06-27 16:44:07 +09001086 }
1087
Hugo Benichibb91c572017-05-22 10:44:02 +09001088 private static int transportToLegacyType(int transport) {
Paul Jensend7b6ca92015-05-13 14:05:12 -04001089 switch (transport) {
Lorenzo Colitti7369d8d12016-06-28 21:28:28 +09001090 case TRANSPORT_ETHERNET:
1091 return TYPE_ETHERNET;
Paul Jensend7b6ca92015-05-13 14:05:12 -04001092 case TRANSPORT_WIFI:
1093 return TYPE_WIFI;
1094 case TRANSPORT_CELLULAR:
1095 return TYPE_MOBILE;
1096 default:
Hugo Benichi16f0a942017-06-20 14:07:59 +09001097 return TYPE_NONE;
Paul Jensend7b6ca92015-05-13 14:05:12 -04001098 }
1099 }
1100
1101 private void verifyActiveNetwork(int transport) {
1102 // Test getActiveNetworkInfo()
1103 assertNotNull(mCm.getActiveNetworkInfo());
1104 assertEquals(transportToLegacyType(transport), mCm.getActiveNetworkInfo().getType());
1105 // Test getActiveNetwork()
1106 assertNotNull(mCm.getActiveNetwork());
Robin Leed2baf792016-03-24 12:07:00 +00001107 assertEquals(mCm.getActiveNetwork(), mCm.getActiveNetworkForUid(Process.myUid()));
Hugo Benichi16f0a942017-06-20 14:07:59 +09001108 if (!NetworkCapabilities.isValidTransport(transport)) {
1109 throw new IllegalStateException("Unknown transport " + transport);
1110 }
Paul Jensend7b6ca92015-05-13 14:05:12 -04001111 switch (transport) {
1112 case TRANSPORT_WIFI:
1113 assertEquals(mCm.getActiveNetwork(), mWiFiNetworkAgent.getNetwork());
1114 break;
1115 case TRANSPORT_CELLULAR:
1116 assertEquals(mCm.getActiveNetwork(), mCellNetworkAgent.getNetwork());
1117 break;
1118 default:
Hugo Benichi16f0a942017-06-20 14:07:59 +09001119 break;
Paul Jensend7b6ca92015-05-13 14:05:12 -04001120 }
1121 // Test getNetworkInfo(Network)
1122 assertNotNull(mCm.getNetworkInfo(mCm.getActiveNetwork()));
Hugo Benichibb91c572017-05-22 10:44:02 +09001123 assertEquals(transportToLegacyType(transport),
1124 mCm.getNetworkInfo(mCm.getActiveNetwork()).getType());
Paul Jensend7b6ca92015-05-13 14:05:12 -04001125 // Test getNetworkCapabilities(Network)
1126 assertNotNull(mCm.getNetworkCapabilities(mCm.getActiveNetwork()));
1127 assertTrue(mCm.getNetworkCapabilities(mCm.getActiveNetwork()).hasTransport(transport));
1128 }
1129
1130 private void verifyNoNetwork() {
Hugo Benichic1014502017-07-19 10:10:52 +09001131 waitForIdle();
Paul Jensend7b6ca92015-05-13 14:05:12 -04001132 // Test getActiveNetworkInfo()
1133 assertNull(mCm.getActiveNetworkInfo());
1134 // Test getActiveNetwork()
1135 assertNull(mCm.getActiveNetwork());
Robin Leed2baf792016-03-24 12:07:00 +00001136 assertNull(mCm.getActiveNetworkForUid(Process.myUid()));
Paul Jensend7b6ca92015-05-13 14:05:12 -04001137 // Test getAllNetworks()
Hugo Benichifed512a2017-06-26 10:06:49 +09001138 assertEmpty(mCm.getAllNetworks());
Paul Jensend7b6ca92015-05-13 14:05:12 -04001139 }
1140
1141 /**
1142 * Return a ConditionVariable that opens when {@code count} numbers of CONNECTIVITY_ACTION
1143 * broadcasts are received.
1144 */
1145 private ConditionVariable waitForConnectivityBroadcasts(final int count) {
1146 final ConditionVariable cv = new ConditionVariable();
1147 mServiceContext.registerReceiver(new BroadcastReceiver() {
1148 private int remaining = count;
1149 public void onReceive(Context context, Intent intent) {
1150 if (--remaining == 0) {
1151 cv.open();
1152 mServiceContext.unregisterReceiver(this);
1153 }
1154 }
1155 }, new IntentFilter(CONNECTIVITY_ACTION));
1156 return cv;
1157 }
1158
Hugo Benichi4a0c5d72017-10-11 11:26:25 +09001159 @Test
Lorenzo Colitti42cdf572017-03-21 18:54:11 +09001160 public void testNetworkTypes() {
1161 // Ensure that our mocks for the networkAttributes config variable work as expected. If they
1162 // don't, then tests that depend on CONNECTIVITY_ACTION broadcasts for these network types
1163 // will fail. Failing here is much easier to debug.
1164 assertTrue(mCm.isNetworkSupported(TYPE_WIFI));
1165 assertTrue(mCm.isNetworkSupported(TYPE_MOBILE));
Lorenzo Colitti7bbe3ee2017-08-24 22:35:10 +09001166 assertTrue(mCm.isNetworkSupported(TYPE_MOBILE_MMS));
1167 assertFalse(mCm.isNetworkSupported(TYPE_MOBILE_FOTA));
1168
1169 // Check that TYPE_ETHERNET is supported. Unlike the asserts above, which only validate our
1170 // mocks, this assert exercises the ConnectivityService code path that ensures that
1171 // TYPE_ETHERNET is supported if the ethernet service is running.
1172 assertTrue(mCm.isNetworkSupported(TYPE_ETHERNET));
Lorenzo Colitti42cdf572017-03-21 18:54:11 +09001173 }
1174
Hugo Benichi4a0c5d72017-10-11 11:26:25 +09001175 @Test
Paul Jensend7b6ca92015-05-13 14:05:12 -04001176 public void testLingering() throws Exception {
Paul Jensend7b6ca92015-05-13 14:05:12 -04001177 verifyNoNetwork();
1178 mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
1179 mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
1180 assertNull(mCm.getActiveNetworkInfo());
1181 assertNull(mCm.getActiveNetwork());
1182 // Test bringing up validated cellular.
1183 ConditionVariable cv = waitForConnectivityBroadcasts(1);
1184 mCellNetworkAgent.connect(true);
Paul Jensen3d911462015-06-12 06:40:24 -04001185 waitFor(cv);
Paul Jensend7b6ca92015-05-13 14:05:12 -04001186 verifyActiveNetwork(TRANSPORT_CELLULAR);
Hugo Benichifed512a2017-06-26 10:06:49 +09001187 assertLength(2, mCm.getAllNetworks());
Paul Jensend7b6ca92015-05-13 14:05:12 -04001188 assertTrue(mCm.getAllNetworks()[0].equals(mCm.getActiveNetwork()) ||
1189 mCm.getAllNetworks()[1].equals(mCm.getActiveNetwork()));
1190 assertTrue(mCm.getAllNetworks()[0].equals(mWiFiNetworkAgent.getNetwork()) ||
1191 mCm.getAllNetworks()[1].equals(mWiFiNetworkAgent.getNetwork()));
1192 // Test bringing up validated WiFi.
1193 cv = waitForConnectivityBroadcasts(2);
1194 mWiFiNetworkAgent.connect(true);
Paul Jensen3d911462015-06-12 06:40:24 -04001195 waitFor(cv);
Paul Jensend7b6ca92015-05-13 14:05:12 -04001196 verifyActiveNetwork(TRANSPORT_WIFI);
Hugo Benichifed512a2017-06-26 10:06:49 +09001197 assertLength(2, mCm.getAllNetworks());
Paul Jensend7b6ca92015-05-13 14:05:12 -04001198 assertTrue(mCm.getAllNetworks()[0].equals(mCm.getActiveNetwork()) ||
1199 mCm.getAllNetworks()[1].equals(mCm.getActiveNetwork()));
1200 assertTrue(mCm.getAllNetworks()[0].equals(mCellNetworkAgent.getNetwork()) ||
1201 mCm.getAllNetworks()[1].equals(mCellNetworkAgent.getNetwork()));
1202 // Test cellular linger timeout.
Lorenzo Colittid2706122017-01-30 17:45:49 +09001203 waitFor(mCellNetworkAgent.getDisconnectedCV());
Hugo Benichibb91c572017-05-22 10:44:02 +09001204 waitForIdle();
Hugo Benichifed512a2017-06-26 10:06:49 +09001205 assertLength(1, mCm.getAllNetworks());
Paul Jensend7b6ca92015-05-13 14:05:12 -04001206 verifyActiveNetwork(TRANSPORT_WIFI);
Hugo Benichifed512a2017-06-26 10:06:49 +09001207 assertLength(1, mCm.getAllNetworks());
Paul Jensend7b6ca92015-05-13 14:05:12 -04001208 assertEquals(mCm.getAllNetworks()[0], mCm.getActiveNetwork());
1209 // Test WiFi disconnect.
1210 cv = waitForConnectivityBroadcasts(1);
1211 mWiFiNetworkAgent.disconnect();
Paul Jensen3d911462015-06-12 06:40:24 -04001212 waitFor(cv);
Paul Jensend7b6ca92015-05-13 14:05:12 -04001213 verifyNoNetwork();
1214 }
1215
Hugo Benichi4a0c5d72017-10-11 11:26:25 +09001216 @Test
Paul Jensend7b6ca92015-05-13 14:05:12 -04001217 public void testValidatedCellularOutscoresUnvalidatedWiFi() throws Exception {
1218 // Test bringing up unvalidated WiFi
1219 mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
1220 ConditionVariable cv = waitForConnectivityBroadcasts(1);
1221 mWiFiNetworkAgent.connect(false);
Paul Jensen3d911462015-06-12 06:40:24 -04001222 waitFor(cv);
Paul Jensend7b6ca92015-05-13 14:05:12 -04001223 verifyActiveNetwork(TRANSPORT_WIFI);
1224 // Test bringing up unvalidated cellular
1225 mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
1226 mCellNetworkAgent.connect(false);
Hugo Benichibb91c572017-05-22 10:44:02 +09001227 waitForIdle();
Paul Jensend7b6ca92015-05-13 14:05:12 -04001228 verifyActiveNetwork(TRANSPORT_WIFI);
1229 // Test cellular disconnect.
1230 mCellNetworkAgent.disconnect();
Hugo Benichibb91c572017-05-22 10:44:02 +09001231 waitForIdle();
Paul Jensend7b6ca92015-05-13 14:05:12 -04001232 verifyActiveNetwork(TRANSPORT_WIFI);
1233 // Test bringing up validated cellular
1234 mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
1235 cv = waitForConnectivityBroadcasts(2);
1236 mCellNetworkAgent.connect(true);
Paul Jensen3d911462015-06-12 06:40:24 -04001237 waitFor(cv);
Paul Jensend7b6ca92015-05-13 14:05:12 -04001238 verifyActiveNetwork(TRANSPORT_CELLULAR);
1239 // Test cellular disconnect.
1240 cv = waitForConnectivityBroadcasts(2);
1241 mCellNetworkAgent.disconnect();
Paul Jensen3d911462015-06-12 06:40:24 -04001242 waitFor(cv);
Paul Jensend7b6ca92015-05-13 14:05:12 -04001243 verifyActiveNetwork(TRANSPORT_WIFI);
1244 // Test WiFi disconnect.
1245 cv = waitForConnectivityBroadcasts(1);
1246 mWiFiNetworkAgent.disconnect();
Paul Jensen3d911462015-06-12 06:40:24 -04001247 waitFor(cv);
Paul Jensend7b6ca92015-05-13 14:05:12 -04001248 verifyNoNetwork();
1249 }
1250
Hugo Benichi4a0c5d72017-10-11 11:26:25 +09001251 @Test
Paul Jensend7b6ca92015-05-13 14:05:12 -04001252 public void testUnvalidatedWifiOutscoresUnvalidatedCellular() throws Exception {
1253 // Test bringing up unvalidated cellular.
1254 mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
1255 ConditionVariable cv = waitForConnectivityBroadcasts(1);
1256 mCellNetworkAgent.connect(false);
Paul Jensen3d911462015-06-12 06:40:24 -04001257 waitFor(cv);
Paul Jensend7b6ca92015-05-13 14:05:12 -04001258 verifyActiveNetwork(TRANSPORT_CELLULAR);
1259 // Test bringing up unvalidated WiFi.
1260 mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
1261 cv = waitForConnectivityBroadcasts(2);
1262 mWiFiNetworkAgent.connect(false);
Paul Jensen3d911462015-06-12 06:40:24 -04001263 waitFor(cv);
Paul Jensend7b6ca92015-05-13 14:05:12 -04001264 verifyActiveNetwork(TRANSPORT_WIFI);
1265 // Test WiFi disconnect.
1266 cv = waitForConnectivityBroadcasts(2);
1267 mWiFiNetworkAgent.disconnect();
Paul Jensen3d911462015-06-12 06:40:24 -04001268 waitFor(cv);
Paul Jensend7b6ca92015-05-13 14:05:12 -04001269 verifyActiveNetwork(TRANSPORT_CELLULAR);
1270 // Test cellular disconnect.
1271 cv = waitForConnectivityBroadcasts(1);
1272 mCellNetworkAgent.disconnect();
Paul Jensen3d911462015-06-12 06:40:24 -04001273 waitFor(cv);
Paul Jensend7b6ca92015-05-13 14:05:12 -04001274 verifyNoNetwork();
1275 }
1276
Hugo Benichi4a0c5d72017-10-11 11:26:25 +09001277 @Test
Paul Jensene0988542015-06-25 15:30:08 -04001278 public void testUnlingeringDoesNotValidate() throws Exception {
Paul Jensencf4c2c62015-07-01 14:16:32 -04001279 // Test bringing up unvalidated WiFi.
Paul Jensene0988542015-06-25 15:30:08 -04001280 mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
Paul Jensencf4c2c62015-07-01 14:16:32 -04001281 ConditionVariable cv = waitForConnectivityBroadcasts(1);
1282 mWiFiNetworkAgent.connect(false);
Paul Jensene0988542015-06-25 15:30:08 -04001283 waitFor(cv);
1284 verifyActiveNetwork(TRANSPORT_WIFI);
Paul Jensencf4c2c62015-07-01 14:16:32 -04001285 assertFalse(mCm.getNetworkCapabilities(mWiFiNetworkAgent.getNetwork()).hasCapability(
Paul Jensene0988542015-06-25 15:30:08 -04001286 NET_CAPABILITY_VALIDATED));
Paul Jensencf4c2c62015-07-01 14:16:32 -04001287 // Test bringing up validated cellular.
1288 mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
Paul Jensene0988542015-06-25 15:30:08 -04001289 cv = waitForConnectivityBroadcasts(2);
Paul Jensencf4c2c62015-07-01 14:16:32 -04001290 mCellNetworkAgent.connect(true);
Paul Jensene0988542015-06-25 15:30:08 -04001291 waitFor(cv);
1292 verifyActiveNetwork(TRANSPORT_CELLULAR);
Paul Jensencf4c2c62015-07-01 14:16:32 -04001293 assertFalse(mCm.getNetworkCapabilities(mWiFiNetworkAgent.getNetwork()).hasCapability(
1294 NET_CAPABILITY_VALIDATED));
1295 // Test cellular disconnect.
1296 cv = waitForConnectivityBroadcasts(2);
1297 mCellNetworkAgent.disconnect();
1298 waitFor(cv);
1299 verifyActiveNetwork(TRANSPORT_WIFI);
Paul Jensene0988542015-06-25 15:30:08 -04001300 // Unlingering a network should not cause it to be marked as validated.
Paul Jensencf4c2c62015-07-01 14:16:32 -04001301 assertFalse(mCm.getNetworkCapabilities(mWiFiNetworkAgent.getNetwork()).hasCapability(
Paul Jensene0988542015-06-25 15:30:08 -04001302 NET_CAPABILITY_VALIDATED));
1303 }
1304
Hugo Benichi4a0c5d72017-10-11 11:26:25 +09001305 @Test
Paul Jensen3d911462015-06-12 06:40:24 -04001306 public void testCellularOutscoresWeakWifi() throws Exception {
1307 // Test bringing up validated cellular.
1308 mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
1309 ConditionVariable cv = waitForConnectivityBroadcasts(1);
1310 mCellNetworkAgent.connect(true);
1311 waitFor(cv);
1312 verifyActiveNetwork(TRANSPORT_CELLULAR);
1313 // Test bringing up validated WiFi.
1314 mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
1315 cv = waitForConnectivityBroadcasts(2);
1316 mWiFiNetworkAgent.connect(true);
1317 waitFor(cv);
1318 verifyActiveNetwork(TRANSPORT_WIFI);
1319 // Test WiFi getting really weak.
1320 cv = waitForConnectivityBroadcasts(2);
1321 mWiFiNetworkAgent.adjustScore(-11);
1322 waitFor(cv);
1323 verifyActiveNetwork(TRANSPORT_CELLULAR);
1324 // Test WiFi restoring signal strength.
1325 cv = waitForConnectivityBroadcasts(2);
1326 mWiFiNetworkAgent.adjustScore(11);
1327 waitFor(cv);
1328 verifyActiveNetwork(TRANSPORT_WIFI);
Paul Jensen3d911462015-06-12 06:40:24 -04001329 }
1330
Hugo Benichi4a0c5d72017-10-11 11:26:25 +09001331 @Test
Paul Jensene0988542015-06-25 15:30:08 -04001332 public void testReapingNetwork() throws Exception {
1333 // Test bringing up WiFi without NET_CAPABILITY_INTERNET.
1334 // Expect it to be torn down immediately because it satisfies no requests.
1335 mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
1336 ConditionVariable cv = mWiFiNetworkAgent.getDisconnectedCV();
1337 mWiFiNetworkAgent.connectWithoutInternet();
1338 waitFor(cv);
1339 // Test bringing up cellular without NET_CAPABILITY_INTERNET.
1340 // Expect it to be torn down immediately because it satisfies no requests.
1341 mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
1342 cv = mCellNetworkAgent.getDisconnectedCV();
1343 mCellNetworkAgent.connectWithoutInternet();
1344 waitFor(cv);
1345 // Test bringing up validated WiFi.
1346 mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
1347 cv = waitForConnectivityBroadcasts(1);
1348 mWiFiNetworkAgent.connect(true);
1349 waitFor(cv);
1350 verifyActiveNetwork(TRANSPORT_WIFI);
1351 // Test bringing up unvalidated cellular.
1352 // Expect it to be torn down because it could never be the highest scoring network
1353 // satisfying the default request even if it validated.
1354 mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
1355 cv = mCellNetworkAgent.getDisconnectedCV();
1356 mCellNetworkAgent.connect(false);
1357 waitFor(cv);
1358 verifyActiveNetwork(TRANSPORT_WIFI);
1359 cv = mWiFiNetworkAgent.getDisconnectedCV();
1360 mWiFiNetworkAgent.disconnect();
1361 waitFor(cv);
1362 }
1363
Hugo Benichi4a0c5d72017-10-11 11:26:25 +09001364 @Test
Paul Jensene0988542015-06-25 15:30:08 -04001365 public void testCellularFallback() throws Exception {
1366 // Test bringing up validated cellular.
1367 mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
1368 ConditionVariable cv = waitForConnectivityBroadcasts(1);
1369 mCellNetworkAgent.connect(true);
1370 waitFor(cv);
1371 verifyActiveNetwork(TRANSPORT_CELLULAR);
1372 // Test bringing up validated WiFi.
1373 mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
1374 cv = waitForConnectivityBroadcasts(2);
1375 mWiFiNetworkAgent.connect(true);
1376 waitFor(cv);
1377 verifyActiveNetwork(TRANSPORT_WIFI);
1378 // Reevaluate WiFi (it'll instantly fail DNS).
1379 cv = waitForConnectivityBroadcasts(2);
1380 assertTrue(mCm.getNetworkCapabilities(mWiFiNetworkAgent.getNetwork()).hasCapability(
1381 NET_CAPABILITY_VALIDATED));
1382 mCm.reportBadNetwork(mWiFiNetworkAgent.getNetwork());
1383 // Should quickly fall back to Cellular.
1384 waitFor(cv);
1385 assertFalse(mCm.getNetworkCapabilities(mWiFiNetworkAgent.getNetwork()).hasCapability(
1386 NET_CAPABILITY_VALIDATED));
1387 verifyActiveNetwork(TRANSPORT_CELLULAR);
1388 // Reevaluate cellular (it'll instantly fail DNS).
1389 cv = waitForConnectivityBroadcasts(2);
1390 assertTrue(mCm.getNetworkCapabilities(mCellNetworkAgent.getNetwork()).hasCapability(
1391 NET_CAPABILITY_VALIDATED));
1392 mCm.reportBadNetwork(mCellNetworkAgent.getNetwork());
1393 // Should quickly fall back to WiFi.
1394 waitFor(cv);
1395 assertFalse(mCm.getNetworkCapabilities(mCellNetworkAgent.getNetwork()).hasCapability(
1396 NET_CAPABILITY_VALIDATED));
1397 assertFalse(mCm.getNetworkCapabilities(mWiFiNetworkAgent.getNetwork()).hasCapability(
1398 NET_CAPABILITY_VALIDATED));
1399 verifyActiveNetwork(TRANSPORT_WIFI);
Paul Jensene0988542015-06-25 15:30:08 -04001400 }
1401
Hugo Benichi4a0c5d72017-10-11 11:26:25 +09001402 @Test
Paul Jensene0988542015-06-25 15:30:08 -04001403 public void testWiFiFallback() throws Exception {
1404 // Test bringing up unvalidated WiFi.
1405 mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
1406 ConditionVariable cv = waitForConnectivityBroadcasts(1);
1407 mWiFiNetworkAgent.connect(false);
1408 waitFor(cv);
1409 verifyActiveNetwork(TRANSPORT_WIFI);
1410 // Test bringing up validated cellular.
1411 mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
1412 cv = waitForConnectivityBroadcasts(2);
1413 mCellNetworkAgent.connect(true);
1414 waitFor(cv);
1415 verifyActiveNetwork(TRANSPORT_CELLULAR);
1416 // Reevaluate cellular (it'll instantly fail DNS).
1417 cv = waitForConnectivityBroadcasts(2);
1418 assertTrue(mCm.getNetworkCapabilities(mCellNetworkAgent.getNetwork()).hasCapability(
1419 NET_CAPABILITY_VALIDATED));
1420 mCm.reportBadNetwork(mCellNetworkAgent.getNetwork());
1421 // Should quickly fall back to WiFi.
1422 waitFor(cv);
1423 assertFalse(mCm.getNetworkCapabilities(mCellNetworkAgent.getNetwork()).hasCapability(
1424 NET_CAPABILITY_VALIDATED));
1425 verifyActiveNetwork(TRANSPORT_WIFI);
Paul Jensene0988542015-06-25 15:30:08 -04001426 }
1427
Paul Jensen3d911462015-06-12 06:40:24 -04001428 enum CallbackState {
1429 NONE,
1430 AVAILABLE,
Erik Klineacdd6392016-07-07 16:50:58 +09001431 NETWORK_CAPABILITIES,
1432 LINK_PROPERTIES,
Erik Kline1d3db322017-02-28 16:20:20 +09001433 SUSPENDED,
Chalard Jean804b8fb2018-01-30 22:41:41 +09001434 RESUMED,
Paul Jensen3d911462015-06-12 06:40:24 -04001435 LOSING,
Erik Kline3841a482015-11-25 12:49:38 +09001436 LOST,
1437 UNAVAILABLE
Paul Jensen3d911462015-06-12 06:40:24 -04001438 }
1439
Hugo Benichi4e1619f2016-12-20 17:05:06 +09001440 private static class CallbackInfo {
1441 public final CallbackState state;
1442 public final Network network;
1443 public final Object arg;
1444 public CallbackInfo(CallbackState s, Network n, Object o) {
1445 state = s; network = n; arg = o;
1446 }
1447 public String toString() {
Erik Kline1d3db322017-02-28 16:20:20 +09001448 return String.format("%s (%s) (%s)", state, network, arg);
Hugo Benichi4e1619f2016-12-20 17:05:06 +09001449 }
1450 @Override
1451 public boolean equals(Object o) {
1452 if (!(o instanceof CallbackInfo)) return false;
1453 // Ignore timeMs, since it's unpredictable.
1454 CallbackInfo other = (CallbackInfo) o;
1455 return (state == other.state) && Objects.equals(network, other.network);
1456 }
1457 @Override
1458 public int hashCode() {
1459 return Objects.hash(state, network);
1460 }
1461 }
1462
Lorenzo Colitti83fa2582015-08-07 12:49:01 +09001463 /**
1464 * Utility NetworkCallback for testing. The caller must explicitly test for all the callbacks
1465 * this class receives, by calling expectCallback() exactly once each time a callback is
1466 * received. assertNoCallback may be called at any time.
1467 */
Paul Jensen3d911462015-06-12 06:40:24 -04001468 private class TestNetworkCallback extends NetworkCallback {
Lorenzo Colitti6ee0a922016-06-27 16:44:07 +09001469 private final LinkedBlockingQueue<CallbackInfo> mCallbacks = new LinkedBlockingQueue<>();
Chalard Jeanfb0c87e2018-04-18 19:18:58 +09001470 private Network mLastAvailableNetwork;
Lorenzo Colitti6ee0a922016-06-27 16:44:07 +09001471
Erik Klineacdd6392016-07-07 16:50:58 +09001472 protected void setLastCallback(CallbackState state, Network network, Object o) {
Lorenzo Colittib57578ca2016-07-01 01:53:25 +09001473 mCallbacks.offer(new CallbackInfo(state, network, o));
Lorenzo Colitti6ee0a922016-06-27 16:44:07 +09001474 }
Paul Jensen3d911462015-06-12 06:40:24 -04001475
Erik Klineacdd6392016-07-07 16:50:58 +09001476 @Override
Paul Jensen3d911462015-06-12 06:40:24 -04001477 public void onAvailable(Network network) {
Chalard Jeanfb0c87e2018-04-18 19:18:58 +09001478 mLastAvailableNetwork = network;
Lorenzo Colittib57578ca2016-07-01 01:53:25 +09001479 setLastCallback(CallbackState.AVAILABLE, network, null);
Paul Jensen3d911462015-06-12 06:40:24 -04001480 }
1481
Erik Klineacdd6392016-07-07 16:50:58 +09001482 @Override
Erik Kline1d3db322017-02-28 16:20:20 +09001483 public void onCapabilitiesChanged(Network network, NetworkCapabilities netCap) {
1484 setLastCallback(CallbackState.NETWORK_CAPABILITIES, network, netCap);
1485 }
1486
1487 @Override
1488 public void onLinkPropertiesChanged(Network network, LinkProperties linkProp) {
1489 setLastCallback(CallbackState.LINK_PROPERTIES, network, linkProp);
1490 }
1491
1492 @Override
Erik Kline3841a482015-11-25 12:49:38 +09001493 public void onUnavailable() {
1494 setLastCallback(CallbackState.UNAVAILABLE, null, null);
1495 }
1496
1497 @Override
Erik Kline1d3db322017-02-28 16:20:20 +09001498 public void onNetworkSuspended(Network network) {
1499 setLastCallback(CallbackState.SUSPENDED, network, null);
1500 }
1501
1502 @Override
Chalard Jean804b8fb2018-01-30 22:41:41 +09001503 public void onNetworkResumed(Network network) {
1504 setLastCallback(CallbackState.RESUMED, network, null);
1505 }
1506
1507 @Override
Paul Jensen3d911462015-06-12 06:40:24 -04001508 public void onLosing(Network network, int maxMsToLive) {
Lorenzo Colittib57578ca2016-07-01 01:53:25 +09001509 setLastCallback(CallbackState.LOSING, network, maxMsToLive /* autoboxed int */);
Paul Jensen3d911462015-06-12 06:40:24 -04001510 }
1511
Erik Klineacdd6392016-07-07 16:50:58 +09001512 @Override
Paul Jensen3d911462015-06-12 06:40:24 -04001513 public void onLost(Network network) {
Chalard Jeanfb0c87e2018-04-18 19:18:58 +09001514 mLastAvailableNetwork = null;
Lorenzo Colittib57578ca2016-07-01 01:53:25 +09001515 setLastCallback(CallbackState.LOST, network, null);
1516 }
1517
Chalard Jeanfb0c87e2018-04-18 19:18:58 +09001518 public Network getLastAvailableNetwork() {
1519 return mLastAvailableNetwork;
1520 }
1521
Hugo Benichi4e1619f2016-12-20 17:05:06 +09001522 CallbackInfo nextCallback(int timeoutMs) {
1523 CallbackInfo cb = null;
1524 try {
1525 cb = mCallbacks.poll(timeoutMs, TimeUnit.MILLISECONDS);
1526 } catch (InterruptedException e) {
1527 }
1528 if (cb == null) {
1529 // LinkedBlockingQueue.poll() returns null if it timeouts.
1530 fail("Did not receive callback after " + timeoutMs + "ms");
1531 }
1532 return cb;
1533 }
1534
Erik Kline1d3db322017-02-28 16:20:20 +09001535 CallbackInfo expectCallback(CallbackState state, MockNetworkAgent agent, int timeoutMs) {
1536 final Network expectedNetwork = (agent != null) ? agent.getNetwork() : null;
1537 CallbackInfo expected = new CallbackInfo(state, expectedNetwork, 0);
Hugo Benichi4e1619f2016-12-20 17:05:06 +09001538 CallbackInfo actual = nextCallback(timeoutMs);
1539 assertEquals("Unexpected callback:", expected, actual);
Erik Kline1d3db322017-02-28 16:20:20 +09001540
Lorenzo Colittib57578ca2016-07-01 01:53:25 +09001541 if (state == CallbackState.LOSING) {
1542 String msg = String.format(
1543 "Invalid linger time value %d, must be between %d and %d",
Remi NGUYEN VAN605f12d2018-07-11 18:17:06 +09001544 actual.arg, 0, mService.mLingerDelayMs);
Lorenzo Colittib57578ca2016-07-01 01:53:25 +09001545 int maxMsToLive = (Integer) actual.arg;
Remi NGUYEN VAN605f12d2018-07-11 18:17:06 +09001546 assertTrue(msg, 0 <= maxMsToLive && maxMsToLive <= mService.mLingerDelayMs);
Lorenzo Colittib57578ca2016-07-01 01:53:25 +09001547 }
Erik Kline1d3db322017-02-28 16:20:20 +09001548
1549 return actual;
Erik Klinea2d29402016-03-16 15:31:39 +09001550 }
1551
Erik Kline1d3db322017-02-28 16:20:20 +09001552 CallbackInfo expectCallback(CallbackState state, MockNetworkAgent agent) {
Remi NGUYEN VANef8377d2018-07-26 16:39:45 +09001553 return expectCallback(state, agent, TEST_CALLBACK_TIMEOUT_MS);
Erik Kline1d3db322017-02-28 16:20:20 +09001554 }
1555
Hugo Benichi16f0a942017-06-20 14:07:59 +09001556 CallbackInfo expectCallbackLike(Predicate<CallbackInfo> fn) {
Remi NGUYEN VANef8377d2018-07-26 16:39:45 +09001557 return expectCallbackLike(fn, TEST_CALLBACK_TIMEOUT_MS);
Hugo Benichi16f0a942017-06-20 14:07:59 +09001558 }
1559
1560 CallbackInfo expectCallbackLike(Predicate<CallbackInfo> fn, int timeoutMs) {
1561 int timeLeft = timeoutMs;
1562 while (timeLeft > 0) {
1563 long start = SystemClock.elapsedRealtime();
1564 CallbackInfo info = nextCallback(timeLeft);
1565 if (fn.test(info)) {
1566 return info;
1567 }
1568 timeLeft -= (SystemClock.elapsedRealtime() - start);
1569 }
1570 fail("Did not receive expected callback after " + timeoutMs + "ms");
1571 return null;
1572 }
1573
Lorenzo Colitti27334542018-01-12 16:22:21 +09001574 // Expects onAvailable and the callbacks that follow it. These are:
1575 // - onSuspended, iff the network was suspended when the callbacks fire.
1576 // - onCapabilitiesChanged.
1577 // - onLinkPropertiesChanged.
1578 //
1579 // @param agent the network to expect the callbacks on.
1580 // @param expectSuspended whether to expect a SUSPENDED callback.
1581 // @param expectValidated the expected value of the VALIDATED capability in the
1582 // onCapabilitiesChanged callback.
1583 // @param timeoutMs how long to wait for the callbacks.
1584 void expectAvailableCallbacks(MockNetworkAgent agent, boolean expectSuspended,
1585 boolean expectValidated, int timeoutMs) {
Erik Kline1d3db322017-02-28 16:20:20 +09001586 expectCallback(CallbackState.AVAILABLE, agent, timeoutMs);
Erik Klinec75d4fa2017-02-15 19:59:17 +09001587 if (expectSuspended) {
1588 expectCallback(CallbackState.SUSPENDED, agent, timeoutMs);
Erik Kline1d3db322017-02-28 16:20:20 +09001589 }
Lorenzo Colitti27334542018-01-12 16:22:21 +09001590 if (expectValidated) {
Chalard Jean1fa777d2018-02-16 16:07:53 +09001591 expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, agent, timeoutMs);
Lorenzo Colitti27334542018-01-12 16:22:21 +09001592 } else {
Chalard Jean1fa777d2018-02-16 16:07:53 +09001593 expectCapabilitiesWithout(NET_CAPABILITY_VALIDATED, agent, timeoutMs);
Lorenzo Colitti27334542018-01-12 16:22:21 +09001594 }
Erik Klinec75d4fa2017-02-15 19:59:17 +09001595 expectCallback(CallbackState.LINK_PROPERTIES, agent, timeoutMs);
Erik Kline1d3db322017-02-28 16:20:20 +09001596 }
1597
Lorenzo Colitti27334542018-01-12 16:22:21 +09001598 // Expects the available callbacks (validated), plus onSuspended.
1599 void expectAvailableAndSuspendedCallbacks(MockNetworkAgent agent, boolean expectValidated) {
Remi NGUYEN VANef8377d2018-07-26 16:39:45 +09001600 expectAvailableCallbacks(agent, true, expectValidated, TEST_CALLBACK_TIMEOUT_MS);
Erik Kline1d3db322017-02-28 16:20:20 +09001601 }
1602
Lorenzo Colitti27334542018-01-12 16:22:21 +09001603 void expectAvailableCallbacksValidated(MockNetworkAgent agent) {
Remi NGUYEN VANef8377d2018-07-26 16:39:45 +09001604 expectAvailableCallbacks(agent, false, true, TEST_CALLBACK_TIMEOUT_MS);
Erik Kline1d3db322017-02-28 16:20:20 +09001605 }
1606
Lorenzo Colitti27334542018-01-12 16:22:21 +09001607 void expectAvailableCallbacksUnvalidated(MockNetworkAgent agent) {
Remi NGUYEN VANef8377d2018-07-26 16:39:45 +09001608 expectAvailableCallbacks(agent, false, false, TEST_CALLBACK_TIMEOUT_MS);
Lorenzo Colitti27334542018-01-12 16:22:21 +09001609 }
1610
1611 // Expects the available callbacks (where the onCapabilitiesChanged must contain the
1612 // VALIDATED capability), plus another onCapabilitiesChanged which is identical to the
1613 // one we just sent.
1614 // TODO: this is likely a bug. Fix it and remove this method.
1615 void expectAvailableDoubleValidatedCallbacks(MockNetworkAgent agent) {
Remi NGUYEN VANef8377d2018-07-26 16:39:45 +09001616 expectCallback(CallbackState.AVAILABLE, agent, TEST_CALLBACK_TIMEOUT_MS);
Lorenzo Colitti27334542018-01-12 16:22:21 +09001617 NetworkCapabilities nc1 = expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, agent);
Remi NGUYEN VANef8377d2018-07-26 16:39:45 +09001618 expectCallback(CallbackState.LINK_PROPERTIES, agent, TEST_CALLBACK_TIMEOUT_MS);
Lorenzo Colitti27334542018-01-12 16:22:21 +09001619 NetworkCapabilities nc2 = expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, agent);
1620 assertEquals(nc1, nc2);
1621 }
1622
1623 // Expects the available callbacks where the onCapabilitiesChanged must not have validated,
1624 // then expects another onCapabilitiesChanged that has the validated bit set. This is used
1625 // when a network connects and satisfies a callback, and then immediately validates.
1626 void expectAvailableThenValidatedCallbacks(MockNetworkAgent agent) {
1627 expectAvailableCallbacksUnvalidated(agent);
Erik Kline1d3db322017-02-28 16:20:20 +09001628 expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, agent);
1629 }
1630
Lorenzo Colitti27334542018-01-12 16:22:21 +09001631 NetworkCapabilities expectCapabilitiesWith(int capability, MockNetworkAgent agent) {
Remi NGUYEN VANef8377d2018-07-26 16:39:45 +09001632 return expectCapabilitiesWith(capability, agent, TEST_CALLBACK_TIMEOUT_MS);
Chalard Jean1fa777d2018-02-16 16:07:53 +09001633 }
1634
1635 NetworkCapabilities expectCapabilitiesWith(int capability, MockNetworkAgent agent,
1636 int timeoutMs) {
1637 CallbackInfo cbi = expectCallback(CallbackState.NETWORK_CAPABILITIES, agent, timeoutMs);
Erik Kline1d3db322017-02-28 16:20:20 +09001638 NetworkCapabilities nc = (NetworkCapabilities) cbi.arg;
1639 assertTrue(nc.hasCapability(capability));
Lorenzo Colitti27334542018-01-12 16:22:21 +09001640 return nc;
Erik Kline1d3db322017-02-28 16:20:20 +09001641 }
1642
Lorenzo Colitti27334542018-01-12 16:22:21 +09001643 NetworkCapabilities expectCapabilitiesWithout(int capability, MockNetworkAgent agent) {
Remi NGUYEN VANef8377d2018-07-26 16:39:45 +09001644 return expectCapabilitiesWithout(capability, agent, TEST_CALLBACK_TIMEOUT_MS);
Chalard Jean1fa777d2018-02-16 16:07:53 +09001645 }
1646
1647 NetworkCapabilities expectCapabilitiesWithout(int capability, MockNetworkAgent agent,
1648 int timeoutMs) {
1649 CallbackInfo cbi = expectCallback(CallbackState.NETWORK_CAPABILITIES, agent, timeoutMs);
Erik Kline1d3db322017-02-28 16:20:20 +09001650 NetworkCapabilities nc = (NetworkCapabilities) cbi.arg;
1651 assertFalse(nc.hasCapability(capability));
Lorenzo Colitti27334542018-01-12 16:22:21 +09001652 return nc;
Paul Jensen3d911462015-06-12 06:40:24 -04001653 }
1654
Chalard Jean0b214af2018-01-12 17:22:49 +09001655 void expectCapabilitiesLike(Predicate<NetworkCapabilities> fn, MockNetworkAgent agent) {
1656 CallbackInfo cbi = expectCallback(CallbackState.NETWORK_CAPABILITIES, agent);
Chalard Jeanf89e8da2018-05-18 21:47:45 +09001657 assertTrue("Received capabilities don't match expectations : " + cbi.arg,
1658 fn.test((NetworkCapabilities) cbi.arg));
Chalard Jean0b214af2018-01-12 17:22:49 +09001659 }
1660
Lorenzo Colitti83fa2582015-08-07 12:49:01 +09001661 void assertNoCallback() {
Hugo Benichibb91c572017-05-22 10:44:02 +09001662 waitForIdle();
Lorenzo Colitti6ee0a922016-06-27 16:44:07 +09001663 CallbackInfo c = mCallbacks.peek();
1664 assertNull("Unexpected callback: " + c, c);
1665 }
1666 }
1667
1668 // Can't be part of TestNetworkCallback because "cannot be declared static; static methods can
1669 // only be declared in a static or top level type".
1670 static void assertNoCallbacks(TestNetworkCallback ... callbacks) {
1671 for (TestNetworkCallback c : callbacks) {
1672 c.assertNoCallback();
Paul Jensen3d911462015-06-12 06:40:24 -04001673 }
1674 }
1675
Hugo Benichi4a0c5d72017-10-11 11:26:25 +09001676 @Test
Paul Jensen3d911462015-06-12 06:40:24 -04001677 public void testStateChangeNetworkCallbacks() throws Exception {
Lorenzo Colitti6ee0a922016-06-27 16:44:07 +09001678 final TestNetworkCallback genericNetworkCallback = new TestNetworkCallback();
Paul Jensen3d911462015-06-12 06:40:24 -04001679 final TestNetworkCallback wifiNetworkCallback = new TestNetworkCallback();
1680 final TestNetworkCallback cellNetworkCallback = new TestNetworkCallback();
Lorenzo Colitti6ee0a922016-06-27 16:44:07 +09001681 final NetworkRequest genericRequest = new NetworkRequest.Builder()
1682 .clearCapabilities().build();
Paul Jensen3d911462015-06-12 06:40:24 -04001683 final NetworkRequest wifiRequest = new NetworkRequest.Builder()
1684 .addTransportType(TRANSPORT_WIFI).build();
1685 final NetworkRequest cellRequest = new NetworkRequest.Builder()
1686 .addTransportType(TRANSPORT_CELLULAR).build();
Lorenzo Colitti6ee0a922016-06-27 16:44:07 +09001687 mCm.registerNetworkCallback(genericRequest, genericNetworkCallback);
Paul Jensen3d911462015-06-12 06:40:24 -04001688 mCm.registerNetworkCallback(wifiRequest, wifiNetworkCallback);
1689 mCm.registerNetworkCallback(cellRequest, cellNetworkCallback);
1690
1691 // Test unvalidated networks
Paul Jensen3d911462015-06-12 06:40:24 -04001692 ConditionVariable cv = waitForConnectivityBroadcasts(1);
1693 mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
1694 mCellNetworkAgent.connect(false);
Lorenzo Colitti27334542018-01-12 16:22:21 +09001695 genericNetworkCallback.expectAvailableCallbacksUnvalidated(mCellNetworkAgent);
1696 cellNetworkCallback.expectAvailableCallbacksUnvalidated(mCellNetworkAgent);
Paul Jensen3d911462015-06-12 06:40:24 -04001697 assertEquals(mCellNetworkAgent.getNetwork(), mCm.getActiveNetwork());
1698 waitFor(cv);
Lorenzo Colitti6ee0a922016-06-27 16:44:07 +09001699 assertNoCallbacks(genericNetworkCallback, wifiNetworkCallback, cellNetworkCallback);
Paul Jensen3d911462015-06-12 06:40:24 -04001700
Paul Jensen3d911462015-06-12 06:40:24 -04001701 // This should not trigger spurious onAvailable() callbacks, b/21762680.
1702 mCellNetworkAgent.adjustScore(-1);
Hugo Benichibb91c572017-05-22 10:44:02 +09001703 waitForIdle();
Lorenzo Colitti6ee0a922016-06-27 16:44:07 +09001704 assertNoCallbacks(genericNetworkCallback, wifiNetworkCallback, cellNetworkCallback);
Paul Jensen3d911462015-06-12 06:40:24 -04001705 assertEquals(mCellNetworkAgent.getNetwork(), mCm.getActiveNetwork());
1706
Paul Jensen3d911462015-06-12 06:40:24 -04001707 cv = waitForConnectivityBroadcasts(2);
1708 mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
1709 mWiFiNetworkAgent.connect(false);
Lorenzo Colitti27334542018-01-12 16:22:21 +09001710 genericNetworkCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
1711 wifiNetworkCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
Paul Jensen3d911462015-06-12 06:40:24 -04001712 assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetwork());
1713 waitFor(cv);
Lorenzo Colitti6ee0a922016-06-27 16:44:07 +09001714 assertNoCallbacks(genericNetworkCallback, wifiNetworkCallback, cellNetworkCallback);
Paul Jensen3d911462015-06-12 06:40:24 -04001715
Paul Jensen3d911462015-06-12 06:40:24 -04001716 cv = waitForConnectivityBroadcasts(2);
1717 mWiFiNetworkAgent.disconnect();
Lorenzo Colitti6ee0a922016-06-27 16:44:07 +09001718 genericNetworkCallback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
1719 wifiNetworkCallback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
Lorenzo Colitti83fa2582015-08-07 12:49:01 +09001720 cellNetworkCallback.assertNoCallback();
Paul Jensen3d911462015-06-12 06:40:24 -04001721 waitFor(cv);
Lorenzo Colitti6ee0a922016-06-27 16:44:07 +09001722 assertNoCallbacks(genericNetworkCallback, wifiNetworkCallback, cellNetworkCallback);
Paul Jensen3d911462015-06-12 06:40:24 -04001723
Paul Jensen3d911462015-06-12 06:40:24 -04001724 cv = waitForConnectivityBroadcasts(1);
1725 mCellNetworkAgent.disconnect();
Lorenzo Colitti6ee0a922016-06-27 16:44:07 +09001726 genericNetworkCallback.expectCallback(CallbackState.LOST, mCellNetworkAgent);
1727 cellNetworkCallback.expectCallback(CallbackState.LOST, mCellNetworkAgent);
Paul Jensen3d911462015-06-12 06:40:24 -04001728 waitFor(cv);
Lorenzo Colitti6ee0a922016-06-27 16:44:07 +09001729 assertNoCallbacks(genericNetworkCallback, wifiNetworkCallback, cellNetworkCallback);
Paul Jensen3d911462015-06-12 06:40:24 -04001730
1731 // Test validated networks
Paul Jensen3d911462015-06-12 06:40:24 -04001732 mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
1733 mCellNetworkAgent.connect(true);
Lorenzo Colitti27334542018-01-12 16:22:21 +09001734 genericNetworkCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
1735 cellNetworkCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
Paul Jensen3d911462015-06-12 06:40:24 -04001736 assertEquals(mCellNetworkAgent.getNetwork(), mCm.getActiveNetwork());
Lorenzo Colitti6ee0a922016-06-27 16:44:07 +09001737 assertNoCallbacks(genericNetworkCallback, wifiNetworkCallback, cellNetworkCallback);
Paul Jensen3d911462015-06-12 06:40:24 -04001738
Paul Jensen3d911462015-06-12 06:40:24 -04001739 // This should not trigger spurious onAvailable() callbacks, b/21762680.
1740 mCellNetworkAgent.adjustScore(-1);
Hugo Benichibb91c572017-05-22 10:44:02 +09001741 waitForIdle();
Lorenzo Colitti6ee0a922016-06-27 16:44:07 +09001742 assertNoCallbacks(genericNetworkCallback, wifiNetworkCallback, cellNetworkCallback);
Paul Jensen3d911462015-06-12 06:40:24 -04001743 assertEquals(mCellNetworkAgent.getNetwork(), mCm.getActiveNetwork());
1744
Paul Jensen3d911462015-06-12 06:40:24 -04001745 mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
1746 mWiFiNetworkAgent.connect(true);
Lorenzo Colitti27334542018-01-12 16:22:21 +09001747 genericNetworkCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
Lorenzo Colitti6ee0a922016-06-27 16:44:07 +09001748 genericNetworkCallback.expectCallback(CallbackState.LOSING, mCellNetworkAgent);
Erik Kline1d3db322017-02-28 16:20:20 +09001749 genericNetworkCallback.expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, mWiFiNetworkAgent);
Lorenzo Colitti27334542018-01-12 16:22:21 +09001750 wifiNetworkCallback.expectAvailableThenValidatedCallbacks(mWiFiNetworkAgent);
Lorenzo Colitti6ee0a922016-06-27 16:44:07 +09001751 cellNetworkCallback.expectCallback(CallbackState.LOSING, mCellNetworkAgent);
Paul Jensen3d911462015-06-12 06:40:24 -04001752 assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetwork());
Lorenzo Colitti6ee0a922016-06-27 16:44:07 +09001753 assertNoCallbacks(genericNetworkCallback, wifiNetworkCallback, cellNetworkCallback);
Paul Jensen3d911462015-06-12 06:40:24 -04001754
Paul Jensen3d911462015-06-12 06:40:24 -04001755 mWiFiNetworkAgent.disconnect();
Lorenzo Colitti6ee0a922016-06-27 16:44:07 +09001756 genericNetworkCallback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
1757 wifiNetworkCallback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
1758 assertNoCallbacks(genericNetworkCallback, wifiNetworkCallback, cellNetworkCallback);
Paul Jensen3d911462015-06-12 06:40:24 -04001759
Paul Jensen3d911462015-06-12 06:40:24 -04001760 mCellNetworkAgent.disconnect();
Lorenzo Colitti6ee0a922016-06-27 16:44:07 +09001761 genericNetworkCallback.expectCallback(CallbackState.LOST, mCellNetworkAgent);
1762 cellNetworkCallback.expectCallback(CallbackState.LOST, mCellNetworkAgent);
1763 assertNoCallbacks(genericNetworkCallback, wifiNetworkCallback, cellNetworkCallback);
Paul Jensen3d911462015-06-12 06:40:24 -04001764 }
1765
Hugo Benichi4a0c5d72017-10-11 11:26:25 +09001766 @Test
Lorenzo Colitti7369d8d12016-06-28 21:28:28 +09001767 public void testMultipleLingering() {
Remi NGUYEN VAN605f12d2018-07-11 18:17:06 +09001768 // This test would be flaky with the default 120ms timer: that is short enough that
1769 // lingered networks are torn down before assertions can be run. We don't want to mock the
1770 // lingering timer to keep the WakeupMessage logic realistic: this has already proven useful
1771 // in detecting races.
1772 mService.mLingerDelayMs = 300;
1773
Lorenzo Colitti7369d8d12016-06-28 21:28:28 +09001774 NetworkRequest request = new NetworkRequest.Builder()
1775 .clearCapabilities().addCapability(NET_CAPABILITY_NOT_METERED)
1776 .build();
1777 TestNetworkCallback callback = new TestNetworkCallback();
1778 mCm.registerNetworkCallback(request, callback);
1779
1780 TestNetworkCallback defaultCallback = new TestNetworkCallback();
1781 mCm.registerDefaultNetworkCallback(defaultCallback);
1782
1783 mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
1784 mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
1785 mEthernetNetworkAgent = new MockNetworkAgent(TRANSPORT_ETHERNET);
1786
1787 mCellNetworkAgent.addCapability(NET_CAPABILITY_NOT_METERED);
1788 mWiFiNetworkAgent.addCapability(NET_CAPABILITY_NOT_METERED);
1789 mEthernetNetworkAgent.addCapability(NET_CAPABILITY_NOT_METERED);
1790
1791 mCellNetworkAgent.connect(true);
Lorenzo Colitti27334542018-01-12 16:22:21 +09001792 callback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
1793 defaultCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
Lorenzo Colitti7369d8d12016-06-28 21:28:28 +09001794 assertEquals(mCellNetworkAgent.getNetwork(), mCm.getActiveNetwork());
Chalard Jeanfb0c87e2018-04-18 19:18:58 +09001795 assertEquals(defaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
Lorenzo Colitti7369d8d12016-06-28 21:28:28 +09001796
1797 mWiFiNetworkAgent.connect(true);
1798 // We get AVAILABLE on wifi when wifi connects and satisfies our unmetered request.
1799 // We then get LOSING when wifi validates and cell is outscored.
Lorenzo Colitti27334542018-01-12 16:22:21 +09001800 callback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
Erik Kline1d3db322017-02-28 16:20:20 +09001801 // TODO: Investigate sending validated before losing.
Lorenzo Colitti7369d8d12016-06-28 21:28:28 +09001802 callback.expectCallback(CallbackState.LOSING, mCellNetworkAgent);
Erik Kline1d3db322017-02-28 16:20:20 +09001803 callback.expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, mWiFiNetworkAgent);
Lorenzo Colitti27334542018-01-12 16:22:21 +09001804 defaultCallback.expectAvailableDoubleValidatedCallbacks(mWiFiNetworkAgent);
Lorenzo Colitti7369d8d12016-06-28 21:28:28 +09001805 assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetwork());
Chalard Jeanfb0c87e2018-04-18 19:18:58 +09001806 assertEquals(defaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
Lorenzo Colitti7369d8d12016-06-28 21:28:28 +09001807
1808 mEthernetNetworkAgent.connect(true);
Lorenzo Colitti27334542018-01-12 16:22:21 +09001809 callback.expectAvailableCallbacksUnvalidated(mEthernetNetworkAgent);
Erik Kline1d3db322017-02-28 16:20:20 +09001810 // TODO: Investigate sending validated before losing.
Lorenzo Colitti7369d8d12016-06-28 21:28:28 +09001811 callback.expectCallback(CallbackState.LOSING, mWiFiNetworkAgent);
Erik Kline1d3db322017-02-28 16:20:20 +09001812 callback.expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, mEthernetNetworkAgent);
Lorenzo Colitti27334542018-01-12 16:22:21 +09001813 defaultCallback.expectAvailableDoubleValidatedCallbacks(mEthernetNetworkAgent);
Lorenzo Colitti7369d8d12016-06-28 21:28:28 +09001814 assertEquals(mEthernetNetworkAgent.getNetwork(), mCm.getActiveNetwork());
Chalard Jeanfb0c87e2018-04-18 19:18:58 +09001815 assertEquals(defaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
Lorenzo Colitti7369d8d12016-06-28 21:28:28 +09001816
1817 mEthernetNetworkAgent.disconnect();
1818 callback.expectCallback(CallbackState.LOST, mEthernetNetworkAgent);
1819 defaultCallback.expectCallback(CallbackState.LOST, mEthernetNetworkAgent);
Lorenzo Colitti27334542018-01-12 16:22:21 +09001820 defaultCallback.expectAvailableCallbacksValidated(mWiFiNetworkAgent);
Chalard Jeanfb0c87e2018-04-18 19:18:58 +09001821 assertEquals(defaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
Lorenzo Colitti7369d8d12016-06-28 21:28:28 +09001822
1823 for (int i = 0; i < 4; i++) {
1824 MockNetworkAgent oldNetwork, newNetwork;
1825 if (i % 2 == 0) {
1826 mWiFiNetworkAgent.adjustScore(-15);
1827 oldNetwork = mWiFiNetworkAgent;
1828 newNetwork = mCellNetworkAgent;
1829 } else {
1830 mWiFiNetworkAgent.adjustScore(15);
1831 oldNetwork = mCellNetworkAgent;
1832 newNetwork = mWiFiNetworkAgent;
1833
1834 }
1835 callback.expectCallback(CallbackState.LOSING, oldNetwork);
Lorenzo Colittib57578ca2016-07-01 01:53:25 +09001836 // TODO: should we send an AVAILABLE callback to newNetwork, to indicate that it is no
1837 // longer lingering?
Lorenzo Colitti27334542018-01-12 16:22:21 +09001838 defaultCallback.expectAvailableCallbacksValidated(newNetwork);
Lorenzo Colitti7369d8d12016-06-28 21:28:28 +09001839 assertEquals(newNetwork.getNetwork(), mCm.getActiveNetwork());
1840 }
1841 assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetwork());
1842
1843 // Verify that if a network no longer satisfies a request, we send LOST and not LOSING, even
1844 // if the network is still up.
1845 mWiFiNetworkAgent.removeCapability(NET_CAPABILITY_NOT_METERED);
Erik Kline1d3db322017-02-28 16:20:20 +09001846 // We expect a notification about the capabilities change, and nothing else.
1847 defaultCallback.expectCapabilitiesWithout(NET_CAPABILITY_NOT_METERED, mWiFiNetworkAgent);
1848 defaultCallback.assertNoCallback();
Lorenzo Colitti7369d8d12016-06-28 21:28:28 +09001849 callback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
Chalard Jeanfb0c87e2018-04-18 19:18:58 +09001850 assertEquals(defaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
Lorenzo Colitti7369d8d12016-06-28 21:28:28 +09001851
1852 // Wifi no longer satisfies our listen, which is for an unmetered network.
1853 // But because its score is 55, it's still up (and the default network).
Lorenzo Colitti7369d8d12016-06-28 21:28:28 +09001854 assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetwork());
1855
1856 // Disconnect our test networks.
1857 mWiFiNetworkAgent.disconnect();
1858 defaultCallback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
Lorenzo Colitti27334542018-01-12 16:22:21 +09001859 defaultCallback.expectAvailableCallbacksValidated(mCellNetworkAgent);
Chalard Jeanfb0c87e2018-04-18 19:18:58 +09001860 assertEquals(defaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
Lorenzo Colitti7369d8d12016-06-28 21:28:28 +09001861 mCellNetworkAgent.disconnect();
1862 defaultCallback.expectCallback(CallbackState.LOST, mCellNetworkAgent);
Chalard Jeanfb0c87e2018-04-18 19:18:58 +09001863 waitForIdle();
1864 assertEquals(null, mCm.getActiveNetwork());
Lorenzo Colitti7369d8d12016-06-28 21:28:28 +09001865
1866 mCm.unregisterNetworkCallback(callback);
Hugo Benichibb91c572017-05-22 10:44:02 +09001867 waitForIdle();
Lorenzo Colitti7369d8d12016-06-28 21:28:28 +09001868
1869 // Check that a network is only lingered or torn down if it would not satisfy a request even
1870 // if it validated.
1871 request = new NetworkRequest.Builder().clearCapabilities().build();
1872 callback = new TestNetworkCallback();
1873
1874 mCm.registerNetworkCallback(request, callback);
1875
1876 mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
1877 mCellNetworkAgent.connect(false); // Score: 10
Lorenzo Colitti27334542018-01-12 16:22:21 +09001878 callback.expectAvailableCallbacksUnvalidated(mCellNetworkAgent);
1879 defaultCallback.expectAvailableCallbacksUnvalidated(mCellNetworkAgent);
Lorenzo Colitti7369d8d12016-06-28 21:28:28 +09001880 assertEquals(mCellNetworkAgent.getNetwork(), mCm.getActiveNetwork());
Chalard Jeanfb0c87e2018-04-18 19:18:58 +09001881 assertEquals(defaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
Lorenzo Colitti7369d8d12016-06-28 21:28:28 +09001882
1883 // Bring up wifi with a score of 20.
1884 // Cell stays up because it would satisfy the default request if it validated.
1885 mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
1886 mWiFiNetworkAgent.connect(false); // Score: 20
Lorenzo Colitti27334542018-01-12 16:22:21 +09001887 callback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
1888 defaultCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
Lorenzo Colitti7369d8d12016-06-28 21:28:28 +09001889 assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetwork());
Chalard Jeanfb0c87e2018-04-18 19:18:58 +09001890 assertEquals(defaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
Lorenzo Colitti7369d8d12016-06-28 21:28:28 +09001891
1892 mWiFiNetworkAgent.disconnect();
1893 callback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
1894 defaultCallback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
Lorenzo Colitti27334542018-01-12 16:22:21 +09001895 defaultCallback.expectAvailableCallbacksUnvalidated(mCellNetworkAgent);
Lorenzo Colitti7369d8d12016-06-28 21:28:28 +09001896 assertEquals(mCellNetworkAgent.getNetwork(), mCm.getActiveNetwork());
Chalard Jeanfb0c87e2018-04-18 19:18:58 +09001897 assertEquals(defaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
Lorenzo Colitti7369d8d12016-06-28 21:28:28 +09001898
1899 // Bring up wifi with a score of 70.
Lorenzo Colitti09e20212016-07-04 16:24:16 +09001900 // Cell is lingered because it would not satisfy any request, even if it validated.
Lorenzo Colitti7369d8d12016-06-28 21:28:28 +09001901 mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
1902 mWiFiNetworkAgent.adjustScore(50);
1903 mWiFiNetworkAgent.connect(false); // Score: 70
Lorenzo Colitti27334542018-01-12 16:22:21 +09001904 callback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
Lorenzo Colittib57578ca2016-07-01 01:53:25 +09001905 callback.expectCallback(CallbackState.LOSING, mCellNetworkAgent);
Lorenzo Colitti27334542018-01-12 16:22:21 +09001906 defaultCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
Lorenzo Colitti7369d8d12016-06-28 21:28:28 +09001907 assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetwork());
Chalard Jeanfb0c87e2018-04-18 19:18:58 +09001908 assertEquals(defaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
Lorenzo Colitti7369d8d12016-06-28 21:28:28 +09001909
1910 // Tear down wifi.
1911 mWiFiNetworkAgent.disconnect();
1912 callback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
1913 defaultCallback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
Lorenzo Colitti27334542018-01-12 16:22:21 +09001914 defaultCallback.expectAvailableCallbacksUnvalidated(mCellNetworkAgent);
Lorenzo Colitti7369d8d12016-06-28 21:28:28 +09001915 assertEquals(mCellNetworkAgent.getNetwork(), mCm.getActiveNetwork());
Chalard Jeanfb0c87e2018-04-18 19:18:58 +09001916 assertEquals(defaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
Lorenzo Colitti7369d8d12016-06-28 21:28:28 +09001917
Lorenzo Colittib57578ca2016-07-01 01:53:25 +09001918 // Bring up wifi, then validate it. Previous versions would immediately tear down cell, but
1919 // it's arguably correct to linger it, since it was the default network before it validated.
Lorenzo Colitti7369d8d12016-06-28 21:28:28 +09001920 mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
1921 mWiFiNetworkAgent.connect(true);
Lorenzo Colitti27334542018-01-12 16:22:21 +09001922 callback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
Erik Kline1d3db322017-02-28 16:20:20 +09001923 // TODO: Investigate sending validated before losing.
Lorenzo Colittib57578ca2016-07-01 01:53:25 +09001924 callback.expectCallback(CallbackState.LOSING, mCellNetworkAgent);
Erik Kline1d3db322017-02-28 16:20:20 +09001925 callback.expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, mWiFiNetworkAgent);
Lorenzo Colitti27334542018-01-12 16:22:21 +09001926 defaultCallback.expectAvailableThenValidatedCallbacks(mWiFiNetworkAgent);
Lorenzo Colitti7369d8d12016-06-28 21:28:28 +09001927 assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetwork());
Chalard Jeanfb0c87e2018-04-18 19:18:58 +09001928 assertEquals(defaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
Lorenzo Colitti7369d8d12016-06-28 21:28:28 +09001929
1930 mWiFiNetworkAgent.disconnect();
1931 callback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
Lorenzo Colitti09e20212016-07-04 16:24:16 +09001932 defaultCallback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
Lorenzo Colitti27334542018-01-12 16:22:21 +09001933 defaultCallback.expectAvailableCallbacksUnvalidated(mCellNetworkAgent);
Lorenzo Colittib57578ca2016-07-01 01:53:25 +09001934 mCellNetworkAgent.disconnect();
1935 callback.expectCallback(CallbackState.LOST, mCellNetworkAgent);
1936 defaultCallback.expectCallback(CallbackState.LOST, mCellNetworkAgent);
Chalard Jeanfb0c87e2018-04-18 19:18:58 +09001937 waitForIdle();
1938 assertEquals(null, mCm.getActiveNetwork());
Lorenzo Colitti09e20212016-07-04 16:24:16 +09001939
Lorenzo Colittib57578ca2016-07-01 01:53:25 +09001940 // If a network is lingering, and we add and remove a request from it, resume lingering.
Lorenzo Colitti09e20212016-07-04 16:24:16 +09001941 mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
1942 mCellNetworkAgent.connect(true);
Lorenzo Colitti27334542018-01-12 16:22:21 +09001943 callback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
1944 defaultCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
Chalard Jeanfb0c87e2018-04-18 19:18:58 +09001945 assertEquals(defaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
Lorenzo Colitti09e20212016-07-04 16:24:16 +09001946 mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
1947 mWiFiNetworkAgent.connect(true);
Lorenzo Colitti27334542018-01-12 16:22:21 +09001948 defaultCallback.expectAvailableDoubleValidatedCallbacks(mWiFiNetworkAgent);
1949 callback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
Erik Kline1d3db322017-02-28 16:20:20 +09001950 // TODO: Investigate sending validated before losing.
Lorenzo Colitti09e20212016-07-04 16:24:16 +09001951 callback.expectCallback(CallbackState.LOSING, mCellNetworkAgent);
Erik Kline1d3db322017-02-28 16:20:20 +09001952 callback.expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, mWiFiNetworkAgent);
Chalard Jeanfb0c87e2018-04-18 19:18:58 +09001953 assertEquals(defaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
Lorenzo Colitti09e20212016-07-04 16:24:16 +09001954
1955 NetworkRequest cellRequest = new NetworkRequest.Builder()
1956 .addTransportType(TRANSPORT_CELLULAR).build();
1957 NetworkCallback noopCallback = new NetworkCallback();
1958 mCm.requestNetwork(cellRequest, noopCallback);
Lorenzo Colittib57578ca2016-07-01 01:53:25 +09001959 // TODO: should this cause an AVAILABLE callback, to indicate that the network is no longer
1960 // lingering?
Lorenzo Colitti09e20212016-07-04 16:24:16 +09001961 mCm.unregisterNetworkCallback(noopCallback);
Lorenzo Colittib57578ca2016-07-01 01:53:25 +09001962 callback.expectCallback(CallbackState.LOSING, mCellNetworkAgent);
Lorenzo Colitti09e20212016-07-04 16:24:16 +09001963
Lorenzo Colittib57578ca2016-07-01 01:53:25 +09001964 // Similar to the above: lingering can start even after the lingered request is removed.
1965 // Disconnect wifi and switch to cell.
Lorenzo Colitti09e20212016-07-04 16:24:16 +09001966 mWiFiNetworkAgent.disconnect();
1967 callback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
Lorenzo Colittib57578ca2016-07-01 01:53:25 +09001968 defaultCallback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
Lorenzo Colitti27334542018-01-12 16:22:21 +09001969 defaultCallback.expectAvailableCallbacksValidated(mCellNetworkAgent);
Chalard Jeanfb0c87e2018-04-18 19:18:58 +09001970 assertEquals(defaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
Lorenzo Colittib57578ca2016-07-01 01:53:25 +09001971
1972 // Cell is now the default network. Pin it with a cell-specific request.
1973 noopCallback = new NetworkCallback(); // Can't reuse NetworkCallbacks. http://b/20701525
1974 mCm.requestNetwork(cellRequest, noopCallback);
1975
1976 // Now connect wifi, and expect it to become the default network.
1977 mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
1978 mWiFiNetworkAgent.connect(true);
Lorenzo Colitti27334542018-01-12 16:22:21 +09001979 callback.expectAvailableThenValidatedCallbacks(mWiFiNetworkAgent);
1980 defaultCallback.expectAvailableDoubleValidatedCallbacks(mWiFiNetworkAgent);
Chalard Jeanfb0c87e2018-04-18 19:18:58 +09001981 assertEquals(defaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
Lorenzo Colittib57578ca2016-07-01 01:53:25 +09001982 // The default request is lingering on cell, but nothing happens to cell, and we send no
1983 // callbacks for it, because it's kept up by cellRequest.
1984 callback.assertNoCallback();
1985 // Now unregister cellRequest and expect cell to start lingering.
1986 mCm.unregisterNetworkCallback(noopCallback);
1987 callback.expectCallback(CallbackState.LOSING, mCellNetworkAgent);
1988
1989 // Let linger run its course.
1990 callback.assertNoCallback();
Remi NGUYEN VAN605f12d2018-07-11 18:17:06 +09001991 final int lingerTimeoutMs = mService.mLingerDelayMs + mService.mLingerDelayMs / 4;
Hugo Benichidfb559a2016-12-20 14:57:49 +09001992 callback.expectCallback(CallbackState.LOST, mCellNetworkAgent, lingerTimeoutMs);
Lorenzo Colittib57578ca2016-07-01 01:53:25 +09001993
Lorenzo Colitti02cc8392017-05-17 01:28:09 +09001994 // Register a TRACK_DEFAULT request and check that it does not affect lingering.
1995 TestNetworkCallback trackDefaultCallback = new TestNetworkCallback();
1996 mCm.registerDefaultNetworkCallback(trackDefaultCallback);
Lorenzo Colitti27334542018-01-12 16:22:21 +09001997 trackDefaultCallback.expectAvailableCallbacksValidated(mWiFiNetworkAgent);
Lorenzo Colitti02cc8392017-05-17 01:28:09 +09001998 mEthernetNetworkAgent = new MockNetworkAgent(TRANSPORT_ETHERNET);
1999 mEthernetNetworkAgent.connect(true);
Lorenzo Colitti27334542018-01-12 16:22:21 +09002000 callback.expectAvailableCallbacksUnvalidated(mEthernetNetworkAgent);
Lorenzo Colitti02cc8392017-05-17 01:28:09 +09002001 callback.expectCallback(CallbackState.LOSING, mWiFiNetworkAgent);
2002 callback.expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, mEthernetNetworkAgent);
Lorenzo Colitti27334542018-01-12 16:22:21 +09002003 trackDefaultCallback.expectAvailableDoubleValidatedCallbacks(mEthernetNetworkAgent);
2004 defaultCallback.expectAvailableDoubleValidatedCallbacks(mEthernetNetworkAgent);
Chalard Jeanfb0c87e2018-04-18 19:18:58 +09002005 assertEquals(defaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
Lorenzo Colitti02cc8392017-05-17 01:28:09 +09002006
2007 // Let linger run its course.
2008 callback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent, lingerTimeoutMs);
2009
Lorenzo Colittib57578ca2016-07-01 01:53:25 +09002010 // Clean up.
Lorenzo Colitti02cc8392017-05-17 01:28:09 +09002011 mEthernetNetworkAgent.disconnect();
2012 callback.expectCallback(CallbackState.LOST, mEthernetNetworkAgent);
2013 defaultCallback.expectCallback(CallbackState.LOST, mEthernetNetworkAgent);
2014 trackDefaultCallback.expectCallback(CallbackState.LOST, mEthernetNetworkAgent);
Lorenzo Colitti7369d8d12016-06-28 21:28:28 +09002015
2016 mCm.unregisterNetworkCallback(callback);
2017 mCm.unregisterNetworkCallback(defaultCallback);
Lorenzo Colitti02cc8392017-05-17 01:28:09 +09002018 mCm.unregisterNetworkCallback(trackDefaultCallback);
2019 }
2020
Hugo Benichi4a0c5d72017-10-11 11:26:25 +09002021 @Test
Chalard Jean1fa777d2018-02-16 16:07:53 +09002022 public void testNetworkGoesIntoBackgroundAfterLinger() {
2023 setMobileDataAlwaysOn(true);
2024 NetworkRequest request = new NetworkRequest.Builder()
2025 .clearCapabilities()
2026 .build();
2027 TestNetworkCallback callback = new TestNetworkCallback();
2028 mCm.registerNetworkCallback(request, callback);
2029
2030 TestNetworkCallback defaultCallback = new TestNetworkCallback();
2031 mCm.registerDefaultNetworkCallback(defaultCallback);
2032
2033 mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
2034 mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
2035
2036 mCellNetworkAgent.connect(true);
2037 callback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
2038 defaultCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
2039
2040 // Wifi comes up and cell lingers.
2041 mWiFiNetworkAgent.connect(true);
2042 defaultCallback.expectAvailableDoubleValidatedCallbacks(mWiFiNetworkAgent);
2043 callback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
2044 callback.expectCallback(CallbackState.LOSING, mCellNetworkAgent);
2045 callback.expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, mWiFiNetworkAgent);
2046
2047 // File a request for cellular, then release it.
2048 NetworkRequest cellRequest = new NetworkRequest.Builder()
2049 .addTransportType(TRANSPORT_CELLULAR).build();
2050 NetworkCallback noopCallback = new NetworkCallback();
2051 mCm.requestNetwork(cellRequest, noopCallback);
2052 mCm.unregisterNetworkCallback(noopCallback);
2053 callback.expectCallback(CallbackState.LOSING, mCellNetworkAgent);
2054
2055 // Let linger run its course.
Chalard Jeanb72b62d2018-02-16 16:08:35 +09002056 callback.assertNoCallback();
Chalard Jean1fa777d2018-02-16 16:07:53 +09002057 final int lingerTimeoutMs = TEST_LINGER_DELAY_MS + TEST_LINGER_DELAY_MS / 4;
2058 callback.expectCapabilitiesWithout(NET_CAPABILITY_FOREGROUND, mCellNetworkAgent,
2059 lingerTimeoutMs);
2060
2061 // Clean up.
2062 mCm.unregisterNetworkCallback(defaultCallback);
2063 mCm.unregisterNetworkCallback(callback);
2064 }
2065
2066 @Test
Lorenzo Colitti02cc8392017-05-17 01:28:09 +09002067 public void testExplicitlySelected() {
2068 NetworkRequest request = new NetworkRequest.Builder()
2069 .clearCapabilities().addCapability(NET_CAPABILITY_INTERNET)
2070 .build();
2071 TestNetworkCallback callback = new TestNetworkCallback();
2072 mCm.registerNetworkCallback(request, callback);
2073
2074 // Bring up validated cell.
2075 mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
2076 mCellNetworkAgent.connect(true);
Lorenzo Colitti27334542018-01-12 16:22:21 +09002077 callback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
Lorenzo Colitti02cc8392017-05-17 01:28:09 +09002078
2079 // Bring up unvalidated wifi with explicitlySelected=true.
2080 mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
2081 mWiFiNetworkAgent.explicitlySelected(false);
2082 mWiFiNetworkAgent.connect(false);
Lorenzo Colitti27334542018-01-12 16:22:21 +09002083 callback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
Lorenzo Colitti02cc8392017-05-17 01:28:09 +09002084
2085 // Cell Remains the default.
2086 assertEquals(mCellNetworkAgent.getNetwork(), mCm.getActiveNetwork());
2087
2088 // Lower wifi's score to below than cell, and check that it doesn't disconnect because
2089 // it's explicitly selected.
2090 mWiFiNetworkAgent.adjustScore(-40);
2091 mWiFiNetworkAgent.adjustScore(40);
2092 callback.assertNoCallback();
2093
2094 // If the user chooses yes on the "No Internet access, stay connected?" dialog, we switch to
2095 // wifi even though it's unvalidated.
2096 mCm.setAcceptUnvalidated(mWiFiNetworkAgent.getNetwork(), true, false);
2097 callback.expectCallback(CallbackState.LOSING, mCellNetworkAgent);
2098 assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetwork());
2099
2100 // Disconnect wifi, and then reconnect, again with explicitlySelected=true.
2101 mWiFiNetworkAgent.disconnect();
2102 callback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
2103 mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
2104 mWiFiNetworkAgent.explicitlySelected(false);
2105 mWiFiNetworkAgent.connect(false);
Lorenzo Colitti27334542018-01-12 16:22:21 +09002106 callback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
Lorenzo Colitti02cc8392017-05-17 01:28:09 +09002107
2108 // If the user chooses no on the "No Internet access, stay connected?" dialog, we ask the
2109 // network to disconnect.
2110 mCm.setAcceptUnvalidated(mWiFiNetworkAgent.getNetwork(), false, false);
2111 callback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
2112
2113 // Reconnect, again with explicitlySelected=true, but this time validate.
2114 mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
2115 mWiFiNetworkAgent.explicitlySelected(false);
2116 mWiFiNetworkAgent.connect(true);
Lorenzo Colitti27334542018-01-12 16:22:21 +09002117 callback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
Lorenzo Colitti02cc8392017-05-17 01:28:09 +09002118 callback.expectCallback(CallbackState.LOSING, mCellNetworkAgent);
2119 callback.expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, mWiFiNetworkAgent);
2120 assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetwork());
2121
2122 // BUG: the network will no longer linger, even though it's validated and outscored.
2123 // TODO: fix this.
2124 mEthernetNetworkAgent = new MockNetworkAgent(TRANSPORT_ETHERNET);
2125 mEthernetNetworkAgent.connect(true);
Lorenzo Colitti27334542018-01-12 16:22:21 +09002126 callback.expectAvailableThenValidatedCallbacks(mEthernetNetworkAgent);
Lorenzo Colitti02cc8392017-05-17 01:28:09 +09002127 assertEquals(mEthernetNetworkAgent.getNetwork(), mCm.getActiveNetwork());
2128 callback.assertNoCallback();
2129
2130 // Clean up.
2131 mWiFiNetworkAgent.disconnect();
2132 mCellNetworkAgent.disconnect();
2133 mEthernetNetworkAgent.disconnect();
2134
2135 callback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
2136 callback.expectCallback(CallbackState.LOST, mCellNetworkAgent);
2137 callback.expectCallback(CallbackState.LOST, mEthernetNetworkAgent);
Lorenzo Colitti7369d8d12016-06-28 21:28:28 +09002138 }
2139
Paul Jensen85cf78e2015-06-25 13:25:07 -04002140 private void tryNetworkFactoryRequests(int capability) throws Exception {
Paul Jensen487ffe72015-07-24 15:57:11 -04002141 // Verify NOT_RESTRICTED is set appropriately
2142 final NetworkCapabilities nc = new NetworkRequest.Builder().addCapability(capability)
2143 .build().networkCapabilities;
2144 if (capability == NET_CAPABILITY_CBS || capability == NET_CAPABILITY_DUN ||
2145 capability == NET_CAPABILITY_EIMS || capability == NET_CAPABILITY_FOTA ||
2146 capability == NET_CAPABILITY_IA || capability == NET_CAPABILITY_IMS ||
Paul Jensenaae613d2015-08-19 11:06:15 -04002147 capability == NET_CAPABILITY_RCS || capability == NET_CAPABILITY_XCAP) {
Paul Jensen487ffe72015-07-24 15:57:11 -04002148 assertFalse(nc.hasCapability(NET_CAPABILITY_NOT_RESTRICTED));
2149 } else {
2150 assertTrue(nc.hasCapability(NET_CAPABILITY_NOT_RESTRICTED));
2151 }
2152
Robert Greenwalt348e98d2015-06-05 17:55:36 -07002153 NetworkCapabilities filter = new NetworkCapabilities();
Paul Jensen85cf78e2015-06-25 13:25:07 -04002154 filter.addCapability(capability);
Robert Greenwalt348e98d2015-06-05 17:55:36 -07002155 final HandlerThread handlerThread = new HandlerThread("testNetworkFactoryRequests");
2156 handlerThread.start();
Paul Jensen0a2823e2015-06-12 10:31:09 -04002157 final MockNetworkFactory testFactory = new MockNetworkFactory(handlerThread.getLooper(),
Robert Greenwalt348e98d2015-06-05 17:55:36 -07002158 mServiceContext, "testFactory", filter);
2159 testFactory.setScoreFilter(40);
Paul Jensen0a2823e2015-06-12 10:31:09 -04002160 ConditionVariable cv = testFactory.getNetworkStartedCV();
Lorenzo Colittiffa390b2015-08-08 01:55:44 +09002161 testFactory.expectAddRequests(1);
Robert Greenwalt348e98d2015-06-05 17:55:36 -07002162 testFactory.register();
Lorenzo Colittiffa390b2015-08-08 01:55:44 +09002163 testFactory.waitForNetworkRequests(1);
Paul Jensen85cf78e2015-06-25 13:25:07 -04002164 int expectedRequestCount = 1;
2165 NetworkCallback networkCallback = null;
2166 // For non-INTERNET capabilities we cannot rely on the default request being present, so
2167 // add one.
2168 if (capability != NET_CAPABILITY_INTERNET) {
Paul Jensen85cf78e2015-06-25 13:25:07 -04002169 assertFalse(testFactory.getMyStartRequested());
2170 NetworkRequest request = new NetworkRequest.Builder().addCapability(capability).build();
2171 networkCallback = new NetworkCallback();
Lorenzo Colittiffa390b2015-08-08 01:55:44 +09002172 testFactory.expectAddRequests(1);
Paul Jensen85cf78e2015-06-25 13:25:07 -04002173 mCm.requestNetwork(request, networkCallback);
2174 expectedRequestCount++;
Lorenzo Colittiffa390b2015-08-08 01:55:44 +09002175 testFactory.waitForNetworkRequests(expectedRequestCount);
Paul Jensen85cf78e2015-06-25 13:25:07 -04002176 }
Paul Jensen3d911462015-06-12 06:40:24 -04002177 waitFor(cv);
Paul Jensen85cf78e2015-06-25 13:25:07 -04002178 assertEquals(expectedRequestCount, testFactory.getMyRequestCount());
2179 assertTrue(testFactory.getMyStartRequested());
Robert Greenwalt348e98d2015-06-05 17:55:36 -07002180
Paul Jensen85cf78e2015-06-25 13:25:07 -04002181 // Now bring in a higher scored network.
Robert Greenwalt348e98d2015-06-05 17:55:36 -07002182 MockNetworkAgent testAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
Paul Jensen85cf78e2015-06-25 13:25:07 -04002183 // Rather than create a validated network which complicates things by registering it's
2184 // own NetworkRequest during startup, just bump up the score to cancel out the
2185 // unvalidated penalty.
2186 testAgent.adjustScore(40);
2187 cv = testFactory.getNetworkStoppedCV();
Lorenzo Colittiffa390b2015-08-08 01:55:44 +09002188
2189 // When testAgent connects, ConnectivityService will re-send us all current requests with
2190 // the new score. There are expectedRequestCount such requests, and we must wait for all of
2191 // them.
2192 testFactory.expectAddRequests(expectedRequestCount);
Paul Jensen85cf78e2015-06-25 13:25:07 -04002193 testAgent.connect(false);
2194 testAgent.addCapability(capability);
Paul Jensen3d911462015-06-12 06:40:24 -04002195 waitFor(cv);
Lorenzo Colittiffa390b2015-08-08 01:55:44 +09002196 testFactory.waitForNetworkRequests(expectedRequestCount);
Paul Jensen85cf78e2015-06-25 13:25:07 -04002197 assertFalse(testFactory.getMyStartRequested());
Robert Greenwalt348e98d2015-06-05 17:55:36 -07002198
Paul Jensen85cf78e2015-06-25 13:25:07 -04002199 // Bring in a bunch of requests.
Lorenzo Colittiffa390b2015-08-08 01:55:44 +09002200 testFactory.expectAddRequests(10);
2201 assertEquals(expectedRequestCount, testFactory.getMyRequestCount());
Robert Greenwalt348e98d2015-06-05 17:55:36 -07002202 ConnectivityManager.NetworkCallback[] networkCallbacks =
2203 new ConnectivityManager.NetworkCallback[10];
2204 for (int i = 0; i< networkCallbacks.length; i++) {
2205 networkCallbacks[i] = new ConnectivityManager.NetworkCallback();
2206 NetworkRequest.Builder builder = new NetworkRequest.Builder();
Paul Jensen85cf78e2015-06-25 13:25:07 -04002207 builder.addCapability(capability);
Robert Greenwalt348e98d2015-06-05 17:55:36 -07002208 mCm.requestNetwork(builder.build(), networkCallbacks[i]);
2209 }
Paul Jensen85cf78e2015-06-25 13:25:07 -04002210 testFactory.waitForNetworkRequests(10 + expectedRequestCount);
2211 assertFalse(testFactory.getMyStartRequested());
Robert Greenwalt348e98d2015-06-05 17:55:36 -07002212
Paul Jensen85cf78e2015-06-25 13:25:07 -04002213 // Remove the requests.
Lorenzo Colittiffa390b2015-08-08 01:55:44 +09002214 testFactory.expectRemoveRequests(10);
Robert Greenwalt348e98d2015-06-05 17:55:36 -07002215 for (int i = 0; i < networkCallbacks.length; i++) {
2216 mCm.unregisterNetworkCallback(networkCallbacks[i]);
2217 }
Paul Jensen85cf78e2015-06-25 13:25:07 -04002218 testFactory.waitForNetworkRequests(expectedRequestCount);
2219 assertFalse(testFactory.getMyStartRequested());
Robert Greenwalt348e98d2015-06-05 17:55:36 -07002220
Paul Jensen85cf78e2015-06-25 13:25:07 -04002221 // Drop the higher scored network.
2222 cv = testFactory.getNetworkStartedCV();
Robert Greenwalt348e98d2015-06-05 17:55:36 -07002223 testAgent.disconnect();
Paul Jensen3d911462015-06-12 06:40:24 -04002224 waitFor(cv);
Paul Jensen85cf78e2015-06-25 13:25:07 -04002225 assertEquals(expectedRequestCount, testFactory.getMyRequestCount());
2226 assertTrue(testFactory.getMyStartRequested());
Robert Greenwalt348e98d2015-06-05 17:55:36 -07002227
2228 testFactory.unregister();
Paul Jensen85cf78e2015-06-25 13:25:07 -04002229 if (networkCallback != null) mCm.unregisterNetworkCallback(networkCallback);
Robert Greenwalt348e98d2015-06-05 17:55:36 -07002230 handlerThread.quit();
2231 }
2232
Hugo Benichi4a0c5d72017-10-11 11:26:25 +09002233 @Test
Paul Jensen85cf78e2015-06-25 13:25:07 -04002234 public void testNetworkFactoryRequests() throws Exception {
2235 tryNetworkFactoryRequests(NET_CAPABILITY_MMS);
2236 tryNetworkFactoryRequests(NET_CAPABILITY_SUPL);
2237 tryNetworkFactoryRequests(NET_CAPABILITY_DUN);
2238 tryNetworkFactoryRequests(NET_CAPABILITY_FOTA);
2239 tryNetworkFactoryRequests(NET_CAPABILITY_IMS);
2240 tryNetworkFactoryRequests(NET_CAPABILITY_CBS);
2241 tryNetworkFactoryRequests(NET_CAPABILITY_WIFI_P2P);
2242 tryNetworkFactoryRequests(NET_CAPABILITY_IA);
2243 tryNetworkFactoryRequests(NET_CAPABILITY_RCS);
2244 tryNetworkFactoryRequests(NET_CAPABILITY_XCAP);
2245 tryNetworkFactoryRequests(NET_CAPABILITY_EIMS);
2246 tryNetworkFactoryRequests(NET_CAPABILITY_NOT_METERED);
2247 tryNetworkFactoryRequests(NET_CAPABILITY_INTERNET);
2248 tryNetworkFactoryRequests(NET_CAPABILITY_TRUSTED);
2249 tryNetworkFactoryRequests(NET_CAPABILITY_NOT_VPN);
2250 // Skipping VALIDATED and CAPTIVE_PORTAL as they're disallowed.
2251 }
2252
Hugo Benichi4a0c5d72017-10-11 11:26:25 +09002253 @Test
Paul Jensenbb2e0e92015-06-16 15:11:58 -04002254 public void testNoMutableNetworkRequests() throws Exception {
2255 PendingIntent pendingIntent = PendingIntent.getBroadcast(mContext, 0, new Intent("a"), 0);
Hugo Benichi16f0a942017-06-20 14:07:59 +09002256 NetworkRequest request1 = new NetworkRequest.Builder()
2257 .addCapability(NET_CAPABILITY_VALIDATED)
2258 .build();
2259 NetworkRequest request2 = new NetworkRequest.Builder()
2260 .addCapability(NET_CAPABILITY_CAPTIVE_PORTAL)
2261 .build();
2262
2263 Class<IllegalArgumentException> expected = IllegalArgumentException.class;
2264 assertException(() -> { mCm.requestNetwork(request1, new NetworkCallback()); }, expected);
2265 assertException(() -> { mCm.requestNetwork(request1, pendingIntent); }, expected);
2266 assertException(() -> { mCm.requestNetwork(request2, new NetworkCallback()); }, expected);
2267 assertException(() -> { mCm.requestNetwork(request2, pendingIntent); }, expected);
Paul Jensenbb2e0e92015-06-16 15:11:58 -04002268 }
Robert Greenwalt348e98d2015-06-05 17:55:36 -07002269
Hugo Benichi4a0c5d72017-10-11 11:26:25 +09002270 @Test
Paul Jensene0988542015-06-25 15:30:08 -04002271 public void testMMSonWiFi() throws Exception {
2272 // Test bringing up cellular without MMS NetworkRequest gets reaped
2273 mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
2274 mCellNetworkAgent.addCapability(NET_CAPABILITY_MMS);
2275 ConditionVariable cv = mCellNetworkAgent.getDisconnectedCV();
2276 mCellNetworkAgent.connectWithoutInternet();
2277 waitFor(cv);
Hugo Benichibb91c572017-05-22 10:44:02 +09002278 waitForIdle();
Hugo Benichifed512a2017-06-26 10:06:49 +09002279 assertEmpty(mCm.getAllNetworks());
Paul Jensene0988542015-06-25 15:30:08 -04002280 verifyNoNetwork();
Hugo Benichibb91c572017-05-22 10:44:02 +09002281
Paul Jensene0988542015-06-25 15:30:08 -04002282 // Test bringing up validated WiFi.
2283 mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
2284 cv = waitForConnectivityBroadcasts(1);
2285 mWiFiNetworkAgent.connect(true);
2286 waitFor(cv);
2287 verifyActiveNetwork(TRANSPORT_WIFI);
Hugo Benichibb91c572017-05-22 10:44:02 +09002288
Paul Jensene0988542015-06-25 15:30:08 -04002289 // Register MMS NetworkRequest
2290 NetworkRequest.Builder builder = new NetworkRequest.Builder();
2291 builder.addCapability(NetworkCapabilities.NET_CAPABILITY_MMS);
2292 final TestNetworkCallback networkCallback = new TestNetworkCallback();
2293 mCm.requestNetwork(builder.build(), networkCallback);
Hugo Benichibb91c572017-05-22 10:44:02 +09002294
Paul Jensene0988542015-06-25 15:30:08 -04002295 // Test bringing up unvalidated cellular with MMS
2296 mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
2297 mCellNetworkAgent.addCapability(NET_CAPABILITY_MMS);
Paul Jensene0988542015-06-25 15:30:08 -04002298 mCellNetworkAgent.connectWithoutInternet();
Lorenzo Colitti27334542018-01-12 16:22:21 +09002299 networkCallback.expectAvailableCallbacksUnvalidated(mCellNetworkAgent);
Paul Jensene0988542015-06-25 15:30:08 -04002300 verifyActiveNetwork(TRANSPORT_WIFI);
Hugo Benichibb91c572017-05-22 10:44:02 +09002301
Paul Jensene0988542015-06-25 15:30:08 -04002302 // Test releasing NetworkRequest disconnects cellular with MMS
2303 cv = mCellNetworkAgent.getDisconnectedCV();
2304 mCm.unregisterNetworkCallback(networkCallback);
2305 waitFor(cv);
2306 verifyActiveNetwork(TRANSPORT_WIFI);
2307 }
2308
Hugo Benichi4a0c5d72017-10-11 11:26:25 +09002309 @Test
Paul Jensene0988542015-06-25 15:30:08 -04002310 public void testMMSonCell() throws Exception {
2311 // Test bringing up cellular without MMS
2312 mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
2313 ConditionVariable cv = waitForConnectivityBroadcasts(1);
2314 mCellNetworkAgent.connect(false);
2315 waitFor(cv);
2316 verifyActiveNetwork(TRANSPORT_CELLULAR);
Hugo Benichibb91c572017-05-22 10:44:02 +09002317
Paul Jensene0988542015-06-25 15:30:08 -04002318 // Register MMS NetworkRequest
2319 NetworkRequest.Builder builder = new NetworkRequest.Builder();
2320 builder.addCapability(NetworkCapabilities.NET_CAPABILITY_MMS);
2321 final TestNetworkCallback networkCallback = new TestNetworkCallback();
2322 mCm.requestNetwork(builder.build(), networkCallback);
Hugo Benichibb91c572017-05-22 10:44:02 +09002323
Paul Jensene0988542015-06-25 15:30:08 -04002324 // Test bringing up MMS cellular network
Paul Jensene0988542015-06-25 15:30:08 -04002325 MockNetworkAgent mmsNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
2326 mmsNetworkAgent.addCapability(NET_CAPABILITY_MMS);
2327 mmsNetworkAgent.connectWithoutInternet();
Lorenzo Colitti27334542018-01-12 16:22:21 +09002328 networkCallback.expectAvailableCallbacksUnvalidated(mmsNetworkAgent);
Paul Jensene0988542015-06-25 15:30:08 -04002329 verifyActiveNetwork(TRANSPORT_CELLULAR);
Hugo Benichibb91c572017-05-22 10:44:02 +09002330
Paul Jensene0988542015-06-25 15:30:08 -04002331 // Test releasing MMS NetworkRequest does not disconnect main cellular NetworkAgent
2332 cv = mmsNetworkAgent.getDisconnectedCV();
2333 mCm.unregisterNetworkCallback(networkCallback);
2334 waitFor(cv);
2335 verifyActiveNetwork(TRANSPORT_CELLULAR);
2336 }
2337
Hugo Benichi4a0c5d72017-10-11 11:26:25 +09002338 @Test
Paul Jensencf4c2c62015-07-01 14:16:32 -04002339 public void testCaptivePortal() {
2340 final TestNetworkCallback captivePortalCallback = new TestNetworkCallback();
2341 final NetworkRequest captivePortalRequest = new NetworkRequest.Builder()
2342 .addCapability(NET_CAPABILITY_CAPTIVE_PORTAL).build();
2343 mCm.registerNetworkCallback(captivePortalRequest, captivePortalCallback);
2344
2345 final TestNetworkCallback validatedCallback = new TestNetworkCallback();
2346 final NetworkRequest validatedRequest = new NetworkRequest.Builder()
2347 .addCapability(NET_CAPABILITY_VALIDATED).build();
2348 mCm.registerNetworkCallback(validatedRequest, validatedCallback);
Paul Jensencf4c2c62015-07-01 14:16:32 -04002349
2350 // Bring up a network with a captive portal.
2351 // Expect onAvailable callback of listen for NET_CAPABILITY_CAPTIVE_PORTAL.
Paul Jensencf4c2c62015-07-01 14:16:32 -04002352 mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
Paul Jensen232437312016-04-06 09:51:26 -04002353 String firstRedirectUrl = "http://example.com/firstPath";
2354 mWiFiNetworkAgent.connectWithCaptivePortal(firstRedirectUrl);
Lorenzo Colitti27334542018-01-12 16:22:21 +09002355 captivePortalCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
Paul Jensen232437312016-04-06 09:51:26 -04002356 assertEquals(mWiFiNetworkAgent.waitForRedirectUrl(), firstRedirectUrl);
Paul Jensencf4c2c62015-07-01 14:16:32 -04002357
2358 // Take down network.
2359 // Expect onLost callback.
Paul Jensencf4c2c62015-07-01 14:16:32 -04002360 mWiFiNetworkAgent.disconnect();
Lorenzo Colitti6ee0a922016-06-27 16:44:07 +09002361 captivePortalCallback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
Paul Jensencf4c2c62015-07-01 14:16:32 -04002362
2363 // Bring up a network with a captive portal.
2364 // Expect onAvailable callback of listen for NET_CAPABILITY_CAPTIVE_PORTAL.
Paul Jensencf4c2c62015-07-01 14:16:32 -04002365 mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
Paul Jensen232437312016-04-06 09:51:26 -04002366 String secondRedirectUrl = "http://example.com/secondPath";
2367 mWiFiNetworkAgent.connectWithCaptivePortal(secondRedirectUrl);
Lorenzo Colitti27334542018-01-12 16:22:21 +09002368 captivePortalCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
Paul Jensen232437312016-04-06 09:51:26 -04002369 assertEquals(mWiFiNetworkAgent.waitForRedirectUrl(), secondRedirectUrl);
Paul Jensencf4c2c62015-07-01 14:16:32 -04002370
2371 // Make captive portal disappear then revalidate.
2372 // Expect onLost callback because network no longer provides NET_CAPABILITY_CAPTIVE_PORTAL.
Paul Jensencf4c2c62015-07-01 14:16:32 -04002373 mWiFiNetworkAgent.getWrappedNetworkMonitor().gen204ProbeResult = 204;
2374 mCm.reportNetworkConnectivity(mWiFiNetworkAgent.getNetwork(), true);
Lorenzo Colitti6ee0a922016-06-27 16:44:07 +09002375 captivePortalCallback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
Paul Jensencf4c2c62015-07-01 14:16:32 -04002376
2377 // Expect NET_CAPABILITY_VALIDATED onAvailable callback.
Lorenzo Colitti27334542018-01-12 16:22:21 +09002378 validatedCallback.expectAvailableDoubleValidatedCallbacks(mWiFiNetworkAgent);
Paul Jensencf4c2c62015-07-01 14:16:32 -04002379
2380 // Break network connectivity.
2381 // Expect NET_CAPABILITY_VALIDATED onLost callback.
Paul Jensencf4c2c62015-07-01 14:16:32 -04002382 mWiFiNetworkAgent.getWrappedNetworkMonitor().gen204ProbeResult = 500;
2383 mCm.reportNetworkConnectivity(mWiFiNetworkAgent.getNetwork(), false);
Lorenzo Colitti6ee0a922016-06-27 16:44:07 +09002384 validatedCallback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
Paul Jensencf4c2c62015-07-01 14:16:32 -04002385 }
Lorenzo Colitti7914ce52015-09-08 13:21:48 +09002386
Hugo Benichi4a0c5d72017-10-11 11:26:25 +09002387 @Test
Lorenzo Colitti4734cdb2017-04-27 14:30:21 +09002388 public void testCaptivePortalApp() {
2389 final TestNetworkCallback captivePortalCallback = new TestNetworkCallback();
2390 final NetworkRequest captivePortalRequest = new NetworkRequest.Builder()
2391 .addCapability(NET_CAPABILITY_CAPTIVE_PORTAL).build();
2392 mCm.registerNetworkCallback(captivePortalRequest, captivePortalCallback);
2393
2394 final TestNetworkCallback validatedCallback = new TestNetworkCallback();
2395 final NetworkRequest validatedRequest = new NetworkRequest.Builder()
2396 .addCapability(NET_CAPABILITY_VALIDATED).build();
2397 mCm.registerNetworkCallback(validatedRequest, validatedCallback);
2398
2399 // Bring up wifi.
2400 mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
2401 mWiFiNetworkAgent.connect(true);
Lorenzo Colitti27334542018-01-12 16:22:21 +09002402 validatedCallback.expectAvailableDoubleValidatedCallbacks(mWiFiNetworkAgent);
Lorenzo Colitti4734cdb2017-04-27 14:30:21 +09002403 Network wifiNetwork = mWiFiNetworkAgent.getNetwork();
2404
2405 // Check that calling startCaptivePortalApp does nothing.
2406 final int fastTimeoutMs = 100;
2407 mCm.startCaptivePortalApp(wifiNetwork);
2408 mServiceContext.expectNoStartActivityIntent(fastTimeoutMs);
2409
2410 // Turn into a captive portal.
2411 mWiFiNetworkAgent.getWrappedNetworkMonitor().gen204ProbeResult = 302;
2412 mCm.reportNetworkConnectivity(wifiNetwork, false);
Lorenzo Colitti27334542018-01-12 16:22:21 +09002413 captivePortalCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
Lorenzo Colitti4734cdb2017-04-27 14:30:21 +09002414 validatedCallback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
2415
2416 // Check that startCaptivePortalApp sends the expected intent.
2417 mCm.startCaptivePortalApp(wifiNetwork);
2418 Intent intent = mServiceContext.expectStartActivityIntent(TIMEOUT_MS);
2419 assertEquals(ConnectivityManager.ACTION_CAPTIVE_PORTAL_SIGN_IN, intent.getAction());
2420 assertEquals(wifiNetwork, intent.getExtra(ConnectivityManager.EXTRA_NETWORK));
2421
2422 // Have the app report that the captive portal is dismissed, and check that we revalidate.
2423 mWiFiNetworkAgent.getWrappedNetworkMonitor().gen204ProbeResult = 204;
2424 CaptivePortal c = (CaptivePortal) intent.getExtra(ConnectivityManager.EXTRA_CAPTIVE_PORTAL);
2425 c.reportCaptivePortalDismissed();
Lorenzo Colitti27334542018-01-12 16:22:21 +09002426 validatedCallback.expectAvailableCallbacksValidated(mWiFiNetworkAgent);
Lorenzo Colitti4734cdb2017-04-27 14:30:21 +09002427 captivePortalCallback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
2428
2429 mCm.unregisterNetworkCallback(validatedCallback);
2430 mCm.unregisterNetworkCallback(captivePortalCallback);
2431 }
2432
Hugo Benichi4a0c5d72017-10-11 11:26:25 +09002433 @Test
Calvin On1f64f3f2016-10-11 15:10:46 -07002434 public void testAvoidOrIgnoreCaptivePortals() {
2435 final TestNetworkCallback captivePortalCallback = new TestNetworkCallback();
2436 final NetworkRequest captivePortalRequest = new NetworkRequest.Builder()
2437 .addCapability(NET_CAPABILITY_CAPTIVE_PORTAL).build();
2438 mCm.registerNetworkCallback(captivePortalRequest, captivePortalCallback);
2439
2440 final TestNetworkCallback validatedCallback = new TestNetworkCallback();
2441 final NetworkRequest validatedRequest = new NetworkRequest.Builder()
2442 .addCapability(NET_CAPABILITY_VALIDATED).build();
2443 mCm.registerNetworkCallback(validatedRequest, validatedCallback);
2444
2445 setCaptivePortalMode(Settings.Global.CAPTIVE_PORTAL_MODE_AVOID);
2446 // Bring up a network with a captive portal.
2447 // Expect it to fail to connect and not result in any callbacks.
2448 mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
2449 String firstRedirectUrl = "http://example.com/firstPath";
2450
2451 ConditionVariable disconnectCv = mWiFiNetworkAgent.getDisconnectedCV();
2452 ConditionVariable avoidCv = mWiFiNetworkAgent.getPreventReconnectReceived();
2453 mWiFiNetworkAgent.connectWithCaptivePortal(firstRedirectUrl);
2454 waitFor(disconnectCv);
2455 waitFor(avoidCv);
2456
2457 assertNoCallbacks(captivePortalCallback, validatedCallback);
2458
2459 // Now test ignore mode.
2460 setCaptivePortalMode(Settings.Global.CAPTIVE_PORTAL_MODE_IGNORE);
2461
2462 // Bring up a network with a captive portal.
2463 // Since we're ignoring captive portals, the network will validate.
2464 mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
2465 String secondRedirectUrl = "http://example.com/secondPath";
2466 mWiFiNetworkAgent.connectWithCaptivePortal(secondRedirectUrl);
2467
2468 // Expect NET_CAPABILITY_VALIDATED onAvailable callback.
Lorenzo Colitti27334542018-01-12 16:22:21 +09002469 validatedCallback.expectAvailableCallbacksValidated(mWiFiNetworkAgent);
Calvin On1f64f3f2016-10-11 15:10:46 -07002470 // But there should be no CaptivePortal callback.
2471 captivePortalCallback.assertNoCallback();
2472 }
2473
Lorenzo Colitti6556a222017-04-03 17:46:35 +09002474 private NetworkRequest.Builder newWifiRequestBuilder() {
2475 return new NetworkRequest.Builder().addTransportType(TRANSPORT_WIFI);
2476 }
2477
Hugo Benichi4a0c5d72017-10-11 11:26:25 +09002478 @Test
Lorenzo Colitti6556a222017-04-03 17:46:35 +09002479 public void testNetworkSpecifier() {
Lorenzo Colitti6556a222017-04-03 17:46:35 +09002480 NetworkRequest rEmpty1 = newWifiRequestBuilder().build();
Etan Cohena7434272017-04-03 12:17:51 -07002481 NetworkRequest rEmpty2 = newWifiRequestBuilder().setNetworkSpecifier((String) null).build();
Lorenzo Colitti6556a222017-04-03 17:46:35 +09002482 NetworkRequest rEmpty3 = newWifiRequestBuilder().setNetworkSpecifier("").build();
Etan Cohena7434272017-04-03 12:17:51 -07002483 NetworkRequest rEmpty4 = newWifiRequestBuilder().setNetworkSpecifier(
2484 (NetworkSpecifier) null).build();
Lorenzo Colitti6556a222017-04-03 17:46:35 +09002485 NetworkRequest rFoo = newWifiRequestBuilder().setNetworkSpecifier("foo").build();
Etan Cohena7434272017-04-03 12:17:51 -07002486 NetworkRequest rBar = newWifiRequestBuilder().setNetworkSpecifier(
2487 new StringNetworkSpecifier("bar")).build();
Lorenzo Colitti6556a222017-04-03 17:46:35 +09002488
2489 TestNetworkCallback cEmpty1 = new TestNetworkCallback();
2490 TestNetworkCallback cEmpty2 = new TestNetworkCallback();
2491 TestNetworkCallback cEmpty3 = new TestNetworkCallback();
Etan Cohena7434272017-04-03 12:17:51 -07002492 TestNetworkCallback cEmpty4 = new TestNetworkCallback();
Lorenzo Colitti6556a222017-04-03 17:46:35 +09002493 TestNetworkCallback cFoo = new TestNetworkCallback();
2494 TestNetworkCallback cBar = new TestNetworkCallback();
2495 TestNetworkCallback[] emptyCallbacks = new TestNetworkCallback[] {
2496 cEmpty1, cEmpty2, cEmpty3 };
2497
2498 mCm.registerNetworkCallback(rEmpty1, cEmpty1);
2499 mCm.registerNetworkCallback(rEmpty2, cEmpty2);
2500 mCm.registerNetworkCallback(rEmpty3, cEmpty3);
Etan Cohena7434272017-04-03 12:17:51 -07002501 mCm.registerNetworkCallback(rEmpty4, cEmpty4);
Lorenzo Colitti6556a222017-04-03 17:46:35 +09002502 mCm.registerNetworkCallback(rFoo, cFoo);
2503 mCm.registerNetworkCallback(rBar, cBar);
2504
2505 mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
2506 mWiFiNetworkAgent.connect(false);
Lorenzo Colitti27334542018-01-12 16:22:21 +09002507 cEmpty1.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
2508 cEmpty2.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
2509 cEmpty3.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
2510 cEmpty4.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
Lorenzo Colitti6556a222017-04-03 17:46:35 +09002511 assertNoCallbacks(cFoo, cBar);
2512
Etan Cohena7434272017-04-03 12:17:51 -07002513 mWiFiNetworkAgent.setNetworkSpecifier(new StringNetworkSpecifier("foo"));
Lorenzo Colitti27334542018-01-12 16:22:21 +09002514 cFoo.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
Lorenzo Colitti6556a222017-04-03 17:46:35 +09002515 for (TestNetworkCallback c: emptyCallbacks) {
2516 c.expectCallback(CallbackState.NETWORK_CAPABILITIES, mWiFiNetworkAgent);
2517 }
2518 cFoo.expectCallback(CallbackState.NETWORK_CAPABILITIES, mWiFiNetworkAgent);
2519 cFoo.assertNoCallback();
2520
Etan Cohena7434272017-04-03 12:17:51 -07002521 mWiFiNetworkAgent.setNetworkSpecifier(new StringNetworkSpecifier("bar"));
Lorenzo Colitti6556a222017-04-03 17:46:35 +09002522 cFoo.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
Lorenzo Colitti27334542018-01-12 16:22:21 +09002523 cBar.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
Lorenzo Colitti6556a222017-04-03 17:46:35 +09002524 for (TestNetworkCallback c: emptyCallbacks) {
2525 c.expectCallback(CallbackState.NETWORK_CAPABILITIES, mWiFiNetworkAgent);
2526 }
2527 cBar.expectCallback(CallbackState.NETWORK_CAPABILITIES, mWiFiNetworkAgent);
2528 cBar.assertNoCallback();
2529
2530 mWiFiNetworkAgent.setNetworkSpecifier(null);
2531 cBar.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
2532 for (TestNetworkCallback c: emptyCallbacks) {
2533 c.expectCallback(CallbackState.NETWORK_CAPABILITIES, mWiFiNetworkAgent);
2534 }
2535
2536 assertNoCallbacks(cEmpty1, cEmpty2, cEmpty3, cFoo, cBar);
2537 }
2538
Hugo Benichi4a0c5d72017-10-11 11:26:25 +09002539 @Test
Etan Cohenddb9ef02015-11-18 10:56:15 -08002540 public void testInvalidNetworkSpecifier() {
Etan Cohenddb9ef02015-11-18 10:56:15 -08002541 try {
2542 NetworkRequest.Builder builder = new NetworkRequest.Builder();
Etan Cohena7434272017-04-03 12:17:51 -07002543 builder.setNetworkSpecifier(new MatchAllNetworkSpecifier());
2544 fail("NetworkRequest builder with MatchAllNetworkSpecifier");
2545 } catch (IllegalArgumentException expected) {
2546 // expected
Etan Cohenddb9ef02015-11-18 10:56:15 -08002547 }
2548
Etan Cohenddb9ef02015-11-18 10:56:15 -08002549 try {
2550 NetworkCapabilities networkCapabilities = new NetworkCapabilities();
2551 networkCapabilities.addTransportType(TRANSPORT_WIFI)
Etan Cohena7434272017-04-03 12:17:51 -07002552 .setNetworkSpecifier(new MatchAllNetworkSpecifier());
Etan Cohenddb9ef02015-11-18 10:56:15 -08002553 mService.requestNetwork(networkCapabilities, null, 0, null,
2554 ConnectivityManager.TYPE_WIFI);
Etan Cohena7434272017-04-03 12:17:51 -07002555 fail("ConnectivityService requestNetwork with MatchAllNetworkSpecifier");
2556 } catch (IllegalArgumentException expected) {
2557 // expected
Etan Cohenddb9ef02015-11-18 10:56:15 -08002558 }
2559
Etan Cohena7434272017-04-03 12:17:51 -07002560 class NonParcelableSpecifier extends NetworkSpecifier {
2561 public boolean satisfiedBy(NetworkSpecifier other) { return false; }
2562 };
2563 class ParcelableSpecifier extends NonParcelableSpecifier implements Parcelable {
2564 @Override public int describeContents() { return 0; }
2565 @Override public void writeToParcel(Parcel p, int flags) {}
2566 }
2567 NetworkRequest.Builder builder;
2568
2569 builder = new NetworkRequest.Builder().addTransportType(TRANSPORT_ETHERNET);
2570 try {
2571 builder.setNetworkSpecifier(new NonParcelableSpecifier());
2572 Parcel parcelW = Parcel.obtain();
2573 builder.build().writeToParcel(parcelW, 0);
2574 fail("Parceling a non-parcelable specifier did not throw an exception");
2575 } catch (Exception e) {
2576 // expected
2577 }
2578
2579 builder = new NetworkRequest.Builder().addTransportType(TRANSPORT_ETHERNET);
2580 builder.setNetworkSpecifier(new ParcelableSpecifier());
2581 NetworkRequest nr = builder.build();
2582 assertNotNull(nr);
2583
2584 try {
2585 Parcel parcelW = Parcel.obtain();
2586 nr.writeToParcel(parcelW, 0);
2587 byte[] bytes = parcelW.marshall();
2588 parcelW.recycle();
2589
2590 Parcel parcelR = Parcel.obtain();
2591 parcelR.unmarshall(bytes, 0, bytes.length);
2592 parcelR.setDataPosition(0);
2593 NetworkRequest rereadNr = NetworkRequest.CREATOR.createFromParcel(parcelR);
2594 fail("Unparceling a non-framework NetworkSpecifier did not throw an exception");
2595 } catch (Exception e) {
2596 // expected
2597 }
Etan Cohenddb9ef02015-11-18 10:56:15 -08002598 }
2599
Hugo Benichi4a0c5d72017-10-11 11:26:25 +09002600 @Test
Etan Cohen859748f2017-04-03 17:42:34 -07002601 public void testNetworkSpecifierUidSpoofSecurityException() {
2602 class UidAwareNetworkSpecifier extends NetworkSpecifier implements Parcelable {
2603 @Override
2604 public boolean satisfiedBy(NetworkSpecifier other) {
2605 return true;
2606 }
2607
2608 @Override
2609 public void assertValidFromUid(int requestorUid) {
2610 throw new SecurityException("failure");
2611 }
2612
2613 @Override
2614 public int describeContents() { return 0; }
2615 @Override
2616 public void writeToParcel(Parcel dest, int flags) {}
2617 }
2618
2619 mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
2620 mWiFiNetworkAgent.connect(false);
2621
2622 UidAwareNetworkSpecifier networkSpecifier = new UidAwareNetworkSpecifier();
2623 NetworkRequest networkRequest = newWifiRequestBuilder().setNetworkSpecifier(
2624 networkSpecifier).build();
2625 TestNetworkCallback networkCallback = new TestNetworkCallback();
2626 try {
2627 mCm.requestNetwork(networkRequest, networkCallback);
2628 fail("Network request with spoofed UID did not throw a SecurityException");
2629 } catch (SecurityException e) {
2630 // expected
2631 }
2632 }
2633
Hugo Benichi4a0c5d72017-10-11 11:26:25 +09002634 @Test
Erik Klinea2d29402016-03-16 15:31:39 +09002635 public void testRegisterDefaultNetworkCallback() throws Exception {
2636 final TestNetworkCallback defaultNetworkCallback = new TestNetworkCallback();
2637 mCm.registerDefaultNetworkCallback(defaultNetworkCallback);
2638 defaultNetworkCallback.assertNoCallback();
2639
2640 // Create a TRANSPORT_CELLULAR request to keep the mobile interface up
2641 // whenever Wi-Fi is up. Without this, the mobile network agent is
2642 // reaped before any other activity can take place.
2643 final TestNetworkCallback cellNetworkCallback = new TestNetworkCallback();
2644 final NetworkRequest cellRequest = new NetworkRequest.Builder()
2645 .addTransportType(TRANSPORT_CELLULAR).build();
2646 mCm.requestNetwork(cellRequest, cellNetworkCallback);
2647 cellNetworkCallback.assertNoCallback();
2648
2649 // Bring up cell and expect CALLBACK_AVAILABLE.
2650 mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
2651 mCellNetworkAgent.connect(true);
Lorenzo Colitti27334542018-01-12 16:22:21 +09002652 cellNetworkCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
2653 defaultNetworkCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
Chalard Jeanfb0c87e2018-04-18 19:18:58 +09002654 assertEquals(defaultNetworkCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
Erik Klinea2d29402016-03-16 15:31:39 +09002655
2656 // Bring up wifi and expect CALLBACK_AVAILABLE.
2657 mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
2658 mWiFiNetworkAgent.connect(true);
2659 cellNetworkCallback.assertNoCallback();
Lorenzo Colitti27334542018-01-12 16:22:21 +09002660 defaultNetworkCallback.expectAvailableDoubleValidatedCallbacks(mWiFiNetworkAgent);
Chalard Jeanfb0c87e2018-04-18 19:18:58 +09002661 assertEquals(defaultNetworkCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
Erik Klinea2d29402016-03-16 15:31:39 +09002662
2663 // Bring down cell. Expect no default network callback, since it wasn't the default.
2664 mCellNetworkAgent.disconnect();
2665 cellNetworkCallback.expectCallback(CallbackState.LOST, mCellNetworkAgent);
2666 defaultNetworkCallback.assertNoCallback();
Chalard Jeanfb0c87e2018-04-18 19:18:58 +09002667 assertEquals(defaultNetworkCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
Erik Klinea2d29402016-03-16 15:31:39 +09002668
2669 // Bring up cell. Expect no default network callback, since it won't be the default.
2670 mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
2671 mCellNetworkAgent.connect(true);
Lorenzo Colitti27334542018-01-12 16:22:21 +09002672 cellNetworkCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
Erik Klinea2d29402016-03-16 15:31:39 +09002673 defaultNetworkCallback.assertNoCallback();
Chalard Jeanfb0c87e2018-04-18 19:18:58 +09002674 assertEquals(defaultNetworkCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
Erik Klinea2d29402016-03-16 15:31:39 +09002675
2676 // Bring down wifi. Expect the default network callback to notified of LOST wifi
2677 // followed by AVAILABLE cell.
2678 mWiFiNetworkAgent.disconnect();
2679 cellNetworkCallback.assertNoCallback();
2680 defaultNetworkCallback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
Lorenzo Colitti27334542018-01-12 16:22:21 +09002681 defaultNetworkCallback.expectAvailableCallbacksValidated(mCellNetworkAgent);
Erik Klinea2d29402016-03-16 15:31:39 +09002682 mCellNetworkAgent.disconnect();
2683 cellNetworkCallback.expectCallback(CallbackState.LOST, mCellNetworkAgent);
2684 defaultNetworkCallback.expectCallback(CallbackState.LOST, mCellNetworkAgent);
Chalard Jeanfb0c87e2018-04-18 19:18:58 +09002685 waitForIdle();
2686 assertEquals(null, mCm.getActiveNetwork());
2687
2688 final int uid = Process.myUid();
2689 final MockNetworkAgent vpnNetworkAgent = new MockNetworkAgent(TRANSPORT_VPN);
2690 final ArraySet<UidRange> ranges = new ArraySet<>();
2691 ranges.add(new UidRange(uid, uid));
Chalard Jeanf89e8da2018-05-18 21:47:45 +09002692 mMockVpn.setNetworkAgent(vpnNetworkAgent);
2693 mMockVpn.setUids(ranges);
Chalard Jeanfb0c87e2018-04-18 19:18:58 +09002694 vpnNetworkAgent.connect(true);
Chalard Jeanf89e8da2018-05-18 21:47:45 +09002695 mMockVpn.connect();
Chalard Jeanfb0c87e2018-04-18 19:18:58 +09002696 defaultNetworkCallback.expectAvailableThenValidatedCallbacks(vpnNetworkAgent);
2697 assertEquals(defaultNetworkCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
2698
2699 vpnNetworkAgent.disconnect();
2700 defaultNetworkCallback.expectCallback(CallbackState.LOST, vpnNetworkAgent);
2701 waitForIdle();
2702 assertEquals(null, mCm.getActiveNetwork());
Erik Klinea2d29402016-03-16 15:31:39 +09002703 }
2704
Hugo Benichi4a0c5d72017-10-11 11:26:25 +09002705 @Test
Erik Kline1d3db322017-02-28 16:20:20 +09002706 public void testAdditionalStateCallbacks() throws Exception {
Erik Klineacdd6392016-07-07 16:50:58 +09002707 // File a network request for mobile.
Erik Kline1d3db322017-02-28 16:20:20 +09002708 final TestNetworkCallback cellNetworkCallback = new TestNetworkCallback();
Erik Klineacdd6392016-07-07 16:50:58 +09002709 final NetworkRequest cellRequest = new NetworkRequest.Builder()
2710 .addTransportType(TRANSPORT_CELLULAR).build();
2711 mCm.requestNetwork(cellRequest, cellNetworkCallback);
2712
2713 // Bring up the mobile network.
2714 mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
2715 mCellNetworkAgent.connect(true);
2716
Erik Kline1d3db322017-02-28 16:20:20 +09002717 // We should get onAvailable(), onCapabilitiesChanged(), and
2718 // onLinkPropertiesChanged() in rapid succession. Additionally, we
2719 // should get onCapabilitiesChanged() when the mobile network validates.
Lorenzo Colitti27334542018-01-12 16:22:21 +09002720 cellNetworkCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
Erik Klineacdd6392016-07-07 16:50:58 +09002721 cellNetworkCallback.assertNoCallback();
2722
2723 // Update LinkProperties.
2724 final LinkProperties lp = new LinkProperties();
2725 lp.setInterfaceName("foonet_data0");
2726 mCellNetworkAgent.sendLinkProperties(lp);
2727 // We should get onLinkPropertiesChanged().
2728 cellNetworkCallback.expectCallback(CallbackState.LINK_PROPERTIES, mCellNetworkAgent);
2729 cellNetworkCallback.assertNoCallback();
2730
Erik Kline1d3db322017-02-28 16:20:20 +09002731 // Suspend the network.
2732 mCellNetworkAgent.suspend();
Chalard Jean804b8fb2018-01-30 22:41:41 +09002733 cellNetworkCallback.expectCapabilitiesWithout(NET_CAPABILITY_NOT_SUSPENDED,
2734 mCellNetworkAgent);
Erik Kline1d3db322017-02-28 16:20:20 +09002735 cellNetworkCallback.expectCallback(CallbackState.SUSPENDED, mCellNetworkAgent);
2736 cellNetworkCallback.assertNoCallback();
2737
Erik Klineacdd6392016-07-07 16:50:58 +09002738 // Register a garden variety default network request.
Chalard Jean804b8fb2018-01-30 22:41:41 +09002739 TestNetworkCallback dfltNetworkCallback = new TestNetworkCallback();
Erik Klineacdd6392016-07-07 16:50:58 +09002740 mCm.registerDefaultNetworkCallback(dfltNetworkCallback);
Erik Kline1d3db322017-02-28 16:20:20 +09002741 // We should get onAvailable(), onCapabilitiesChanged(), onLinkPropertiesChanged(),
2742 // as well as onNetworkSuspended() in rapid succession.
Lorenzo Colitti27334542018-01-12 16:22:21 +09002743 dfltNetworkCallback.expectAvailableAndSuspendedCallbacks(mCellNetworkAgent, true);
Erik Klineacdd6392016-07-07 16:50:58 +09002744 dfltNetworkCallback.assertNoCallback();
Chalard Jean804b8fb2018-01-30 22:41:41 +09002745 mCm.unregisterNetworkCallback(dfltNetworkCallback);
2746
2747 mCellNetworkAgent.resume();
2748 cellNetworkCallback.expectCapabilitiesWith(NET_CAPABILITY_NOT_SUSPENDED,
2749 mCellNetworkAgent);
2750 cellNetworkCallback.expectCallback(CallbackState.RESUMED, mCellNetworkAgent);
2751 cellNetworkCallback.assertNoCallback();
2752
2753 dfltNetworkCallback = new TestNetworkCallback();
2754 mCm.registerDefaultNetworkCallback(dfltNetworkCallback);
2755 // This time onNetworkSuspended should not be called.
2756 dfltNetworkCallback.expectAvailableCallbacksValidated(mCellNetworkAgent);
2757 dfltNetworkCallback.assertNoCallback();
Erik Klineacdd6392016-07-07 16:50:58 +09002758
Erik Klineacdd6392016-07-07 16:50:58 +09002759 mCm.unregisterNetworkCallback(dfltNetworkCallback);
2760 mCm.unregisterNetworkCallback(cellNetworkCallback);
2761 }
2762
Calvin On1f64f3f2016-10-11 15:10:46 -07002763 private void setCaptivePortalMode(int mode) {
2764 ContentResolver cr = mServiceContext.getContentResolver();
2765 Settings.Global.putInt(cr, Settings.Global.CAPTIVE_PORTAL_MODE, mode);
2766 }
2767
Lorenzo Colittie14d49a2016-07-20 21:35:19 +09002768 private void setMobileDataAlwaysOn(boolean enable) {
2769 ContentResolver cr = mServiceContext.getContentResolver();
2770 Settings.Global.putInt(cr, Settings.Global.MOBILE_DATA_ALWAYS_ON, enable ? 1 : 0);
2771 mService.updateMobileDataAlwaysOn();
Hugo Benichibb91c572017-05-22 10:44:02 +09002772 waitForIdle();
Lorenzo Colittie14d49a2016-07-20 21:35:19 +09002773 }
2774
Erik Kline79c6d052018-03-21 07:18:33 -07002775 private void setPrivateDnsSettings(String mode, String specifier) {
2776 final ContentResolver cr = mServiceContext.getContentResolver();
2777 Settings.Global.putString(cr, Settings.Global.PRIVATE_DNS_MODE, mode);
2778 Settings.Global.putString(cr, Settings.Global.PRIVATE_DNS_SPECIFIER, specifier);
2779 mService.updatePrivateDnsSettings();
2780 waitForIdle();
2781 }
2782
Lorenzo Colittie14d49a2016-07-20 21:35:19 +09002783 private boolean isForegroundNetwork(MockNetworkAgent network) {
2784 NetworkCapabilities nc = mCm.getNetworkCapabilities(network.getNetwork());
2785 assertNotNull(nc);
2786 return nc.hasCapability(NET_CAPABILITY_FOREGROUND);
2787 }
2788
Hugo Benichi4a0c5d72017-10-11 11:26:25 +09002789 @Test
Lorenzo Colittie14d49a2016-07-20 21:35:19 +09002790 public void testBackgroundNetworks() throws Exception {
2791 // Create a background request. We can't do this ourselves because ConnectivityService
2792 // doesn't have an API for it. So just turn on mobile data always on.
2793 setMobileDataAlwaysOn(true);
2794 final NetworkRequest request = new NetworkRequest.Builder().build();
2795 final NetworkRequest fgRequest = new NetworkRequest.Builder()
2796 .addCapability(NET_CAPABILITY_FOREGROUND).build();
2797 final TestNetworkCallback callback = new TestNetworkCallback();
2798 final TestNetworkCallback fgCallback = new TestNetworkCallback();
2799 mCm.registerNetworkCallback(request, callback);
2800 mCm.registerNetworkCallback(fgRequest, fgCallback);
2801
2802 mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
2803 mCellNetworkAgent.connect(true);
Lorenzo Colitti27334542018-01-12 16:22:21 +09002804 callback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
2805 fgCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
Lorenzo Colittie14d49a2016-07-20 21:35:19 +09002806 assertTrue(isForegroundNetwork(mCellNetworkAgent));
2807
2808 mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
2809 mWiFiNetworkAgent.connect(true);
2810
2811 // When wifi connects, cell lingers.
Lorenzo Colitti27334542018-01-12 16:22:21 +09002812 callback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
Lorenzo Colittie14d49a2016-07-20 21:35:19 +09002813 callback.expectCallback(CallbackState.LOSING, mCellNetworkAgent);
Erik Kline1d3db322017-02-28 16:20:20 +09002814 callback.expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, mWiFiNetworkAgent);
Lorenzo Colitti27334542018-01-12 16:22:21 +09002815 fgCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
Lorenzo Colittie14d49a2016-07-20 21:35:19 +09002816 fgCallback.expectCallback(CallbackState.LOSING, mCellNetworkAgent);
Erik Kline1d3db322017-02-28 16:20:20 +09002817 fgCallback.expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, mWiFiNetworkAgent);
Lorenzo Colittie14d49a2016-07-20 21:35:19 +09002818 assertTrue(isForegroundNetwork(mCellNetworkAgent));
2819 assertTrue(isForegroundNetwork(mWiFiNetworkAgent));
2820
2821 // When lingering is complete, cell is still there but is now in the background.
Hugo Benichibb91c572017-05-22 10:44:02 +09002822 waitForIdle();
Hugo Benichidfb559a2016-12-20 14:57:49 +09002823 int timeoutMs = TEST_LINGER_DELAY_MS + TEST_LINGER_DELAY_MS / 4;
2824 fgCallback.expectCallback(CallbackState.LOST, mCellNetworkAgent, timeoutMs);
Erik Kline1d3db322017-02-28 16:20:20 +09002825 // Expect a network capabilities update sans FOREGROUND.
2826 callback.expectCapabilitiesWithout(NET_CAPABILITY_FOREGROUND, mCellNetworkAgent);
Lorenzo Colittie14d49a2016-07-20 21:35:19 +09002827 assertFalse(isForegroundNetwork(mCellNetworkAgent));
2828 assertTrue(isForegroundNetwork(mWiFiNetworkAgent));
2829
2830 // File a cell request and check that cell comes into the foreground.
2831 final NetworkRequest cellRequest = new NetworkRequest.Builder()
2832 .addTransportType(TRANSPORT_CELLULAR).build();
2833 final TestNetworkCallback cellCallback = new TestNetworkCallback();
2834 mCm.requestNetwork(cellRequest, cellCallback);
Erik Kline1d3db322017-02-28 16:20:20 +09002835 // NOTE: This request causes the network's capabilities to change. This
2836 // is currently delivered before the onAvailable() callbacks.
2837 // TODO: Fix this.
2838 cellCallback.expectCapabilitiesWith(NET_CAPABILITY_FOREGROUND, mCellNetworkAgent);
Lorenzo Colitti27334542018-01-12 16:22:21 +09002839 cellCallback.expectAvailableCallbacksValidated(mCellNetworkAgent);
2840 fgCallback.expectAvailableCallbacksValidated(mCellNetworkAgent);
Erik Kline1d3db322017-02-28 16:20:20 +09002841 // Expect a network capabilities update with FOREGROUND, because the most recent
2842 // request causes its state to change.
2843 callback.expectCapabilitiesWith(NET_CAPABILITY_FOREGROUND, mCellNetworkAgent);
Lorenzo Colittie14d49a2016-07-20 21:35:19 +09002844 assertTrue(isForegroundNetwork(mCellNetworkAgent));
2845 assertTrue(isForegroundNetwork(mWiFiNetworkAgent));
2846
2847 // Release the request. The network immediately goes into the background, since it was not
2848 // lingering.
2849 mCm.unregisterNetworkCallback(cellCallback);
2850 fgCallback.expectCallback(CallbackState.LOST, mCellNetworkAgent);
Erik Kline1d3db322017-02-28 16:20:20 +09002851 // Expect a network capabilities update sans FOREGROUND.
2852 callback.expectCapabilitiesWithout(NET_CAPABILITY_FOREGROUND, mCellNetworkAgent);
Lorenzo Colittie14d49a2016-07-20 21:35:19 +09002853 assertFalse(isForegroundNetwork(mCellNetworkAgent));
2854 assertTrue(isForegroundNetwork(mWiFiNetworkAgent));
2855
2856 // Disconnect wifi and check that cell is foreground again.
2857 mWiFiNetworkAgent.disconnect();
2858 callback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
2859 fgCallback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
Lorenzo Colitti27334542018-01-12 16:22:21 +09002860 fgCallback.expectAvailableCallbacksValidated(mCellNetworkAgent);
Lorenzo Colittie14d49a2016-07-20 21:35:19 +09002861 assertTrue(isForegroundNetwork(mCellNetworkAgent));
2862
2863 mCm.unregisterNetworkCallback(callback);
2864 mCm.unregisterNetworkCallback(fgCallback);
2865 }
2866
Hugo Benichi849b81b2017-05-25 13:42:31 +09002867 @Ignore // This test has instrinsic chances of spurious failures: ignore for continuous testing.
Hugo Benichi02f8f9c2017-05-29 13:13:52 +09002868 public void benchmarkRequestRegistrationAndCallbackDispatch() throws Exception {
Hugo Benichicbf8ff82016-11-15 11:25:52 +09002869 // TODO: turn this unit test into a real benchmarking test.
Lorenzo Colitti6ee0a922016-06-27 16:44:07 +09002870 // Benchmarks connecting and switching performance in the presence of a large number of
2871 // NetworkRequests.
2872 // 1. File NUM_REQUESTS requests.
2873 // 2. Have a network connect. Wait for NUM_REQUESTS onAvailable callbacks to fire.
2874 // 3. Have a new network connect and outscore the previous. Wait for NUM_REQUESTS onLosing
2875 // and NUM_REQUESTS onAvailable callbacks to fire.
2876 // See how long it took.
2877 final int NUM_REQUESTS = 90;
Hugo Benichi02f8f9c2017-05-29 13:13:52 +09002878 final int REGISTER_TIME_LIMIT_MS = 200;
2879 final int CONNECT_TIME_LIMIT_MS = 60;
2880 final int SWITCH_TIME_LIMIT_MS = 60;
Hugo Benichibb91c572017-05-22 10:44:02 +09002881 final int UNREGISTER_TIME_LIMIT_MS = 20;
2882
Lorenzo Colitti6ee0a922016-06-27 16:44:07 +09002883 final NetworkRequest request = new NetworkRequest.Builder().clearCapabilities().build();
2884 final NetworkCallback[] callbacks = new NetworkCallback[NUM_REQUESTS];
2885 final CountDownLatch availableLatch = new CountDownLatch(NUM_REQUESTS);
2886 final CountDownLatch losingLatch = new CountDownLatch(NUM_REQUESTS);
2887
Lorenzo Colitti6ee0a922016-06-27 16:44:07 +09002888 for (int i = 0; i < NUM_REQUESTS; i++) {
2889 callbacks[i] = new NetworkCallback() {
2890 @Override public void onAvailable(Network n) { availableLatch.countDown(); }
2891 @Override public void onLosing(Network n, int t) { losingLatch.countDown(); }
2892 };
Lorenzo Colitti6ee0a922016-06-27 16:44:07 +09002893 }
Lorenzo Colitti6ee0a922016-06-27 16:44:07 +09002894
Hugo Benichicbf8ff82016-11-15 11:25:52 +09002895 assertTimeLimit("Registering callbacks", REGISTER_TIME_LIMIT_MS, () -> {
2896 for (NetworkCallback cb : callbacks) {
2897 mCm.registerNetworkCallback(request, cb);
2898 }
2899 });
2900
Lorenzo Colitti6ee0a922016-06-27 16:44:07 +09002901 mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
2902 // Don't request that the network validate, because otherwise connect() will block until
2903 // the network gets NET_CAPABILITY_VALIDATED, after all the callbacks below have fired,
2904 // and we won't actually measure anything.
2905 mCellNetworkAgent.connect(false);
Lorenzo Colitti6ee0a922016-06-27 16:44:07 +09002906
Hugo Benichicbf8ff82016-11-15 11:25:52 +09002907 long onAvailableDispatchingDuration = durationOf(() -> {
Hugo Benichibb91c572017-05-22 10:44:02 +09002908 awaitLatch(availableLatch, 10 * CONNECT_TIME_LIMIT_MS);
Hugo Benichicbf8ff82016-11-15 11:25:52 +09002909 });
Hugo Benichibb91c572017-05-22 10:44:02 +09002910 Log.d(TAG, String.format("Dispatched %d of %d onAvailable callbacks in %dms",
2911 NUM_REQUESTS - availableLatch.getCount(), NUM_REQUESTS,
2912 onAvailableDispatchingDuration));
2913 assertTrue(String.format("Dispatching %d onAvailable callbacks in %dms, expected %dms",
2914 NUM_REQUESTS, onAvailableDispatchingDuration, CONNECT_TIME_LIMIT_MS),
2915 onAvailableDispatchingDuration <= CONNECT_TIME_LIMIT_MS);
Hugo Benichicbf8ff82016-11-15 11:25:52 +09002916
Lorenzo Colitti6ee0a922016-06-27 16:44:07 +09002917 // Give wifi a high enough score that we'll linger cell when wifi comes up.
Hugo Benichibb91c572017-05-22 10:44:02 +09002918 mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
Lorenzo Colitti6ee0a922016-06-27 16:44:07 +09002919 mWiFiNetworkAgent.adjustScore(40);
2920 mWiFiNetworkAgent.connect(false);
Hugo Benichicbf8ff82016-11-15 11:25:52 +09002921
2922 long onLostDispatchingDuration = durationOf(() -> {
Hugo Benichibb91c572017-05-22 10:44:02 +09002923 awaitLatch(losingLatch, 10 * SWITCH_TIME_LIMIT_MS);
Hugo Benichicbf8ff82016-11-15 11:25:52 +09002924 });
Hugo Benichibb91c572017-05-22 10:44:02 +09002925 Log.d(TAG, String.format("Dispatched %d of %d onLosing callbacks in %dms",
2926 NUM_REQUESTS - losingLatch.getCount(), NUM_REQUESTS, onLostDispatchingDuration));
2927 assertTrue(String.format("Dispatching %d onLosing callbacks in %dms, expected %dms",
2928 NUM_REQUESTS, onLostDispatchingDuration, SWITCH_TIME_LIMIT_MS),
2929 onLostDispatchingDuration <= SWITCH_TIME_LIMIT_MS);
Lorenzo Colitti6ee0a922016-06-27 16:44:07 +09002930
Hugo Benichicbf8ff82016-11-15 11:25:52 +09002931 assertTimeLimit("Unregistering callbacks", UNREGISTER_TIME_LIMIT_MS, () -> {
2932 for (NetworkCallback cb : callbacks) {
2933 mCm.unregisterNetworkCallback(cb);
2934 }
2935 });
2936 }
2937
2938 private long durationOf(Runnable fn) {
2939 long startTime = SystemClock.elapsedRealtime();
2940 fn.run();
2941 return SystemClock.elapsedRealtime() - startTime;
2942 }
2943
2944 private void assertTimeLimit(String descr, long timeLimit, Runnable fn) {
2945 long timeTaken = durationOf(fn);
2946 String msg = String.format("%s: took %dms, limit was %dms", descr, timeTaken, timeLimit);
Lorenzo Colitti6ee0a922016-06-27 16:44:07 +09002947 Log.d(TAG, msg);
Hugo Benichicbf8ff82016-11-15 11:25:52 +09002948 assertTrue(msg, timeTaken <= timeLimit);
2949 }
2950
2951 private boolean awaitLatch(CountDownLatch l, long timeoutMs) {
2952 try {
Hugo Benichibb91c572017-05-22 10:44:02 +09002953 return l.await(timeoutMs, TimeUnit.MILLISECONDS);
Hugo Benichicbf8ff82016-11-15 11:25:52 +09002954 } catch (InterruptedException e) {}
2955 return false;
Lorenzo Colitti6ee0a922016-06-27 16:44:07 +09002956 }
2957
Hugo Benichi4a0c5d72017-10-11 11:26:25 +09002958 @Test
Lorenzo Colitti762ea7a2016-06-05 21:00:23 +09002959 public void testMobileDataAlwaysOn() throws Exception {
2960 final TestNetworkCallback cellNetworkCallback = new TestNetworkCallback();
2961 final NetworkRequest cellRequest = new NetworkRequest.Builder()
2962 .addTransportType(TRANSPORT_CELLULAR).build();
2963 mCm.registerNetworkCallback(cellRequest, cellNetworkCallback);
2964
2965 final HandlerThread handlerThread = new HandlerThread("MobileDataAlwaysOnFactory");
2966 handlerThread.start();
2967 NetworkCapabilities filter = new NetworkCapabilities()
2968 .addTransportType(TRANSPORT_CELLULAR)
2969 .addCapability(NET_CAPABILITY_INTERNET);
2970 final MockNetworkFactory testFactory = new MockNetworkFactory(handlerThread.getLooper(),
2971 mServiceContext, "testFactory", filter);
2972 testFactory.setScoreFilter(40);
2973
2974 // Register the factory and expect it to start looking for a network.
2975 testFactory.expectAddRequests(1);
2976 testFactory.register();
2977 testFactory.waitForNetworkRequests(1);
2978 assertTrue(testFactory.getMyStartRequested());
2979
2980 // Bring up wifi. The factory stops looking for a network.
2981 mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
2982 testFactory.expectAddRequests(2); // Because the default request changes score twice.
2983 mWiFiNetworkAgent.connect(true);
2984 testFactory.waitForNetworkRequests(1);
2985 assertFalse(testFactory.getMyStartRequested());
2986
2987 ContentResolver cr = mServiceContext.getContentResolver();
2988
2989 // Turn on mobile data always on. The factory starts looking again.
2990 testFactory.expectAddRequests(1);
Lorenzo Colittie14d49a2016-07-20 21:35:19 +09002991 setMobileDataAlwaysOn(true);
Lorenzo Colitti762ea7a2016-06-05 21:00:23 +09002992 testFactory.waitForNetworkRequests(2);
2993 assertTrue(testFactory.getMyStartRequested());
2994
2995 // Bring up cell data and check that the factory stops looking.
Hugo Benichifed512a2017-06-26 10:06:49 +09002996 assertLength(1, mCm.getAllNetworks());
Lorenzo Colitti762ea7a2016-06-05 21:00:23 +09002997 mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
2998 testFactory.expectAddRequests(2); // Because the cell request changes score twice.
2999 mCellNetworkAgent.connect(true);
Lorenzo Colitti27334542018-01-12 16:22:21 +09003000 cellNetworkCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
Lorenzo Colitti762ea7a2016-06-05 21:00:23 +09003001 testFactory.waitForNetworkRequests(2);
3002 assertFalse(testFactory.getMyStartRequested()); // Because the cell network outscores us.
3003
3004 // Check that cell data stays up.
Hugo Benichibb91c572017-05-22 10:44:02 +09003005 waitForIdle();
Lorenzo Colitti762ea7a2016-06-05 21:00:23 +09003006 verifyActiveNetwork(TRANSPORT_WIFI);
Hugo Benichifed512a2017-06-26 10:06:49 +09003007 assertLength(2, mCm.getAllNetworks());
Lorenzo Colitti762ea7a2016-06-05 21:00:23 +09003008
3009 // Turn off mobile data always on and expect the request to disappear...
3010 testFactory.expectRemoveRequests(1);
Lorenzo Colittie14d49a2016-07-20 21:35:19 +09003011 setMobileDataAlwaysOn(false);
Lorenzo Colitti762ea7a2016-06-05 21:00:23 +09003012 testFactory.waitForNetworkRequests(1);
3013
3014 // ... and cell data to be torn down.
Lorenzo Colitti6ee0a922016-06-27 16:44:07 +09003015 cellNetworkCallback.expectCallback(CallbackState.LOST, mCellNetworkAgent);
Hugo Benichifed512a2017-06-26 10:06:49 +09003016 assertLength(1, mCm.getAllNetworks());
Lorenzo Colitti762ea7a2016-06-05 21:00:23 +09003017
3018 testFactory.unregister();
3019 mCm.unregisterNetworkCallback(cellNetworkCallback);
3020 handlerThread.quit();
3021 }
3022
Hugo Benichi4a0c5d72017-10-11 11:26:25 +09003023 @Test
Lorenzo Colitti73b209382016-09-15 22:18:09 +09003024 public void testAvoidBadWifiSetting() throws Exception {
Lorenzo Colitti165c51c2016-09-19 01:00:19 +09003025 final ContentResolver cr = mServiceContext.getContentResolver();
Lorenzo Colitti58ebe1c2017-01-24 09:41:36 +09003026 final WrappedMultinetworkPolicyTracker tracker = mService.getMultinetworkPolicyTracker();
Lorenzo Colitti165c51c2016-09-19 01:00:19 +09003027 final String settingName = Settings.Global.NETWORK_AVOID_BAD_WIFI;
3028
Erik Kline065ab6e2016-10-02 18:02:14 +09003029 tracker.configRestrictsAvoidBadWifi = false;
Lorenzo Colitti165c51c2016-09-19 01:00:19 +09003030 String[] values = new String[] {null, "0", "1"};
3031 for (int i = 0; i < values.length; i++) {
3032 Settings.Global.putInt(cr, settingName, 1);
Erik Kline065ab6e2016-10-02 18:02:14 +09003033 tracker.reevaluate();
Hugo Benichibb91c572017-05-22 10:44:02 +09003034 waitForIdle();
Lorenzo Colitti165c51c2016-09-19 01:00:19 +09003035 String msg = String.format("config=false, setting=%s", values[i]);
Lorenzo Colitti30145d72017-01-27 18:46:03 +09003036 assertTrue(mService.avoidBadWifi());
Erik Kline065ab6e2016-10-02 18:02:14 +09003037 assertFalse(msg, tracker.shouldNotifyWifiUnvalidated());
Lorenzo Colitti165c51c2016-09-19 01:00:19 +09003038 }
3039
Erik Kline065ab6e2016-10-02 18:02:14 +09003040 tracker.configRestrictsAvoidBadWifi = true;
Lorenzo Colitti165c51c2016-09-19 01:00:19 +09003041
3042 Settings.Global.putInt(cr, settingName, 0);
Erik Kline065ab6e2016-10-02 18:02:14 +09003043 tracker.reevaluate();
Hugo Benichibb91c572017-05-22 10:44:02 +09003044 waitForIdle();
Lorenzo Colitti30145d72017-01-27 18:46:03 +09003045 assertFalse(mService.avoidBadWifi());
Erik Kline065ab6e2016-10-02 18:02:14 +09003046 assertFalse(tracker.shouldNotifyWifiUnvalidated());
Lorenzo Colitti165c51c2016-09-19 01:00:19 +09003047
3048 Settings.Global.putInt(cr, settingName, 1);
Erik Kline065ab6e2016-10-02 18:02:14 +09003049 tracker.reevaluate();
Hugo Benichibb91c572017-05-22 10:44:02 +09003050 waitForIdle();
Lorenzo Colitti30145d72017-01-27 18:46:03 +09003051 assertTrue(mService.avoidBadWifi());
Erik Kline065ab6e2016-10-02 18:02:14 +09003052 assertFalse(tracker.shouldNotifyWifiUnvalidated());
Lorenzo Colitti165c51c2016-09-19 01:00:19 +09003053
3054 Settings.Global.putString(cr, settingName, null);
Erik Kline065ab6e2016-10-02 18:02:14 +09003055 tracker.reevaluate();
Hugo Benichibb91c572017-05-22 10:44:02 +09003056 waitForIdle();
Lorenzo Colitti30145d72017-01-27 18:46:03 +09003057 assertFalse(mService.avoidBadWifi());
Erik Kline065ab6e2016-10-02 18:02:14 +09003058 assertTrue(tracker.shouldNotifyWifiUnvalidated());
Lorenzo Colitti165c51c2016-09-19 01:00:19 +09003059 }
3060
Hugo Benichi4a0c5d72017-10-11 11:26:25 +09003061 @Test
Lorenzo Colitti165c51c2016-09-19 01:00:19 +09003062 public void testAvoidBadWifi() throws Exception {
Erik Kline065ab6e2016-10-02 18:02:14 +09003063 final ContentResolver cr = mServiceContext.getContentResolver();
Lorenzo Colitti58ebe1c2017-01-24 09:41:36 +09003064 final WrappedMultinetworkPolicyTracker tracker = mService.getMultinetworkPolicyTracker();
Lorenzo Colitti73b209382016-09-15 22:18:09 +09003065
Lorenzo Colitti165c51c2016-09-19 01:00:19 +09003066 // Pretend we're on a carrier that restricts switching away from bad wifi.
Erik Kline065ab6e2016-10-02 18:02:14 +09003067 tracker.configRestrictsAvoidBadWifi = true;
Lorenzo Colitti165c51c2016-09-19 01:00:19 +09003068
Lorenzo Colitti73b209382016-09-15 22:18:09 +09003069 // File a request for cell to ensure it doesn't go down.
3070 final TestNetworkCallback cellNetworkCallback = new TestNetworkCallback();
3071 final NetworkRequest cellRequest = new NetworkRequest.Builder()
3072 .addTransportType(TRANSPORT_CELLULAR).build();
3073 mCm.requestNetwork(cellRequest, cellNetworkCallback);
3074
3075 TestNetworkCallback defaultCallback = new TestNetworkCallback();
3076 mCm.registerDefaultNetworkCallback(defaultCallback);
3077
3078 NetworkRequest validatedWifiRequest = new NetworkRequest.Builder()
3079 .addTransportType(TRANSPORT_WIFI)
3080 .addCapability(NET_CAPABILITY_VALIDATED)
3081 .build();
3082 TestNetworkCallback validatedWifiCallback = new TestNetworkCallback();
3083 mCm.registerNetworkCallback(validatedWifiRequest, validatedWifiCallback);
3084
Lorenzo Colitti73b209382016-09-15 22:18:09 +09003085 Settings.Global.putInt(cr, Settings.Global.NETWORK_AVOID_BAD_WIFI, 0);
Erik Kline065ab6e2016-10-02 18:02:14 +09003086 tracker.reevaluate();
Lorenzo Colitti73b209382016-09-15 22:18:09 +09003087
3088 // Bring up validated cell.
3089 mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
3090 mCellNetworkAgent.connect(true);
Lorenzo Colitti27334542018-01-12 16:22:21 +09003091 cellNetworkCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
3092 defaultCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
Lorenzo Colitti73b209382016-09-15 22:18:09 +09003093 Network cellNetwork = mCellNetworkAgent.getNetwork();
3094
3095 // Bring up validated wifi.
3096 mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
3097 mWiFiNetworkAgent.connect(true);
Lorenzo Colitti27334542018-01-12 16:22:21 +09003098 defaultCallback.expectAvailableDoubleValidatedCallbacks(mWiFiNetworkAgent);
3099 validatedWifiCallback.expectAvailableDoubleValidatedCallbacks(mWiFiNetworkAgent);
Lorenzo Colitti73b209382016-09-15 22:18:09 +09003100 Network wifiNetwork = mWiFiNetworkAgent.getNetwork();
3101
3102 // Fail validation on wifi.
3103 mWiFiNetworkAgent.getWrappedNetworkMonitor().gen204ProbeResult = 599;
3104 mCm.reportNetworkConnectivity(wifiNetwork, false);
Erik Kline1d3db322017-02-28 16:20:20 +09003105 defaultCallback.expectCapabilitiesWithout(NET_CAPABILITY_VALIDATED, mWiFiNetworkAgent);
Lorenzo Colitti73b209382016-09-15 22:18:09 +09003106 validatedWifiCallback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
3107
3108 // Because avoid bad wifi is off, we don't switch to cellular.
3109 defaultCallback.assertNoCallback();
3110 assertFalse(mCm.getNetworkCapabilities(wifiNetwork).hasCapability(
3111 NET_CAPABILITY_VALIDATED));
3112 assertTrue(mCm.getNetworkCapabilities(cellNetwork).hasCapability(
3113 NET_CAPABILITY_VALIDATED));
3114 assertEquals(mCm.getActiveNetwork(), wifiNetwork);
3115
Lorenzo Colitti165c51c2016-09-19 01:00:19 +09003116 // Simulate switching to a carrier that does not restrict avoiding bad wifi, and expect
3117 // that we switch back to cell.
Erik Kline065ab6e2016-10-02 18:02:14 +09003118 tracker.configRestrictsAvoidBadWifi = false;
3119 tracker.reevaluate();
Lorenzo Colitti27334542018-01-12 16:22:21 +09003120 defaultCallback.expectAvailableCallbacksValidated(mCellNetworkAgent);
Lorenzo Colitti165c51c2016-09-19 01:00:19 +09003121 assertEquals(mCm.getActiveNetwork(), cellNetwork);
3122
3123 // Switch back to a restrictive carrier.
Erik Kline065ab6e2016-10-02 18:02:14 +09003124 tracker.configRestrictsAvoidBadWifi = true;
3125 tracker.reevaluate();
Lorenzo Colitti27334542018-01-12 16:22:21 +09003126 defaultCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
Lorenzo Colitti165c51c2016-09-19 01:00:19 +09003127 assertEquals(mCm.getActiveNetwork(), wifiNetwork);
3128
3129 // Simulate the user selecting "switch" on the dialog, and check that we switch to cell.
3130 mCm.setAvoidUnvalidated(wifiNetwork);
Lorenzo Colitti27334542018-01-12 16:22:21 +09003131 defaultCallback.expectAvailableCallbacksValidated(mCellNetworkAgent);
Lorenzo Colitti165c51c2016-09-19 01:00:19 +09003132 assertFalse(mCm.getNetworkCapabilities(wifiNetwork).hasCapability(
3133 NET_CAPABILITY_VALIDATED));
3134 assertTrue(mCm.getNetworkCapabilities(cellNetwork).hasCapability(
3135 NET_CAPABILITY_VALIDATED));
3136 assertEquals(mCm.getActiveNetwork(), cellNetwork);
3137
3138 // Disconnect and reconnect wifi to clear the one-time switch above.
3139 mWiFiNetworkAgent.disconnect();
3140 mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
3141 mWiFiNetworkAgent.connect(true);
Lorenzo Colitti27334542018-01-12 16:22:21 +09003142 defaultCallback.expectAvailableDoubleValidatedCallbacks(mWiFiNetworkAgent);
3143 validatedWifiCallback.expectAvailableDoubleValidatedCallbacks(mWiFiNetworkAgent);
Lorenzo Colitti165c51c2016-09-19 01:00:19 +09003144 wifiNetwork = mWiFiNetworkAgent.getNetwork();
3145
3146 // Fail validation on wifi and expect the dialog to appear.
3147 mWiFiNetworkAgent.getWrappedNetworkMonitor().gen204ProbeResult = 599;
3148 mCm.reportNetworkConnectivity(wifiNetwork, false);
Erik Kline1d3db322017-02-28 16:20:20 +09003149 defaultCallback.expectCapabilitiesWithout(NET_CAPABILITY_VALIDATED, mWiFiNetworkAgent);
Lorenzo Colitti165c51c2016-09-19 01:00:19 +09003150 validatedWifiCallback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
3151
3152 // Simulate the user selecting "switch" and checking the don't ask again checkbox.
Lorenzo Colitti73b209382016-09-15 22:18:09 +09003153 Settings.Global.putInt(cr, Settings.Global.NETWORK_AVOID_BAD_WIFI, 1);
Erik Kline065ab6e2016-10-02 18:02:14 +09003154 tracker.reevaluate();
Lorenzo Colitti73b209382016-09-15 22:18:09 +09003155
3156 // We now switch to cell.
Lorenzo Colitti27334542018-01-12 16:22:21 +09003157 defaultCallback.expectAvailableCallbacksValidated(mCellNetworkAgent);
Lorenzo Colitti73b209382016-09-15 22:18:09 +09003158 assertFalse(mCm.getNetworkCapabilities(wifiNetwork).hasCapability(
3159 NET_CAPABILITY_VALIDATED));
3160 assertTrue(mCm.getNetworkCapabilities(cellNetwork).hasCapability(
3161 NET_CAPABILITY_VALIDATED));
3162 assertEquals(mCm.getActiveNetwork(), cellNetwork);
3163
Lorenzo Colitti165c51c2016-09-19 01:00:19 +09003164 // Simulate the user turning the cellular fallback setting off and then on.
3165 // We switch to wifi and then to cell.
3166 Settings.Global.putString(cr, Settings.Global.NETWORK_AVOID_BAD_WIFI, null);
Erik Kline065ab6e2016-10-02 18:02:14 +09003167 tracker.reevaluate();
Lorenzo Colitti27334542018-01-12 16:22:21 +09003168 defaultCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
Lorenzo Colitti165c51c2016-09-19 01:00:19 +09003169 assertEquals(mCm.getActiveNetwork(), wifiNetwork);
3170 Settings.Global.putInt(cr, Settings.Global.NETWORK_AVOID_BAD_WIFI, 1);
Erik Kline065ab6e2016-10-02 18:02:14 +09003171 tracker.reevaluate();
Lorenzo Colitti27334542018-01-12 16:22:21 +09003172 defaultCallback.expectAvailableCallbacksValidated(mCellNetworkAgent);
Lorenzo Colitti165c51c2016-09-19 01:00:19 +09003173 assertEquals(mCm.getActiveNetwork(), cellNetwork);
3174
Lorenzo Colitti73b209382016-09-15 22:18:09 +09003175 // If cell goes down, we switch to wifi.
3176 mCellNetworkAgent.disconnect();
3177 defaultCallback.expectCallback(CallbackState.LOST, mCellNetworkAgent);
Lorenzo Colitti27334542018-01-12 16:22:21 +09003178 defaultCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
Lorenzo Colitti73b209382016-09-15 22:18:09 +09003179 validatedWifiCallback.assertNoCallback();
3180
3181 mCm.unregisterNetworkCallback(cellNetworkCallback);
3182 mCm.unregisterNetworkCallback(validatedWifiCallback);
3183 mCm.unregisterNetworkCallback(defaultCallback);
3184 }
3185
Hugo Benichi4a0c5d72017-10-11 11:26:25 +09003186 @Test
Lorenzo Colitti2de49252017-01-24 18:08:41 +09003187 public void testMeteredMultipathPreferenceSetting() throws Exception {
3188 final ContentResolver cr = mServiceContext.getContentResolver();
3189 final WrappedMultinetworkPolicyTracker tracker = mService.getMultinetworkPolicyTracker();
3190 final String settingName = Settings.Global.NETWORK_METERED_MULTIPATH_PREFERENCE;
3191
3192 for (int config : Arrays.asList(0, 3, 2)) {
3193 for (String setting: Arrays.asList(null, "0", "2", "1")) {
3194 tracker.configMeteredMultipathPreference = config;
3195 Settings.Global.putString(cr, settingName, setting);
3196 tracker.reevaluate();
Hugo Benichibb91c572017-05-22 10:44:02 +09003197 waitForIdle();
Lorenzo Colitti2de49252017-01-24 18:08:41 +09003198
3199 final int expected = (setting != null) ? Integer.parseInt(setting) : config;
3200 String msg = String.format("config=%d, setting=%s", config, setting);
3201 assertEquals(msg, expected, mCm.getMultipathPreference(null));
3202 }
3203 }
3204 }
3205
Erik Kline3841a482015-11-25 12:49:38 +09003206 /**
3207 * Validate that a satisfied network request does not trigger onUnavailable() once the
3208 * time-out period expires.
3209 */
Hugo Benichi4a0c5d72017-10-11 11:26:25 +09003210 @Test
Erik Kline3841a482015-11-25 12:49:38 +09003211 public void testSatisfiedNetworkRequestDoesNotTriggerOnUnavailable() {
3212 NetworkRequest nr = new NetworkRequest.Builder().addTransportType(
3213 NetworkCapabilities.TRANSPORT_WIFI).build();
3214 final TestNetworkCallback networkCallback = new TestNetworkCallback();
Hugo Benichidfb559a2016-12-20 14:57:49 +09003215 final int timeoutMs = 150;
3216 mCm.requestNetwork(nr, networkCallback, timeoutMs);
Erik Kline3841a482015-11-25 12:49:38 +09003217
3218 mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
3219 mWiFiNetworkAgent.connect(false);
Lorenzo Colitti27334542018-01-12 16:22:21 +09003220 networkCallback.expectAvailableCallbacks(mWiFiNetworkAgent, false, false, timeoutMs);
Erik Kline3841a482015-11-25 12:49:38 +09003221
3222 // pass timeout and validate that UNAVAILABLE is not called
Etan Cohenbf3b1ba2016-10-27 15:05:50 -07003223 networkCallback.assertNoCallback();
3224 }
3225
3226 /**
3227 * Validate that a satisfied network request followed by a disconnected (lost) network does
3228 * not trigger onUnavailable() once the time-out period expires.
3229 */
Hugo Benichi4a0c5d72017-10-11 11:26:25 +09003230 @Test
Etan Cohenbf3b1ba2016-10-27 15:05:50 -07003231 public void testSatisfiedThenLostNetworkRequestDoesNotTriggerOnUnavailable() {
3232 NetworkRequest nr = new NetworkRequest.Builder().addTransportType(
3233 NetworkCapabilities.TRANSPORT_WIFI).build();
3234 final TestNetworkCallback networkCallback = new TestNetworkCallback();
Hugo Benichi91c7ff92017-06-26 10:20:00 +09003235 final int requestTimeoutMs = 50;
Hugo Benichidfb559a2016-12-20 14:57:49 +09003236 mCm.requestNetwork(nr, networkCallback, requestTimeoutMs);
Etan Cohenbf3b1ba2016-10-27 15:05:50 -07003237
3238 mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
3239 mWiFiNetworkAgent.connect(false);
Hugo Benichi91c7ff92017-06-26 10:20:00 +09003240 final int assertTimeoutMs = 100;
Lorenzo Colitti27334542018-01-12 16:22:21 +09003241 networkCallback.expectAvailableCallbacks(mWiFiNetworkAgent, false, false, assertTimeoutMs);
Etan Cohenbf3b1ba2016-10-27 15:05:50 -07003242 mWiFiNetworkAgent.disconnect();
3243 networkCallback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
3244
Hugo Benichi91c7ff92017-06-26 10:20:00 +09003245 // Validate that UNAVAILABLE is not called
Erik Kline3841a482015-11-25 12:49:38 +09003246 networkCallback.assertNoCallback();
3247 }
3248
3249 /**
3250 * Validate that when a time-out is specified for a network request the onUnavailable()
3251 * callback is called when time-out expires. Then validate that if network request is
3252 * (somehow) satisfied - the callback isn't called later.
3253 */
Hugo Benichi4a0c5d72017-10-11 11:26:25 +09003254 @Test
Erik Kline3841a482015-11-25 12:49:38 +09003255 public void testTimedoutNetworkRequest() {
3256 NetworkRequest nr = new NetworkRequest.Builder().addTransportType(
3257 NetworkCapabilities.TRANSPORT_WIFI).build();
3258 final TestNetworkCallback networkCallback = new TestNetworkCallback();
Hugo Benichidfb559a2016-12-20 14:57:49 +09003259 final int timeoutMs = 10;
3260 mCm.requestNetwork(nr, networkCallback, timeoutMs);
Erik Kline3841a482015-11-25 12:49:38 +09003261
3262 // pass timeout and validate that UNAVAILABLE is called
3263 networkCallback.expectCallback(CallbackState.UNAVAILABLE, null);
3264
3265 // create a network satisfying request - validate that request not triggered
3266 mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
3267 mWiFiNetworkAgent.connect(false);
3268 networkCallback.assertNoCallback();
3269 }
3270
3271 /**
Hugo Benichi91c7ff92017-06-26 10:20:00 +09003272 * Validate that when a network request is unregistered (cancelled), no posterior event can
3273 * trigger the callback.
Erik Kline3841a482015-11-25 12:49:38 +09003274 */
Hugo Benichi4a0c5d72017-10-11 11:26:25 +09003275 @Test
Hugo Benichi91c7ff92017-06-26 10:20:00 +09003276 public void testNoCallbackAfterUnregisteredNetworkRequest() {
Erik Kline3841a482015-11-25 12:49:38 +09003277 NetworkRequest nr = new NetworkRequest.Builder().addTransportType(
3278 NetworkCapabilities.TRANSPORT_WIFI).build();
3279 final TestNetworkCallback networkCallback = new TestNetworkCallback();
Hugo Benichidfb559a2016-12-20 14:57:49 +09003280 final int timeoutMs = 10;
Hugo Benichi91c7ff92017-06-26 10:20:00 +09003281
Hugo Benichidfb559a2016-12-20 14:57:49 +09003282 mCm.requestNetwork(nr, networkCallback, timeoutMs);
Erik Kline3841a482015-11-25 12:49:38 +09003283 mCm.unregisterNetworkCallback(networkCallback);
Hugo Benichi91c7ff92017-06-26 10:20:00 +09003284 // Regardless of the timeout, unregistering the callback in ConnectivityManager ensures
3285 // that this callback will not be called.
Erik Kline3841a482015-11-25 12:49:38 +09003286 networkCallback.assertNoCallback();
3287
3288 // create a network satisfying request - validate that request not triggered
3289 mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
3290 mWiFiNetworkAgent.connect(false);
3291 networkCallback.assertNoCallback();
3292 }
3293
Lorenzo Colitti7914ce52015-09-08 13:21:48 +09003294 private static class TestKeepaliveCallback extends PacketKeepaliveCallback {
3295
3296 public static enum CallbackType { ON_STARTED, ON_STOPPED, ON_ERROR };
3297
3298 private class CallbackValue {
3299 public CallbackType callbackType;
3300 public int error;
3301
3302 public CallbackValue(CallbackType type) {
3303 this.callbackType = type;
3304 this.error = PacketKeepalive.SUCCESS;
3305 assertTrue("onError callback must have error", type != CallbackType.ON_ERROR);
3306 }
3307
3308 public CallbackValue(CallbackType type, int error) {
3309 this.callbackType = type;
3310 this.error = error;
3311 assertEquals("error can only be set for onError", type, CallbackType.ON_ERROR);
3312 }
3313
3314 @Override
3315 public boolean equals(Object o) {
3316 return o instanceof CallbackValue &&
3317 this.callbackType == ((CallbackValue) o).callbackType &&
3318 this.error == ((CallbackValue) o).error;
3319 }
3320
3321 @Override
3322 public String toString() {
3323 return String.format("%s(%s, %d)", getClass().getSimpleName(), callbackType, error);
3324 }
3325 }
3326
3327 private LinkedBlockingQueue<CallbackValue> mCallbacks = new LinkedBlockingQueue<>();
3328
3329 @Override
3330 public void onStarted() {
3331 mCallbacks.add(new CallbackValue(CallbackType.ON_STARTED));
3332 }
3333
3334 @Override
3335 public void onStopped() {
3336 mCallbacks.add(new CallbackValue(CallbackType.ON_STOPPED));
3337 }
3338
3339 @Override
3340 public void onError(int error) {
3341 mCallbacks.add(new CallbackValue(CallbackType.ON_ERROR, error));
3342 }
3343
3344 private void expectCallback(CallbackValue callbackValue) {
3345 try {
3346 assertEquals(
3347 callbackValue,
3348 mCallbacks.poll(TIMEOUT_MS, TimeUnit.MILLISECONDS));
3349 } catch (InterruptedException e) {
3350 fail(callbackValue.callbackType + " callback not seen after " + TIMEOUT_MS + " ms");
3351 }
3352 }
3353
3354 public void expectStarted() {
3355 expectCallback(new CallbackValue(CallbackType.ON_STARTED));
3356 }
3357
3358 public void expectStopped() {
3359 expectCallback(new CallbackValue(CallbackType.ON_STOPPED));
3360 }
3361
3362 public void expectError(int error) {
3363 expectCallback(new CallbackValue(CallbackType.ON_ERROR, error));
3364 }
3365 }
3366
3367 private Network connectKeepaliveNetwork(LinkProperties lp) {
3368 // Ensure the network is disconnected before we do anything.
3369 if (mWiFiNetworkAgent != null) {
3370 assertNull(mCm.getNetworkCapabilities(mWiFiNetworkAgent.getNetwork()));
3371 }
3372
3373 mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
3374 ConditionVariable cv = waitForConnectivityBroadcasts(1);
3375 mWiFiNetworkAgent.connect(true);
3376 waitFor(cv);
3377 verifyActiveNetwork(TRANSPORT_WIFI);
3378 mWiFiNetworkAgent.sendLinkProperties(lp);
Hugo Benichibb91c572017-05-22 10:44:02 +09003379 waitForIdle();
Lorenzo Colitti7914ce52015-09-08 13:21:48 +09003380 return mWiFiNetworkAgent.getNetwork();
3381 }
3382
Hugo Benichi4a0c5d72017-10-11 11:26:25 +09003383 @Test
Lorenzo Colitti7914ce52015-09-08 13:21:48 +09003384 public void testPacketKeepalives() throws Exception {
3385 InetAddress myIPv4 = InetAddress.getByName("192.0.2.129");
3386 InetAddress notMyIPv4 = InetAddress.getByName("192.0.2.35");
3387 InetAddress myIPv6 = InetAddress.getByName("2001:db8::1");
3388 InetAddress dstIPv4 = InetAddress.getByName("8.8.8.8");
3389 InetAddress dstIPv6 = InetAddress.getByName("2001:4860:4860::8888");
3390
Nathan Harold63dd8132018-02-14 13:09:45 -08003391 final int validKaInterval = 15;
3392 final int invalidKaInterval = 9;
3393
Lorenzo Colitti7914ce52015-09-08 13:21:48 +09003394 LinkProperties lp = new LinkProperties();
3395 lp.setInterfaceName("wlan12");
3396 lp.addLinkAddress(new LinkAddress(myIPv6, 64));
3397 lp.addLinkAddress(new LinkAddress(myIPv4, 25));
3398 lp.addRoute(new RouteInfo(InetAddress.getByName("fe80::1234")));
3399 lp.addRoute(new RouteInfo(InetAddress.getByName("192.0.2.254")));
3400
3401 Network notMyNet = new Network(61234);
3402 Network myNet = connectKeepaliveNetwork(lp);
3403
3404 TestKeepaliveCallback callback = new TestKeepaliveCallback();
3405 PacketKeepalive ka;
3406
3407 // Attempt to start keepalives with invalid parameters and check for errors.
Nathan Harold63dd8132018-02-14 13:09:45 -08003408 ka = mCm.startNattKeepalive(notMyNet, validKaInterval, callback, myIPv4, 1234, dstIPv4);
Lorenzo Colitti7914ce52015-09-08 13:21:48 +09003409 callback.expectError(PacketKeepalive.ERROR_INVALID_NETWORK);
3410
Nathan Harold63dd8132018-02-14 13:09:45 -08003411 ka = mCm.startNattKeepalive(myNet, invalidKaInterval, callback, myIPv4, 1234, dstIPv4);
Lorenzo Colitti7914ce52015-09-08 13:21:48 +09003412 callback.expectError(PacketKeepalive.ERROR_INVALID_INTERVAL);
3413
Nathan Harold63dd8132018-02-14 13:09:45 -08003414 ka = mCm.startNattKeepalive(myNet, validKaInterval, callback, myIPv4, 1234, dstIPv6);
Lorenzo Colitti7914ce52015-09-08 13:21:48 +09003415 callback.expectError(PacketKeepalive.ERROR_INVALID_IP_ADDRESS);
3416
Nathan Harold63dd8132018-02-14 13:09:45 -08003417 ka = mCm.startNattKeepalive(myNet, validKaInterval, callback, myIPv6, 1234, dstIPv4);
Lorenzo Colitti7914ce52015-09-08 13:21:48 +09003418 callback.expectError(PacketKeepalive.ERROR_INVALID_IP_ADDRESS);
3419
Nathan Harold63dd8132018-02-14 13:09:45 -08003420 // NAT-T is only supported for IPv4.
3421 ka = mCm.startNattKeepalive(myNet, validKaInterval, callback, myIPv6, 1234, dstIPv6);
3422 callback.expectError(PacketKeepalive.ERROR_INVALID_IP_ADDRESS);
Lorenzo Colitti7914ce52015-09-08 13:21:48 +09003423
Nathan Harold63dd8132018-02-14 13:09:45 -08003424 ka = mCm.startNattKeepalive(myNet, validKaInterval, callback, myIPv4, 123456, dstIPv4);
Lorenzo Colitti7914ce52015-09-08 13:21:48 +09003425 callback.expectError(PacketKeepalive.ERROR_INVALID_PORT);
3426
Nathan Harold63dd8132018-02-14 13:09:45 -08003427 ka = mCm.startNattKeepalive(myNet, validKaInterval, callback, myIPv4, 123456, dstIPv4);
Lorenzo Colitti7914ce52015-09-08 13:21:48 +09003428 callback.expectError(PacketKeepalive.ERROR_INVALID_PORT);
3429
Nathan Harold63dd8132018-02-14 13:09:45 -08003430 ka = mCm.startNattKeepalive(myNet, validKaInterval, callback, myIPv4, 12345, dstIPv4);
Lorenzo Colitti7914ce52015-09-08 13:21:48 +09003431 callback.expectError(PacketKeepalive.ERROR_HARDWARE_UNSUPPORTED);
3432
Nathan Harold63dd8132018-02-14 13:09:45 -08003433 ka = mCm.startNattKeepalive(myNet, validKaInterval, callback, myIPv4, 12345, dstIPv4);
Lorenzo Colitti7914ce52015-09-08 13:21:48 +09003434 callback.expectError(PacketKeepalive.ERROR_HARDWARE_UNSUPPORTED);
3435
3436 // Check that a started keepalive can be stopped.
3437 mWiFiNetworkAgent.setStartKeepaliveError(PacketKeepalive.SUCCESS);
Nathan Harold63dd8132018-02-14 13:09:45 -08003438 ka = mCm.startNattKeepalive(myNet, validKaInterval, callback, myIPv4, 12345, dstIPv4);
Lorenzo Colitti7914ce52015-09-08 13:21:48 +09003439 callback.expectStarted();
3440 mWiFiNetworkAgent.setStopKeepaliveError(PacketKeepalive.SUCCESS);
3441 ka.stop();
3442 callback.expectStopped();
3443
3444 // Check that deleting the IP address stops the keepalive.
3445 LinkProperties bogusLp = new LinkProperties(lp);
Nathan Harold63dd8132018-02-14 13:09:45 -08003446 ka = mCm.startNattKeepalive(myNet, validKaInterval, callback, myIPv4, 12345, dstIPv4);
Lorenzo Colitti7914ce52015-09-08 13:21:48 +09003447 callback.expectStarted();
3448 bogusLp.removeLinkAddress(new LinkAddress(myIPv4, 25));
3449 bogusLp.addLinkAddress(new LinkAddress(notMyIPv4, 25));
3450 mWiFiNetworkAgent.sendLinkProperties(bogusLp);
3451 callback.expectError(PacketKeepalive.ERROR_INVALID_IP_ADDRESS);
3452 mWiFiNetworkAgent.sendLinkProperties(lp);
3453
3454 // Check that a started keepalive is stopped correctly when the network disconnects.
Nathan Harold63dd8132018-02-14 13:09:45 -08003455 ka = mCm.startNattKeepalive(myNet, validKaInterval, callback, myIPv4, 12345, dstIPv4);
Lorenzo Colitti7914ce52015-09-08 13:21:48 +09003456 callback.expectStarted();
3457 mWiFiNetworkAgent.disconnect();
Lorenzo Colitti30145d72017-01-27 18:46:03 +09003458 waitFor(mWiFiNetworkAgent.getDisconnectedCV());
Lorenzo Colitti7914ce52015-09-08 13:21:48 +09003459 callback.expectError(PacketKeepalive.ERROR_INVALID_NETWORK);
3460
3461 // ... and that stopping it after that has no adverse effects.
Hugo Benichibb91c572017-05-22 10:44:02 +09003462 waitForIdle();
Hugo Benichidfb559a2016-12-20 14:57:49 +09003463 final Network myNetAlias = myNet;
Lorenzo Colitti30145d72017-01-27 18:46:03 +09003464 assertNull(mCm.getNetworkCapabilities(myNetAlias));
Lorenzo Colitti7914ce52015-09-08 13:21:48 +09003465 ka.stop();
3466
3467 // Reconnect.
3468 myNet = connectKeepaliveNetwork(lp);
3469 mWiFiNetworkAgent.setStartKeepaliveError(PacketKeepalive.SUCCESS);
3470
3471 // Check things work as expected when the keepalive is stopped and the network disconnects.
Nathan Harold63dd8132018-02-14 13:09:45 -08003472 ka = mCm.startNattKeepalive(myNet, validKaInterval, callback, myIPv4, 12345, dstIPv4);
Lorenzo Colitti7914ce52015-09-08 13:21:48 +09003473 callback.expectStarted();
3474 ka.stop();
3475 mWiFiNetworkAgent.disconnect();
Lorenzo Colitti30145d72017-01-27 18:46:03 +09003476 waitFor(mWiFiNetworkAgent.getDisconnectedCV());
Hugo Benichibb91c572017-05-22 10:44:02 +09003477 waitForIdle();
Lorenzo Colitti7914ce52015-09-08 13:21:48 +09003478 callback.expectStopped();
3479
3480 // Reconnect.
3481 myNet = connectKeepaliveNetwork(lp);
3482 mWiFiNetworkAgent.setStartKeepaliveError(PacketKeepalive.SUCCESS);
3483
3484 // Check that keepalive slots start from 1 and increment. The first one gets slot 1.
3485 mWiFiNetworkAgent.setExpectedKeepaliveSlot(1);
Nathan Harold63dd8132018-02-14 13:09:45 -08003486 ka = mCm.startNattKeepalive(myNet, validKaInterval, callback, myIPv4, 12345, dstIPv4);
Lorenzo Colitti7914ce52015-09-08 13:21:48 +09003487 callback.expectStarted();
3488
3489 // The second one gets slot 2.
3490 mWiFiNetworkAgent.setExpectedKeepaliveSlot(2);
3491 TestKeepaliveCallback callback2 = new TestKeepaliveCallback();
Nathan Harold63dd8132018-02-14 13:09:45 -08003492 PacketKeepalive ka2 = mCm.startNattKeepalive(
3493 myNet, validKaInterval, callback2, myIPv4, 6789, dstIPv4);
Lorenzo Colitti7914ce52015-09-08 13:21:48 +09003494 callback2.expectStarted();
3495
3496 // Now stop the first one and create a third. This also gets slot 1.
3497 ka.stop();
3498 callback.expectStopped();
3499
3500 mWiFiNetworkAgent.setExpectedKeepaliveSlot(1);
3501 TestKeepaliveCallback callback3 = new TestKeepaliveCallback();
Nathan Harold63dd8132018-02-14 13:09:45 -08003502 PacketKeepalive ka3 = mCm.startNattKeepalive(
3503 myNet, validKaInterval, callback3, myIPv4, 9876, dstIPv4);
Lorenzo Colitti7914ce52015-09-08 13:21:48 +09003504 callback3.expectStarted();
3505
3506 ka2.stop();
3507 callback2.expectStopped();
3508
3509 ka3.stop();
3510 callback3.expectStopped();
3511 }
Udam Sainib7c24872016-01-04 12:16:14 -08003512
Hugo Benichi4a0c5d72017-10-11 11:26:25 +09003513 @Test
Udam Sainib7c24872016-01-04 12:16:14 -08003514 public void testGetCaptivePortalServerUrl() throws Exception {
3515 String url = mCm.getCaptivePortalServerUrl();
3516 assertEquals("http://connectivitycheck.gstatic.com/generate_204", url);
3517 }
Lorenzo Colitti531a3442016-03-01 12:55:58 +09003518
3519 private static class TestNetworkPinner extends NetworkPinner {
3520 public static boolean awaitPin(int timeoutMs) {
3521 synchronized(sLock) {
3522 if (sNetwork == null) {
3523 try {
3524 sLock.wait(timeoutMs);
3525 } catch (InterruptedException e) {}
3526 }
3527 return sNetwork != null;
3528 }
3529 }
3530
3531 public static boolean awaitUnpin(int timeoutMs) {
3532 synchronized(sLock) {
3533 if (sNetwork != null) {
3534 try {
3535 sLock.wait(timeoutMs);
3536 } catch (InterruptedException e) {}
3537 }
3538 return sNetwork == null;
3539 }
3540 }
3541 }
3542
3543 private void assertPinnedToWifiWithCellDefault() {
3544 assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getBoundNetworkForProcess());
3545 assertEquals(mCellNetworkAgent.getNetwork(), mCm.getActiveNetwork());
3546 }
3547
3548 private void assertPinnedToWifiWithWifiDefault() {
3549 assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getBoundNetworkForProcess());
3550 assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetwork());
3551 }
3552
3553 private void assertNotPinnedToWifi() {
3554 assertNull(mCm.getBoundNetworkForProcess());
3555 assertEquals(mCellNetworkAgent.getNetwork(), mCm.getActiveNetwork());
3556 }
3557
Hugo Benichi4a0c5d72017-10-11 11:26:25 +09003558 @Test
Lorenzo Colitti531a3442016-03-01 12:55:58 +09003559 public void testNetworkPinner() {
3560 NetworkRequest wifiRequest = new NetworkRequest.Builder()
3561 .addTransportType(TRANSPORT_WIFI)
3562 .build();
3563 assertNull(mCm.getBoundNetworkForProcess());
3564
3565 TestNetworkPinner.pin(mServiceContext, wifiRequest);
3566 assertNull(mCm.getBoundNetworkForProcess());
3567
3568 mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
3569 mCellNetworkAgent.connect(true);
3570 mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
3571 mWiFiNetworkAgent.connect(false);
3572
3573 // When wi-fi connects, expect to be pinned.
3574 assertTrue(TestNetworkPinner.awaitPin(100));
3575 assertPinnedToWifiWithCellDefault();
3576
3577 // Disconnect and expect the pin to drop.
3578 mWiFiNetworkAgent.disconnect();
3579 assertTrue(TestNetworkPinner.awaitUnpin(100));
3580 assertNotPinnedToWifi();
3581
3582 // Reconnecting does not cause the pin to come back.
3583 mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
3584 mWiFiNetworkAgent.connect(false);
3585 assertFalse(TestNetworkPinner.awaitPin(100));
3586 assertNotPinnedToWifi();
3587
3588 // Pinning while connected causes the pin to take effect immediately.
3589 TestNetworkPinner.pin(mServiceContext, wifiRequest);
3590 assertTrue(TestNetworkPinner.awaitPin(100));
3591 assertPinnedToWifiWithCellDefault();
3592
3593 // Explicitly unpin and expect to use the default network again.
3594 TestNetworkPinner.unpin();
3595 assertNotPinnedToWifi();
3596
3597 // Disconnect cell and wifi.
3598 ConditionVariable cv = waitForConnectivityBroadcasts(3); // cell down, wifi up, wifi down.
3599 mCellNetworkAgent.disconnect();
3600 mWiFiNetworkAgent.disconnect();
3601 waitFor(cv);
3602
3603 // Pinning takes effect even if the pinned network is the default when the pin is set...
3604 TestNetworkPinner.pin(mServiceContext, wifiRequest);
3605 mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
3606 mWiFiNetworkAgent.connect(false);
3607 assertTrue(TestNetworkPinner.awaitPin(100));
3608 assertPinnedToWifiWithWifiDefault();
3609
3610 // ... and is maintained even when that network is no longer the default.
3611 cv = waitForConnectivityBroadcasts(1);
3612 mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
3613 mCellNetworkAgent.connect(true);
3614 waitFor(cv);
3615 assertPinnedToWifiWithCellDefault();
3616 }
Paul Jensen4e1d3fd2016-04-08 13:56:52 -04003617
Hugo Benichi4a0c5d72017-10-11 11:26:25 +09003618 @Test
Hugo Benichi893a7622017-09-29 09:34:08 +09003619 public void testNetworkCallbackMaximum() {
Jeff Sharkeye0c29952018-02-20 17:24:55 -07003620 // We can only have 99 callbacks, because MultipathPolicyTracker is
3621 // already one of them.
3622 final int MAX_REQUESTS = 99;
3623 final int CALLBACKS = 89;
Hugo Benichi893a7622017-09-29 09:34:08 +09003624 final int INTENTS = 10;
3625 assertEquals(MAX_REQUESTS, CALLBACKS + INTENTS);
3626
Paul Jensen4e1d3fd2016-04-08 13:56:52 -04003627 NetworkRequest networkRequest = new NetworkRequest.Builder().build();
Hugo Benichi893a7622017-09-29 09:34:08 +09003628 ArrayList<Object> registered = new ArrayList<>();
Paul Jensen4e1d3fd2016-04-08 13:56:52 -04003629
Hugo Benichi893a7622017-09-29 09:34:08 +09003630 int j = 0;
3631 while (j++ < CALLBACKS / 2) {
3632 NetworkCallback cb = new NetworkCallback();
3633 mCm.requestNetwork(networkRequest, cb);
3634 registered.add(cb);
Paul Jensen4e1d3fd2016-04-08 13:56:52 -04003635 }
Hugo Benichi893a7622017-09-29 09:34:08 +09003636 while (j++ < CALLBACKS) {
3637 NetworkCallback cb = new NetworkCallback();
3638 mCm.registerNetworkCallback(networkRequest, cb);
3639 registered.add(cb);
3640 }
3641 j = 0;
3642 while (j++ < INTENTS / 2) {
3643 PendingIntent pi = PendingIntent.getBroadcast(mContext, 0, new Intent("a" + j), 0);
3644 mCm.requestNetwork(networkRequest, pi);
3645 registered.add(pi);
3646 }
3647 while (j++ < INTENTS) {
3648 PendingIntent pi = PendingIntent.getBroadcast(mContext, 0, new Intent("b" + j), 0);
3649 mCm.registerNetworkCallback(networkRequest, pi);
3650 registered.add(pi);
3651 }
Paul Jensen4e1d3fd2016-04-08 13:56:52 -04003652
Hugo Benichi893a7622017-09-29 09:34:08 +09003653 // Test that the limit is enforced when MAX_REQUESTS simultaneous requests are added.
Paul Jensen4e1d3fd2016-04-08 13:56:52 -04003654 try {
Hugo Benichi893a7622017-09-29 09:34:08 +09003655 mCm.requestNetwork(networkRequest, new NetworkCallback());
3656 fail("Registering " + MAX_REQUESTS + " network requests did not throw exception");
Hugo Benichicb883232017-05-11 13:16:17 +09003657 } catch (TooManyRequestsException expected) {}
Hugo Benichi893a7622017-09-29 09:34:08 +09003658 try {
3659 mCm.registerNetworkCallback(networkRequest, new NetworkCallback());
3660 fail("Registering " + MAX_REQUESTS + " network callbacks did not throw exception");
3661 } catch (TooManyRequestsException expected) {}
3662 try {
3663 mCm.requestNetwork(networkRequest,
3664 PendingIntent.getBroadcast(mContext, 0, new Intent("c"), 0));
3665 fail("Registering " + MAX_REQUESTS + " PendingIntent requests did not throw exception");
3666 } catch (TooManyRequestsException expected) {}
3667 try {
3668 mCm.registerNetworkCallback(networkRequest,
3669 PendingIntent.getBroadcast(mContext, 0, new Intent("d"), 0));
3670 fail("Registering " + MAX_REQUESTS
3671 + " PendingIntent callbacks did not throw exception");
3672 } catch (TooManyRequestsException expected) {}
Paul Jensen4e1d3fd2016-04-08 13:56:52 -04003673
Hugo Benichi893a7622017-09-29 09:34:08 +09003674 for (Object o : registered) {
3675 if (o instanceof NetworkCallback) {
3676 mCm.unregisterNetworkCallback((NetworkCallback)o);
Paul Jensen4e1d3fd2016-04-08 13:56:52 -04003677 }
Hugo Benichi893a7622017-09-29 09:34:08 +09003678 if (o instanceof PendingIntent) {
3679 mCm.unregisterNetworkCallback((PendingIntent)o);
3680 }
Paul Jensen4e1d3fd2016-04-08 13:56:52 -04003681 }
Hugo Benichi893a7622017-09-29 09:34:08 +09003682 waitForIdle();
Paul Jensen4e1d3fd2016-04-08 13:56:52 -04003683
3684 // Test that the limit is not hit when MAX_REQUESTS requests are added and removed.
3685 for (int i = 0; i < MAX_REQUESTS; i++) {
3686 NetworkCallback networkCallback = new NetworkCallback();
3687 mCm.requestNetwork(networkRequest, networkCallback);
3688 mCm.unregisterNetworkCallback(networkCallback);
3689 }
Hugo Benichi1e5039e2017-10-12 23:09:25 +09003690 waitForIdle();
Hugo Benichi893a7622017-09-29 09:34:08 +09003691
Paul Jensen4e1d3fd2016-04-08 13:56:52 -04003692 for (int i = 0; i < MAX_REQUESTS; i++) {
3693 NetworkCallback networkCallback = new NetworkCallback();
3694 mCm.registerNetworkCallback(networkRequest, networkCallback);
3695 mCm.unregisterNetworkCallback(networkCallback);
3696 }
Hugo Benichi1e5039e2017-10-12 23:09:25 +09003697 waitForIdle();
Hugo Benichi893a7622017-09-29 09:34:08 +09003698
Paul Jensen4e1d3fd2016-04-08 13:56:52 -04003699 for (int i = 0; i < MAX_REQUESTS; i++) {
3700 PendingIntent pendingIntent =
Hugo Benichi893a7622017-09-29 09:34:08 +09003701 PendingIntent.getBroadcast(mContext, 0, new Intent("e" + i), 0);
Paul Jensen4e1d3fd2016-04-08 13:56:52 -04003702 mCm.requestNetwork(networkRequest, pendingIntent);
3703 mCm.unregisterNetworkCallback(pendingIntent);
3704 }
Hugo Benichi1e5039e2017-10-12 23:09:25 +09003705 waitForIdle();
Hugo Benichi893a7622017-09-29 09:34:08 +09003706
Paul Jensen4e1d3fd2016-04-08 13:56:52 -04003707 for (int i = 0; i < MAX_REQUESTS; i++) {
3708 PendingIntent pendingIntent =
Hugo Benichi893a7622017-09-29 09:34:08 +09003709 PendingIntent.getBroadcast(mContext, 0, new Intent("f" + i), 0);
Paul Jensen4e1d3fd2016-04-08 13:56:52 -04003710 mCm.registerNetworkCallback(networkRequest, pendingIntent);
3711 mCm.unregisterNetworkCallback(pendingIntent);
3712 }
3713 }
Hugo Benichifed512a2017-06-26 10:06:49 +09003714
Hugo Benichi4a0c5d72017-10-11 11:26:25 +09003715 @Test
Hugo Benichi16f0a942017-06-20 14:07:59 +09003716 public void testNetworkInfoOfTypeNone() {
3717 ConditionVariable broadcastCV = waitForConnectivityBroadcasts(1);
3718
3719 verifyNoNetwork();
Hugo Benichic1014502017-07-19 10:10:52 +09003720 MockNetworkAgent wifiAware = new MockNetworkAgent(TRANSPORT_WIFI_AWARE);
Hugo Benichi16f0a942017-06-20 14:07:59 +09003721 assertNull(mCm.getActiveNetworkInfo());
3722
3723 Network[] allNetworks = mCm.getAllNetworks();
3724 assertLength(1, allNetworks);
3725 Network network = allNetworks[0];
3726 NetworkCapabilities capabilities = mCm.getNetworkCapabilities(network);
3727 assertTrue(capabilities.hasTransport(TRANSPORT_WIFI_AWARE));
3728
3729 final NetworkRequest request =
3730 new NetworkRequest.Builder().addTransportType(TRANSPORT_WIFI_AWARE).build();
3731 final TestNetworkCallback callback = new TestNetworkCallback();
3732 mCm.registerNetworkCallback(request, callback);
3733
Hugo Benichic1014502017-07-19 10:10:52 +09003734 // Bring up wifi aware network.
3735 wifiAware.connect(false, false);
Lorenzo Colitti27334542018-01-12 16:22:21 +09003736 callback.expectAvailableCallbacksUnvalidated(wifiAware);
Hugo Benichi16f0a942017-06-20 14:07:59 +09003737
3738 assertNull(mCm.getActiveNetworkInfo());
3739 assertNull(mCm.getActiveNetwork());
Hugo Benichic1014502017-07-19 10:10:52 +09003740 // TODO: getAllNetworkInfo is dirty and returns a non-empty array right from the start
Hugo Benichi16f0a942017-06-20 14:07:59 +09003741 // of this test. Fix it and uncomment the assert below.
3742 //assertEmpty(mCm.getAllNetworkInfo());
3743
Hugo Benichic1014502017-07-19 10:10:52 +09003744 // Disconnect wifi aware network.
3745 wifiAware.disconnect();
3746 callback.expectCallbackLike((info) -> info.state == CallbackState.LOST, TIMEOUT_MS);
Hugo Benichi16f0a942017-06-20 14:07:59 +09003747 mCm.unregisterNetworkCallback(callback);
3748
3749 verifyNoNetwork();
3750 if (broadcastCV.block(10)) {
3751 fail("expected no broadcast, but got CONNECTIVITY_ACTION broadcast");
3752 }
3753 }
3754
Hugo Benichi4a0c5d72017-10-11 11:26:25 +09003755 @Test
Hugo Benichi16f0a942017-06-20 14:07:59 +09003756 public void testDeprecatedAndUnsupportedOperations() throws Exception {
3757 final int TYPE_NONE = ConnectivityManager.TYPE_NONE;
3758 assertNull(mCm.getNetworkInfo(TYPE_NONE));
3759 assertNull(mCm.getNetworkForType(TYPE_NONE));
3760 assertNull(mCm.getLinkProperties(TYPE_NONE));
3761 assertFalse(mCm.isNetworkSupported(TYPE_NONE));
3762
3763 assertException(() -> { mCm.networkCapabilitiesForType(TYPE_NONE); },
3764 IllegalArgumentException.class);
3765
3766 Class<UnsupportedOperationException> unsupported = UnsupportedOperationException.class;
3767 assertException(() -> { mCm.startUsingNetworkFeature(TYPE_WIFI, ""); }, unsupported);
3768 assertException(() -> { mCm.stopUsingNetworkFeature(TYPE_WIFI, ""); }, unsupported);
3769 // TODO: let test context have configuration application target sdk version
3770 // and test that pre-M requesting for TYPE_NONE sends back APN_REQUEST_FAILED
3771 assertException(() -> { mCm.startUsingNetworkFeature(TYPE_NONE, ""); }, unsupported);
3772 assertException(() -> { mCm.stopUsingNetworkFeature(TYPE_NONE, ""); }, unsupported);
3773 assertException(() -> { mCm.requestRouteToHostAddress(TYPE_NONE, null); }, unsupported);
3774 }
3775
Hugo Benichi4a0c5d72017-10-11 11:26:25 +09003776 @Test
Rubin Xu1bb5c082017-09-05 18:40:49 +01003777 public void testLinkPropertiesEnsuresDirectlyConnectedRoutes() {
3778 final NetworkRequest networkRequest = new NetworkRequest.Builder()
3779 .addTransportType(TRANSPORT_WIFI).build();
3780 final TestNetworkCallback networkCallback = new TestNetworkCallback();
3781 mCm.registerNetworkCallback(networkRequest, networkCallback);
3782
3783 LinkProperties lp = new LinkProperties();
Erik Kline79c6d052018-03-21 07:18:33 -07003784 lp.setInterfaceName(WIFI_IFNAME);
Rubin Xu1bb5c082017-09-05 18:40:49 +01003785 LinkAddress myIpv4Address = new LinkAddress("192.168.12.3/24");
3786 RouteInfo myIpv4DefaultRoute = new RouteInfo((IpPrefix) null,
3787 NetworkUtils.numericToInetAddress("192.168.12.1"), lp.getInterfaceName());
3788 lp.addLinkAddress(myIpv4Address);
3789 lp.addRoute(myIpv4DefaultRoute);
3790
3791 // Verify direct routes are added when network agent is first registered in
3792 // ConnectivityService.
3793 MockNetworkAgent networkAgent = new MockNetworkAgent(TRANSPORT_WIFI, lp);
3794 networkAgent.connect(true);
3795 networkCallback.expectCallback(CallbackState.AVAILABLE, networkAgent);
3796 networkCallback.expectCallback(CallbackState.NETWORK_CAPABILITIES, networkAgent);
3797 CallbackInfo cbi = networkCallback.expectCallback(CallbackState.LINK_PROPERTIES,
3798 networkAgent);
3799 networkCallback.expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, networkAgent);
3800 networkCallback.assertNoCallback();
3801 checkDirectlyConnectedRoutes(cbi.arg, Arrays.asList(myIpv4Address),
3802 Arrays.asList(myIpv4DefaultRoute));
3803 checkDirectlyConnectedRoutes(mCm.getLinkProperties(networkAgent.getNetwork()),
3804 Arrays.asList(myIpv4Address), Arrays.asList(myIpv4DefaultRoute));
3805
3806 // Verify direct routes are added during subsequent link properties updates.
3807 LinkProperties newLp = new LinkProperties(lp);
3808 LinkAddress myIpv6Address1 = new LinkAddress("fe80::cafe/64");
3809 LinkAddress myIpv6Address2 = new LinkAddress("2001:db8::2/64");
3810 newLp.addLinkAddress(myIpv6Address1);
3811 newLp.addLinkAddress(myIpv6Address2);
3812 networkAgent.sendLinkProperties(newLp);
3813 cbi = networkCallback.expectCallback(CallbackState.LINK_PROPERTIES, networkAgent);
3814 networkCallback.assertNoCallback();
3815 checkDirectlyConnectedRoutes(cbi.arg,
3816 Arrays.asList(myIpv4Address, myIpv6Address1, myIpv6Address2),
3817 Arrays.asList(myIpv4DefaultRoute));
3818 mCm.unregisterNetworkCallback(networkCallback);
3819 }
3820
Jeff Sharkey72f9c422017-10-27 17:22:59 -06003821 @Test
3822 public void testStatsIfacesChanged() throws Exception {
3823 mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
Lorenzo Colittic78da292018-01-19 00:50:48 +09003824 mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
3825
3826 Network[] onlyCell = new Network[]{mCellNetworkAgent.getNetwork()};
3827 Network[] onlyWifi = new Network[]{mWiFiNetworkAgent.getNetwork()};
Jeff Sharkey72f9c422017-10-27 17:22:59 -06003828
3829 // Simple connection should have updated ifaces
3830 mCellNetworkAgent.connect(false);
3831 waitForIdle();
Lorenzo Colittic78da292018-01-19 00:50:48 +09003832 verify(mStatsService, atLeastOnce()).forceUpdateIfaces(onlyCell);
3833 reset(mStatsService);
3834
3835 // Default network switch should update ifaces.
3836 mWiFiNetworkAgent.connect(false);
3837 waitForIdle();
3838 verify(mStatsService, atLeastOnce()).forceUpdateIfaces(onlyWifi);
3839 reset(mStatsService);
3840
3841 // Disconnect should update ifaces.
3842 mWiFiNetworkAgent.disconnect();
3843 waitForIdle();
3844 verify(mStatsService, atLeastOnce()).forceUpdateIfaces(onlyCell);
Jeff Sharkey72f9c422017-10-27 17:22:59 -06003845 reset(mStatsService);
3846
3847 // Metered change should update ifaces
3848 mCellNetworkAgent.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED);
3849 waitForIdle();
Lorenzo Colittic78da292018-01-19 00:50:48 +09003850 verify(mStatsService, atLeastOnce()).forceUpdateIfaces(onlyCell);
Jeff Sharkey72f9c422017-10-27 17:22:59 -06003851 reset(mStatsService);
3852
3853 mCellNetworkAgent.removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED);
3854 waitForIdle();
Lorenzo Colittic78da292018-01-19 00:50:48 +09003855 verify(mStatsService, atLeastOnce()).forceUpdateIfaces(onlyCell);
Jeff Sharkey72f9c422017-10-27 17:22:59 -06003856 reset(mStatsService);
3857
3858 // Captive portal change shouldn't update ifaces
3859 mCellNetworkAgent.addCapability(NetworkCapabilities.NET_CAPABILITY_CAPTIVE_PORTAL);
3860 waitForIdle();
Lorenzo Colittic78da292018-01-19 00:50:48 +09003861 verify(mStatsService, never()).forceUpdateIfaces(onlyCell);
Jeff Sharkey72f9c422017-10-27 17:22:59 -06003862 reset(mStatsService);
3863
3864 // Roaming change should update ifaces
3865 mCellNetworkAgent.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING);
3866 waitForIdle();
Lorenzo Colittic78da292018-01-19 00:50:48 +09003867 verify(mStatsService, atLeastOnce()).forceUpdateIfaces(onlyCell);
Jeff Sharkey72f9c422017-10-27 17:22:59 -06003868 reset(mStatsService);
3869 }
3870
Erik Klinee89953b2018-01-11 16:11:10 +09003871 @Test
3872 public void testBasicDnsConfigurationPushed() throws Exception {
Erik Kline79c6d052018-03-21 07:18:33 -07003873 setPrivateDnsSettings(PRIVATE_DNS_MODE_OPPORTUNISTIC, "ignored.example.com");
3874 ArgumentCaptor<String[]> tlsServers = ArgumentCaptor.forClass(String[].class);
3875
3876 // Clear any interactions that occur as a result of CS starting up.
3877 reset(mNetworkManagementService);
3878
3879 final String[] EMPTY_STRING_ARRAY = new String[0];
Erik Klinee89953b2018-01-11 16:11:10 +09003880 mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
3881 waitForIdle();
3882 verify(mNetworkManagementService, never()).setDnsConfigurationForNetwork(
Erik Kline79c6d052018-03-21 07:18:33 -07003883 anyInt(), eq(EMPTY_STRING_ARRAY), any(), any(), eq(""), eq(EMPTY_STRING_ARRAY));
3884 verifyNoMoreInteractions(mNetworkManagementService);
Erik Klinee89953b2018-01-11 16:11:10 +09003885
3886 final LinkProperties cellLp = new LinkProperties();
Erik Kline79c6d052018-03-21 07:18:33 -07003887 cellLp.setInterfaceName(MOBILE_IFNAME);
Erik Kline117e7f32018-03-04 21:01:01 +09003888 // Add IPv4 and IPv6 default routes, because DNS-over-TLS code does
3889 // "is-reachable" testing in order to not program netd with unreachable
3890 // nameservers that it might try repeated to validate.
3891 cellLp.addLinkAddress(new LinkAddress("192.0.2.4/24"));
Erik Kline79c6d052018-03-21 07:18:33 -07003892 cellLp.addRoute(new RouteInfo((IpPrefix) null, InetAddress.getByName("192.0.2.4"),
3893 MOBILE_IFNAME));
Erik Kline117e7f32018-03-04 21:01:01 +09003894 cellLp.addLinkAddress(new LinkAddress("2001:db8:1::1/64"));
Erik Kline79c6d052018-03-21 07:18:33 -07003895 cellLp.addRoute(new RouteInfo((IpPrefix) null, InetAddress.getByName("2001:db8:1::1"),
3896 MOBILE_IFNAME));
Erik Klinee89953b2018-01-11 16:11:10 +09003897 mCellNetworkAgent.sendLinkProperties(cellLp);
3898 mCellNetworkAgent.connect(false);
3899 waitForIdle();
Erik Klinee89953b2018-01-11 16:11:10 +09003900 // CS tells netd about the empty DNS config for this network.
Erik Kline79c6d052018-03-21 07:18:33 -07003901 verify(mNetworkManagementService, atLeastOnce()).setDnsConfigurationForNetwork(
3902 anyInt(), eq(EMPTY_STRING_ARRAY), any(), any(), eq(""), eq(EMPTY_STRING_ARRAY));
Erik Klinee89953b2018-01-11 16:11:10 +09003903 reset(mNetworkManagementService);
3904
3905 cellLp.addDnsServer(InetAddress.getByName("2001:db8::1"));
3906 mCellNetworkAgent.sendLinkProperties(cellLp);
3907 waitForIdle();
Erik Kline79c6d052018-03-21 07:18:33 -07003908 verify(mNetworkManagementService, atLeastOnce()).setDnsConfigurationForNetwork(
Erik Kline117e7f32018-03-04 21:01:01 +09003909 anyInt(), mStringArrayCaptor.capture(), any(), any(),
Erik Kline79c6d052018-03-21 07:18:33 -07003910 eq(""), tlsServers.capture());
Erik Klinee89953b2018-01-11 16:11:10 +09003911 assertEquals(1, mStringArrayCaptor.getValue().length);
3912 assertTrue(ArrayUtils.contains(mStringArrayCaptor.getValue(), "2001:db8::1"));
Erik Kline79c6d052018-03-21 07:18:33 -07003913 // Opportunistic mode.
3914 assertTrue(ArrayUtils.contains(tlsServers.getValue(), "2001:db8::1"));
Erik Klinee89953b2018-01-11 16:11:10 +09003915 reset(mNetworkManagementService);
3916
3917 cellLp.addDnsServer(InetAddress.getByName("192.0.2.1"));
3918 mCellNetworkAgent.sendLinkProperties(cellLp);
3919 waitForIdle();
Erik Kline79c6d052018-03-21 07:18:33 -07003920 verify(mNetworkManagementService, atLeastOnce()).setDnsConfigurationForNetwork(
Erik Kline117e7f32018-03-04 21:01:01 +09003921 anyInt(), mStringArrayCaptor.capture(), any(), any(),
Erik Kline79c6d052018-03-21 07:18:33 -07003922 eq(""), tlsServers.capture());
Erik Kline117e7f32018-03-04 21:01:01 +09003923 assertEquals(2, mStringArrayCaptor.getValue().length);
3924 assertTrue(ArrayUtils.containsAll(mStringArrayCaptor.getValue(),
3925 new String[]{"2001:db8::1", "192.0.2.1"}));
Erik Kline79c6d052018-03-21 07:18:33 -07003926 // Opportunistic mode.
3927 assertEquals(2, tlsServers.getValue().length);
3928 assertTrue(ArrayUtils.containsAll(tlsServers.getValue(),
3929 new String[]{"2001:db8::1", "192.0.2.1"}));
Erik Kline117e7f32018-03-04 21:01:01 +09003930 reset(mNetworkManagementService);
3931
3932 final String TLS_SPECIFIER = "tls.example.com";
3933 final String TLS_SERVER6 = "2001:db8:53::53";
3934 final InetAddress[] TLS_IPS = new InetAddress[]{ InetAddress.getByName(TLS_SERVER6) };
3935 final String[] TLS_SERVERS = new String[]{ TLS_SERVER6 };
3936 final Handler h = mCellNetworkAgent.getWrappedNetworkMonitor().connectivityHandler;
3937 h.sendMessage(h.obtainMessage(
3938 NetworkMonitor.EVENT_PRIVATE_DNS_CONFIG_RESOLVED, 0,
3939 mCellNetworkAgent.getNetwork().netId,
3940 new DnsManager.PrivateDnsConfig(TLS_SPECIFIER, TLS_IPS)));
3941 waitForIdle();
Erik Kline79c6d052018-03-21 07:18:33 -07003942 verify(mNetworkManagementService, atLeastOnce()).setDnsConfigurationForNetwork(
Erik Kline117e7f32018-03-04 21:01:01 +09003943 anyInt(), mStringArrayCaptor.capture(), any(), any(),
3944 eq(TLS_SPECIFIER), eq(TLS_SERVERS));
Erik Klinee89953b2018-01-11 16:11:10 +09003945 assertEquals(2, mStringArrayCaptor.getValue().length);
3946 assertTrue(ArrayUtils.containsAll(mStringArrayCaptor.getValue(),
3947 new String[]{"2001:db8::1", "192.0.2.1"}));
3948 reset(mNetworkManagementService);
3949 }
3950
Erik Kline79c6d052018-03-21 07:18:33 -07003951 @Test
3952 public void testPrivateDnsSettingsChange() throws Exception {
3953 final String[] EMPTY_STRING_ARRAY = new String[0];
3954 ArgumentCaptor<String[]> tlsServers = ArgumentCaptor.forClass(String[].class);
3955
3956 // Clear any interactions that occur as a result of CS starting up.
3957 reset(mNetworkManagementService);
3958
3959 // The default on Android is opportunistic mode ("Automatic").
3960 setPrivateDnsSettings(PRIVATE_DNS_MODE_OPPORTUNISTIC, "ignored.example.com");
3961
dalyk1fcb7392018-03-05 12:42:22 -05003962 final TestNetworkCallback cellNetworkCallback = new TestNetworkCallback();
3963 final NetworkRequest cellRequest = new NetworkRequest.Builder()
3964 .addTransportType(TRANSPORT_CELLULAR).build();
3965 mCm.requestNetwork(cellRequest, cellNetworkCallback);
3966
Erik Kline79c6d052018-03-21 07:18:33 -07003967 mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
3968 waitForIdle();
3969 // CS tells netd about the empty DNS config for this network.
3970 verify(mNetworkManagementService, never()).setDnsConfigurationForNetwork(
3971 anyInt(), eq(EMPTY_STRING_ARRAY), any(), any(), eq(""), eq(EMPTY_STRING_ARRAY));
3972 verifyNoMoreInteractions(mNetworkManagementService);
3973
3974 final LinkProperties cellLp = new LinkProperties();
3975 cellLp.setInterfaceName(MOBILE_IFNAME);
3976 // Add IPv4 and IPv6 default routes, because DNS-over-TLS code does
3977 // "is-reachable" testing in order to not program netd with unreachable
3978 // nameservers that it might try repeated to validate.
3979 cellLp.addLinkAddress(new LinkAddress("192.0.2.4/24"));
3980 cellLp.addRoute(new RouteInfo((IpPrefix) null, InetAddress.getByName("192.0.2.4"),
3981 MOBILE_IFNAME));
3982 cellLp.addLinkAddress(new LinkAddress("2001:db8:1::1/64"));
3983 cellLp.addRoute(new RouteInfo((IpPrefix) null, InetAddress.getByName("2001:db8:1::1"),
3984 MOBILE_IFNAME));
3985 cellLp.addDnsServer(InetAddress.getByName("2001:db8::1"));
3986 cellLp.addDnsServer(InetAddress.getByName("192.0.2.1"));
3987
3988 mCellNetworkAgent.sendLinkProperties(cellLp);
3989 mCellNetworkAgent.connect(false);
3990 waitForIdle();
3991 verify(mNetworkManagementService, atLeastOnce()).setDnsConfigurationForNetwork(
3992 anyInt(), mStringArrayCaptor.capture(), any(), any(),
3993 eq(""), tlsServers.capture());
3994 assertEquals(2, mStringArrayCaptor.getValue().length);
3995 assertTrue(ArrayUtils.containsAll(mStringArrayCaptor.getValue(),
3996 new String[]{"2001:db8::1", "192.0.2.1"}));
3997 // Opportunistic mode.
3998 assertEquals(2, tlsServers.getValue().length);
3999 assertTrue(ArrayUtils.containsAll(tlsServers.getValue(),
4000 new String[]{"2001:db8::1", "192.0.2.1"}));
4001 reset(mNetworkManagementService);
dalyk1fcb7392018-03-05 12:42:22 -05004002 cellNetworkCallback.expectCallback(CallbackState.AVAILABLE, mCellNetworkAgent);
4003 cellNetworkCallback.expectCallback(CallbackState.NETWORK_CAPABILITIES,
4004 mCellNetworkAgent);
4005 CallbackInfo cbi = cellNetworkCallback.expectCallback(
4006 CallbackState.LINK_PROPERTIES, mCellNetworkAgent);
4007 cellNetworkCallback.assertNoCallback();
4008 assertFalse(((LinkProperties)cbi.arg).isPrivateDnsActive());
4009 assertNull(((LinkProperties)cbi.arg).getPrivateDnsServerName());
Erik Kline79c6d052018-03-21 07:18:33 -07004010
4011 setPrivateDnsSettings(PRIVATE_DNS_MODE_OFF, "ignored.example.com");
4012 verify(mNetworkManagementService, times(1)).setDnsConfigurationForNetwork(
4013 anyInt(), mStringArrayCaptor.capture(), any(), any(),
4014 eq(""), eq(EMPTY_STRING_ARRAY));
4015 assertEquals(2, mStringArrayCaptor.getValue().length);
4016 assertTrue(ArrayUtils.containsAll(mStringArrayCaptor.getValue(),
4017 new String[]{"2001:db8::1", "192.0.2.1"}));
4018 reset(mNetworkManagementService);
dalyk1fcb7392018-03-05 12:42:22 -05004019 cellNetworkCallback.assertNoCallback();
Erik Kline79c6d052018-03-21 07:18:33 -07004020
4021 setPrivateDnsSettings(PRIVATE_DNS_MODE_OPPORTUNISTIC, "ignored.example.com");
4022 verify(mNetworkManagementService, atLeastOnce()).setDnsConfigurationForNetwork(
4023 anyInt(), mStringArrayCaptor.capture(), any(), any(),
4024 eq(""), tlsServers.capture());
4025 assertEquals(2, mStringArrayCaptor.getValue().length);
4026 assertTrue(ArrayUtils.containsAll(mStringArrayCaptor.getValue(),
4027 new String[]{"2001:db8::1", "192.0.2.1"}));
4028 assertEquals(2, tlsServers.getValue().length);
4029 assertTrue(ArrayUtils.containsAll(tlsServers.getValue(),
4030 new String[]{"2001:db8::1", "192.0.2.1"}));
4031 reset(mNetworkManagementService);
dalyk1fcb7392018-03-05 12:42:22 -05004032 cellNetworkCallback.assertNoCallback();
Erik Kline79c6d052018-03-21 07:18:33 -07004033
dalyk1fcb7392018-03-05 12:42:22 -05004034 setPrivateDnsSettings(PRIVATE_DNS_MODE_PROVIDER_HOSTNAME, "strict.example.com");
4035 // Can't test dns configuration for strict mode without properly mocking
4036 // out the DNS lookups, but can test that LinkProperties is updated.
4037 cbi = cellNetworkCallback.expectCallback(CallbackState.LINK_PROPERTIES,
4038 mCellNetworkAgent);
4039 cellNetworkCallback.assertNoCallback();
4040 assertTrue(((LinkProperties)cbi.arg).isPrivateDnsActive());
4041 assertEquals("strict.example.com", ((LinkProperties)cbi.arg).getPrivateDnsServerName());
4042 }
4043
4044 @Test
4045 public void testLinkPropertiesWithPrivateDnsValidationEvents() throws Exception {
4046 // The default on Android is opportunistic mode ("Automatic").
4047 setPrivateDnsSettings(PRIVATE_DNS_MODE_OPPORTUNISTIC, "ignored.example.com");
4048
4049 final TestNetworkCallback cellNetworkCallback = new TestNetworkCallback();
4050 final NetworkRequest cellRequest = new NetworkRequest.Builder()
4051 .addTransportType(TRANSPORT_CELLULAR).build();
4052 mCm.requestNetwork(cellRequest, cellNetworkCallback);
4053
4054 mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
4055 waitForIdle();
4056 LinkProperties lp = new LinkProperties();
4057 mCellNetworkAgent.sendLinkProperties(lp);
4058 mCellNetworkAgent.connect(false);
4059 waitForIdle();
4060 cellNetworkCallback.expectCallback(CallbackState.AVAILABLE, mCellNetworkAgent);
4061 cellNetworkCallback.expectCallback(CallbackState.NETWORK_CAPABILITIES,
4062 mCellNetworkAgent);
4063 CallbackInfo cbi = cellNetworkCallback.expectCallback(
4064 CallbackState.LINK_PROPERTIES, mCellNetworkAgent);
4065 cellNetworkCallback.assertNoCallback();
4066 assertFalse(((LinkProperties)cbi.arg).isPrivateDnsActive());
4067 assertNull(((LinkProperties)cbi.arg).getPrivateDnsServerName());
4068 Set<InetAddress> dnsServers = new HashSet<>();
4069 checkDnsServers(cbi.arg, dnsServers);
4070
4071 // Send a validation event for a server that is not part of the current
4072 // resolver config. The validation event should be ignored.
4073 mService.mNetdEventCallback.onPrivateDnsValidationEvent(
4074 mCellNetworkAgent.getNetwork().netId, "", "145.100.185.18", true);
4075 cellNetworkCallback.assertNoCallback();
4076
4077 // Add a dns server to the LinkProperties.
4078 LinkProperties lp2 = new LinkProperties(lp);
4079 lp2.addDnsServer(InetAddress.getByName("145.100.185.16"));
4080 mCellNetworkAgent.sendLinkProperties(lp2);
4081 cbi = cellNetworkCallback.expectCallback(CallbackState.LINK_PROPERTIES,
4082 mCellNetworkAgent);
4083 cellNetworkCallback.assertNoCallback();
4084 assertFalse(((LinkProperties)cbi.arg).isPrivateDnsActive());
4085 assertNull(((LinkProperties)cbi.arg).getPrivateDnsServerName());
4086 dnsServers.add(InetAddress.getByName("145.100.185.16"));
4087 checkDnsServers(cbi.arg, dnsServers);
4088
4089 // Send a validation event containing a hostname that is not part of
4090 // the current resolver config. The validation event should be ignored.
4091 mService.mNetdEventCallback.onPrivateDnsValidationEvent(
4092 mCellNetworkAgent.getNetwork().netId, "145.100.185.16", "hostname", true);
4093 cellNetworkCallback.assertNoCallback();
4094
4095 // Send a validation event where validation failed.
4096 mService.mNetdEventCallback.onPrivateDnsValidationEvent(
4097 mCellNetworkAgent.getNetwork().netId, "145.100.185.16", "", false);
4098 cellNetworkCallback.assertNoCallback();
4099
4100 // Send a validation event where validation succeeded for a server in
4101 // the current resolver config. A LinkProperties callback with updated
4102 // private dns fields should be sent.
4103 mService.mNetdEventCallback.onPrivateDnsValidationEvent(
4104 mCellNetworkAgent.getNetwork().netId, "145.100.185.16", "", true);
4105 cbi = cellNetworkCallback.expectCallback(CallbackState.LINK_PROPERTIES,
4106 mCellNetworkAgent);
4107 cellNetworkCallback.assertNoCallback();
4108 assertTrue(((LinkProperties)cbi.arg).isPrivateDnsActive());
4109 assertNull(((LinkProperties)cbi.arg).getPrivateDnsServerName());
4110 checkDnsServers(cbi.arg, dnsServers);
4111
4112 // The private dns fields in LinkProperties should be preserved when
4113 // the network agent sends unrelated changes.
4114 LinkProperties lp3 = new LinkProperties(lp2);
4115 lp3.setMtu(1300);
4116 mCellNetworkAgent.sendLinkProperties(lp3);
4117 cbi = cellNetworkCallback.expectCallback(CallbackState.LINK_PROPERTIES,
4118 mCellNetworkAgent);
4119 cellNetworkCallback.assertNoCallback();
4120 assertTrue(((LinkProperties)cbi.arg).isPrivateDnsActive());
4121 assertNull(((LinkProperties)cbi.arg).getPrivateDnsServerName());
4122 checkDnsServers(cbi.arg, dnsServers);
4123 assertEquals(1300, ((LinkProperties)cbi.arg).getMtu());
4124
4125 // Removing the only validated server should affect the private dns
4126 // fields in LinkProperties.
4127 LinkProperties lp4 = new LinkProperties(lp3);
4128 lp4.removeDnsServer(InetAddress.getByName("145.100.185.16"));
4129 mCellNetworkAgent.sendLinkProperties(lp4);
4130 cbi = cellNetworkCallback.expectCallback(CallbackState.LINK_PROPERTIES,
4131 mCellNetworkAgent);
4132 cellNetworkCallback.assertNoCallback();
4133 assertFalse(((LinkProperties)cbi.arg).isPrivateDnsActive());
4134 assertNull(((LinkProperties)cbi.arg).getPrivateDnsServerName());
4135 dnsServers.remove(InetAddress.getByName("145.100.185.16"));
4136 checkDnsServers(cbi.arg, dnsServers);
4137 assertEquals(1300, ((LinkProperties)cbi.arg).getMtu());
Erik Kline79c6d052018-03-21 07:18:33 -07004138 }
4139
Rubin Xu1bb5c082017-09-05 18:40:49 +01004140 private void checkDirectlyConnectedRoutes(Object callbackObj,
4141 Collection<LinkAddress> linkAddresses, Collection<RouteInfo> otherRoutes) {
4142 assertTrue(callbackObj instanceof LinkProperties);
4143 LinkProperties lp = (LinkProperties) callbackObj;
4144
4145 Set<RouteInfo> expectedRoutes = new ArraySet<>();
4146 expectedRoutes.addAll(otherRoutes);
4147 for (LinkAddress address : linkAddresses) {
4148 RouteInfo localRoute = new RouteInfo(address, null, lp.getInterfaceName());
4149 // Duplicates in linkAddresses are considered failures
4150 assertTrue(expectedRoutes.add(localRoute));
4151 }
4152 List<RouteInfo> observedRoutes = lp.getRoutes();
4153 assertEquals(expectedRoutes.size(), observedRoutes.size());
4154 assertTrue(observedRoutes.containsAll(expectedRoutes));
4155 }
4156
dalyk1fcb7392018-03-05 12:42:22 -05004157 private static void checkDnsServers(Object callbackObj, Set<InetAddress> dnsServers) {
4158 assertTrue(callbackObj instanceof LinkProperties);
4159 LinkProperties lp = (LinkProperties) callbackObj;
4160 assertEquals(dnsServers.size(), lp.getDnsServers().size());
4161 assertTrue(lp.getDnsServers().containsAll(dnsServers));
4162 }
4163
Hugo Benichifed512a2017-06-26 10:06:49 +09004164 private static <T> void assertEmpty(T[] ts) {
4165 int length = ts.length;
4166 assertEquals("expected empty array, but length was " + length, 0, length);
4167 }
4168
4169 private static <T> void assertLength(int expected, T[] got) {
4170 int length = got.length;
4171 assertEquals(String.format("expected array of length %s, but length was %s for %s",
4172 expected, length, Arrays.toString(got)), expected, length);
4173 }
Hugo Benichi16f0a942017-06-20 14:07:59 +09004174
4175 private static <T> void assertException(Runnable block, Class<T> expected) {
4176 try {
4177 block.run();
4178 fail("Expected exception of type " + expected);
4179 } catch (Exception got) {
4180 if (!got.getClass().equals(expected)) {
4181 fail("Expected exception of type " + expected + " but got " + got);
4182 }
4183 return;
4184 }
4185 }
Chalard Jean0b214af2018-01-12 17:22:49 +09004186
4187 @Test
4188 public void testVpnNetworkActive() {
4189 final int uid = Process.myUid();
4190
4191 final TestNetworkCallback genericNetworkCallback = new TestNetworkCallback();
Chalard Jeanb552c462018-02-21 18:43:54 +09004192 final TestNetworkCallback genericNotVpnNetworkCallback = new TestNetworkCallback();
Chalard Jean0b214af2018-01-12 17:22:49 +09004193 final TestNetworkCallback wifiNetworkCallback = new TestNetworkCallback();
4194 final TestNetworkCallback vpnNetworkCallback = new TestNetworkCallback();
Chalard Jeanfb0c87e2018-04-18 19:18:58 +09004195 final TestNetworkCallback defaultCallback = new TestNetworkCallback();
Chalard Jeanb552c462018-02-21 18:43:54 +09004196 final NetworkRequest genericNotVpnRequest = new NetworkRequest.Builder().build();
4197 final NetworkRequest genericRequest = new NetworkRequest.Builder()
4198 .removeCapability(NET_CAPABILITY_NOT_VPN).build();
Chalard Jean0b214af2018-01-12 17:22:49 +09004199 final NetworkRequest wifiRequest = new NetworkRequest.Builder()
4200 .addTransportType(TRANSPORT_WIFI).build();
4201 final NetworkRequest vpnNetworkRequest = new NetworkRequest.Builder()
Chalard Jeanb552c462018-02-21 18:43:54 +09004202 .removeCapability(NET_CAPABILITY_NOT_VPN)
Chalard Jean0b214af2018-01-12 17:22:49 +09004203 .addTransportType(TRANSPORT_VPN).build();
4204 mCm.registerNetworkCallback(genericRequest, genericNetworkCallback);
Chalard Jeanb552c462018-02-21 18:43:54 +09004205 mCm.registerNetworkCallback(genericNotVpnRequest, genericNotVpnNetworkCallback);
Chalard Jean0b214af2018-01-12 17:22:49 +09004206 mCm.registerNetworkCallback(wifiRequest, wifiNetworkCallback);
4207 mCm.registerNetworkCallback(vpnNetworkRequest, vpnNetworkCallback);
Chalard Jeanfb0c87e2018-04-18 19:18:58 +09004208 mCm.registerDefaultNetworkCallback(defaultCallback);
4209 defaultCallback.assertNoCallback();
Chalard Jean0b214af2018-01-12 17:22:49 +09004210
4211 mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
4212 mWiFiNetworkAgent.connect(false);
4213
4214 genericNetworkCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
Chalard Jeanb552c462018-02-21 18:43:54 +09004215 genericNotVpnNetworkCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
Chalard Jean0b214af2018-01-12 17:22:49 +09004216 wifiNetworkCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
Chalard Jeanfb0c87e2018-04-18 19:18:58 +09004217 defaultCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
Chalard Jean0b214af2018-01-12 17:22:49 +09004218 vpnNetworkCallback.assertNoCallback();
Chalard Jeanfb0c87e2018-04-18 19:18:58 +09004219 assertEquals(defaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
Chalard Jean0b214af2018-01-12 17:22:49 +09004220
4221 final MockNetworkAgent vpnNetworkAgent = new MockNetworkAgent(TRANSPORT_VPN);
4222 final ArraySet<UidRange> ranges = new ArraySet<>();
4223 ranges.add(new UidRange(uid, uid));
Chalard Jeanf89e8da2018-05-18 21:47:45 +09004224 mMockVpn.setNetworkAgent(vpnNetworkAgent);
4225 mMockVpn.setUids(ranges);
Chalard Jean0b214af2018-01-12 17:22:49 +09004226 vpnNetworkAgent.connect(false);
Chalard Jeanf89e8da2018-05-18 21:47:45 +09004227 mMockVpn.connect();
Chalard Jean0b214af2018-01-12 17:22:49 +09004228
4229 genericNetworkCallback.expectAvailableCallbacksUnvalidated(vpnNetworkAgent);
Chalard Jeanb552c462018-02-21 18:43:54 +09004230 genericNotVpnNetworkCallback.assertNoCallback();
Chalard Jean0b214af2018-01-12 17:22:49 +09004231 wifiNetworkCallback.assertNoCallback();
4232 vpnNetworkCallback.expectAvailableCallbacksUnvalidated(vpnNetworkAgent);
Chalard Jeanfb0c87e2018-04-18 19:18:58 +09004233 defaultCallback.expectAvailableCallbacksUnvalidated(vpnNetworkAgent);
4234 assertEquals(defaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
Chalard Jean0b214af2018-01-12 17:22:49 +09004235
4236 genericNetworkCallback.expectCallback(CallbackState.NETWORK_CAPABILITIES, vpnNetworkAgent);
Chalard Jeanb552c462018-02-21 18:43:54 +09004237 genericNotVpnNetworkCallback.assertNoCallback();
Chalard Jeanf19db372018-01-26 19:24:40 +09004238 vpnNetworkCallback.expectCapabilitiesLike(nc -> null == nc.getUids(), vpnNetworkAgent);
Chalard Jeanfb0c87e2018-04-18 19:18:58 +09004239 defaultCallback.expectCallback(CallbackState.NETWORK_CAPABILITIES, vpnNetworkAgent);
4240 assertEquals(defaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
Chalard Jean0b214af2018-01-12 17:22:49 +09004241
4242 ranges.clear();
4243 vpnNetworkAgent.setUids(ranges);
4244
4245 genericNetworkCallback.expectCallback(CallbackState.LOST, vpnNetworkAgent);
Chalard Jeanb552c462018-02-21 18:43:54 +09004246 genericNotVpnNetworkCallback.assertNoCallback();
Chalard Jean0b214af2018-01-12 17:22:49 +09004247 wifiNetworkCallback.assertNoCallback();
4248 vpnNetworkCallback.expectCallback(CallbackState.LOST, vpnNetworkAgent);
4249
Chalard Jeanfb0c87e2018-04-18 19:18:58 +09004250 // TODO : The default network callback should actually get a LOST call here (also see the
4251 // comment below for AVAILABLE). This is because ConnectivityService does not look at UID
4252 // ranges at all when determining whether a network should be rematched. In practice, VPNs
4253 // can't currently update their UIDs without disconnecting, so this does not matter too
4254 // much, but that is the reason the test here has to check for an update to the
4255 // capabilities instead of the expected LOST then AVAILABLE.
4256 defaultCallback.expectCallback(CallbackState.NETWORK_CAPABILITIES, vpnNetworkAgent);
4257
Chalard Jean0b214af2018-01-12 17:22:49 +09004258 ranges.add(new UidRange(uid, uid));
Chalard Jeanf89e8da2018-05-18 21:47:45 +09004259 mMockVpn.setUids(ranges);
Chalard Jean0b214af2018-01-12 17:22:49 +09004260
4261 genericNetworkCallback.expectAvailableCallbacksValidated(vpnNetworkAgent);
Chalard Jeanb552c462018-02-21 18:43:54 +09004262 genericNotVpnNetworkCallback.assertNoCallback();
Chalard Jean0b214af2018-01-12 17:22:49 +09004263 wifiNetworkCallback.assertNoCallback();
4264 vpnNetworkCallback.expectAvailableCallbacksValidated(vpnNetworkAgent);
Chalard Jeanfb0c87e2018-04-18 19:18:58 +09004265 // TODO : Here like above, AVAILABLE would be correct, but because this can't actually
4266 // happen outside of the test, ConnectivityService does not rematch callbacks.
4267 defaultCallback.expectCallback(CallbackState.NETWORK_CAPABILITIES, vpnNetworkAgent);
Chalard Jean0b214af2018-01-12 17:22:49 +09004268
4269 mWiFiNetworkAgent.disconnect();
4270
4271 genericNetworkCallback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
Chalard Jeanb552c462018-02-21 18:43:54 +09004272 genericNotVpnNetworkCallback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
Chalard Jean0b214af2018-01-12 17:22:49 +09004273 wifiNetworkCallback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
4274 vpnNetworkCallback.assertNoCallback();
Chalard Jeanfb0c87e2018-04-18 19:18:58 +09004275 defaultCallback.assertNoCallback();
Chalard Jean0b214af2018-01-12 17:22:49 +09004276
4277 vpnNetworkAgent.disconnect();
4278
4279 genericNetworkCallback.expectCallback(CallbackState.LOST, vpnNetworkAgent);
Chalard Jeanb552c462018-02-21 18:43:54 +09004280 genericNotVpnNetworkCallback.assertNoCallback();
Chalard Jean0b214af2018-01-12 17:22:49 +09004281 wifiNetworkCallback.assertNoCallback();
4282 vpnNetworkCallback.expectCallback(CallbackState.LOST, vpnNetworkAgent);
Chalard Jeanfb0c87e2018-04-18 19:18:58 +09004283 defaultCallback.expectCallback(CallbackState.LOST, vpnNetworkAgent);
4284 assertEquals(null, mCm.getActiveNetwork());
Chalard Jean0b214af2018-01-12 17:22:49 +09004285
4286 mCm.unregisterNetworkCallback(genericNetworkCallback);
4287 mCm.unregisterNetworkCallback(wifiNetworkCallback);
4288 mCm.unregisterNetworkCallback(vpnNetworkCallback);
Chalard Jeanfb0c87e2018-04-18 19:18:58 +09004289 mCm.unregisterNetworkCallback(defaultCallback);
Chalard Jean0b214af2018-01-12 17:22:49 +09004290 }
Chalard Jean26400492018-04-18 20:18:38 +09004291
4292 @Test
4293 public void testVpnWithAndWithoutInternet() {
4294 final int uid = Process.myUid();
4295
4296 final TestNetworkCallback defaultCallback = new TestNetworkCallback();
4297 mCm.registerDefaultNetworkCallback(defaultCallback);
4298 defaultCallback.assertNoCallback();
4299
4300 mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
4301 mWiFiNetworkAgent.connect(true);
4302
4303 defaultCallback.expectAvailableThenValidatedCallbacks(mWiFiNetworkAgent);
4304 assertEquals(defaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
4305
4306 MockNetworkAgent vpnNetworkAgent = new MockNetworkAgent(TRANSPORT_VPN);
4307 final ArraySet<UidRange> ranges = new ArraySet<>();
4308 ranges.add(new UidRange(uid, uid));
Chalard Jeanf89e8da2018-05-18 21:47:45 +09004309 mMockVpn.setNetworkAgent(vpnNetworkAgent);
4310 mMockVpn.setUids(ranges);
Chalard Jean26400492018-04-18 20:18:38 +09004311 vpnNetworkAgent.connect(true /* validated */, false /* hasInternet */);
Chalard Jeanf89e8da2018-05-18 21:47:45 +09004312 mMockVpn.connect();
Chalard Jean26400492018-04-18 20:18:38 +09004313
4314 defaultCallback.assertNoCallback();
4315 assertEquals(defaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
4316
4317 vpnNetworkAgent.disconnect();
4318 defaultCallback.assertNoCallback();
4319
4320 vpnNetworkAgent = new MockNetworkAgent(TRANSPORT_VPN);
Chalard Jeanf89e8da2018-05-18 21:47:45 +09004321 mMockVpn.setNetworkAgent(vpnNetworkAgent);
4322 mMockVpn.setUids(ranges);
Chalard Jean26400492018-04-18 20:18:38 +09004323 vpnNetworkAgent.connect(true /* validated */, true /* hasInternet */);
Chalard Jeanf89e8da2018-05-18 21:47:45 +09004324 mMockVpn.connect();
Chalard Jean26400492018-04-18 20:18:38 +09004325 defaultCallback.expectAvailableThenValidatedCallbacks(vpnNetworkAgent);
4326 assertEquals(defaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
4327
4328 vpnNetworkAgent.disconnect();
4329 defaultCallback.expectCallback(CallbackState.LOST, vpnNetworkAgent);
4330 defaultCallback.expectAvailableCallbacksValidated(mWiFiNetworkAgent);
4331
4332 vpnNetworkAgent = new MockNetworkAgent(TRANSPORT_VPN);
Chalard Jean26400492018-04-18 20:18:38 +09004333 ranges.clear();
Chalard Jeanf89e8da2018-05-18 21:47:45 +09004334 mMockVpn.setNetworkAgent(vpnNetworkAgent);
4335 mMockVpn.setUids(ranges);
Chalard Jean26400492018-04-18 20:18:38 +09004336 vpnNetworkAgent.connect(false /* validated */, true /* hasInternet */);
Chalard Jeanf89e8da2018-05-18 21:47:45 +09004337 mMockVpn.connect();
Chalard Jean26400492018-04-18 20:18:38 +09004338 defaultCallback.assertNoCallback();
4339
4340 mCm.unregisterNetworkCallback(defaultCallback);
4341 }
Chalard Jeanf89e8da2018-05-18 21:47:45 +09004342
4343 @Test
4344 public void testVpnSetUnderlyingNetworks() {
4345 final int uid = Process.myUid();
4346
4347 final TestNetworkCallback vpnNetworkCallback = new TestNetworkCallback();
4348 final NetworkRequest vpnNetworkRequest = new NetworkRequest.Builder()
4349 .removeCapability(NET_CAPABILITY_NOT_VPN)
4350 .addTransportType(TRANSPORT_VPN)
4351 .build();
4352 NetworkCapabilities nc;
4353 mCm.registerNetworkCallback(vpnNetworkRequest, vpnNetworkCallback);
4354 vpnNetworkCallback.assertNoCallback();
4355
4356 final MockNetworkAgent vpnNetworkAgent = new MockNetworkAgent(TRANSPORT_VPN);
4357 final ArraySet<UidRange> ranges = new ArraySet<>();
4358 ranges.add(new UidRange(uid, uid));
4359 mMockVpn.setNetworkAgent(vpnNetworkAgent);
4360 mMockVpn.connect();
4361 mMockVpn.setUids(ranges);
4362 vpnNetworkAgent.connect(true /* validated */, false /* hasInternet */);
4363
4364 vpnNetworkCallback.expectAvailableThenValidatedCallbacks(vpnNetworkAgent);
4365 nc = mCm.getNetworkCapabilities(vpnNetworkAgent.getNetwork());
4366 assertTrue(nc.hasTransport(TRANSPORT_VPN));
4367 assertFalse(nc.hasTransport(TRANSPORT_CELLULAR));
4368 assertFalse(nc.hasTransport(TRANSPORT_WIFI));
4369 // For safety reasons a VPN without underlying networks is considered metered.
4370 assertFalse(nc.hasCapability(NET_CAPABILITY_NOT_METERED));
4371
4372 // Connect cell and use it as an underlying network.
4373 mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
4374 mCellNetworkAgent.connect(true);
4375
4376 mService.setUnderlyingNetworksForVpn(
4377 new Network[] { mCellNetworkAgent.getNetwork() });
4378
4379 vpnNetworkCallback.expectCapabilitiesLike((caps) -> caps.hasTransport(TRANSPORT_VPN)
4380 && caps.hasTransport(TRANSPORT_CELLULAR) && !caps.hasTransport(TRANSPORT_WIFI)
4381 && !caps.hasCapability(NET_CAPABILITY_NOT_METERED),
4382 vpnNetworkAgent);
4383
4384 mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
4385 mWiFiNetworkAgent.addCapability(NET_CAPABILITY_NOT_METERED);
4386 mWiFiNetworkAgent.connect(true);
4387
4388 mService.setUnderlyingNetworksForVpn(
4389 new Network[] { mCellNetworkAgent.getNetwork(), mWiFiNetworkAgent.getNetwork() });
4390
4391 vpnNetworkCallback.expectCapabilitiesLike((caps) -> caps.hasTransport(TRANSPORT_VPN)
4392 && caps.hasTransport(TRANSPORT_CELLULAR) && caps.hasTransport(TRANSPORT_WIFI)
4393 && !caps.hasCapability(NET_CAPABILITY_NOT_METERED),
4394 vpnNetworkAgent);
4395
4396 // Don't disconnect, but note the VPN is not using wifi any more.
4397 mService.setUnderlyingNetworksForVpn(
4398 new Network[] { mCellNetworkAgent.getNetwork() });
4399
4400 vpnNetworkCallback.expectCapabilitiesLike((caps) -> caps.hasTransport(TRANSPORT_VPN)
4401 && caps.hasTransport(TRANSPORT_CELLULAR) && !caps.hasTransport(TRANSPORT_WIFI)
4402 && !caps.hasCapability(NET_CAPABILITY_NOT_METERED),
4403 vpnNetworkAgent);
4404
4405 // Use Wifi but not cell. Note the VPN is now unmetered.
4406 mService.setUnderlyingNetworksForVpn(
4407 new Network[] { mWiFiNetworkAgent.getNetwork() });
4408
4409 vpnNetworkCallback.expectCapabilitiesLike((caps) -> caps.hasTransport(TRANSPORT_VPN)
4410 && !caps.hasTransport(TRANSPORT_CELLULAR) && caps.hasTransport(TRANSPORT_WIFI)
4411 && caps.hasCapability(NET_CAPABILITY_NOT_METERED),
4412 vpnNetworkAgent);
4413
4414 // Use both again.
4415 mService.setUnderlyingNetworksForVpn(
4416 new Network[] { mCellNetworkAgent.getNetwork(), mWiFiNetworkAgent.getNetwork() });
4417
4418 vpnNetworkCallback.expectCapabilitiesLike((caps) -> caps.hasTransport(TRANSPORT_VPN)
4419 && caps.hasTransport(TRANSPORT_CELLULAR) && caps.hasTransport(TRANSPORT_WIFI)
4420 && !caps.hasCapability(NET_CAPABILITY_NOT_METERED),
4421 vpnNetworkAgent);
4422
Chalard Jean6b65ec72018-05-18 22:02:56 +09004423 // Disconnect cell. Receive update without even removing the dead network from the
4424 // underlying networks – it's dead anyway. Not metered any more.
4425 mCellNetworkAgent.disconnect();
4426 vpnNetworkCallback.expectCapabilitiesLike((caps) -> caps.hasTransport(TRANSPORT_VPN)
4427 && !caps.hasTransport(TRANSPORT_CELLULAR) && caps.hasTransport(TRANSPORT_WIFI)
4428 && caps.hasCapability(NET_CAPABILITY_NOT_METERED),
4429 vpnNetworkAgent);
Chalard Jeanf89e8da2018-05-18 21:47:45 +09004430
Chalard Jeanb3ab0d12018-05-21 15:30:56 +09004431 // Disconnect wifi too. No underlying networks means this is now metered.
Chalard Jean6b65ec72018-05-18 22:02:56 +09004432 mWiFiNetworkAgent.disconnect();
4433 vpnNetworkCallback.expectCapabilitiesLike((caps) -> caps.hasTransport(TRANSPORT_VPN)
4434 && !caps.hasTransport(TRANSPORT_CELLULAR) && !caps.hasTransport(TRANSPORT_WIFI)
Chalard Jeanb3ab0d12018-05-21 15:30:56 +09004435 && !caps.hasCapability(NET_CAPABILITY_NOT_METERED),
Chalard Jean6b65ec72018-05-18 22:02:56 +09004436 vpnNetworkAgent);
Chalard Jeanf89e8da2018-05-18 21:47:45 +09004437
4438 mMockVpn.disconnect();
4439 }
junyulai4a192e22018-06-13 15:00:37 +08004440
4441 /**
4442 * Make simulated InterfaceConfig for Nat464Xlat to query clat lower layer info.
4443 */
4444 private InterfaceConfiguration getClatInterfaceConfig(LinkAddress la) {
4445 InterfaceConfiguration cfg = new InterfaceConfiguration();
4446 cfg.setHardwareAddress("11:22:33:44:55:66");
4447 cfg.setLinkAddress(la);
4448 return cfg;
4449 }
4450
4451 /**
4452 * Make expected stack link properties, copied from Nat464Xlat.
4453 */
4454 private LinkProperties makeClatLinkProperties(LinkAddress la) {
4455 LinkAddress clatAddress = la;
4456 LinkProperties stacked = new LinkProperties();
4457 stacked.setInterfaceName(CLAT_PREFIX + MOBILE_IFNAME);
4458 RouteInfo ipv4Default = new RouteInfo(
4459 new LinkAddress(Inet4Address.ANY, 0),
4460 clatAddress.getAddress(), CLAT_PREFIX + MOBILE_IFNAME);
4461 stacked.addRoute(ipv4Default);
4462 stacked.addLinkAddress(clatAddress);
4463 return stacked;
4464 }
4465
4466 @Test
4467 public void testStackedLinkProperties() throws UnknownHostException, RemoteException {
4468 final LinkAddress myIpv4 = new LinkAddress("1.2.3.4/24");
4469 final LinkAddress myIpv6 = new LinkAddress("2001:db8:1::1/64");
4470 final NetworkRequest networkRequest = new NetworkRequest.Builder()
4471 .addTransportType(TRANSPORT_CELLULAR)
4472 .addCapability(NET_CAPABILITY_INTERNET)
4473 .build();
4474 final TestNetworkCallback networkCallback = new TestNetworkCallback();
4475 mCm.registerNetworkCallback(networkRequest, networkCallback);
4476
4477 // Prepare ipv6 only link properties and connect.
4478 mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
4479 final LinkProperties cellLp = new LinkProperties();
4480 cellLp.setInterfaceName(MOBILE_IFNAME);
4481 cellLp.addLinkAddress(myIpv6);
4482 cellLp.addRoute(new RouteInfo((IpPrefix) null, myIpv6.getAddress(), MOBILE_IFNAME));
4483 cellLp.addRoute(new RouteInfo(myIpv6, null, MOBILE_IFNAME));
4484 reset(mNetworkManagementService);
4485 when(mNetworkManagementService.getInterfaceConfig(CLAT_PREFIX + MOBILE_IFNAME))
4486 .thenReturn(getClatInterfaceConfig(myIpv4));
4487
4488 // Connect with ipv6 link properties, then expect clat setup ipv4 and update link
4489 // properties properly.
4490 mCellNetworkAgent.sendLinkProperties(cellLp);
4491 mCellNetworkAgent.connect(true);
4492 networkCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
4493 verify(mNetworkManagementService, times(1)).startClatd(MOBILE_IFNAME);
4494 Nat464Xlat clat = mService.getNat464Xlat(mCellNetworkAgent);
4495
4496 // Clat iface up, expect stack link updated.
4497 clat.interfaceLinkStateChanged(CLAT_PREFIX + MOBILE_IFNAME, true);
4498 waitForIdle();
4499 List<LinkProperties> stackedLps = mCm.getLinkProperties(mCellNetworkAgent.getNetwork())
4500 .getStackedLinks();
4501 assertEquals(makeClatLinkProperties(myIpv4), stackedLps.get(0));
4502
4503 // Change trivial linkproperties and see if stacked link is preserved.
4504 cellLp.addDnsServer(InetAddress.getByName("8.8.8.8"));
4505 mCellNetworkAgent.sendLinkProperties(cellLp);
4506 waitForIdle();
4507 networkCallback.expectCallback(CallbackState.LINK_PROPERTIES, mCellNetworkAgent);
4508
4509 List<LinkProperties> stackedLpsAfterChange =
4510 mCm.getLinkProperties(mCellNetworkAgent.getNetwork()).getStackedLinks();
4511 assertNotEquals(stackedLpsAfterChange, Collections.EMPTY_LIST);
4512 assertEquals(makeClatLinkProperties(myIpv4), stackedLpsAfterChange.get(0));
4513
4514 // Add ipv4 address, expect stacked linkproperties be cleaned up
4515 cellLp.addLinkAddress(myIpv4);
4516 cellLp.addRoute(new RouteInfo(myIpv4, null, MOBILE_IFNAME));
4517 mCellNetworkAgent.sendLinkProperties(cellLp);
4518 waitForIdle();
4519 networkCallback.expectCallback(CallbackState.LINK_PROPERTIES, mCellNetworkAgent);
4520 verify(mNetworkManagementService, times(1)).stopClatd(MOBILE_IFNAME);
4521
4522 // Clat iface removed, expect linkproperties revert to original one
4523 clat.interfaceRemoved(CLAT_PREFIX + MOBILE_IFNAME);
4524 waitForIdle();
4525 networkCallback.expectCallback(CallbackState.LINK_PROPERTIES, mCellNetworkAgent);
4526 LinkProperties actualLpAfterIpv4 = mCm.getLinkProperties(mCellNetworkAgent.getNetwork());
4527 assertEquals(cellLp, actualLpAfterIpv4);
4528
4529 // Clean up
4530 mCellNetworkAgent.disconnect();
4531 mCm.unregisterNetworkCallback(networkCallback);
4532 }
Jeff Sharkeyfb878b62012-07-26 18:32:30 -07004533}