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 android.net; 18 19 import static android.net.ConnectivityManager.TYPE_NONE; 20 import static android.net.NetworkCapabilities.NET_CAPABILITY_CBS; 21 import static android.net.NetworkCapabilities.NET_CAPABILITY_DUN; 22 import static android.net.NetworkCapabilities.NET_CAPABILITY_FOTA; 23 import static android.net.NetworkCapabilities.NET_CAPABILITY_IMS; 24 import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET; 25 import static android.net.NetworkCapabilities.NET_CAPABILITY_MMS; 26 import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED; 27 import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VPN; 28 import static android.net.NetworkCapabilities.NET_CAPABILITY_SUPL; 29 import static android.net.NetworkCapabilities.NET_CAPABILITY_TRUSTED; 30 import static android.net.NetworkCapabilities.NET_CAPABILITY_WIFI_P2P; 31 import static android.net.NetworkCapabilities.TRANSPORT_BLUETOOTH; 32 import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR; 33 import static android.net.NetworkCapabilities.TRANSPORT_ETHERNET; 34 import static android.net.NetworkCapabilities.TRANSPORT_WIFI; 35 import static android.net.NetworkRequest.Type.BACKGROUND_REQUEST; 36 import static android.net.NetworkRequest.Type.REQUEST; 37 import static android.net.NetworkRequest.Type.TRACK_DEFAULT; 38 import static android.net.NetworkRequest.Type.TRACK_SYSTEM_DEFAULT; 39 40 import static com.android.testutils.MiscAsserts.assertThrows; 41 42 import static org.junit.Assert.assertFalse; 43 import static org.junit.Assert.assertNotNull; 44 import static org.junit.Assert.assertNull; 45 import static org.junit.Assert.assertTrue; 46 import static org.junit.Assert.fail; 47 import static org.mockito.ArgumentMatchers.anyBoolean; 48 import static org.mockito.ArgumentMatchers.eq; 49 import static org.mockito.ArgumentMatchers.nullable; 50 import static org.mockito.Mockito.CALLS_REAL_METHODS; 51 import static org.mockito.Mockito.after; 52 import static org.mockito.Mockito.any; 53 import static org.mockito.Mockito.anyInt; 54 import static org.mockito.Mockito.doReturn; 55 import static org.mockito.Mockito.inOrder; 56 import static org.mockito.Mockito.mock; 57 import static org.mockito.Mockito.never; 58 import static org.mockito.Mockito.reset; 59 import static org.mockito.Mockito.timeout; 60 import static org.mockito.Mockito.times; 61 import static org.mockito.Mockito.verify; 62 import static org.mockito.Mockito.when; 63 64 import android.app.PendingIntent; 65 import android.content.Context; 66 import android.content.pm.ApplicationInfo; 67 import android.net.ConnectivityManager.NetworkCallback; 68 import android.os.Build.VERSION_CODES; 69 import android.os.Bundle; 70 import android.os.Handler; 71 import android.os.Looper; 72 import android.os.Message; 73 import android.os.Messenger; 74 import android.os.Process; 75 76 import androidx.annotation.NonNull; 77 import androidx.test.filters.SmallTest; 78 79 import com.android.internal.util.test.BroadcastInterceptingContext; 80 import com.android.testutils.DevSdkIgnoreRule; 81 import com.android.testutils.DevSdkIgnoreRunner; 82 83 import org.junit.Before; 84 import org.junit.Rule; 85 import org.junit.Test; 86 import org.junit.runner.RunWith; 87 import org.mockito.ArgumentCaptor; 88 import org.mockito.InOrder; 89 import org.mockito.Mock; 90 import org.mockito.MockitoAnnotations; 91 92 import java.lang.ref.WeakReference; 93 94 @RunWith(DevSdkIgnoreRunner.class) 95 @SmallTest 96 @DevSdkIgnoreRule.IgnoreUpTo(VERSION_CODES.R) 97 public class ConnectivityManagerTest { 98 @Rule 99 public final DevSdkIgnoreRule mIgnoreRule = new DevSdkIgnoreRule(); 100 private static final int TIMEOUT_MS = 30_000; 101 private static final int SHORT_TIMEOUT_MS = 150; 102 103 @Mock Context mCtx; 104 @Mock IConnectivityManager mService; 105 @Mock NetworkPolicyManager mNpm; 106 107 @Before setUp()108 public void setUp() { 109 MockitoAnnotations.initMocks(this); 110 } 111 verifyNetworkCapabilities( int legacyType, int transportType, int... capabilities)112 static NetworkCapabilities verifyNetworkCapabilities( 113 int legacyType, int transportType, int... capabilities) { 114 final NetworkCapabilities nc = ConnectivityManager.networkCapabilitiesForType(legacyType); 115 assertNotNull(nc); 116 assertTrue(nc.hasTransport(transportType)); 117 for (int capability : capabilities) { 118 assertTrue(nc.hasCapability(capability)); 119 } 120 121 return nc; 122 } 123 verifyUnrestrictedNetworkCapabilities(int legacyType, int transportType)124 static void verifyUnrestrictedNetworkCapabilities(int legacyType, int transportType) { 125 verifyNetworkCapabilities( 126 legacyType, 127 transportType, 128 NET_CAPABILITY_INTERNET, 129 NET_CAPABILITY_NOT_RESTRICTED, 130 NET_CAPABILITY_NOT_VPN, 131 NET_CAPABILITY_TRUSTED); 132 } 133 verifyRestrictedMobileNetworkCapabilities(int legacyType, int capability)134 static void verifyRestrictedMobileNetworkCapabilities(int legacyType, int capability) { 135 final NetworkCapabilities nc = verifyNetworkCapabilities( 136 legacyType, 137 TRANSPORT_CELLULAR, 138 capability, 139 NET_CAPABILITY_NOT_VPN, 140 NET_CAPABILITY_TRUSTED); 141 142 assertFalse(nc.hasCapability(NET_CAPABILITY_INTERNET)); 143 assertFalse(nc.hasCapability(NET_CAPABILITY_NOT_RESTRICTED)); 144 } 145 146 @Test testNetworkCapabilitiesForTypeMobile()147 public void testNetworkCapabilitiesForTypeMobile() { 148 verifyUnrestrictedNetworkCapabilities( 149 ConnectivityManager.TYPE_MOBILE, TRANSPORT_CELLULAR); 150 } 151 152 @Test testNetworkCapabilitiesForTypeMobileCbs()153 public void testNetworkCapabilitiesForTypeMobileCbs() { 154 verifyRestrictedMobileNetworkCapabilities( 155 ConnectivityManager.TYPE_MOBILE_CBS, NET_CAPABILITY_CBS); 156 } 157 158 @Test testNetworkCapabilitiesForTypeMobileDun()159 public void testNetworkCapabilitiesForTypeMobileDun() { 160 verifyRestrictedMobileNetworkCapabilities( 161 ConnectivityManager.TYPE_MOBILE_DUN, NET_CAPABILITY_DUN); 162 } 163 164 @Test testNetworkCapabilitiesForTypeMobileFota()165 public void testNetworkCapabilitiesForTypeMobileFota() { 166 verifyRestrictedMobileNetworkCapabilities( 167 ConnectivityManager.TYPE_MOBILE_FOTA, NET_CAPABILITY_FOTA); 168 } 169 170 @Test testNetworkCapabilitiesForTypeMobileHipri()171 public void testNetworkCapabilitiesForTypeMobileHipri() { 172 verifyUnrestrictedNetworkCapabilities( 173 ConnectivityManager.TYPE_MOBILE_HIPRI, TRANSPORT_CELLULAR); 174 } 175 176 @Test testNetworkCapabilitiesForTypeMobileIms()177 public void testNetworkCapabilitiesForTypeMobileIms() { 178 verifyRestrictedMobileNetworkCapabilities( 179 ConnectivityManager.TYPE_MOBILE_IMS, NET_CAPABILITY_IMS); 180 } 181 182 @Test testNetworkCapabilitiesForTypeMobileMms()183 public void testNetworkCapabilitiesForTypeMobileMms() { 184 final NetworkCapabilities nc = verifyNetworkCapabilities( 185 ConnectivityManager.TYPE_MOBILE_MMS, 186 TRANSPORT_CELLULAR, 187 NET_CAPABILITY_MMS, 188 NET_CAPABILITY_NOT_VPN, 189 NET_CAPABILITY_TRUSTED); 190 191 assertFalse(nc.hasCapability(NET_CAPABILITY_INTERNET)); 192 } 193 194 @Test testNetworkCapabilitiesForTypeMobileSupl()195 public void testNetworkCapabilitiesForTypeMobileSupl() { 196 final NetworkCapabilities nc = verifyNetworkCapabilities( 197 ConnectivityManager.TYPE_MOBILE_SUPL, 198 TRANSPORT_CELLULAR, 199 NET_CAPABILITY_SUPL, 200 NET_CAPABILITY_NOT_VPN, 201 NET_CAPABILITY_TRUSTED); 202 203 assertFalse(nc.hasCapability(NET_CAPABILITY_INTERNET)); 204 } 205 206 @Test testNetworkCapabilitiesForTypeWifi()207 public void testNetworkCapabilitiesForTypeWifi() { 208 verifyUnrestrictedNetworkCapabilities( 209 ConnectivityManager.TYPE_WIFI, TRANSPORT_WIFI); 210 } 211 212 @Test testNetworkCapabilitiesForTypeWifiP2p()213 public void testNetworkCapabilitiesForTypeWifiP2p() { 214 final NetworkCapabilities nc = verifyNetworkCapabilities( 215 ConnectivityManager.TYPE_WIFI_P2P, 216 TRANSPORT_WIFI, 217 NET_CAPABILITY_NOT_RESTRICTED, NET_CAPABILITY_NOT_VPN, 218 NET_CAPABILITY_TRUSTED, NET_CAPABILITY_WIFI_P2P); 219 220 assertFalse(nc.hasCapability(NET_CAPABILITY_INTERNET)); 221 } 222 223 @Test testNetworkCapabilitiesForTypeBluetooth()224 public void testNetworkCapabilitiesForTypeBluetooth() { 225 verifyUnrestrictedNetworkCapabilities( 226 ConnectivityManager.TYPE_BLUETOOTH, TRANSPORT_BLUETOOTH); 227 } 228 229 @Test testNetworkCapabilitiesForTypeEthernet()230 public void testNetworkCapabilitiesForTypeEthernet() { 231 verifyUnrestrictedNetworkCapabilities( 232 ConnectivityManager.TYPE_ETHERNET, TRANSPORT_ETHERNET); 233 } 234 235 @Test testCallbackRelease()236 public void testCallbackRelease() throws Exception { 237 ConnectivityManager manager = new ConnectivityManager(mCtx, mService); 238 NetworkRequest request = makeRequest(1); 239 NetworkCallback callback = mock(ConnectivityManager.NetworkCallback.class, 240 CALLS_REAL_METHODS); 241 Handler handler = new Handler(Looper.getMainLooper()); 242 ArgumentCaptor<Messenger> captor = ArgumentCaptor.forClass(Messenger.class); 243 244 // register callback 245 when(mService.requestNetwork(anyInt(), any(), anyInt(), captor.capture(), anyInt(), any(), 246 anyInt(), anyInt(), any(), nullable(String.class), anyInt())).thenReturn(request); 247 manager.requestNetwork(request, callback, handler); 248 249 // callback triggers 250 captor.getValue().send(makeMessage(request, ConnectivityManager.CALLBACK_AVAILABLE)); 251 verify(callback, timeout(TIMEOUT_MS).times(1)).onAvailable(any(Network.class), 252 any(NetworkCapabilities.class), any(LinkProperties.class), anyBoolean()); 253 254 // unregister callback 255 manager.unregisterNetworkCallback(callback); 256 verify(mService, times(1)).releaseNetworkRequest(request); 257 258 // callback does not trigger anymore. 259 captor.getValue().send(makeMessage(request, ConnectivityManager.CALLBACK_LOSING)); 260 verify(callback, after(SHORT_TIMEOUT_MS).never()).onLosing(any(), anyInt()); 261 } 262 263 @Test testCallbackRecycling()264 public void testCallbackRecycling() throws Exception { 265 ConnectivityManager manager = new ConnectivityManager(mCtx, mService); 266 NetworkRequest req1 = makeRequest(1); 267 NetworkRequest req2 = makeRequest(2); 268 NetworkCallback callback = mock(ConnectivityManager.NetworkCallback.class, 269 CALLS_REAL_METHODS); 270 Handler handler = new Handler(Looper.getMainLooper()); 271 ArgumentCaptor<Messenger> captor = ArgumentCaptor.forClass(Messenger.class); 272 273 // register callback 274 when(mService.requestNetwork(anyInt(), any(), anyInt(), captor.capture(), anyInt(), any(), 275 anyInt(), anyInt(), any(), nullable(String.class), anyInt())).thenReturn(req1); 276 manager.requestNetwork(req1, callback, handler); 277 278 // callback triggers 279 captor.getValue().send(makeMessage(req1, ConnectivityManager.CALLBACK_AVAILABLE)); 280 verify(callback, timeout(TIMEOUT_MS).times(1)).onAvailable(any(Network.class), 281 any(NetworkCapabilities.class), any(LinkProperties.class), anyBoolean()); 282 283 // unregister callback 284 manager.unregisterNetworkCallback(callback); 285 verify(mService, times(1)).releaseNetworkRequest(req1); 286 287 // callback does not trigger anymore. 288 captor.getValue().send(makeMessage(req1, ConnectivityManager.CALLBACK_LOSING)); 289 verify(callback, after(SHORT_TIMEOUT_MS).never()).onLosing(any(), anyInt()); 290 291 // callback can be registered again 292 when(mService.requestNetwork(anyInt(), any(), anyInt(), captor.capture(), anyInt(), any(), 293 anyInt(), anyInt(), any(), nullable(String.class), anyInt())).thenReturn(req2); 294 manager.requestNetwork(req2, callback, handler); 295 296 // callback triggers 297 captor.getValue().send(makeMessage(req2, ConnectivityManager.CALLBACK_LOST)); 298 verify(callback, timeout(TIMEOUT_MS).times(1)).onLost(any()); 299 300 // unregister callback 301 manager.unregisterNetworkCallback(callback); 302 verify(mService, times(1)).releaseNetworkRequest(req2); 303 } 304 305 // TODO: turn on this test when request callback 1:1 mapping is enforced 306 //@Test noDoubleCallbackRegistration()307 private void noDoubleCallbackRegistration() throws Exception { 308 ConnectivityManager manager = new ConnectivityManager(mCtx, mService); 309 NetworkRequest request = makeRequest(1); 310 NetworkCallback callback = new ConnectivityManager.NetworkCallback(); 311 ApplicationInfo info = new ApplicationInfo(); 312 // TODO: update version when starting to enforce 1:1 mapping 313 info.targetSdkVersion = VERSION_CODES.N_MR1 + 1; 314 315 when(mCtx.getApplicationInfo()).thenReturn(info); 316 when(mService.requestNetwork(anyInt(), any(), anyInt(), any(), anyInt(), any(), anyInt(), 317 anyInt(), any(), nullable(String.class), anyInt())).thenReturn(request); 318 319 Handler handler = new Handler(Looper.getMainLooper()); 320 manager.requestNetwork(request, callback, handler); 321 322 // callback is already registered, reregistration should fail. 323 Class<IllegalArgumentException> wantException = IllegalArgumentException.class; 324 expectThrowable(() -> manager.requestNetwork(request, callback), wantException); 325 326 manager.unregisterNetworkCallback(callback); 327 verify(mService, times(1)).releaseNetworkRequest(request); 328 329 // unregistering the callback should make it registrable again. 330 manager.requestNetwork(request, callback); 331 } 332 333 @Test testDefaultNetworkActiveListener()334 public void testDefaultNetworkActiveListener() throws Exception { 335 final ConnectivityManager manager = new ConnectivityManager(mCtx, mService); 336 final ConnectivityManager.OnNetworkActiveListener listener = 337 mock(ConnectivityManager.OnNetworkActiveListener.class); 338 assertThrows(IllegalArgumentException.class, 339 () -> manager.removeDefaultNetworkActiveListener(listener)); 340 manager.addDefaultNetworkActiveListener(listener); 341 verify(mService, times(1)).registerNetworkActivityListener(any()); 342 manager.removeDefaultNetworkActiveListener(listener); 343 verify(mService, times(1)).unregisterNetworkActivityListener(any()); 344 assertThrows(IllegalArgumentException.class, 345 () -> manager.removeDefaultNetworkActiveListener(listener)); 346 } 347 348 @Test testArgumentValidation()349 public void testArgumentValidation() throws Exception { 350 ConnectivityManager manager = new ConnectivityManager(mCtx, mService); 351 352 NetworkRequest request = mock(NetworkRequest.class); 353 NetworkCallback callback = mock(NetworkCallback.class); 354 Handler handler = mock(Handler.class); 355 NetworkCallback nullCallback = null; 356 PendingIntent nullIntent = null; 357 358 mustFail(() -> manager.requestNetwork(null, callback)); 359 mustFail(() -> manager.requestNetwork(request, nullCallback)); 360 mustFail(() -> manager.requestNetwork(request, callback, null)); 361 mustFail(() -> manager.requestNetwork(request, callback, -1)); 362 mustFail(() -> manager.requestNetwork(request, nullIntent)); 363 364 mustFail(() -> manager.requestBackgroundNetwork(null, callback, handler)); 365 mustFail(() -> manager.requestBackgroundNetwork(request, null, handler)); 366 mustFail(() -> manager.requestBackgroundNetwork(request, callback, null)); 367 368 mustFail(() -> manager.registerNetworkCallback(null, callback, handler)); 369 mustFail(() -> manager.registerNetworkCallback(request, null, handler)); 370 mustFail(() -> manager.registerNetworkCallback(request, callback, null)); 371 mustFail(() -> manager.registerNetworkCallback(request, nullIntent)); 372 373 mustFail(() -> manager.registerDefaultNetworkCallback(null, handler)); 374 mustFail(() -> manager.registerDefaultNetworkCallback(callback, null)); 375 376 mustFail(() -> manager.registerSystemDefaultNetworkCallback(null, handler)); 377 mustFail(() -> manager.registerSystemDefaultNetworkCallback(callback, null)); 378 379 mustFail(() -> manager.registerBestMatchingNetworkCallback(null, callback, handler)); 380 mustFail(() -> manager.registerBestMatchingNetworkCallback(request, null, handler)); 381 mustFail(() -> manager.registerBestMatchingNetworkCallback(request, callback, null)); 382 383 mustFail(() -> manager.unregisterNetworkCallback(nullCallback)); 384 mustFail(() -> manager.unregisterNetworkCallback(nullIntent)); 385 mustFail(() -> manager.releaseNetworkRequest(nullIntent)); 386 } 387 mustFail(Runnable fn)388 static void mustFail(Runnable fn) { 389 try { 390 fn.run(); 391 fail(); 392 } catch (Exception expected) { 393 } 394 } 395 396 @Test testRequestType()397 public void testRequestType() throws Exception { 398 final String testPkgName = "MyPackage"; 399 final String testAttributionTag = "MyTag"; 400 final ConnectivityManager manager = new ConnectivityManager(mCtx, mService); 401 when(mCtx.getOpPackageName()).thenReturn(testPkgName); 402 when(mCtx.getAttributionTag()).thenReturn(testAttributionTag); 403 final NetworkRequest request = makeRequest(1); 404 final NetworkCallback callback = new ConnectivityManager.NetworkCallback(); 405 406 manager.requestNetwork(request, callback); 407 verify(mService).requestNetwork(eq(Process.INVALID_UID), eq(request.networkCapabilities), 408 eq(REQUEST.ordinal()), any(), anyInt(), any(), eq(TYPE_NONE), anyInt(), 409 eq(testPkgName), eq(testAttributionTag), anyInt()); 410 reset(mService); 411 412 // Verify that register network callback does not calls requestNetwork at all. 413 manager.registerNetworkCallback(request, callback); 414 verify(mService, never()).requestNetwork(anyInt(), any(), anyInt(), any(), anyInt(), any(), 415 anyInt(), anyInt(), any(), any(), anyInt()); 416 verify(mService).listenForNetwork(eq(request.networkCapabilities), any(), any(), anyInt(), 417 eq(testPkgName), eq(testAttributionTag), anyInt()); 418 reset(mService); 419 420 Handler handler = new Handler(ConnectivityThread.getInstanceLooper()); 421 422 manager.registerDefaultNetworkCallback(callback); 423 verify(mService).requestNetwork(eq(Process.INVALID_UID), eq(null), 424 eq(TRACK_DEFAULT.ordinal()), any(), anyInt(), any(), eq(TYPE_NONE), anyInt(), 425 eq(testPkgName), eq(testAttributionTag), anyInt()); 426 reset(mService); 427 428 manager.registerDefaultNetworkCallbackForUid(42, callback, handler); 429 verify(mService).requestNetwork(eq(42), eq(null), 430 eq(TRACK_DEFAULT.ordinal()), any(), anyInt(), any(), eq(TYPE_NONE), anyInt(), 431 eq(testPkgName), eq(testAttributionTag), anyInt()); 432 433 manager.requestBackgroundNetwork(request, callback, handler); 434 verify(mService).requestNetwork(eq(Process.INVALID_UID), eq(request.networkCapabilities), 435 eq(BACKGROUND_REQUEST.ordinal()), any(), anyInt(), any(), eq(TYPE_NONE), anyInt(), 436 eq(testPkgName), eq(testAttributionTag), anyInt()); 437 reset(mService); 438 439 manager.registerSystemDefaultNetworkCallback(callback, handler); 440 verify(mService).requestNetwork(eq(Process.INVALID_UID), eq(null), 441 eq(TRACK_SYSTEM_DEFAULT.ordinal()), any(), anyInt(), any(), eq(TYPE_NONE), anyInt(), 442 eq(testPkgName), eq(testAttributionTag), anyInt()); 443 reset(mService); 444 } 445 makeMessage(NetworkRequest req, int messageType)446 static Message makeMessage(NetworkRequest req, int messageType) { 447 Bundle bundle = new Bundle(); 448 bundle.putParcelable(NetworkRequest.class.getSimpleName(), req); 449 // Pass default objects as we don't care which get passed here 450 bundle.putParcelable(Network.class.getSimpleName(), new Network(1)); 451 bundle.putParcelable(NetworkCapabilities.class.getSimpleName(), new NetworkCapabilities()); 452 bundle.putParcelable(LinkProperties.class.getSimpleName(), new LinkProperties()); 453 Message msg = Message.obtain(); 454 msg.what = messageType; 455 msg.setData(bundle); 456 return msg; 457 } 458 makeRequest(int requestId)459 static NetworkRequest makeRequest(int requestId) { 460 NetworkRequest request = new NetworkRequest.Builder().clearCapabilities().build(); 461 return new NetworkRequest(request.networkCapabilities, ConnectivityManager.TYPE_NONE, 462 requestId, NetworkRequest.Type.NONE); 463 } 464 expectThrowable(Runnable block, Class<? extends Throwable> throwableType)465 static void expectThrowable(Runnable block, Class<? extends Throwable> throwableType) { 466 try { 467 block.run(); 468 } catch (Throwable t) { 469 if (t.getClass().equals(throwableType)) { 470 return; 471 } 472 fail("expected exception of type " + throwableType + ", but was " + t.getClass()); 473 } 474 fail("expected exception of type " + throwableType); 475 } 476 477 private static class MockContext extends BroadcastInterceptingContext { MockContext(Context base)478 MockContext(Context base) { 479 super(base); 480 } 481 482 @Override getApplicationContext()483 public Context getApplicationContext() { 484 return mock(Context.class); 485 } 486 } 487 makeConnectivityManagerAndReturnContext()488 private WeakReference<Context> makeConnectivityManagerAndReturnContext() { 489 // Mockito may have an internal reference to the mock, creating MockContext for testing. 490 final Context c = new MockContext(mock(Context.class)); 491 492 new ConnectivityManager(c, mService); 493 494 return new WeakReference<>(c); 495 } 496 forceGC()497 private void forceGC() { 498 // First GC ensures that objects are collected for finalization, then second GC ensures 499 // they're garbage-collected after being finalized. 500 System.gc(); 501 System.runFinalization(); 502 System.gc(); 503 } 504 505 @Test testConnectivityManagerDoesNotLeakContext()506 public void testConnectivityManagerDoesNotLeakContext() throws Exception { 507 final WeakReference<Context> ref = makeConnectivityManagerAndReturnContext(); 508 509 final int attempts = 600; 510 final long waitIntervalMs = 50; 511 for (int i = 0; i < attempts; i++) { 512 forceGC(); 513 if (ref.get() == null) break; 514 515 Thread.sleep(waitIntervalMs); 516 } 517 518 assertNull("ConnectivityManager weak reference still not null after " + attempts 519 + " attempts", ref.get()); 520 } 521 522 @Test testDeclaredMethodsFlag_requestWithMixedMethods_RegistrationFlagsMatch()523 public void testDeclaredMethodsFlag_requestWithMixedMethods_RegistrationFlagsMatch() 524 throws Exception { 525 doReturn(ConnectivityManager.FEATURE_USE_DECLARED_METHODS_FOR_CALLBACKS) 526 .when(mService).getEnabledConnectivityManagerFeatures(); 527 final ConnectivityManager manager = new ConnectivityManager(mCtx, mService); 528 529 final NetworkRequest request = new NetworkRequest.Builder().build(); 530 final NetworkCallback callback1 = new ConnectivityManager.NetworkCallback() { 531 @Override 532 public void onPreCheck(@NonNull Network network) {} 533 @Override 534 public void onAvailable(@NonNull Network network) {} 535 @Override 536 public void onLost(@NonNull Network network) {} 537 @Override 538 public void onCapabilitiesChanged(@NonNull Network network, 539 @NonNull NetworkCapabilities networkCapabilities) {} 540 @Override 541 public void onLocalNetworkInfoChanged(@NonNull Network network, 542 @NonNull LocalNetworkInfo localNetworkInfo) {} 543 @Override 544 public void onNetworkResumed(@NonNull Network network) {} 545 @Override 546 public void onBlockedStatusChanged(@NonNull Network network, int blocked) {} 547 }; 548 manager.requestNetwork(request, callback1); 549 550 final InOrder inOrder = inOrder(mService); 551 inOrder.verify(mService).requestNetwork( 552 anyInt(), any(), anyInt(), any(), anyInt(), any(), anyInt(), anyInt(), any(), any(), 553 eq(1 << ConnectivityManager.CALLBACK_PRECHECK 554 | 1 << ConnectivityManager.CALLBACK_AVAILABLE 555 | 1 << ConnectivityManager.CALLBACK_LOST 556 | 1 << ConnectivityManager.CALLBACK_CAP_CHANGED 557 | 1 << ConnectivityManager.CALLBACK_LOCAL_NETWORK_INFO_CHANGED 558 | 1 << ConnectivityManager.CALLBACK_RESUMED 559 | 1 << ConnectivityManager.CALLBACK_BLK_CHANGED)); 560 } 561 562 @Test testDeclaredMethodsFlag_listenWithMixedMethods_RegistrationFlagsMatch()563 public void testDeclaredMethodsFlag_listenWithMixedMethods_RegistrationFlagsMatch() 564 throws Exception { 565 final NetworkRequest request = new NetworkRequest.Builder().build(); 566 doReturn(ConnectivityManager.FEATURE_USE_DECLARED_METHODS_FOR_CALLBACKS) 567 .when(mService).getEnabledConnectivityManagerFeatures(); 568 final ConnectivityManager manager = new ConnectivityManager(mCtx, mService); 569 570 final NetworkCallback callback2 = new ConnectivityManager.NetworkCallback() { 571 @Override 572 public void onLosing(@NonNull Network network, int maxMsToLive) {} 573 @Override 574 public void onUnavailable() {} 575 @Override 576 public void onLinkPropertiesChanged(@NonNull Network network, 577 @NonNull LinkProperties linkProperties) {} 578 @Override 579 public void onNetworkSuspended(@NonNull Network network) {} 580 }; 581 manager.registerNetworkCallback(request, callback2); 582 // Call a second time with the same callback to exercise caching 583 manager.registerNetworkCallback(request, callback2); 584 585 verify(mService, times(2)).listenForNetwork( 586 any(), any(), any(), anyInt(), any(), any(), 587 eq(1 << ConnectivityManager.CALLBACK_LOSING 588 // AVAILABLE calls IP_CHANGED and SUSPENDED so it gets added 589 | 1 << ConnectivityManager.CALLBACK_AVAILABLE 590 | 1 << ConnectivityManager.CALLBACK_UNAVAIL 591 | 1 << ConnectivityManager.CALLBACK_IP_CHANGED 592 | 1 << ConnectivityManager.CALLBACK_SUSPENDED)); 593 } 594 595 @Test testDeclaredMethodsFlag_requestWithHiddenAvailableCallback_RegistrationFlagsMatch()596 public void testDeclaredMethodsFlag_requestWithHiddenAvailableCallback_RegistrationFlagsMatch() 597 throws Exception { 598 doReturn(ConnectivityManager.FEATURE_USE_DECLARED_METHODS_FOR_CALLBACKS) 599 .when(mService).getEnabledConnectivityManagerFeatures(); 600 final ConnectivityManager manager = new ConnectivityManager(mCtx, mService); 601 602 final NetworkCallback hiddenOnAvailableCb = new ConnectivityManager.NetworkCallback() { 603 // This overload is @hide but might still be used by (bad) apps 604 @Override 605 public void onAvailable(@NonNull Network network, 606 @NonNull NetworkCapabilities networkCapabilities, 607 @NonNull LinkProperties linkProperties, boolean blocked) {} 608 }; 609 manager.registerDefaultNetworkCallback(hiddenOnAvailableCb); 610 611 verify(mService).requestNetwork( 612 anyInt(), any(), anyInt(), any(), anyInt(), any(), anyInt(), anyInt(), any(), any(), 613 eq(1 << ConnectivityManager.CALLBACK_AVAILABLE)); 614 } 615 616 public static class NetworkCallbackWithOnLostOnly extends NetworkCallback { 617 @Override onLost(@onNull Network network)618 public void onLost(@NonNull Network network) {} 619 } 620 621 @Test testDeclaredMethodsFlag_requestWithoutAvailableCallback_RegistrationFlagsMatch()622 public void testDeclaredMethodsFlag_requestWithoutAvailableCallback_RegistrationFlagsMatch() 623 throws Exception { 624 doReturn(ConnectivityManager.FEATURE_USE_DECLARED_METHODS_FOR_CALLBACKS) 625 .when(mService).getEnabledConnectivityManagerFeatures(); 626 final ConnectivityManager manager = new ConnectivityManager(mCtx, mService); 627 final Handler handler = new Handler(Looper.getMainLooper()); 628 629 final NetworkCallback noOnAvailableCb = new NetworkCallbackWithOnLostOnly(); 630 manager.registerSystemDefaultNetworkCallback(noOnAvailableCb, handler); 631 632 verify(mService).requestNetwork( 633 anyInt(), any(), anyInt(), any(), anyInt(), any(), anyInt(), anyInt(), any(), any(), 634 eq(1 << ConnectivityManager.CALLBACK_LOST)); 635 } 636 637 @Test testDeclaredMethodsFlag_listenWithMock_OptimizationDisabled()638 public void testDeclaredMethodsFlag_listenWithMock_OptimizationDisabled() 639 throws Exception { 640 doReturn(ConnectivityManager.FEATURE_USE_DECLARED_METHODS_FOR_CALLBACKS) 641 .when(mService).getEnabledConnectivityManagerFeatures(); 642 final ConnectivityManager manager = new ConnectivityManager(mCtx, mService); 643 final Handler handler = new Handler(Looper.getMainLooper()); 644 645 final NetworkRequest request = new NetworkRequest.Builder().build(); 646 manager.registerNetworkCallback(request, mock(NetworkCallbackWithOnLostOnly.class), 647 handler); 648 649 verify(mService).listenForNetwork( 650 any(), any(), any(), anyInt(), any(), any(), 651 // Mock that does not call the constructor -> do not use the optimization 652 eq(~0)); 653 } 654 655 @Test testDeclaredMethodsFlag_requestWitNoCallback_OptimizationDisabled()656 public void testDeclaredMethodsFlag_requestWitNoCallback_OptimizationDisabled() 657 throws Exception { 658 doReturn(ConnectivityManager.FEATURE_USE_DECLARED_METHODS_FOR_CALLBACKS) 659 .when(mService).getEnabledConnectivityManagerFeatures(); 660 final ConnectivityManager manager = new ConnectivityManager(mCtx, mService); 661 final Handler handler = new Handler(Looper.getMainLooper()); 662 663 final NetworkRequest request = new NetworkRequest.Builder().build(); 664 final NetworkCallback noCallbackAtAll = new ConnectivityManager.NetworkCallback() {}; 665 manager.requestBackgroundNetwork(request, noCallbackAtAll, handler); 666 667 verify(mService).requestNetwork( 668 anyInt(), any(), anyInt(), any(), anyInt(), any(), anyInt(), anyInt(), any(), any(), 669 // No callbacks overridden -> do not use the optimization 670 eq(~0)); 671 } 672 } 673