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