1 /* 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 17 package com.android.networkstack.tethering; 18 19 import static android.net.ConnectivityManager.TYPE_MOBILE_DUN; 20 import static android.net.ConnectivityManager.TYPE_MOBILE_HIPRI; 21 import static android.net.ConnectivityManager.TYPE_WIFI; 22 import static android.net.NetworkCapabilities.NET_CAPABILITY_DUN; 23 import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET; 24 import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR; 25 import static android.net.NetworkCapabilities.TRANSPORT_WIFI; 26 27 import static com.android.modules.utils.build.SdkLevel.isAtLeastS; 28 import static com.android.networkstack.tethering.UpstreamNetworkMonitor.TYPE_NONE; 29 30 import static org.junit.Assert.assertEquals; 31 import static org.junit.Assert.assertFalse; 32 import static org.junit.Assert.assertTrue; 33 import static org.mockito.ArgumentMatchers.eq; 34 import static org.mockito.Mockito.any; 35 import static org.mockito.Mockito.anyInt; 36 import static org.mockito.Mockito.anyString; 37 import static org.mockito.Mockito.reset; 38 import static org.mockito.Mockito.spy; 39 import static org.mockito.Mockito.times; 40 import static org.mockito.Mockito.verify; 41 import static org.mockito.Mockito.verifyNoMoreInteractions; 42 import static org.mockito.Mockito.when; 43 44 import android.content.Context; 45 import android.net.ConnectivityManager.NetworkCallback; 46 import android.net.IConnectivityManager; 47 import android.net.IpPrefix; 48 import android.net.LinkAddress; 49 import android.net.LinkProperties; 50 import android.net.NetworkCapabilities; 51 import android.net.NetworkRequest; 52 import android.net.util.SharedLog; 53 import android.os.Handler; 54 import android.os.Looper; 55 import android.os.Message; 56 import android.os.test.TestLooper; 57 58 import androidx.test.filters.SmallTest; 59 import androidx.test.runner.AndroidJUnit4; 60 61 import com.android.internal.util.State; 62 import com.android.internal.util.StateMachine; 63 import com.android.networkstack.tethering.TestConnectivityManager.NetworkRequestInfo; 64 import com.android.networkstack.tethering.TestConnectivityManager.TestNetworkAgent; 65 66 import org.junit.After; 67 import org.junit.Before; 68 import org.junit.Test; 69 import org.junit.runner.RunWith; 70 import org.mockito.ArgumentCaptor; 71 import org.mockito.Mock; 72 import org.mockito.MockitoAnnotations; 73 74 import java.util.ArrayList; 75 import java.util.Collection; 76 import java.util.Collections; 77 import java.util.HashSet; 78 import java.util.Set; 79 80 @RunWith(AndroidJUnit4.class) 81 @SmallTest 82 public class UpstreamNetworkMonitorTest { 83 private static final int EVENT_UNM_UPDATE = 1; 84 85 private static final boolean INCLUDES = true; 86 private static final boolean EXCLUDES = false; 87 88 private static final NetworkCapabilities CELL_CAPABILITIES = new NetworkCapabilities.Builder() 89 .addTransportType(TRANSPORT_CELLULAR).addCapability(NET_CAPABILITY_INTERNET).build(); 90 private static final NetworkCapabilities DUN_CAPABILITIES = new NetworkCapabilities.Builder() 91 .addTransportType(TRANSPORT_CELLULAR).addCapability(NET_CAPABILITY_DUN).build(); 92 private static final NetworkCapabilities WIFI_CAPABILITIES = new NetworkCapabilities.Builder() 93 .addTransportType(TRANSPORT_WIFI).addCapability(NET_CAPABILITY_INTERNET).build(); 94 95 @Mock private Context mContext; 96 @Mock private EntitlementManager mEntitleMgr; 97 @Mock private IConnectivityManager mCS; 98 @Mock private SharedLog mLog; 99 100 private TestStateMachine mSM; 101 private TestConnectivityManager mCM; 102 private UpstreamNetworkMonitor mUNM; 103 104 private final TestLooper mLooper = new TestLooper(); 105 setUp()106 @Before public void setUp() throws Exception { 107 MockitoAnnotations.initMocks(this); 108 reset(mContext); 109 reset(mCS); 110 reset(mLog); 111 when(mLog.forSubComponent(anyString())).thenReturn(mLog); 112 when(mEntitleMgr.isCellularUpstreamPermitted()).thenReturn(true); 113 114 mCM = spy(new TestConnectivityManager(mContext, mCS)); 115 when(mContext.getSystemService(eq(Context.CONNECTIVITY_SERVICE))).thenReturn(mCM); 116 mSM = new TestStateMachine(mLooper.getLooper()); 117 mUNM = new UpstreamNetworkMonitor(mContext, mSM, mLog, EVENT_UNM_UPDATE); 118 } 119 tearDown()120 @After public void tearDown() throws Exception { 121 if (mSM != null) { 122 mSM.quit(); 123 mSM = null; 124 } 125 } 126 127 @Test testStopWithoutStartIsNonFatal()128 public void testStopWithoutStartIsNonFatal() { 129 mUNM.stop(); 130 mUNM.stop(); 131 mUNM.stop(); 132 } 133 134 @Test testDoesNothingBeforeTrackDefaultAndStarted()135 public void testDoesNothingBeforeTrackDefaultAndStarted() throws Exception { 136 assertTrue(mCM.hasNoCallbacks()); 137 assertFalse(mUNM.mobileNetworkRequested()); 138 139 mUNM.setUpstreamConfig(false /* autoUpstream */, true /* dunRequired */); 140 assertTrue(mCM.hasNoCallbacks()); 141 mUNM.setUpstreamConfig(false /* autoUpstream */, false /* dunRequired */); 142 assertTrue(mCM.hasNoCallbacks()); 143 } 144 145 @Test testDefaultNetworkIsTracked()146 public void testDefaultNetworkIsTracked() throws Exception { 147 assertTrue(mCM.hasNoCallbacks()); 148 mUNM.startTrackDefaultNetwork(mEntitleMgr); 149 150 mUNM.startObserveAllNetworks(); 151 assertEquals(1, mCM.mTrackingDefault.size()); 152 153 mUNM.stop(); 154 assertTrue(mCM.onlyHasDefaultCallbacks()); 155 } 156 157 @Test testListensForAllNetworks()158 public void testListensForAllNetworks() throws Exception { 159 assertTrue(mCM.mListening.isEmpty()); 160 161 mUNM.startTrackDefaultNetwork(mEntitleMgr); 162 mUNM.startObserveAllNetworks(); 163 assertFalse(mCM.mListening.isEmpty()); 164 assertTrue(mCM.isListeningForAll()); 165 166 mUNM.stop(); 167 assertTrue(mCM.onlyHasDefaultCallbacks()); 168 } 169 170 @Test testCallbacksRegistered()171 public void testCallbacksRegistered() { 172 mUNM.startTrackDefaultNetwork(mEntitleMgr); 173 // Verify the fired default request matches expectation. 174 final ArgumentCaptor<NetworkRequest> requestCaptor = 175 ArgumentCaptor.forClass(NetworkRequest.class); 176 177 if (isAtLeastS()) { 178 verify(mCM).registerSystemDefaultNetworkCallback(any(), any()); 179 } else { 180 verify(mCM).requestNetwork( 181 requestCaptor.capture(), any(NetworkCallback.class), any(Handler.class)); 182 // For R- devices, Tethering will invoke this function in 2 cases, one is to 183 // request mobile network, the other is to track system default network. Verify 184 // the request is the one tracks default network. 185 assertTrue(TestConnectivityManager.looksLikeDefaultRequest(requestCaptor.getValue())); 186 } 187 188 mUNM.startObserveAllNetworks(); 189 verify(mCM, times(1)).registerNetworkCallback( 190 any(NetworkRequest.class), any(NetworkCallback.class), any(Handler.class)); 191 192 mUNM.stop(); 193 verify(mCM, times(1)).unregisterNetworkCallback(any(NetworkCallback.class)); 194 } 195 196 @Test testRequestsMobileNetwork()197 public void testRequestsMobileNetwork() throws Exception { 198 assertFalse(mUNM.mobileNetworkRequested()); 199 assertEquals(0, mCM.mRequested.size()); 200 201 mUNM.startObserveAllNetworks(); 202 assertFalse(mUNM.mobileNetworkRequested()); 203 assertEquals(0, mCM.mRequested.size()); 204 205 mUNM.setUpstreamConfig(false /* autoUpstream */, false /* dunRequired */); 206 assertFalse(mUNM.mobileNetworkRequested()); 207 assertEquals(0, mCM.mRequested.size()); 208 209 mUNM.setTryCell(true); 210 assertTrue(mUNM.mobileNetworkRequested()); 211 assertUpstreamTypeRequested(TYPE_MOBILE_HIPRI); 212 assertFalse(isDunRequested()); 213 214 mUNM.stop(); 215 assertFalse(mUNM.mobileNetworkRequested()); 216 assertTrue(mCM.hasNoCallbacks()); 217 } 218 219 @Test testDuplicateMobileRequestsIgnored()220 public void testDuplicateMobileRequestsIgnored() throws Exception { 221 assertFalse(mUNM.mobileNetworkRequested()); 222 assertEquals(0, mCM.mRequested.size()); 223 224 mUNM.startObserveAllNetworks(); 225 verify(mCM, times(1)).registerNetworkCallback( 226 any(NetworkRequest.class), any(NetworkCallback.class), any(Handler.class)); 227 assertFalse(mUNM.mobileNetworkRequested()); 228 assertEquals(0, mCM.mRequested.size()); 229 230 mUNM.setUpstreamConfig(false /* autoUpstream */, true /* dunRequired */); 231 mUNM.setTryCell(true); 232 verify(mCM, times(1)).requestNetwork( 233 any(NetworkRequest.class), anyInt(), anyInt(), any(Handler.class), 234 any(NetworkCallback.class)); 235 236 assertTrue(mUNM.mobileNetworkRequested()); 237 assertUpstreamTypeRequested(TYPE_MOBILE_DUN); 238 assertTrue(isDunRequested()); 239 240 // Try a few things that must not result in any state change. 241 mUNM.setTryCell(true); 242 mUNM.setUpstreamConfig(false /* autoUpstream */, true /* dunRequired */); 243 mUNM.setTryCell(true); 244 245 assertTrue(mUNM.mobileNetworkRequested()); 246 assertUpstreamTypeRequested(TYPE_MOBILE_DUN); 247 assertTrue(isDunRequested()); 248 249 mUNM.stop(); 250 verify(mCM, times(2)).unregisterNetworkCallback(any(NetworkCallback.class)); 251 252 verifyNoMoreInteractions(mCM); 253 } 254 255 @Test testRequestsDunNetwork()256 public void testRequestsDunNetwork() throws Exception { 257 assertFalse(mUNM.mobileNetworkRequested()); 258 assertEquals(0, mCM.mRequested.size()); 259 260 mUNM.startObserveAllNetworks(); 261 assertFalse(mUNM.mobileNetworkRequested()); 262 assertEquals(0, mCM.mRequested.size()); 263 264 mUNM.setUpstreamConfig(false /* autoUpstream */, true /* dunRequired */); 265 assertFalse(mUNM.mobileNetworkRequested()); 266 assertEquals(0, mCM.mRequested.size()); 267 268 mUNM.setTryCell(true); 269 assertTrue(mUNM.mobileNetworkRequested()); 270 assertUpstreamTypeRequested(TYPE_MOBILE_DUN); 271 assertTrue(isDunRequested()); 272 273 mUNM.stop(); 274 assertFalse(mUNM.mobileNetworkRequested()); 275 assertTrue(mCM.hasNoCallbacks()); 276 } 277 278 @Test testUpdateMobileRequiresDun()279 public void testUpdateMobileRequiresDun() throws Exception { 280 mUNM.startObserveAllNetworks(); 281 282 // Test going from no-DUN to DUN correctly re-registers callbacks. 283 mUNM.setUpstreamConfig(false /* autoUpstream */, false /* dunRequired */); 284 mUNM.setTryCell(true); 285 assertTrue(mUNM.mobileNetworkRequested()); 286 assertUpstreamTypeRequested(TYPE_MOBILE_HIPRI); 287 assertFalse(isDunRequested()); 288 mUNM.setUpstreamConfig(false /* autoUpstream */, true /* dunRequired */); 289 assertTrue(mUNM.mobileNetworkRequested()); 290 assertUpstreamTypeRequested(TYPE_MOBILE_DUN); 291 assertTrue(isDunRequested()); 292 293 // Test going from DUN to no-DUN correctly re-registers callbacks. 294 mUNM.setUpstreamConfig(false /* autoUpstream */, false /* dunRequired */); 295 assertTrue(mUNM.mobileNetworkRequested()); 296 assertUpstreamTypeRequested(TYPE_MOBILE_HIPRI); 297 assertFalse(isDunRequested()); 298 299 mUNM.stop(); 300 assertFalse(mUNM.mobileNetworkRequested()); 301 } 302 303 @Test testSelectPreferredUpstreamType()304 public void testSelectPreferredUpstreamType() throws Exception { 305 final Collection<Integer> preferredTypes = new ArrayList<>(); 306 preferredTypes.add(TYPE_WIFI); 307 308 mUNM.startTrackDefaultNetwork(mEntitleMgr); 309 mUNM.startObserveAllNetworks(); 310 // There are no networks, so there is nothing to select. 311 assertSatisfiesLegacyType(TYPE_NONE, mUNM.selectPreferredUpstreamType(preferredTypes)); 312 313 final TestNetworkAgent wifiAgent = new TestNetworkAgent(mCM, WIFI_CAPABILITIES); 314 wifiAgent.fakeConnect(); 315 mLooper.dispatchAll(); 316 // WiFi is up, we should prefer it. 317 assertSatisfiesLegacyType(TYPE_WIFI, mUNM.selectPreferredUpstreamType(preferredTypes)); 318 wifiAgent.fakeDisconnect(); 319 mLooper.dispatchAll(); 320 // There are no networks, so there is nothing to select. 321 assertSatisfiesLegacyType(TYPE_NONE, mUNM.selectPreferredUpstreamType(preferredTypes)); 322 323 final TestNetworkAgent cellAgent = new TestNetworkAgent(mCM, CELL_CAPABILITIES); 324 cellAgent.fakeConnect(); 325 mLooper.dispatchAll(); 326 assertSatisfiesLegacyType(TYPE_NONE, mUNM.selectPreferredUpstreamType(preferredTypes)); 327 328 preferredTypes.add(TYPE_MOBILE_DUN); 329 // This is coupled with preferred types in TetheringConfiguration. 330 mUNM.setUpstreamConfig(false /* autoUpstream */, true /* dunRequired */); 331 // DUN is available, but only use regular cell: no upstream selected. 332 assertSatisfiesLegacyType(TYPE_NONE, mUNM.selectPreferredUpstreamType(preferredTypes)); 333 preferredTypes.remove(TYPE_MOBILE_DUN); 334 // No WiFi, but our preferred flavour of cell is up. 335 preferredTypes.add(TYPE_MOBILE_HIPRI); 336 // This is coupled with preferred types in TetheringConfiguration. 337 mUNM.setUpstreamConfig(false /* autoUpstream */, false /* dunRequired */); 338 assertSatisfiesLegacyType(TYPE_MOBILE_HIPRI, 339 mUNM.selectPreferredUpstreamType(preferredTypes)); 340 // mobile is not permitted, we should not use HIPRI. 341 when(mEntitleMgr.isCellularUpstreamPermitted()).thenReturn(false); 342 assertSatisfiesLegacyType(TYPE_NONE, mUNM.selectPreferredUpstreamType(preferredTypes)); 343 when(mEntitleMgr.isCellularUpstreamPermitted()).thenReturn(true); 344 assertSatisfiesLegacyType(TYPE_MOBILE_HIPRI, 345 mUNM.selectPreferredUpstreamType(preferredTypes)); 346 347 wifiAgent.fakeConnect(); 348 mLooper.dispatchAll(); 349 // WiFi is up, and we should prefer it over cell. 350 assertSatisfiesLegacyType(TYPE_WIFI, mUNM.selectPreferredUpstreamType(preferredTypes)); 351 352 preferredTypes.remove(TYPE_MOBILE_HIPRI); 353 preferredTypes.add(TYPE_MOBILE_DUN); 354 // This is coupled with preferred types in TetheringConfiguration. 355 mUNM.setUpstreamConfig(false /* autoUpstream */, true /* dunRequired */); 356 assertSatisfiesLegacyType(TYPE_WIFI, mUNM.selectPreferredUpstreamType(preferredTypes)); 357 358 final TestNetworkAgent dunAgent = new TestNetworkAgent(mCM, DUN_CAPABILITIES); 359 dunAgent.fakeConnect(); 360 mLooper.dispatchAll(); 361 362 // WiFi is still preferred. 363 assertSatisfiesLegacyType(TYPE_WIFI, mUNM.selectPreferredUpstreamType(preferredTypes)); 364 365 // WiFi goes down, cell and DUN are still up but only DUN is preferred. 366 wifiAgent.fakeDisconnect(); 367 mLooper.dispatchAll(); 368 assertSatisfiesLegacyType(TYPE_MOBILE_DUN, 369 mUNM.selectPreferredUpstreamType(preferredTypes)); 370 // mobile is not permitted, we should not use DUN. 371 when(mEntitleMgr.isCellularUpstreamPermitted()).thenReturn(false); 372 assertSatisfiesLegacyType(TYPE_NONE, mUNM.selectPreferredUpstreamType(preferredTypes)); 373 // mobile change back to permitted, DUN should come back 374 when(mEntitleMgr.isCellularUpstreamPermitted()).thenReturn(true); 375 assertSatisfiesLegacyType(TYPE_MOBILE_DUN, 376 mUNM.selectPreferredUpstreamType(preferredTypes)); 377 } 378 379 @Test testGetCurrentPreferredUpstream()380 public void testGetCurrentPreferredUpstream() throws Exception { 381 mUNM.startTrackDefaultNetwork(mEntitleMgr); 382 mUNM.startObserveAllNetworks(); 383 mUNM.setUpstreamConfig(true /* autoUpstream */, false /* dunRequired */); 384 mUNM.setTryCell(true); 385 386 // [0] Mobile connects, DUN not required -> mobile selected. 387 final TestNetworkAgent cellAgent = new TestNetworkAgent(mCM, CELL_CAPABILITIES); 388 cellAgent.fakeConnect(); 389 mCM.makeDefaultNetwork(cellAgent); 390 mLooper.dispatchAll(); 391 assertEquals(cellAgent.networkId, mUNM.getCurrentPreferredUpstream().network); 392 assertEquals(0, mCM.mRequested.size()); 393 394 // [1] Mobile connects but not permitted -> null selected 395 when(mEntitleMgr.isCellularUpstreamPermitted()).thenReturn(false); 396 assertEquals(null, mUNM.getCurrentPreferredUpstream()); 397 when(mEntitleMgr.isCellularUpstreamPermitted()).thenReturn(true); 398 assertEquals(0, mCM.mRequested.size()); 399 400 // [2] WiFi connects but not validated/promoted to default -> mobile selected. 401 final TestNetworkAgent wifiAgent = new TestNetworkAgent(mCM, WIFI_CAPABILITIES); 402 wifiAgent.fakeConnect(); 403 mLooper.dispatchAll(); 404 assertEquals(cellAgent.networkId, mUNM.getCurrentPreferredUpstream().network); 405 assertEquals(0, mCM.mRequested.size()); 406 407 // [3] WiFi validates and is promoted to the default network -> WiFi selected. 408 mCM.makeDefaultNetwork(wifiAgent); 409 mLooper.dispatchAll(); 410 assertEquals(wifiAgent.networkId, mUNM.getCurrentPreferredUpstream().network); 411 assertEquals(0, mCM.mRequested.size()); 412 413 // [4] DUN required, no other changes -> WiFi still selected 414 mUNM.setUpstreamConfig(false /* autoUpstream */, true /* dunRequired */); 415 assertEquals(wifiAgent.networkId, mUNM.getCurrentPreferredUpstream().network); 416 assertEquals(1, mCM.mRequested.size()); 417 assertTrue(isDunRequested()); 418 419 // [5] WiFi no longer validated, mobile becomes default, DUN required -> null selected. 420 mCM.makeDefaultNetwork(cellAgent); 421 mLooper.dispatchAll(); 422 assertEquals(null, mUNM.getCurrentPreferredUpstream()); 423 assertEquals(1, mCM.mRequested.size()); 424 assertTrue(isDunRequested()); 425 426 // [6] DUN network arrives -> DUN selected 427 final TestNetworkAgent dunAgent = new TestNetworkAgent(mCM, CELL_CAPABILITIES); 428 dunAgent.networkCapabilities.addCapability(NET_CAPABILITY_DUN); 429 dunAgent.networkCapabilities.removeCapability(NET_CAPABILITY_INTERNET); 430 dunAgent.fakeConnect(); 431 mLooper.dispatchAll(); 432 assertEquals(dunAgent.networkId, mUNM.getCurrentPreferredUpstream().network); 433 assertEquals(1, mCM.mRequested.size()); 434 435 // [7] Mobile is not permitted -> null selected 436 when(mEntitleMgr.isCellularUpstreamPermitted()).thenReturn(false); 437 assertEquals(null, mUNM.getCurrentPreferredUpstream()); 438 assertEquals(1, mCM.mRequested.size()); 439 440 // [7] Mobile is permitted again -> DUN selected 441 when(mEntitleMgr.isCellularUpstreamPermitted()).thenReturn(true); 442 assertEquals(dunAgent.networkId, mUNM.getCurrentPreferredUpstream().network); 443 assertEquals(1, mCM.mRequested.size()); 444 445 // [8] DUN no longer required -> request is withdrawn 446 mUNM.setUpstreamConfig(true /* autoUpstream */, false /* dunRequired */); 447 assertEquals(0, mCM.mRequested.size()); 448 assertFalse(isDunRequested()); 449 } 450 451 @Test testLocalPrefixes()452 public void testLocalPrefixes() throws Exception { 453 mUNM.startTrackDefaultNetwork(mEntitleMgr); 454 mUNM.startObserveAllNetworks(); 455 456 // [0] Test minimum set of local prefixes. 457 Set<IpPrefix> local = mUNM.getLocalPrefixes(); 458 assertTrue(local.isEmpty()); 459 460 final Set<String> alreadySeen = new HashSet<>(); 461 462 // [1] Pretend Wi-Fi connects. 463 final TestNetworkAgent wifiAgent = new TestNetworkAgent(mCM, WIFI_CAPABILITIES); 464 final LinkProperties wifiLp = wifiAgent.linkProperties; 465 wifiLp.setInterfaceName("wlan0"); 466 final String[] wifi_addrs = { 467 "fe80::827a:bfff:fe6f:374d", "100.112.103.18", 468 "2001:db8:4:fd00:827a:bfff:fe6f:374d", 469 "2001:db8:4:fd00:6dea:325a:fdae:4ef4", 470 "fd6a:a640:60bf:e985::123", // ULA address for good measure. 471 }; 472 for (String addrStr : wifi_addrs) { 473 final String cidr = addrStr.contains(":") ? "/64" : "/20"; 474 wifiLp.addLinkAddress(new LinkAddress(addrStr + cidr)); 475 } 476 wifiAgent.fakeConnect(); 477 wifiAgent.sendLinkProperties(); 478 mLooper.dispatchAll(); 479 480 local = mUNM.getLocalPrefixes(); 481 assertPrefixSet(local, INCLUDES, alreadySeen); 482 final String[] wifiLinkPrefixes = { 483 // Link-local prefixes are excluded and dealt with elsewhere. 484 "100.112.96.0/20", "2001:db8:4:fd00::/64", "fd6a:a640:60bf:e985::/64", 485 }; 486 assertPrefixSet(local, INCLUDES, wifiLinkPrefixes); 487 Collections.addAll(alreadySeen, wifiLinkPrefixes); 488 assertEquals(alreadySeen.size(), local.size()); 489 490 // [2] Pretend mobile connects. 491 final TestNetworkAgent cellAgent = new TestNetworkAgent(mCM, CELL_CAPABILITIES); 492 final LinkProperties cellLp = cellAgent.linkProperties; 493 cellLp.setInterfaceName("rmnet_data0"); 494 final String[] cell_addrs = { 495 "10.102.211.48", "2001:db8:0:1:b50e:70d9:10c9:433d", 496 }; 497 for (String addrStr : cell_addrs) { 498 final String cidr = addrStr.contains(":") ? "/64" : "/27"; 499 cellLp.addLinkAddress(new LinkAddress(addrStr + cidr)); 500 } 501 cellAgent.fakeConnect(); 502 cellAgent.sendLinkProperties(); 503 mLooper.dispatchAll(); 504 505 local = mUNM.getLocalPrefixes(); 506 assertPrefixSet(local, INCLUDES, alreadySeen); 507 final String[] cellLinkPrefixes = { "10.102.211.32/27", "2001:db8:0:1::/64" }; 508 assertPrefixSet(local, INCLUDES, cellLinkPrefixes); 509 Collections.addAll(alreadySeen, cellLinkPrefixes); 510 assertEquals(alreadySeen.size(), local.size()); 511 512 // [3] Pretend DUN connects. 513 final TestNetworkAgent dunAgent = new TestNetworkAgent(mCM, DUN_CAPABILITIES); 514 final LinkProperties dunLp = dunAgent.linkProperties; 515 dunLp.setInterfaceName("rmnet_data1"); 516 final String[] dun_addrs = { 517 "192.0.2.48", "2001:db8:1:2:b50e:70d9:10c9:433d", 518 }; 519 for (String addrStr : dun_addrs) { 520 final String cidr = addrStr.contains(":") ? "/64" : "/27"; 521 dunLp.addLinkAddress(new LinkAddress(addrStr + cidr)); 522 } 523 dunAgent.fakeConnect(); 524 dunAgent.sendLinkProperties(); 525 mLooper.dispatchAll(); 526 527 local = mUNM.getLocalPrefixes(); 528 assertPrefixSet(local, INCLUDES, alreadySeen); 529 final String[] dunLinkPrefixes = { "192.0.2.32/27", "2001:db8:1:2::/64" }; 530 assertPrefixSet(local, INCLUDES, dunLinkPrefixes); 531 Collections.addAll(alreadySeen, dunLinkPrefixes); 532 assertEquals(alreadySeen.size(), local.size()); 533 534 // [4] Pretend Wi-Fi disconnected. It's addresses/prefixes should no 535 // longer be included (should be properly removed). 536 wifiAgent.fakeDisconnect(); 537 mLooper.dispatchAll(); 538 local = mUNM.getLocalPrefixes(); 539 assertPrefixSet(local, EXCLUDES, wifiLinkPrefixes); 540 assertPrefixSet(local, INCLUDES, cellLinkPrefixes); 541 assertPrefixSet(local, INCLUDES, dunLinkPrefixes); 542 543 // [5] Pretend mobile disconnected. 544 cellAgent.fakeDisconnect(); 545 mLooper.dispatchAll(); 546 local = mUNM.getLocalPrefixes(); 547 assertPrefixSet(local, EXCLUDES, wifiLinkPrefixes); 548 assertPrefixSet(local, EXCLUDES, cellLinkPrefixes); 549 assertPrefixSet(local, INCLUDES, dunLinkPrefixes); 550 551 // [6] Pretend DUN disconnected. 552 dunAgent.fakeDisconnect(); 553 mLooper.dispatchAll(); 554 local = mUNM.getLocalPrefixes(); 555 assertTrue(local.isEmpty()); 556 } 557 558 @Test testSelectMobileWhenMobileIsNotDefault()559 public void testSelectMobileWhenMobileIsNotDefault() { 560 final Collection<Integer> preferredTypes = new ArrayList<>(); 561 // Mobile has higher pirority than wifi. 562 preferredTypes.add(TYPE_MOBILE_HIPRI); 563 preferredTypes.add(TYPE_WIFI); 564 mUNM.startTrackDefaultNetwork(mEntitleMgr); 565 mUNM.startObserveAllNetworks(); 566 // Setup wifi and make wifi as default network. 567 final TestNetworkAgent wifiAgent = new TestNetworkAgent(mCM, WIFI_CAPABILITIES); 568 wifiAgent.fakeConnect(); 569 mCM.makeDefaultNetwork(wifiAgent); 570 // Setup mobile network. 571 final TestNetworkAgent cellAgent = new TestNetworkAgent(mCM, CELL_CAPABILITIES); 572 cellAgent.fakeConnect(); 573 mLooper.dispatchAll(); 574 575 assertSatisfiesLegacyType(TYPE_MOBILE_HIPRI, 576 mUNM.selectPreferredUpstreamType(preferredTypes)); 577 verify(mEntitleMgr, times(1)).maybeRunProvisioning(); 578 } 579 assertSatisfiesLegacyType(int legacyType, UpstreamNetworkState ns)580 private void assertSatisfiesLegacyType(int legacyType, UpstreamNetworkState ns) { 581 if (legacyType == TYPE_NONE) { 582 assertTrue(ns == null); 583 return; 584 } 585 586 final NetworkCapabilities nc = 587 UpstreamNetworkMonitor.networkCapabilitiesForType(legacyType); 588 assertTrue(nc.satisfiedByNetworkCapabilities(ns.networkCapabilities)); 589 } 590 assertUpstreamTypeRequested(int upstreamType)591 private void assertUpstreamTypeRequested(int upstreamType) throws Exception { 592 assertEquals(1, mCM.mRequested.size()); 593 assertEquals(1, mCM.mLegacyTypeMap.size()); 594 assertEquals(Integer.valueOf(upstreamType), 595 mCM.mLegacyTypeMap.values().iterator().next()); 596 } 597 isDunRequested()598 private boolean isDunRequested() { 599 for (NetworkRequestInfo nri : mCM.mRequested.values()) { 600 if (nri.request.networkCapabilities.hasCapability(NET_CAPABILITY_DUN)) { 601 return true; 602 } 603 } 604 return false; 605 } 606 607 public static class TestStateMachine extends StateMachine { 608 public final ArrayList<Message> messages = new ArrayList<>(); 609 private final State mLoggingState = new LoggingState(); 610 611 class LoggingState extends State { enter()612 @Override public void enter() { 613 messages.clear(); 614 } 615 exit()616 @Override public void exit() { 617 messages.clear(); 618 } 619 processMessage(Message msg)620 @Override public boolean processMessage(Message msg) { 621 messages.add(msg); 622 return true; 623 } 624 } 625 TestStateMachine(Looper looper)626 public TestStateMachine(Looper looper) { 627 super("UpstreamNetworkMonitor.TestStateMachine", looper); 628 addState(mLoggingState); 629 setInitialState(mLoggingState); 630 super.start(); 631 } 632 } 633 assertPrefixSet(Set<IpPrefix> prefixes, boolean expectation, String... expected)634 static void assertPrefixSet(Set<IpPrefix> prefixes, boolean expectation, String... expected) { 635 final Set<String> expectedSet = new HashSet<>(); 636 Collections.addAll(expectedSet, expected); 637 assertPrefixSet(prefixes, expectation, expectedSet); 638 } 639 assertPrefixSet(Set<IpPrefix> prefixes, boolean expectation, Set<String> expected)640 static void assertPrefixSet(Set<IpPrefix> prefixes, boolean expectation, Set<String> expected) { 641 for (String expectedPrefix : expected) { 642 final String errStr = expectation ? "did not find" : "found"; 643 assertEquals( 644 String.format("Failed expectation: %s prefix: %s", errStr, expectedPrefix), 645 expectation, prefixes.contains(new IpPrefix(expectedPrefix))); 646 } 647 } 648 } 649