blob: 5a1f853e75a92cbe447855b7f3a901c0d391a249 [file] [log] [blame]
Erik Kline885a9092017-01-16 16:27:22 +09001/*
2 * Copyright (C) 2017 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.connectivity.tethering;
18
Erik Klinedd8e8912017-01-18 16:08:06 +090019import static android.net.ConnectivityManager.TYPE_MOBILE_DUN;
20import static android.net.ConnectivityManager.TYPE_MOBILE_HIPRI;
Erik Kline37609992017-06-05 16:02:02 +090021import static android.net.ConnectivityManager.TYPE_NONE;
22import static android.net.ConnectivityManager.TYPE_WIFI;
Erik Kline885a9092017-01-16 16:27:22 +090023import static android.net.NetworkCapabilities.NET_CAPABILITY_DUN;
Erik Kline37609992017-06-05 16:02:02 +090024import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET;
25import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
26import static android.net.NetworkCapabilities.TRANSPORT_WIFI;
markchiena6c72872018-11-13 18:34:56 +090027
Erik Kline885a9092017-01-16 16:27:22 +090028import static org.junit.Assert.assertEquals;
29import static org.junit.Assert.assertFalse;
30import static org.junit.Assert.assertTrue;
Erik Kline35eee132017-01-17 15:06:35 +090031import static org.junit.Assert.fail;
Erik Kline7462f462017-01-23 19:05:28 +090032import static org.mockito.Mockito.any;
33import static org.mockito.Mockito.anyInt;
Erik Kline7747fd42017-05-12 16:52:48 +090034import static org.mockito.Mockito.anyString;
Erik Kline72302902018-06-14 17:36:40 +090035import static org.mockito.Mockito.eq;
Erik Kline885a9092017-01-16 16:27:22 +090036import static org.mockito.Mockito.reset;
Erik Kline7462f462017-01-23 19:05:28 +090037import static org.mockito.Mockito.spy;
38import static org.mockito.Mockito.times;
39import static org.mockito.Mockito.verify;
40import static org.mockito.Mockito.verifyNoMoreInteractions;
Erik Kline7747fd42017-05-12 16:52:48 +090041import static org.mockito.Mockito.when;
Erik Kline885a9092017-01-16 16:27:22 +090042
43import android.content.Context;
44import android.net.ConnectivityManager;
45import android.net.ConnectivityManager.NetworkCallback;
46import android.net.IConnectivityManager;
Erik Kline3a5278f2017-06-24 19:29:10 +090047import android.net.IpPrefix;
48import android.net.LinkAddress;
49import android.net.LinkProperties;
Erik Kline885a9092017-01-16 16:27:22 +090050import android.net.Network;
51import android.net.NetworkCapabilities;
52import android.net.NetworkRequest;
Erik Kline1e2897d2017-06-09 17:08:52 +090053import android.net.NetworkState;
Erik Kline7747fd42017-05-12 16:52:48 +090054import android.net.util.SharedLog;
Brett Chabot1ae2aa62019-03-04 14:14:56 -080055import android.os.Handler;
56import android.os.Message;
57
58import androidx.test.filters.SmallTest;
59import androidx.test.runner.AndroidJUnit4;
Erik Kline885a9092017-01-16 16:27:22 +090060
Erik Klineb583b032017-02-22 12:58:24 +090061import com.android.internal.util.State;
62import com.android.internal.util.StateMachine;
63
64import org.junit.After;
Erik Kline885a9092017-01-16 16:27:22 +090065import org.junit.Before;
Erik Kline885a9092017-01-16 16:27:22 +090066import org.junit.Test;
Brett Chabot1ae2aa62019-03-04 14:14:56 -080067import org.junit.runner.RunWith;
Erik Kline885a9092017-01-16 16:27:22 +090068import org.mockito.Mock;
69import org.mockito.MockitoAnnotations;
70
Erik Klineb583b032017-02-22 12:58:24 +090071import java.util.ArrayList;
Erik Kline37609992017-06-05 16:02:02 +090072import java.util.Collection;
Erik Kline3a5278f2017-06-24 19:29:10 +090073import java.util.Collections;
Erik Kline885a9092017-01-16 16:27:22 +090074import java.util.HashMap;
75import java.util.HashSet;
76import java.util.Map;
Erik Kline72302902018-06-14 17:36:40 +090077import java.util.Objects;
Erik Kline885a9092017-01-16 16:27:22 +090078import java.util.Set;
79
Erik Kline885a9092017-01-16 16:27:22 +090080@RunWith(AndroidJUnit4.class)
81@SmallTest
82public class UpstreamNetworkMonitorTest {
83 private static final int EVENT_UNM_UPDATE = 1;
84
Erik Kline3a5278f2017-06-24 19:29:10 +090085 private static final boolean INCLUDES = true;
86 private static final boolean EXCLUDES = false;
87
Erik Kline72302902018-06-14 17:36:40 +090088 // Actual contents of the request don't matter for this test. The lack of
89 // any specific TRANSPORT_* is sufficient to identify this request.
90 private static final NetworkRequest mDefaultRequest = new NetworkRequest.Builder().build();
91
Erik Kline885a9092017-01-16 16:27:22 +090092 @Mock private Context mContext;
93 @Mock private IConnectivityManager mCS;
Erik Kline7747fd42017-05-12 16:52:48 +090094 @Mock private SharedLog mLog;
Erik Kline885a9092017-01-16 16:27:22 +090095
Erik Klineb583b032017-02-22 12:58:24 +090096 private TestStateMachine mSM;
Erik Kline885a9092017-01-16 16:27:22 +090097 private TestConnectivityManager mCM;
98 private UpstreamNetworkMonitor mUNM;
99
100 @Before public void setUp() throws Exception {
101 MockitoAnnotations.initMocks(this);
102 reset(mContext);
103 reset(mCS);
Erik Kline7747fd42017-05-12 16:52:48 +0900104 reset(mLog);
105 when(mLog.forSubComponent(anyString())).thenReturn(mLog);
Erik Kline885a9092017-01-16 16:27:22 +0900106
Erik Kline7462f462017-01-23 19:05:28 +0900107 mCM = spy(new TestConnectivityManager(mContext, mCS));
Erik Klineb583b032017-02-22 12:58:24 +0900108 mSM = new TestStateMachine();
Erik Kline3a5278f2017-06-24 19:29:10 +0900109 mUNM = new UpstreamNetworkMonitor(
110 (ConnectivityManager) mCM, mSM, mLog, EVENT_UNM_UPDATE);
Erik Klineb583b032017-02-22 12:58:24 +0900111 }
112
113 @After public void tearDown() throws Exception {
114 if (mSM != null) {
115 mSM.quit();
116 mSM = null;
117 }
Erik Kline885a9092017-01-16 16:27:22 +0900118 }
119
120 @Test
Erik Kline72302902018-06-14 17:36:40 +0900121 public void testStopWithoutStartIsNonFatal() {
122 mUNM.stop();
123 mUNM.stop();
124 mUNM.stop();
125 }
126
127 @Test
markchiena6c72872018-11-13 18:34:56 +0900128 public void testDoesNothingBeforeTrackDefaultAndStarted() throws Exception {
Erik Kline35eee132017-01-17 15:06:35 +0900129 assertTrue(mCM.hasNoCallbacks());
130 assertFalse(mUNM.mobileNetworkRequested());
131
132 mUNM.updateMobileRequiresDun(true);
133 assertTrue(mCM.hasNoCallbacks());
134 mUNM.updateMobileRequiresDun(false);
135 assertTrue(mCM.hasNoCallbacks());
Erik Kline885a9092017-01-16 16:27:22 +0900136 }
137
138 @Test
139 public void testDefaultNetworkIsTracked() throws Exception {
markchiena6c72872018-11-13 18:34:56 +0900140 assertTrue(mCM.hasNoCallbacks());
141 mUNM.startTrackDefaultNetwork(mDefaultRequest);
Erik Kline885a9092017-01-16 16:27:22 +0900142
markchiena6c72872018-11-13 18:34:56 +0900143 mUNM.startObserveAllNetworks();
Erik Kline885a9092017-01-16 16:27:22 +0900144 assertEquals(1, mCM.trackingDefault.size());
145
146 mUNM.stop();
markchiena6c72872018-11-13 18:34:56 +0900147 assertTrue(mCM.onlyHasDefaultCallbacks());
Erik Kline885a9092017-01-16 16:27:22 +0900148 }
149
150 @Test
Erik Klined2ec3912017-01-25 00:53:04 +0900151 public void testListensForAllNetworks() throws Exception {
Erik Kline885a9092017-01-16 16:27:22 +0900152 assertTrue(mCM.listening.isEmpty());
153
markchiena6c72872018-11-13 18:34:56 +0900154 mUNM.startTrackDefaultNetwork(mDefaultRequest);
155 mUNM.startObserveAllNetworks();
Erik Kline885a9092017-01-16 16:27:22 +0900156 assertFalse(mCM.listening.isEmpty());
Erik Klined2ec3912017-01-25 00:53:04 +0900157 assertTrue(mCM.isListeningForAll());
Erik Kline885a9092017-01-16 16:27:22 +0900158
159 mUNM.stop();
markchiena6c72872018-11-13 18:34:56 +0900160 assertTrue(mCM.onlyHasDefaultCallbacks());
Erik Kline885a9092017-01-16 16:27:22 +0900161 }
162
163 @Test
Remi NGUYEN VANa911e842018-03-15 11:57:14 +0900164 public void testCallbacksRegistered() {
markchiena6c72872018-11-13 18:34:56 +0900165 mUNM.startTrackDefaultNetwork(mDefaultRequest);
Erik Kline72302902018-06-14 17:36:40 +0900166 verify(mCM, times(1)).requestNetwork(
167 eq(mDefaultRequest), any(NetworkCallback.class), any(Handler.class));
markchiena6c72872018-11-13 18:34:56 +0900168 mUNM.startObserveAllNetworks();
169 verify(mCM, times(1)).registerNetworkCallback(
170 any(NetworkRequest.class), any(NetworkCallback.class), any(Handler.class));
Remi NGUYEN VANa911e842018-03-15 11:57:14 +0900171
172 mUNM.stop();
markchiena6c72872018-11-13 18:34:56 +0900173 verify(mCM, times(1)).unregisterNetworkCallback(any(NetworkCallback.class));
Remi NGUYEN VANa911e842018-03-15 11:57:14 +0900174 }
175
176 @Test
Erik Kline35eee132017-01-17 15:06:35 +0900177 public void testRequestsMobileNetwork() throws Exception {
Erik Kline885a9092017-01-16 16:27:22 +0900178 assertFalse(mUNM.mobileNetworkRequested());
179 assertEquals(0, mCM.requested.size());
180
markchiena6c72872018-11-13 18:34:56 +0900181 mUNM.startObserveAllNetworks();
Erik Kline885a9092017-01-16 16:27:22 +0900182 assertFalse(mUNM.mobileNetworkRequested());
183 assertEquals(0, mCM.requested.size());
184
Erik Klineefdd3f4c2017-01-20 16:31:29 +0900185 mUNM.updateMobileRequiresDun(false);
Erik Kline885a9092017-01-16 16:27:22 +0900186 assertFalse(mUNM.mobileNetworkRequested());
187 assertEquals(0, mCM.requested.size());
188
189 mUNM.registerMobileNetworkRequest();
190 assertTrue(mUNM.mobileNetworkRequested());
Erik Kline973c7df2017-01-23 15:55:16 +0900191 assertUpstreamTypeRequested(TYPE_MOBILE_HIPRI);
Erik Kline885a9092017-01-16 16:27:22 +0900192 assertFalse(mCM.isDunRequested());
193
194 mUNM.stop();
195 assertFalse(mUNM.mobileNetworkRequested());
Erik Kline35eee132017-01-17 15:06:35 +0900196 assertTrue(mCM.hasNoCallbacks());
Erik Kline885a9092017-01-16 16:27:22 +0900197 }
198
199 @Test
Erik Kline7462f462017-01-23 19:05:28 +0900200 public void testDuplicateMobileRequestsIgnored() throws Exception {
201 assertFalse(mUNM.mobileNetworkRequested());
202 assertEquals(0, mCM.requested.size());
203
markchiena6c72872018-11-13 18:34:56 +0900204 mUNM.startObserveAllNetworks();
Erik Kline72302902018-06-14 17:36:40 +0900205 verify(mCM, times(1)).registerNetworkCallback(
Erik Klineb583b032017-02-22 12:58:24 +0900206 any(NetworkRequest.class), any(NetworkCallback.class), any(Handler.class));
Erik Kline7462f462017-01-23 19:05:28 +0900207 assertFalse(mUNM.mobileNetworkRequested());
208 assertEquals(0, mCM.requested.size());
209
210 mUNM.updateMobileRequiresDun(true);
211 mUNM.registerMobileNetworkRequest();
Erik Kline72302902018-06-14 17:36:40 +0900212 verify(mCM, times(1)).requestNetwork(
Erik Klineb583b032017-02-22 12:58:24 +0900213 any(NetworkRequest.class), any(NetworkCallback.class), anyInt(), anyInt(),
214 any(Handler.class));
Erik Kline7462f462017-01-23 19:05:28 +0900215
216 assertTrue(mUNM.mobileNetworkRequested());
217 assertUpstreamTypeRequested(TYPE_MOBILE_DUN);
218 assertTrue(mCM.isDunRequested());
219
220 // Try a few things that must not result in any state change.
221 mUNM.registerMobileNetworkRequest();
222 mUNM.updateMobileRequiresDun(true);
223 mUNM.registerMobileNetworkRequest();
224
225 assertTrue(mUNM.mobileNetworkRequested());
226 assertUpstreamTypeRequested(TYPE_MOBILE_DUN);
227 assertTrue(mCM.isDunRequested());
228
229 mUNM.stop();
markchiena6c72872018-11-13 18:34:56 +0900230 verify(mCM, times(2)).unregisterNetworkCallback(any(NetworkCallback.class));
Erik Kline7462f462017-01-23 19:05:28 +0900231
232 verifyNoMoreInteractions(mCM);
233 }
234
235 @Test
Erik Kline35eee132017-01-17 15:06:35 +0900236 public void testRequestsDunNetwork() throws Exception {
Erik Kline885a9092017-01-16 16:27:22 +0900237 assertFalse(mUNM.mobileNetworkRequested());
238 assertEquals(0, mCM.requested.size());
239
markchiena6c72872018-11-13 18:34:56 +0900240 mUNM.startObserveAllNetworks();
Erik Kline885a9092017-01-16 16:27:22 +0900241 assertFalse(mUNM.mobileNetworkRequested());
242 assertEquals(0, mCM.requested.size());
243
Erik Klineefdd3f4c2017-01-20 16:31:29 +0900244 mUNM.updateMobileRequiresDun(true);
Erik Kline885a9092017-01-16 16:27:22 +0900245 assertFalse(mUNM.mobileNetworkRequested());
246 assertEquals(0, mCM.requested.size());
247
248 mUNM.registerMobileNetworkRequest();
249 assertTrue(mUNM.mobileNetworkRequested());
Erik Kline973c7df2017-01-23 15:55:16 +0900250 assertUpstreamTypeRequested(TYPE_MOBILE_DUN);
Erik Kline885a9092017-01-16 16:27:22 +0900251 assertTrue(mCM.isDunRequested());
252
253 mUNM.stop();
254 assertFalse(mUNM.mobileNetworkRequested());
Erik Kline35eee132017-01-17 15:06:35 +0900255 assertTrue(mCM.hasNoCallbacks());
Erik Kline885a9092017-01-16 16:27:22 +0900256 }
257
Erik Kline973c7df2017-01-23 15:55:16 +0900258 @Test
Erik Kline7462f462017-01-23 19:05:28 +0900259 public void testUpdateMobileRequiresDun() throws Exception {
markchiena6c72872018-11-13 18:34:56 +0900260 mUNM.startObserveAllNetworks();
Erik Kline973c7df2017-01-23 15:55:16 +0900261
262 // Test going from no-DUN to DUN correctly re-registers callbacks.
263 mUNM.updateMobileRequiresDun(false);
264 mUNM.registerMobileNetworkRequest();
265 assertTrue(mUNM.mobileNetworkRequested());
266 assertUpstreamTypeRequested(TYPE_MOBILE_HIPRI);
267 assertFalse(mCM.isDunRequested());
268 mUNM.updateMobileRequiresDun(true);
269 assertTrue(mUNM.mobileNetworkRequested());
270 assertUpstreamTypeRequested(TYPE_MOBILE_DUN);
271 assertTrue(mCM.isDunRequested());
272
273 // Test going from DUN to no-DUN correctly re-registers callbacks.
274 mUNM.updateMobileRequiresDun(false);
275 assertTrue(mUNM.mobileNetworkRequested());
276 assertUpstreamTypeRequested(TYPE_MOBILE_HIPRI);
277 assertFalse(mCM.isDunRequested());
278
279 mUNM.stop();
280 assertFalse(mUNM.mobileNetworkRequested());
281 }
282
Erik Kline37609992017-06-05 16:02:02 +0900283 @Test
284 public void testSelectPreferredUpstreamType() throws Exception {
285 final Collection<Integer> preferredTypes = new ArrayList<>();
286 preferredTypes.add(TYPE_WIFI);
287
markchiena6c72872018-11-13 18:34:56 +0900288 mUNM.startTrackDefaultNetwork(mDefaultRequest);
289 mUNM.startObserveAllNetworks();
Erik Kline37609992017-06-05 16:02:02 +0900290 // There are no networks, so there is nothing to select.
Erik Kline1e2897d2017-06-09 17:08:52 +0900291 assertSatisfiesLegacyType(TYPE_NONE, mUNM.selectPreferredUpstreamType(preferredTypes));
Erik Kline37609992017-06-05 16:02:02 +0900292
293 final TestNetworkAgent wifiAgent = new TestNetworkAgent(mCM, TRANSPORT_WIFI);
294 wifiAgent.fakeConnect();
295 // WiFi is up, we should prefer it.
Erik Kline1e2897d2017-06-09 17:08:52 +0900296 assertSatisfiesLegacyType(TYPE_WIFI, mUNM.selectPreferredUpstreamType(preferredTypes));
Erik Kline37609992017-06-05 16:02:02 +0900297 wifiAgent.fakeDisconnect();
298 // There are no networks, so there is nothing to select.
Erik Kline1e2897d2017-06-09 17:08:52 +0900299 assertSatisfiesLegacyType(TYPE_NONE, mUNM.selectPreferredUpstreamType(preferredTypes));
Erik Kline37609992017-06-05 16:02:02 +0900300
301 final TestNetworkAgent cellAgent = new TestNetworkAgent(mCM, TRANSPORT_CELLULAR);
302 cellAgent.fakeConnect();
Erik Kline1e2897d2017-06-09 17:08:52 +0900303 assertSatisfiesLegacyType(TYPE_NONE, mUNM.selectPreferredUpstreamType(preferredTypes));
Erik Kline37609992017-06-05 16:02:02 +0900304
305 preferredTypes.add(TYPE_MOBILE_DUN);
306 // This is coupled with preferred types in TetheringConfiguration.
307 mUNM.updateMobileRequiresDun(true);
308 // DUN is available, but only use regular cell: no upstream selected.
Erik Kline1e2897d2017-06-09 17:08:52 +0900309 assertSatisfiesLegacyType(TYPE_NONE, mUNM.selectPreferredUpstreamType(preferredTypes));
Erik Kline37609992017-06-05 16:02:02 +0900310 preferredTypes.remove(TYPE_MOBILE_DUN);
311 // No WiFi, but our preferred flavour of cell is up.
312 preferredTypes.add(TYPE_MOBILE_HIPRI);
313 // This is coupled with preferred types in TetheringConfiguration.
314 mUNM.updateMobileRequiresDun(false);
Erik Kline1e2897d2017-06-09 17:08:52 +0900315 assertSatisfiesLegacyType(TYPE_MOBILE_HIPRI,
316 mUNM.selectPreferredUpstreamType(preferredTypes));
Erik Kline37609992017-06-05 16:02:02 +0900317 // Check to see we filed an explicit request.
318 assertEquals(1, mCM.requested.size());
319 NetworkRequest netReq = (NetworkRequest) mCM.requested.values().toArray()[0];
320 assertTrue(netReq.networkCapabilities.hasTransport(TRANSPORT_CELLULAR));
321 assertFalse(netReq.networkCapabilities.hasCapability(NET_CAPABILITY_DUN));
322
323 wifiAgent.fakeConnect();
324 // WiFi is up, and we should prefer it over cell.
Erik Kline1e2897d2017-06-09 17:08:52 +0900325 assertSatisfiesLegacyType(TYPE_WIFI, mUNM.selectPreferredUpstreamType(preferredTypes));
Erik Kline37609992017-06-05 16:02:02 +0900326 assertEquals(0, mCM.requested.size());
327
328 preferredTypes.remove(TYPE_MOBILE_HIPRI);
329 preferredTypes.add(TYPE_MOBILE_DUN);
330 // This is coupled with preferred types in TetheringConfiguration.
331 mUNM.updateMobileRequiresDun(true);
Erik Kline1e2897d2017-06-09 17:08:52 +0900332 assertSatisfiesLegacyType(TYPE_WIFI, mUNM.selectPreferredUpstreamType(preferredTypes));
Erik Kline37609992017-06-05 16:02:02 +0900333
334 final TestNetworkAgent dunAgent = new TestNetworkAgent(mCM, TRANSPORT_CELLULAR);
335 dunAgent.networkCapabilities.addCapability(NET_CAPABILITY_DUN);
336 dunAgent.fakeConnect();
337
338 // WiFi is still preferred.
Erik Kline1e2897d2017-06-09 17:08:52 +0900339 assertSatisfiesLegacyType(TYPE_WIFI, mUNM.selectPreferredUpstreamType(preferredTypes));
Erik Kline37609992017-06-05 16:02:02 +0900340
341 // WiFi goes down, cell and DUN are still up but only DUN is preferred.
342 wifiAgent.fakeDisconnect();
Erik Kline1e2897d2017-06-09 17:08:52 +0900343 assertSatisfiesLegacyType(TYPE_MOBILE_DUN,
344 mUNM.selectPreferredUpstreamType(preferredTypes));
Erik Kline37609992017-06-05 16:02:02 +0900345 // Check to see we filed an explicit request.
346 assertEquals(1, mCM.requested.size());
347 netReq = (NetworkRequest) mCM.requested.values().toArray()[0];
348 assertTrue(netReq.networkCapabilities.hasTransport(TRANSPORT_CELLULAR));
349 assertTrue(netReq.networkCapabilities.hasCapability(NET_CAPABILITY_DUN));
350 }
351
Erik Kline3a5278f2017-06-24 19:29:10 +0900352 @Test
Erik Kline72302902018-06-14 17:36:40 +0900353 public void testGetCurrentPreferredUpstream() throws Exception {
markchiena6c72872018-11-13 18:34:56 +0900354 mUNM.startTrackDefaultNetwork(mDefaultRequest);
355 mUNM.startObserveAllNetworks();
Erik Kline72302902018-06-14 17:36:40 +0900356 mUNM.updateMobileRequiresDun(false);
357
358 // [0] Mobile connects, DUN not required -> mobile selected.
359 final TestNetworkAgent cellAgent = new TestNetworkAgent(mCM, TRANSPORT_CELLULAR);
360 cellAgent.fakeConnect();
361 mCM.makeDefaultNetwork(cellAgent);
362 assertEquals(cellAgent.networkId, mUNM.getCurrentPreferredUpstream().network);
363
364 // [1] WiFi connects but not validated/promoted to default -> mobile selected.
365 final TestNetworkAgent wifiAgent = new TestNetworkAgent(mCM, TRANSPORT_WIFI);
366 wifiAgent.fakeConnect();
367 assertEquals(cellAgent.networkId, mUNM.getCurrentPreferredUpstream().network);
368
369 // [2] WiFi validates and is promoted to the default network -> WiFi selected.
370 mCM.makeDefaultNetwork(wifiAgent);
371 assertEquals(wifiAgent.networkId, mUNM.getCurrentPreferredUpstream().network);
372
373 // [3] DUN required, no other changes -> WiFi still selected
374 mUNM.updateMobileRequiresDun(true);
375 assertEquals(wifiAgent.networkId, mUNM.getCurrentPreferredUpstream().network);
376
377 // [4] WiFi no longer validated, mobile becomes default, DUN required -> null selected.
378 mCM.makeDefaultNetwork(cellAgent);
379 assertEquals(null, mUNM.getCurrentPreferredUpstream());
380 // TODO: make sure that a DUN request has been filed. This is currently
381 // triggered by code over in Tethering, but once that has been moved
382 // into UNM we should test for this here.
383
384 // [5] DUN network arrives -> DUN selected
385 final TestNetworkAgent dunAgent = new TestNetworkAgent(mCM, TRANSPORT_CELLULAR);
386 dunAgent.networkCapabilities.addCapability(NET_CAPABILITY_DUN);
387 dunAgent.networkCapabilities.removeCapability(NET_CAPABILITY_INTERNET);
388 dunAgent.fakeConnect();
389 assertEquals(dunAgent.networkId, mUNM.getCurrentPreferredUpstream().network);
390 }
391
392 @Test
Erik Kline32179ff2017-07-04 18:28:11 +0900393 public void testLocalPrefixes() throws Exception {
markchiena6c72872018-11-13 18:34:56 +0900394 mUNM.startTrackDefaultNetwork(mDefaultRequest);
395 mUNM.startObserveAllNetworks();
Erik Kline3a5278f2017-06-24 19:29:10 +0900396
Erik Kline32179ff2017-07-04 18:28:11 +0900397 // [0] Test minimum set of local prefixes.
398 Set<IpPrefix> local = mUNM.getLocalPrefixes();
399 assertTrue(local.isEmpty());
400
Erik Kline3a5278f2017-06-24 19:29:10 +0900401 final Set<String> alreadySeen = new HashSet<>();
Erik Kline3a5278f2017-06-24 19:29:10 +0900402
403 // [1] Pretend Wi-Fi connects.
404 final TestNetworkAgent wifiAgent = new TestNetworkAgent(mCM, TRANSPORT_WIFI);
Erik Kline72302902018-06-14 17:36:40 +0900405 final LinkProperties wifiLp = wifiAgent.linkProperties;
Erik Kline3a5278f2017-06-24 19:29:10 +0900406 wifiLp.setInterfaceName("wlan0");
407 final String[] WIFI_ADDRS = {
408 "fe80::827a:bfff:fe6f:374d", "100.112.103.18",
409 "2001:db8:4:fd00:827a:bfff:fe6f:374d",
410 "2001:db8:4:fd00:6dea:325a:fdae:4ef4",
411 "fd6a:a640:60bf:e985::123", // ULA address for good measure.
412 };
413 for (String addrStr : WIFI_ADDRS) {
414 final String cidr = addrStr.contains(":") ? "/64" : "/20";
415 wifiLp.addLinkAddress(new LinkAddress(addrStr + cidr));
416 }
417 wifiAgent.fakeConnect();
Erik Kline72302902018-06-14 17:36:40 +0900418 wifiAgent.sendLinkProperties();
Erik Kline3a5278f2017-06-24 19:29:10 +0900419
Erik Kline32179ff2017-07-04 18:28:11 +0900420 local = mUNM.getLocalPrefixes();
421 assertPrefixSet(local, INCLUDES, alreadySeen);
Erik Kline3a5278f2017-06-24 19:29:10 +0900422 final String[] wifiLinkPrefixes = {
Erik Kline32179ff2017-07-04 18:28:11 +0900423 // Link-local prefixes are excluded and dealt with elsewhere.
Erik Kline3a5278f2017-06-24 19:29:10 +0900424 "100.112.96.0/20", "2001:db8:4:fd00::/64", "fd6a:a640:60bf:e985::/64",
425 };
Erik Kline32179ff2017-07-04 18:28:11 +0900426 assertPrefixSet(local, INCLUDES, wifiLinkPrefixes);
Erik Kline3a5278f2017-06-24 19:29:10 +0900427 Collections.addAll(alreadySeen, wifiLinkPrefixes);
Erik Kline32179ff2017-07-04 18:28:11 +0900428 assertEquals(alreadySeen.size(), local.size());
Erik Kline3a5278f2017-06-24 19:29:10 +0900429
430 // [2] Pretend mobile connects.
431 final TestNetworkAgent cellAgent = new TestNetworkAgent(mCM, TRANSPORT_CELLULAR);
Erik Kline72302902018-06-14 17:36:40 +0900432 final LinkProperties cellLp = cellAgent.linkProperties;
Erik Kline3a5278f2017-06-24 19:29:10 +0900433 cellLp.setInterfaceName("rmnet_data0");
434 final String[] CELL_ADDRS = {
435 "10.102.211.48", "2001:db8:0:1:b50e:70d9:10c9:433d",
436 };
437 for (String addrStr : CELL_ADDRS) {
438 final String cidr = addrStr.contains(":") ? "/64" : "/27";
439 cellLp.addLinkAddress(new LinkAddress(addrStr + cidr));
440 }
441 cellAgent.fakeConnect();
Erik Kline72302902018-06-14 17:36:40 +0900442 cellAgent.sendLinkProperties();
Erik Kline3a5278f2017-06-24 19:29:10 +0900443
Erik Kline32179ff2017-07-04 18:28:11 +0900444 local = mUNM.getLocalPrefixes();
445 assertPrefixSet(local, INCLUDES, alreadySeen);
Erik Kline3a5278f2017-06-24 19:29:10 +0900446 final String[] cellLinkPrefixes = { "10.102.211.32/27", "2001:db8:0:1::/64" };
Erik Kline32179ff2017-07-04 18:28:11 +0900447 assertPrefixSet(local, INCLUDES, cellLinkPrefixes);
Erik Kline3a5278f2017-06-24 19:29:10 +0900448 Collections.addAll(alreadySeen, cellLinkPrefixes);
Erik Kline32179ff2017-07-04 18:28:11 +0900449 assertEquals(alreadySeen.size(), local.size());
Erik Kline3a5278f2017-06-24 19:29:10 +0900450
451 // [3] Pretend DUN connects.
452 final TestNetworkAgent dunAgent = new TestNetworkAgent(mCM, TRANSPORT_CELLULAR);
453 dunAgent.networkCapabilities.addCapability(NET_CAPABILITY_DUN);
Erik Kline72302902018-06-14 17:36:40 +0900454 dunAgent.networkCapabilities.removeCapability(NET_CAPABILITY_INTERNET);
455 final LinkProperties dunLp = dunAgent.linkProperties;
Erik Kline3a5278f2017-06-24 19:29:10 +0900456 dunLp.setInterfaceName("rmnet_data1");
457 final String[] DUN_ADDRS = {
458 "192.0.2.48", "2001:db8:1:2:b50e:70d9:10c9:433d",
459 };
460 for (String addrStr : DUN_ADDRS) {
461 final String cidr = addrStr.contains(":") ? "/64" : "/27";
Erik Kline72302902018-06-14 17:36:40 +0900462 dunLp.addLinkAddress(new LinkAddress(addrStr + cidr));
Erik Kline3a5278f2017-06-24 19:29:10 +0900463 }
464 dunAgent.fakeConnect();
Erik Kline72302902018-06-14 17:36:40 +0900465 dunAgent.sendLinkProperties();
Erik Kline3a5278f2017-06-24 19:29:10 +0900466
Erik Kline32179ff2017-07-04 18:28:11 +0900467 local = mUNM.getLocalPrefixes();
468 assertPrefixSet(local, INCLUDES, alreadySeen);
Erik Kline3a5278f2017-06-24 19:29:10 +0900469 final String[] dunLinkPrefixes = { "192.0.2.32/27", "2001:db8:1:2::/64" };
Erik Kline32179ff2017-07-04 18:28:11 +0900470 assertPrefixSet(local, INCLUDES, dunLinkPrefixes);
Erik Kline3a5278f2017-06-24 19:29:10 +0900471 Collections.addAll(alreadySeen, dunLinkPrefixes);
Erik Kline32179ff2017-07-04 18:28:11 +0900472 assertEquals(alreadySeen.size(), local.size());
Erik Kline3a5278f2017-06-24 19:29:10 +0900473
474 // [4] Pretend Wi-Fi disconnected. It's addresses/prefixes should no
475 // longer be included (should be properly removed).
476 wifiAgent.fakeDisconnect();
Erik Kline32179ff2017-07-04 18:28:11 +0900477 local = mUNM.getLocalPrefixes();
478 assertPrefixSet(local, EXCLUDES, wifiLinkPrefixes);
479 assertPrefixSet(local, INCLUDES, cellLinkPrefixes);
480 assertPrefixSet(local, INCLUDES, dunLinkPrefixes);
markchien69955492018-10-01 21:18:15 +0800481
482 // [5] Pretend mobile disconnected.
483 cellAgent.fakeDisconnect();
484 local = mUNM.getLocalPrefixes();
485 assertPrefixSet(local, EXCLUDES, wifiLinkPrefixes);
486 assertPrefixSet(local, EXCLUDES, cellLinkPrefixes);
487 assertPrefixSet(local, INCLUDES, dunLinkPrefixes);
488
489 // [6] Pretend DUN disconnected.
490 dunAgent.fakeDisconnect();
491 local = mUNM.getLocalPrefixes();
492 assertTrue(local.isEmpty());
Erik Kline3a5278f2017-06-24 19:29:10 +0900493 }
494
Erik Kline1e2897d2017-06-09 17:08:52 +0900495 private void assertSatisfiesLegacyType(int legacyType, NetworkState ns) {
496 if (legacyType == TYPE_NONE) {
497 assertTrue(ns == null);
498 return;
499 }
500
501 final NetworkCapabilities nc = ConnectivityManager.networkCapabilitiesForType(legacyType);
502 assertTrue(nc.satisfiedByNetworkCapabilities(ns.networkCapabilities));
503 }
504
Erik Kline973c7df2017-01-23 15:55:16 +0900505 private void assertUpstreamTypeRequested(int upstreamType) throws Exception {
506 assertEquals(1, mCM.requested.size());
507 assertEquals(1, mCM.legacyTypeMap.size());
508 assertEquals(Integer.valueOf(upstreamType),
509 mCM.legacyTypeMap.values().iterator().next());
510 }
511
Erik Kline7462f462017-01-23 19:05:28 +0900512 public static class TestConnectivityManager extends ConnectivityManager {
Erik Klineb583b032017-02-22 12:58:24 +0900513 public Map<NetworkCallback, Handler> allCallbacks = new HashMap<>();
Erik Kline885a9092017-01-16 16:27:22 +0900514 public Set<NetworkCallback> trackingDefault = new HashSet<>();
Erik Kline72302902018-06-14 17:36:40 +0900515 public TestNetworkAgent defaultNetwork = null;
Erik Kline885a9092017-01-16 16:27:22 +0900516 public Map<NetworkCallback, NetworkRequest> listening = new HashMap<>();
517 public Map<NetworkCallback, NetworkRequest> requested = new HashMap<>();
Erik Klinedd8e8912017-01-18 16:08:06 +0900518 public Map<NetworkCallback, Integer> legacyTypeMap = new HashMap<>();
Erik Kline885a9092017-01-16 16:27:22 +0900519
Erik Kline37609992017-06-05 16:02:02 +0900520 private int mNetworkId = 100;
521
Erik Kline885a9092017-01-16 16:27:22 +0900522 public TestConnectivityManager(Context ctx, IConnectivityManager svc) {
523 super(ctx, svc);
524 }
525
Erik Kline35eee132017-01-17 15:06:35 +0900526 boolean hasNoCallbacks() {
markchiena6c72872018-11-13 18:34:56 +0900527 return allCallbacks.isEmpty()
528 && trackingDefault.isEmpty()
529 && listening.isEmpty()
530 && requested.isEmpty()
531 && legacyTypeMap.isEmpty();
532 }
533
534 boolean onlyHasDefaultCallbacks() {
535 return (allCallbacks.size() == 1)
536 && (trackingDefault.size() == 1)
537 && listening.isEmpty()
538 && requested.isEmpty()
539 && legacyTypeMap.isEmpty();
Erik Kline885a9092017-01-16 16:27:22 +0900540 }
541
Erik Klined2ec3912017-01-25 00:53:04 +0900542 boolean isListeningForAll() {
543 final NetworkCapabilities empty = new NetworkCapabilities();
544 empty.clearAll();
545
Erik Kline885a9092017-01-16 16:27:22 +0900546 for (NetworkRequest req : listening.values()) {
Erik Klined2ec3912017-01-25 00:53:04 +0900547 if (req.networkCapabilities.equalRequestableCapabilities(empty)) {
Erik Kline885a9092017-01-16 16:27:22 +0900548 return true;
549 }
550 }
551 return false;
552 }
553
554 boolean isDunRequested() {
555 for (NetworkRequest req : requested.values()) {
556 if (req.networkCapabilities.hasCapability(NET_CAPABILITY_DUN)) {
557 return true;
558 }
559 }
560 return false;
561 }
562
Erik Kline37609992017-06-05 16:02:02 +0900563 int getNetworkId() { return ++mNetworkId; }
564
Erik Kline72302902018-06-14 17:36:40 +0900565 void makeDefaultNetwork(TestNetworkAgent agent) {
566 if (Objects.equals(defaultNetwork, agent)) return;
567
568 final TestNetworkAgent formerDefault = defaultNetwork;
569 defaultNetwork = agent;
570
571 for (NetworkCallback cb : trackingDefault) {
572 if (defaultNetwork != null) {
573 cb.onAvailable(defaultNetwork.networkId);
574 cb.onCapabilitiesChanged(
575 defaultNetwork.networkId, defaultNetwork.networkCapabilities);
576 cb.onLinkPropertiesChanged(
577 defaultNetwork.networkId, defaultNetwork.linkProperties);
578 }
579 }
580 }
581
Erik Kline885a9092017-01-16 16:27:22 +0900582 @Override
Erik Klineb583b032017-02-22 12:58:24 +0900583 public void requestNetwork(NetworkRequest req, NetworkCallback cb, Handler h) {
584 assertFalse(allCallbacks.containsKey(cb));
585 allCallbacks.put(cb, h);
Erik Kline72302902018-06-14 17:36:40 +0900586 if (mDefaultRequest.equals(req)) {
587 assertFalse(trackingDefault.contains(cb));
588 trackingDefault.add(cb);
589 } else {
590 assertFalse(requested.containsKey(cb));
591 requested.put(cb, req);
592 }
Erik Kline885a9092017-01-16 16:27:22 +0900593 }
594
595 @Override
Erik Klineb583b032017-02-22 12:58:24 +0900596 public void requestNetwork(NetworkRequest req, NetworkCallback cb) {
597 fail("Should never be called.");
598 }
599
600 @Override
Erik Klinedd8e8912017-01-18 16:08:06 +0900601 public void requestNetwork(NetworkRequest req, NetworkCallback cb,
Erik Klineb583b032017-02-22 12:58:24 +0900602 int timeoutMs, int legacyType, Handler h) {
603 assertFalse(allCallbacks.containsKey(cb));
604 allCallbacks.put(cb, h);
Erik Klinedd8e8912017-01-18 16:08:06 +0900605 assertFalse(requested.containsKey(cb));
606 requested.put(cb, req);
607 assertFalse(legacyTypeMap.containsKey(cb));
608 if (legacyType != ConnectivityManager.TYPE_NONE) {
609 legacyTypeMap.put(cb, legacyType);
610 }
611 }
612
613 @Override
Erik Klineb583b032017-02-22 12:58:24 +0900614 public void registerNetworkCallback(NetworkRequest req, NetworkCallback cb, Handler h) {
615 assertFalse(allCallbacks.containsKey(cb));
616 allCallbacks.put(cb, h);
Erik Kline885a9092017-01-16 16:27:22 +0900617 assertFalse(listening.containsKey(cb));
618 listening.put(cb, req);
619 }
620
621 @Override
Erik Klineb583b032017-02-22 12:58:24 +0900622 public void registerNetworkCallback(NetworkRequest req, NetworkCallback cb) {
623 fail("Should never be called.");
624 }
625
626 @Override
627 public void registerDefaultNetworkCallback(NetworkCallback cb, Handler h) {
Erik Kline72302902018-06-14 17:36:40 +0900628 fail("Should never be called.");
Erik Kline885a9092017-01-16 16:27:22 +0900629 }
630
631 @Override
Erik Klineb583b032017-02-22 12:58:24 +0900632 public void registerDefaultNetworkCallback(NetworkCallback cb) {
633 fail("Should never be called.");
634 }
635
636 @Override
Erik Kline885a9092017-01-16 16:27:22 +0900637 public void unregisterNetworkCallback(NetworkCallback cb) {
638 if (trackingDefault.contains(cb)) {
639 trackingDefault.remove(cb);
640 } else if (listening.containsKey(cb)) {
641 listening.remove(cb);
642 } else if (requested.containsKey(cb)) {
643 requested.remove(cb);
Erik Klinedd8e8912017-01-18 16:08:06 +0900644 legacyTypeMap.remove(cb);
Erik Kline35eee132017-01-17 15:06:35 +0900645 } else {
646 fail("Unexpected callback removed");
Erik Kline885a9092017-01-16 16:27:22 +0900647 }
Erik Klineb583b032017-02-22 12:58:24 +0900648 allCallbacks.remove(cb);
Erik Kline885a9092017-01-16 16:27:22 +0900649
Erik Klineb583b032017-02-22 12:58:24 +0900650 assertFalse(allCallbacks.containsKey(cb));
Erik Kline885a9092017-01-16 16:27:22 +0900651 assertFalse(trackingDefault.contains(cb));
652 assertFalse(listening.containsKey(cb));
653 assertFalse(requested.containsKey(cb));
654 }
655 }
Erik Klineb583b032017-02-22 12:58:24 +0900656
Erik Kline37609992017-06-05 16:02:02 +0900657 public static class TestNetworkAgent {
658 public final TestConnectivityManager cm;
659 public final Network networkId;
660 public final int transportType;
661 public final NetworkCapabilities networkCapabilities;
Erik Kline72302902018-06-14 17:36:40 +0900662 public final LinkProperties linkProperties;
Erik Kline37609992017-06-05 16:02:02 +0900663
664 public TestNetworkAgent(TestConnectivityManager cm, int transportType) {
665 this.cm = cm;
666 this.networkId = new Network(cm.getNetworkId());
667 this.transportType = transportType;
668 networkCapabilities = new NetworkCapabilities();
669 networkCapabilities.addTransportType(transportType);
670 networkCapabilities.addCapability(NET_CAPABILITY_INTERNET);
Erik Kline72302902018-06-14 17:36:40 +0900671 linkProperties = new LinkProperties();
Erik Kline37609992017-06-05 16:02:02 +0900672 }
673
674 public void fakeConnect() {
675 for (NetworkCallback cb : cm.listening.keySet()) {
676 cb.onAvailable(networkId);
677 cb.onCapabilitiesChanged(networkId, copy(networkCapabilities));
Erik Kline72302902018-06-14 17:36:40 +0900678 cb.onLinkPropertiesChanged(networkId, copy(linkProperties));
Erik Kline37609992017-06-05 16:02:02 +0900679 }
680 }
681
682 public void fakeDisconnect() {
683 for (NetworkCallback cb : cm.listening.keySet()) {
684 cb.onLost(networkId);
685 }
686 }
Erik Kline3a5278f2017-06-24 19:29:10 +0900687
Erik Kline72302902018-06-14 17:36:40 +0900688 public void sendLinkProperties() {
Erik Kline3a5278f2017-06-24 19:29:10 +0900689 for (NetworkCallback cb : cm.listening.keySet()) {
Erik Kline72302902018-06-14 17:36:40 +0900690 cb.onLinkPropertiesChanged(networkId, copy(linkProperties));
Erik Kline3a5278f2017-06-24 19:29:10 +0900691 }
692 }
Erik Kline72302902018-06-14 17:36:40 +0900693
694 @Override
695 public String toString() {
696 return String.format("TestNetworkAgent: %s %s", networkId, networkCapabilities);
697 }
Erik Kline37609992017-06-05 16:02:02 +0900698 }
699
Erik Klineb583b032017-02-22 12:58:24 +0900700 public static class TestStateMachine extends StateMachine {
701 public final ArrayList<Message> messages = new ArrayList<>();
702 private final State mLoggingState = new LoggingState();
703
704 class LoggingState extends State {
705 @Override public void enter() { messages.clear(); }
706
707 @Override public void exit() { messages.clear(); }
708
709 @Override public boolean processMessage(Message msg) {
710 messages.add(msg);
711 return true;
712 }
713 }
714
715 public TestStateMachine() {
716 super("UpstreamNetworkMonitor.TestStateMachine");
717 addState(mLoggingState);
718 setInitialState(mLoggingState);
719 super.start();
720 }
721 }
Erik Kline37609992017-06-05 16:02:02 +0900722
723 static NetworkCapabilities copy(NetworkCapabilities nc) {
724 return new NetworkCapabilities(nc);
725 }
Erik Kline3a5278f2017-06-24 19:29:10 +0900726
Erik Kline72302902018-06-14 17:36:40 +0900727 static LinkProperties copy(LinkProperties lp) {
728 return new LinkProperties(lp);
729 }
730
Erik Kline3a5278f2017-06-24 19:29:10 +0900731 static void assertPrefixSet(Set<IpPrefix> prefixes, boolean expectation, String... expected) {
732 final Set<String> expectedSet = new HashSet<>();
733 Collections.addAll(expectedSet, expected);
734 assertPrefixSet(prefixes, expectation, expectedSet);
735 }
736
737 static void assertPrefixSet(Set<IpPrefix> prefixes, boolean expectation, Set<String> expected) {
738 for (String expectedPrefix : expected) {
739 final String errStr = expectation ? "did not find" : "found";
740 assertEquals(
741 String.format("Failed expectation: %s prefix: %s", errStr, expectedPrefix),
742 expectation, prefixes.contains(new IpPrefix(expectedPrefix)));
743 }
744 }
Erik Kline885a9092017-01-16 16:27:22 +0900745}