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.mock; 56 import static org.mockito.Mockito.never; 57 import static org.mockito.Mockito.reset; 58 import static org.mockito.Mockito.timeout; 59 import static org.mockito.Mockito.times; 60 import static org.mockito.Mockito.verify; 61 import static org.mockito.Mockito.when; 62 63 import android.app.PendingIntent; 64 import android.content.Context; 65 import android.content.pm.ApplicationInfo; 66 import android.net.ConnectivityManager.NetworkCallback; 67 import android.os.Build.VERSION_CODES; 68 import android.os.Bundle; 69 import android.os.Handler; 70 import android.os.Looper; 71 import android.os.Message; 72 import android.os.Messenger; 73 import android.os.Process; 74 75 import androidx.test.filters.SmallTest; 76 77 import com.android.internal.util.test.BroadcastInterceptingContext; 78 import com.android.testutils.DevSdkIgnoreRule; 79 import com.android.testutils.DevSdkIgnoreRunner; 80 81 import org.junit.Before; 82 import org.junit.Rule; 83 import org.junit.Test; 84 import org.junit.runner.RunWith; 85 import org.mockito.ArgumentCaptor; 86 import org.mockito.Mock; 87 import org.mockito.MockitoAnnotations; 88 89 import java.lang.ref.WeakReference; 90 91 @RunWith(DevSdkIgnoreRunner.class) 92 @SmallTest 93 @DevSdkIgnoreRule.IgnoreUpTo(VERSION_CODES.R) 94 public class ConnectivityManagerTest { 95 @Rule 96 public final DevSdkIgnoreRule mIgnoreRule = new DevSdkIgnoreRule(); 97 private static final int TIMEOUT_MS = 30_000; 98 private static final int SHORT_TIMEOUT_MS = 150; 99 100 @Mock Context mCtx; 101 @Mock IConnectivityManager mService; 102 @Mock NetworkPolicyManager mNpm; 103 104 @Before setUp()105 public void setUp() { 106 MockitoAnnotations.initMocks(this); 107 } 108 verifyNetworkCapabilities( int legacyType, int transportType, int... capabilities)109 static NetworkCapabilities verifyNetworkCapabilities( 110 int legacyType, int transportType, int... capabilities) { 111 final NetworkCapabilities nc = ConnectivityManager.networkCapabilitiesForType(legacyType); 112 assertNotNull(nc); 113 assertTrue(nc.hasTransport(transportType)); 114 for (int capability : capabilities) { 115 assertTrue(nc.hasCapability(capability)); 116 } 117 118 return nc; 119 } 120 verifyUnrestrictedNetworkCapabilities(int legacyType, int transportType)121 static void verifyUnrestrictedNetworkCapabilities(int legacyType, int transportType) { 122 verifyNetworkCapabilities( 123 legacyType, 124 transportType, 125 NET_CAPABILITY_INTERNET, 126 NET_CAPABILITY_NOT_RESTRICTED, 127 NET_CAPABILITY_NOT_VPN, 128 NET_CAPABILITY_TRUSTED); 129 } 130 verifyRestrictedMobileNetworkCapabilities(int legacyType, int capability)131 static void verifyRestrictedMobileNetworkCapabilities(int legacyType, int capability) { 132 final NetworkCapabilities nc = verifyNetworkCapabilities( 133 legacyType, 134 TRANSPORT_CELLULAR, 135 capability, 136 NET_CAPABILITY_NOT_VPN, 137 NET_CAPABILITY_TRUSTED); 138 139 assertFalse(nc.hasCapability(NET_CAPABILITY_INTERNET)); 140 assertFalse(nc.hasCapability(NET_CAPABILITY_NOT_RESTRICTED)); 141 } 142 143 @Test testNetworkCapabilitiesForTypeMobile()144 public void testNetworkCapabilitiesForTypeMobile() { 145 verifyUnrestrictedNetworkCapabilities( 146 ConnectivityManager.TYPE_MOBILE, TRANSPORT_CELLULAR); 147 } 148 149 @Test testNetworkCapabilitiesForTypeMobileCbs()150 public void testNetworkCapabilitiesForTypeMobileCbs() { 151 verifyRestrictedMobileNetworkCapabilities( 152 ConnectivityManager.TYPE_MOBILE_CBS, NET_CAPABILITY_CBS); 153 } 154 155 @Test testNetworkCapabilitiesForTypeMobileDun()156 public void testNetworkCapabilitiesForTypeMobileDun() { 157 verifyRestrictedMobileNetworkCapabilities( 158 ConnectivityManager.TYPE_MOBILE_DUN, NET_CAPABILITY_DUN); 159 } 160 161 @Test testNetworkCapabilitiesForTypeMobileFota()162 public void testNetworkCapabilitiesForTypeMobileFota() { 163 verifyRestrictedMobileNetworkCapabilities( 164 ConnectivityManager.TYPE_MOBILE_FOTA, NET_CAPABILITY_FOTA); 165 } 166 167 @Test testNetworkCapabilitiesForTypeMobileHipri()168 public void testNetworkCapabilitiesForTypeMobileHipri() { 169 verifyUnrestrictedNetworkCapabilities( 170 ConnectivityManager.TYPE_MOBILE_HIPRI, TRANSPORT_CELLULAR); 171 } 172 173 @Test testNetworkCapabilitiesForTypeMobileIms()174 public void testNetworkCapabilitiesForTypeMobileIms() { 175 verifyRestrictedMobileNetworkCapabilities( 176 ConnectivityManager.TYPE_MOBILE_IMS, NET_CAPABILITY_IMS); 177 } 178 179 @Test testNetworkCapabilitiesForTypeMobileMms()180 public void testNetworkCapabilitiesForTypeMobileMms() { 181 final NetworkCapabilities nc = verifyNetworkCapabilities( 182 ConnectivityManager.TYPE_MOBILE_MMS, 183 TRANSPORT_CELLULAR, 184 NET_CAPABILITY_MMS, 185 NET_CAPABILITY_NOT_VPN, 186 NET_CAPABILITY_TRUSTED); 187 188 assertFalse(nc.hasCapability(NET_CAPABILITY_INTERNET)); 189 } 190 191 @Test testNetworkCapabilitiesForTypeMobileSupl()192 public void testNetworkCapabilitiesForTypeMobileSupl() { 193 final NetworkCapabilities nc = verifyNetworkCapabilities( 194 ConnectivityManager.TYPE_MOBILE_SUPL, 195 TRANSPORT_CELLULAR, 196 NET_CAPABILITY_SUPL, 197 NET_CAPABILITY_NOT_VPN, 198 NET_CAPABILITY_TRUSTED); 199 200 assertFalse(nc.hasCapability(NET_CAPABILITY_INTERNET)); 201 } 202 203 @Test testNetworkCapabilitiesForTypeWifi()204 public void testNetworkCapabilitiesForTypeWifi() { 205 verifyUnrestrictedNetworkCapabilities( 206 ConnectivityManager.TYPE_WIFI, TRANSPORT_WIFI); 207 } 208 209 @Test testNetworkCapabilitiesForTypeWifiP2p()210 public void testNetworkCapabilitiesForTypeWifiP2p() { 211 final NetworkCapabilities nc = verifyNetworkCapabilities( 212 ConnectivityManager.TYPE_WIFI_P2P, 213 TRANSPORT_WIFI, 214 NET_CAPABILITY_NOT_RESTRICTED, NET_CAPABILITY_NOT_VPN, 215 NET_CAPABILITY_TRUSTED, NET_CAPABILITY_WIFI_P2P); 216 217 assertFalse(nc.hasCapability(NET_CAPABILITY_INTERNET)); 218 } 219 220 @Test testNetworkCapabilitiesForTypeBluetooth()221 public void testNetworkCapabilitiesForTypeBluetooth() { 222 verifyUnrestrictedNetworkCapabilities( 223 ConnectivityManager.TYPE_BLUETOOTH, TRANSPORT_BLUETOOTH); 224 } 225 226 @Test testNetworkCapabilitiesForTypeEthernet()227 public void testNetworkCapabilitiesForTypeEthernet() { 228 verifyUnrestrictedNetworkCapabilities( 229 ConnectivityManager.TYPE_ETHERNET, TRANSPORT_ETHERNET); 230 } 231 232 @Test testCallbackRelease()233 public void testCallbackRelease() throws Exception { 234 ConnectivityManager manager = new ConnectivityManager(mCtx, mService); 235 NetworkRequest request = makeRequest(1); 236 NetworkCallback callback = mock(ConnectivityManager.NetworkCallback.class, 237 CALLS_REAL_METHODS); 238 Handler handler = new Handler(Looper.getMainLooper()); 239 ArgumentCaptor<Messenger> captor = ArgumentCaptor.forClass(Messenger.class); 240 241 // register callback 242 when(mService.requestNetwork(anyInt(), any(), anyInt(), captor.capture(), anyInt(), any(), 243 anyInt(), anyInt(), any(), nullable(String.class))).thenReturn(request); 244 manager.requestNetwork(request, callback, handler); 245 246 // callback triggers 247 captor.getValue().send(makeMessage(request, ConnectivityManager.CALLBACK_AVAILABLE)); 248 verify(callback, timeout(TIMEOUT_MS).times(1)).onAvailable(any(Network.class), 249 any(NetworkCapabilities.class), any(LinkProperties.class), anyBoolean()); 250 251 // unregister callback 252 manager.unregisterNetworkCallback(callback); 253 verify(mService, times(1)).releaseNetworkRequest(request); 254 255 // callback does not trigger anymore. 256 captor.getValue().send(makeMessage(request, ConnectivityManager.CALLBACK_LOSING)); 257 verify(callback, after(SHORT_TIMEOUT_MS).never()).onLosing(any(), anyInt()); 258 } 259 260 @Test testCallbackRecycling()261 public void testCallbackRecycling() throws Exception { 262 ConnectivityManager manager = new ConnectivityManager(mCtx, mService); 263 NetworkRequest req1 = makeRequest(1); 264 NetworkRequest req2 = makeRequest(2); 265 NetworkCallback callback = mock(ConnectivityManager.NetworkCallback.class, 266 CALLS_REAL_METHODS); 267 Handler handler = new Handler(Looper.getMainLooper()); 268 ArgumentCaptor<Messenger> captor = ArgumentCaptor.forClass(Messenger.class); 269 270 // register callback 271 when(mService.requestNetwork(anyInt(), any(), anyInt(), captor.capture(), anyInt(), any(), 272 anyInt(), anyInt(), any(), nullable(String.class))).thenReturn(req1); 273 manager.requestNetwork(req1, callback, handler); 274 275 // callback triggers 276 captor.getValue().send(makeMessage(req1, ConnectivityManager.CALLBACK_AVAILABLE)); 277 verify(callback, timeout(TIMEOUT_MS).times(1)).onAvailable(any(Network.class), 278 any(NetworkCapabilities.class), any(LinkProperties.class), anyBoolean()); 279 280 // unregister callback 281 manager.unregisterNetworkCallback(callback); 282 verify(mService, times(1)).releaseNetworkRequest(req1); 283 284 // callback does not trigger anymore. 285 captor.getValue().send(makeMessage(req1, ConnectivityManager.CALLBACK_LOSING)); 286 verify(callback, after(SHORT_TIMEOUT_MS).never()).onLosing(any(), anyInt()); 287 288 // callback can be registered again 289 when(mService.requestNetwork(anyInt(), any(), anyInt(), captor.capture(), anyInt(), any(), 290 anyInt(), anyInt(), any(), nullable(String.class))).thenReturn(req2); 291 manager.requestNetwork(req2, callback, handler); 292 293 // callback triggers 294 captor.getValue().send(makeMessage(req2, ConnectivityManager.CALLBACK_LOST)); 295 verify(callback, timeout(TIMEOUT_MS).times(1)).onLost(any()); 296 297 // unregister callback 298 manager.unregisterNetworkCallback(callback); 299 verify(mService, times(1)).releaseNetworkRequest(req2); 300 } 301 302 // TODO: turn on this test when request callback 1:1 mapping is enforced 303 //@Test noDoubleCallbackRegistration()304 private void noDoubleCallbackRegistration() throws Exception { 305 ConnectivityManager manager = new ConnectivityManager(mCtx, mService); 306 NetworkRequest request = makeRequest(1); 307 NetworkCallback callback = new ConnectivityManager.NetworkCallback(); 308 ApplicationInfo info = new ApplicationInfo(); 309 // TODO: update version when starting to enforce 1:1 mapping 310 info.targetSdkVersion = VERSION_CODES.N_MR1 + 1; 311 312 when(mCtx.getApplicationInfo()).thenReturn(info); 313 when(mService.requestNetwork(anyInt(), any(), anyInt(), any(), anyInt(), any(), anyInt(), 314 anyInt(), any(), nullable(String.class))).thenReturn(request); 315 316 Handler handler = new Handler(Looper.getMainLooper()); 317 manager.requestNetwork(request, callback, handler); 318 319 // callback is already registered, reregistration should fail. 320 Class<IllegalArgumentException> wantException = IllegalArgumentException.class; 321 expectThrowable(() -> manager.requestNetwork(request, callback), wantException); 322 323 manager.unregisterNetworkCallback(callback); 324 verify(mService, times(1)).releaseNetworkRequest(request); 325 326 // unregistering the callback should make it registrable again. 327 manager.requestNetwork(request, callback); 328 } 329 330 @Test testDefaultNetworkActiveListener()331 public void testDefaultNetworkActiveListener() throws Exception { 332 final ConnectivityManager manager = new ConnectivityManager(mCtx, mService); 333 final ConnectivityManager.OnNetworkActiveListener listener = 334 mock(ConnectivityManager.OnNetworkActiveListener.class); 335 assertThrows(IllegalArgumentException.class, 336 () -> manager.removeDefaultNetworkActiveListener(listener)); 337 manager.addDefaultNetworkActiveListener(listener); 338 verify(mService, times(1)).registerNetworkActivityListener(any()); 339 manager.removeDefaultNetworkActiveListener(listener); 340 verify(mService, times(1)).unregisterNetworkActivityListener(any()); 341 assertThrows(IllegalArgumentException.class, 342 () -> manager.removeDefaultNetworkActiveListener(listener)); 343 } 344 345 @Test testArgumentValidation()346 public void testArgumentValidation() throws Exception { 347 ConnectivityManager manager = new ConnectivityManager(mCtx, mService); 348 349 NetworkRequest request = mock(NetworkRequest.class); 350 NetworkCallback callback = mock(NetworkCallback.class); 351 Handler handler = mock(Handler.class); 352 NetworkCallback nullCallback = null; 353 PendingIntent nullIntent = null; 354 355 mustFail(() -> manager.requestNetwork(null, callback)); 356 mustFail(() -> manager.requestNetwork(request, nullCallback)); 357 mustFail(() -> manager.requestNetwork(request, callback, null)); 358 mustFail(() -> manager.requestNetwork(request, callback, -1)); 359 mustFail(() -> manager.requestNetwork(request, nullIntent)); 360 361 mustFail(() -> manager.requestBackgroundNetwork(null, callback, handler)); 362 mustFail(() -> manager.requestBackgroundNetwork(request, null, handler)); 363 mustFail(() -> manager.requestBackgroundNetwork(request, callback, null)); 364 365 mustFail(() -> manager.registerNetworkCallback(null, callback, handler)); 366 mustFail(() -> manager.registerNetworkCallback(request, null, handler)); 367 mustFail(() -> manager.registerNetworkCallback(request, callback, null)); 368 mustFail(() -> manager.registerNetworkCallback(request, nullIntent)); 369 370 mustFail(() -> manager.registerDefaultNetworkCallback(null, handler)); 371 mustFail(() -> manager.registerDefaultNetworkCallback(callback, null)); 372 373 mustFail(() -> manager.registerSystemDefaultNetworkCallback(null, handler)); 374 mustFail(() -> manager.registerSystemDefaultNetworkCallback(callback, null)); 375 376 mustFail(() -> manager.registerBestMatchingNetworkCallback(null, callback, handler)); 377 mustFail(() -> manager.registerBestMatchingNetworkCallback(request, null, handler)); 378 mustFail(() -> manager.registerBestMatchingNetworkCallback(request, callback, null)); 379 380 mustFail(() -> manager.unregisterNetworkCallback(nullCallback)); 381 mustFail(() -> manager.unregisterNetworkCallback(nullIntent)); 382 mustFail(() -> manager.releaseNetworkRequest(nullIntent)); 383 } 384 mustFail(Runnable fn)385 static void mustFail(Runnable fn) { 386 try { 387 fn.run(); 388 fail(); 389 } catch (Exception expected) { 390 } 391 } 392 393 @Test testRequestType()394 public void testRequestType() throws Exception { 395 final String testPkgName = "MyPackage"; 396 final String testAttributionTag = "MyTag"; 397 final ConnectivityManager manager = new ConnectivityManager(mCtx, mService); 398 when(mCtx.getOpPackageName()).thenReturn(testPkgName); 399 when(mCtx.getAttributionTag()).thenReturn(testAttributionTag); 400 final NetworkRequest request = makeRequest(1); 401 final NetworkCallback callback = new ConnectivityManager.NetworkCallback(); 402 403 manager.requestNetwork(request, callback); 404 verify(mService).requestNetwork(eq(Process.INVALID_UID), eq(request.networkCapabilities), 405 eq(REQUEST.ordinal()), any(), anyInt(), any(), eq(TYPE_NONE), anyInt(), 406 eq(testPkgName), eq(testAttributionTag)); 407 reset(mService); 408 409 // Verify that register network callback does not calls requestNetwork at all. 410 manager.registerNetworkCallback(request, callback); 411 verify(mService, never()).requestNetwork(anyInt(), any(), anyInt(), any(), anyInt(), any(), 412 anyInt(), anyInt(), any(), any()); 413 verify(mService).listenForNetwork(eq(request.networkCapabilities), any(), any(), anyInt(), 414 eq(testPkgName), eq(testAttributionTag)); 415 reset(mService); 416 417 Handler handler = new Handler(ConnectivityThread.getInstanceLooper()); 418 419 manager.registerDefaultNetworkCallback(callback); 420 verify(mService).requestNetwork(eq(Process.INVALID_UID), eq(null), 421 eq(TRACK_DEFAULT.ordinal()), any(), anyInt(), any(), eq(TYPE_NONE), anyInt(), 422 eq(testPkgName), eq(testAttributionTag)); 423 reset(mService); 424 425 manager.registerDefaultNetworkCallbackForUid(42, callback, handler); 426 verify(mService).requestNetwork(eq(42), eq(null), 427 eq(TRACK_DEFAULT.ordinal()), any(), anyInt(), any(), eq(TYPE_NONE), anyInt(), 428 eq(testPkgName), eq(testAttributionTag)); 429 430 manager.requestBackgroundNetwork(request, callback, handler); 431 verify(mService).requestNetwork(eq(Process.INVALID_UID), eq(request.networkCapabilities), 432 eq(BACKGROUND_REQUEST.ordinal()), any(), anyInt(), any(), eq(TYPE_NONE), anyInt(), 433 eq(testPkgName), eq(testAttributionTag)); 434 reset(mService); 435 436 manager.registerSystemDefaultNetworkCallback(callback, handler); 437 verify(mService).requestNetwork(eq(Process.INVALID_UID), eq(null), 438 eq(TRACK_SYSTEM_DEFAULT.ordinal()), any(), anyInt(), any(), eq(TYPE_NONE), anyInt(), 439 eq(testPkgName), eq(testAttributionTag)); 440 reset(mService); 441 } 442 makeMessage(NetworkRequest req, int messageType)443 static Message makeMessage(NetworkRequest req, int messageType) { 444 Bundle bundle = new Bundle(); 445 bundle.putParcelable(NetworkRequest.class.getSimpleName(), req); 446 // Pass default objects as we don't care which get passed here 447 bundle.putParcelable(Network.class.getSimpleName(), new Network(1)); 448 bundle.putParcelable(NetworkCapabilities.class.getSimpleName(), new NetworkCapabilities()); 449 bundle.putParcelable(LinkProperties.class.getSimpleName(), new LinkProperties()); 450 Message msg = Message.obtain(); 451 msg.what = messageType; 452 msg.setData(bundle); 453 return msg; 454 } 455 makeRequest(int requestId)456 static NetworkRequest makeRequest(int requestId) { 457 NetworkRequest request = new NetworkRequest.Builder().clearCapabilities().build(); 458 return new NetworkRequest(request.networkCapabilities, ConnectivityManager.TYPE_NONE, 459 requestId, NetworkRequest.Type.NONE); 460 } 461 expectThrowable(Runnable block, Class<? extends Throwable> throwableType)462 static void expectThrowable(Runnable block, Class<? extends Throwable> throwableType) { 463 try { 464 block.run(); 465 } catch (Throwable t) { 466 if (t.getClass().equals(throwableType)) { 467 return; 468 } 469 fail("expected exception of type " + throwableType + ", but was " + t.getClass()); 470 } 471 fail("expected exception of type " + throwableType); 472 } 473 474 private static class MockContext extends BroadcastInterceptingContext { MockContext(Context base)475 MockContext(Context base) { 476 super(base); 477 } 478 479 @Override getApplicationContext()480 public Context getApplicationContext() { 481 return mock(Context.class); 482 } 483 } 484 makeConnectivityManagerAndReturnContext()485 private WeakReference<Context> makeConnectivityManagerAndReturnContext() { 486 // Mockito may have an internal reference to the mock, creating MockContext for testing. 487 final Context c = new MockContext(mock(Context.class)); 488 489 new ConnectivityManager(c, mService); 490 491 return new WeakReference<>(c); 492 } 493 forceGC()494 private void forceGC() { 495 // First GC ensures that objects are collected for finalization, then second GC ensures 496 // they're garbage-collected after being finalized. 497 System.gc(); 498 System.runFinalization(); 499 System.gc(); 500 } 501 502 @Test testConnectivityManagerDoesNotLeakContext()503 public void testConnectivityManagerDoesNotLeakContext() throws Exception { 504 final WeakReference<Context> ref = makeConnectivityManagerAndReturnContext(); 505 506 final int attempts = 600; 507 final long waitIntervalMs = 50; 508 for (int i = 0; i < attempts; i++) { 509 forceGC(); 510 if (ref.get() == null) break; 511 512 Thread.sleep(waitIntervalMs); 513 } 514 515 assertNull("ConnectivityManager weak reference still not null after " + attempts 516 + " attempts", ref.get()); 517 } 518 mockService(Class<T> clazz, String name, T service)519 private <T> void mockService(Class<T> clazz, String name, T service) { 520 doReturn(service).when(mCtx).getSystemService(name); 521 doReturn(name).when(mCtx).getSystemServiceName(clazz); 522 523 // If the test suite uses the inline mock maker library, such as for coverage tests, 524 // then the final version of getSystemService must also be mocked, as the real 525 // method will not be called by the test and null object is returned since no mock. 526 // Otherwise, mocking a final method will fail the test. 527 if (mCtx.getSystemService(clazz) == null) { 528 doReturn(service).when(mCtx).getSystemService(clazz); 529 } 530 } 531 } 532