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