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