1 /* 2 * Copyright (C) 2020 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.cts; 18 19 import static android.content.pm.PackageManager.FEATURE_TELEPHONY; 20 import static android.net.ConnectivityDiagnosticsManager.ConnectivityDiagnosticsCallback; 21 import static android.net.ConnectivityDiagnosticsManager.ConnectivityReport; 22 import static android.net.ConnectivityDiagnosticsManager.ConnectivityReport.KEY_NETWORK_PROBES_ATTEMPTED_BITMASK; 23 import static android.net.ConnectivityDiagnosticsManager.ConnectivityReport.KEY_NETWORK_PROBES_SUCCEEDED_BITMASK; 24 import static android.net.ConnectivityDiagnosticsManager.ConnectivityReport.KEY_NETWORK_VALIDATION_RESULT; 25 import static android.net.ConnectivityDiagnosticsManager.ConnectivityReport.NETWORK_VALIDATION_RESULT_SKIPPED; 26 import static android.net.ConnectivityDiagnosticsManager.ConnectivityReport.NETWORK_VALIDATION_RESULT_VALID; 27 import static android.net.ConnectivityDiagnosticsManager.DataStallReport; 28 import static android.net.ConnectivityDiagnosticsManager.DataStallReport.DETECTION_METHOD_DNS_EVENTS; 29 import static android.net.ConnectivityDiagnosticsManager.DataStallReport.DETECTION_METHOD_TCP_METRICS; 30 import static android.net.ConnectivityDiagnosticsManager.DataStallReport.KEY_DNS_CONSECUTIVE_TIMEOUTS; 31 import static android.net.ConnectivityDiagnosticsManager.DataStallReport.KEY_TCP_METRICS_COLLECTION_PERIOD_MILLIS; 32 import static android.net.ConnectivityDiagnosticsManager.DataStallReport.KEY_TCP_PACKET_FAIL_RATE; 33 import static android.net.ConnectivityDiagnosticsManager.persistableBundleEquals; 34 import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET; 35 import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VPN; 36 import static android.net.NetworkCapabilities.NET_CAPABILITY_TRUSTED; 37 import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR; 38 import static android.net.NetworkCapabilities.TRANSPORT_TEST; 39 import static android.net.cts.util.CtsNetUtils.TestNetworkCallback; 40 41 import static com.android.compatibility.common.util.SystemUtil.callWithShellPermissionIdentity; 42 import static com.android.compatibility.common.util.SystemUtil.runWithShellPermissionIdentity; 43 import static com.android.testutils.Cleanup.testAndCleanup; 44 45 import static org.junit.Assert.assertEquals; 46 import static org.junit.Assert.assertNotNull; 47 import static org.junit.Assert.assertNull; 48 import static org.junit.Assert.assertTrue; 49 import static org.junit.Assert.fail; 50 import static org.junit.Assume.assumeTrue; 51 52 import android.annotation.NonNull; 53 import android.content.BroadcastReceiver; 54 import android.content.Context; 55 import android.content.Intent; 56 import android.content.IntentFilter; 57 import android.content.pm.PackageInfo; 58 import android.content.pm.PackageManager; 59 import android.net.ConnectivityDiagnosticsManager; 60 import android.net.ConnectivityManager; 61 import android.net.LinkAddress; 62 import android.net.Network; 63 import android.net.NetworkCapabilities; 64 import android.net.NetworkRequest; 65 import android.net.TestNetworkInterface; 66 import android.net.TestNetworkManager; 67 import android.os.Binder; 68 import android.os.Build; 69 import android.os.IBinder; 70 import android.os.ParcelFileDescriptor; 71 import android.os.PersistableBundle; 72 import android.os.Process; 73 import android.platform.test.annotations.AppModeFull; 74 import android.telephony.CarrierConfigManager; 75 import android.telephony.SubscriptionManager; 76 import android.telephony.TelephonyManager; 77 import android.util.ArraySet; 78 import android.util.Pair; 79 80 import androidx.test.InstrumentationRegistry; 81 82 import com.android.internal.telephony.uicc.IccUtils; 83 import com.android.internal.util.ArrayUtils; 84 import com.android.modules.utils.build.SdkLevel; 85 import com.android.net.module.util.ArrayTrackRecord; 86 import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo; 87 import com.android.testutils.DevSdkIgnoreRunner; 88 89 import org.junit.After; 90 import org.junit.Before; 91 import org.junit.Test; 92 import org.junit.runner.RunWith; 93 94 import java.security.MessageDigest; 95 import java.util.ArrayList; 96 import java.util.Collections; 97 import java.util.List; 98 import java.util.Set; 99 import java.util.concurrent.CountDownLatch; 100 import java.util.concurrent.Executor; 101 import java.util.concurrent.TimeUnit; 102 103 @RunWith(DevSdkIgnoreRunner.class) 104 @IgnoreUpTo(Build.VERSION_CODES.Q) // ConnectivityDiagnosticsManager did not exist in Q 105 @AppModeFull(reason = "CHANGE_NETWORK_STATE, MANAGE_TEST_NETWORKS not grantable to instant apps") 106 public class ConnectivityDiagnosticsManagerTest { 107 private static final int CALLBACK_TIMEOUT_MILLIS = 5000; 108 private static final int NO_CALLBACK_INVOKED_TIMEOUT = 500; 109 private static final long TIMESTAMP = 123456789L; 110 private static final int DNS_CONSECUTIVE_TIMEOUTS = 5; 111 private static final int COLLECTION_PERIOD_MILLIS = 5000; 112 private static final int FAIL_RATE_PERCENTAGE = 100; 113 private static final int UNKNOWN_DETECTION_METHOD = 4; 114 private static final int FILTERED_UNKNOWN_DETECTION_METHOD = 0; 115 private static final int CARRIER_CONFIG_CHANGED_BROADCAST_TIMEOUT = 5000; 116 private static final int DELAY_FOR_ADMIN_UIDS_MILLIS = 5000; 117 118 private static final Executor INLINE_EXECUTOR = x -> x.run(); 119 120 private static final NetworkRequest TEST_NETWORK_REQUEST = 121 new NetworkRequest.Builder() 122 .addTransportType(TRANSPORT_TEST) 123 .removeCapability(NET_CAPABILITY_TRUSTED) 124 .removeCapability(NET_CAPABILITY_NOT_VPN) 125 .build(); 126 127 private static final String SHA_256 = "SHA-256"; 128 129 private static final NetworkRequest CELLULAR_NETWORK_REQUEST = 130 new NetworkRequest.Builder() 131 .addTransportType(TRANSPORT_CELLULAR) 132 .addCapability(NET_CAPABILITY_INTERNET) 133 .build(); 134 135 private static final IBinder BINDER = new Binder(); 136 137 // Lock for accessing Shell Permissions. Use of this lock around adoptShellPermissionIdentity, 138 // runWithShellPermissionIdentity, and callWithShellPermissionIdentity ensures Shell Permission 139 // is not interrupted by another operation (which would drop all previously adopted 140 // permissions). 141 private Object mShellPermissionsIdentityLock = new Object(); 142 143 private Context mContext; 144 private ConnectivityManager mConnectivityManager; 145 private ConnectivityDiagnosticsManager mCdm; 146 private CarrierConfigManager mCarrierConfigManager; 147 private PackageManager mPackageManager; 148 private TelephonyManager mTelephonyManager; 149 150 // Callback used to keep TestNetworks up when there are no other outstanding NetworkRequests 151 // for it. 152 private TestNetworkCallback mTestNetworkCallback; 153 private Network mTestNetwork; 154 private ParcelFileDescriptor mTestNetworkFD; 155 156 private List<TestConnectivityDiagnosticsCallback> mRegisteredCallbacks; 157 158 @Before setUp()159 public void setUp() throws Exception { 160 mContext = InstrumentationRegistry.getContext(); 161 mConnectivityManager = mContext.getSystemService(ConnectivityManager.class); 162 mCdm = mContext.getSystemService(ConnectivityDiagnosticsManager.class); 163 mCarrierConfigManager = mContext.getSystemService(CarrierConfigManager.class); 164 mPackageManager = mContext.getPackageManager(); 165 mTelephonyManager = mContext.getSystemService(TelephonyManager.class); 166 167 mTestNetworkCallback = new TestNetworkCallback(); 168 mConnectivityManager.requestNetwork(TEST_NETWORK_REQUEST, mTestNetworkCallback); 169 170 mRegisteredCallbacks = new ArrayList<>(); 171 } 172 173 @After tearDown()174 public void tearDown() throws Exception { 175 mConnectivityManager.unregisterNetworkCallback(mTestNetworkCallback); 176 if (mTestNetwork != null) { 177 runWithShellPermissionIdentity(() -> { 178 final TestNetworkManager tnm = mContext.getSystemService(TestNetworkManager.class); 179 tnm.teardownTestNetwork(mTestNetwork); 180 }); 181 mTestNetwork = null; 182 } 183 184 if (mTestNetworkFD != null) { 185 mTestNetworkFD.close(); 186 mTestNetworkFD = null; 187 } 188 189 for (TestConnectivityDiagnosticsCallback cb : mRegisteredCallbacks) { 190 mCdm.unregisterConnectivityDiagnosticsCallback(cb); 191 } 192 } 193 194 @Test testRegisterConnectivityDiagnosticsCallback()195 public void testRegisterConnectivityDiagnosticsCallback() throws Exception { 196 mTestNetworkFD = setUpTestNetwork().getFileDescriptor(); 197 mTestNetwork = mTestNetworkCallback.waitForAvailable(); 198 199 final TestConnectivityDiagnosticsCallback cb = 200 createAndRegisterConnectivityDiagnosticsCallback(TEST_NETWORK_REQUEST); 201 202 final String interfaceName = 203 mConnectivityManager.getLinkProperties(mTestNetwork).getInterfaceName(); 204 205 cb.expectOnConnectivityReportAvailable(mTestNetwork, interfaceName); 206 cb.assertNoCallback(); 207 } 208 209 @Test testRegisterCallbackWithCarrierPrivileges()210 public void testRegisterCallbackWithCarrierPrivileges() throws Exception { 211 assumeTrue(mPackageManager.hasSystemFeature(FEATURE_TELEPHONY)); 212 213 final int subId = SubscriptionManager.getDefaultSubscriptionId(); 214 if (subId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) { 215 fail("Need an active subscription. Please ensure that the device has working mobile" 216 + " data."); 217 } 218 219 final CarrierConfigReceiver carrierConfigReceiver = new CarrierConfigReceiver(subId); 220 mContext.registerReceiver( 221 carrierConfigReceiver, 222 new IntentFilter(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED)); 223 224 final TestNetworkCallback testNetworkCallback = new TestNetworkCallback(); 225 226 testAndCleanup(() -> { 227 doBroadcastCarrierConfigsAndVerifyOnConnectivityReportAvailable( 228 subId, carrierConfigReceiver, testNetworkCallback); 229 }, () -> { 230 runWithShellPermissionIdentity( 231 () -> mCarrierConfigManager.overrideConfig(subId, null), 232 android.Manifest.permission.MODIFY_PHONE_STATE); 233 mConnectivityManager.unregisterNetworkCallback(testNetworkCallback); 234 mContext.unregisterReceiver(carrierConfigReceiver); 235 }); 236 } 237 getCertHashForThisPackage()238 private String getCertHashForThisPackage() throws Exception { 239 final PackageInfo pkgInfo = 240 mPackageManager.getPackageInfo( 241 mContext.getOpPackageName(), PackageManager.GET_SIGNATURES); 242 final MessageDigest md = MessageDigest.getInstance(SHA_256); 243 final byte[] certHash = md.digest(pkgInfo.signatures[0].toByteArray()); 244 return IccUtils.bytesToHexString(certHash); 245 } 246 doBroadcastCarrierConfigsAndVerifyOnConnectivityReportAvailable( int subId, @NonNull CarrierConfigReceiver carrierConfigReceiver, @NonNull TestNetworkCallback testNetworkCallback)247 private void doBroadcastCarrierConfigsAndVerifyOnConnectivityReportAvailable( 248 int subId, 249 @NonNull CarrierConfigReceiver carrierConfigReceiver, 250 @NonNull TestNetworkCallback testNetworkCallback) 251 throws Exception { 252 final PersistableBundle carrierConfigs = new PersistableBundle(); 253 carrierConfigs.putStringArray( 254 CarrierConfigManager.KEY_CARRIER_CERTIFICATE_STRING_ARRAY, 255 new String[] {getCertHashForThisPackage()}); 256 257 synchronized (mShellPermissionsIdentityLock) { 258 runWithShellPermissionIdentity( 259 () -> { 260 mCarrierConfigManager.overrideConfig(subId, carrierConfigs); 261 mCarrierConfigManager.notifyConfigChangedForSubId(subId); 262 }, 263 android.Manifest.permission.MODIFY_PHONE_STATE); 264 } 265 266 // TODO(b/157779832): This should use android.permission.CHANGE_NETWORK_STATE. However, the 267 // shell does not have CHANGE_NETWORK_STATE, so use CONNECTIVITY_INTERNAL until the shell 268 // permissions are updated. 269 synchronized (mShellPermissionsIdentityLock) { 270 runWithShellPermissionIdentity( 271 () -> mConnectivityManager.requestNetwork( 272 CELLULAR_NETWORK_REQUEST, testNetworkCallback), 273 android.Manifest.permission.CONNECTIVITY_INTERNAL); 274 } 275 276 final Network network = testNetworkCallback.waitForAvailable(); 277 assertNotNull(network); 278 279 assertTrue("Didn't receive broadcast for ACTION_CARRIER_CONFIG_CHANGED for subId=" + subId, 280 carrierConfigReceiver.waitForCarrierConfigChanged()); 281 282 // Wait for CarrierPrivilegesTracker to receive the ACTION_CARRIER_CONFIG_CHANGED 283 // broadcast. CPT then needs to update the corresponding DataConnection, which then 284 // updates ConnectivityService. Unfortunately, this update to the NetworkCapabilities in 285 // CS does not trigger NetworkCallback#onCapabilitiesChanged as changing the 286 // administratorUids is not a publicly visible change. In lieu of a better signal to 287 // deterministically wait for, use Thread#sleep here. 288 // TODO(b/157949581): replace this Thread#sleep with a deterministic signal 289 Thread.sleep(DELAY_FOR_ADMIN_UIDS_MILLIS); 290 291 // TODO(b/217559768): Receiving carrier config change and immediately checking carrier 292 // privileges is racy, as the CP status is updated after receiving the same signal. Move 293 // the CP check after sleep to temporarily reduce the flakiness. This will soon be fixed 294 // by switching to CarrierPrivilegesListener. 295 assertTrue("Don't have Carrier Privileges after adding cert for this package", 296 mTelephonyManager.createForSubscriptionId(subId).hasCarrierPrivileges()); 297 298 final TestConnectivityDiagnosticsCallback connDiagsCallback = 299 createAndRegisterConnectivityDiagnosticsCallback(CELLULAR_NETWORK_REQUEST); 300 301 final String interfaceName = 302 mConnectivityManager.getLinkProperties(network).getInterfaceName(); 303 connDiagsCallback.maybeVerifyConnectivityReportAvailable( 304 network, interfaceName, TRANSPORT_CELLULAR, NETWORK_VALIDATION_RESULT_VALID); 305 connDiagsCallback.assertNoCallback(); 306 } 307 308 @Test testRegisterDuplicateConnectivityDiagnosticsCallback()309 public void testRegisterDuplicateConnectivityDiagnosticsCallback() { 310 final TestConnectivityDiagnosticsCallback cb = 311 createAndRegisterConnectivityDiagnosticsCallback(TEST_NETWORK_REQUEST); 312 313 try { 314 mCdm.registerConnectivityDiagnosticsCallback(TEST_NETWORK_REQUEST, INLINE_EXECUTOR, cb); 315 fail("Registering the same callback twice should throw an IllegalArgumentException"); 316 } catch (IllegalArgumentException expected) { 317 } 318 } 319 320 @Test testUnregisterConnectivityDiagnosticsCallback()321 public void testUnregisterConnectivityDiagnosticsCallback() { 322 final TestConnectivityDiagnosticsCallback cb = new TestConnectivityDiagnosticsCallback(); 323 mCdm.registerConnectivityDiagnosticsCallback(TEST_NETWORK_REQUEST, INLINE_EXECUTOR, cb); 324 mCdm.unregisterConnectivityDiagnosticsCallback(cb); 325 } 326 327 @Test testUnregisterUnknownConnectivityDiagnosticsCallback()328 public void testUnregisterUnknownConnectivityDiagnosticsCallback() { 329 // Expected to silently ignore the unregister() call 330 mCdm.unregisterConnectivityDiagnosticsCallback(new TestConnectivityDiagnosticsCallback()); 331 } 332 333 @Test testOnConnectivityReportAvailable()334 public void testOnConnectivityReportAvailable() throws Exception { 335 final TestConnectivityDiagnosticsCallback cb = 336 createAndRegisterConnectivityDiagnosticsCallback(TEST_NETWORK_REQUEST); 337 338 mTestNetworkFD = setUpTestNetwork().getFileDescriptor(); 339 mTestNetwork = mTestNetworkCallback.waitForAvailable(); 340 341 final String interfaceName = 342 mConnectivityManager.getLinkProperties(mTestNetwork).getInterfaceName(); 343 344 cb.expectOnConnectivityReportAvailable(mTestNetwork, interfaceName); 345 cb.assertNoCallback(); 346 } 347 348 @Test testOnDataStallSuspected_DnsEvents()349 public void testOnDataStallSuspected_DnsEvents() throws Exception { 350 final PersistableBundle extras = new PersistableBundle(); 351 extras.putInt(KEY_DNS_CONSECUTIVE_TIMEOUTS, DNS_CONSECUTIVE_TIMEOUTS); 352 353 verifyOnDataStallSuspected(DETECTION_METHOD_DNS_EVENTS, TIMESTAMP, extras); 354 } 355 356 @Test testOnDataStallSuspected_TcpMetrics()357 public void testOnDataStallSuspected_TcpMetrics() throws Exception { 358 final PersistableBundle extras = new PersistableBundle(); 359 extras.putInt(KEY_TCP_METRICS_COLLECTION_PERIOD_MILLIS, COLLECTION_PERIOD_MILLIS); 360 extras.putInt(KEY_TCP_PACKET_FAIL_RATE, FAIL_RATE_PERCENTAGE); 361 362 verifyOnDataStallSuspected(DETECTION_METHOD_TCP_METRICS, TIMESTAMP, extras); 363 } 364 365 @Test testOnDataStallSuspected_UnknownDetectionMethod()366 public void testOnDataStallSuspected_UnknownDetectionMethod() throws Exception { 367 verifyOnDataStallSuspected( 368 UNKNOWN_DETECTION_METHOD, 369 FILTERED_UNKNOWN_DETECTION_METHOD, 370 TIMESTAMP, 371 PersistableBundle.EMPTY); 372 } 373 verifyOnDataStallSuspected( int detectionMethod, long timestampMillis, @NonNull PersistableBundle extras)374 private void verifyOnDataStallSuspected( 375 int detectionMethod, long timestampMillis, @NonNull PersistableBundle extras) 376 throws Exception { 377 // Input detection method is expected to match received detection method 378 verifyOnDataStallSuspected(detectionMethod, detectionMethod, timestampMillis, extras); 379 } 380 verifyOnDataStallSuspected( int inputDetectionMethod, int expectedDetectionMethod, long timestampMillis, @NonNull PersistableBundle extras)381 private void verifyOnDataStallSuspected( 382 int inputDetectionMethod, 383 int expectedDetectionMethod, 384 long timestampMillis, 385 @NonNull PersistableBundle extras) 386 throws Exception { 387 mTestNetworkFD = setUpTestNetwork().getFileDescriptor(); 388 mTestNetwork = mTestNetworkCallback.waitForAvailable(); 389 390 final TestConnectivityDiagnosticsCallback cb = 391 createAndRegisterConnectivityDiagnosticsCallback(TEST_NETWORK_REQUEST); 392 393 final String interfaceName = 394 mConnectivityManager.getLinkProperties(mTestNetwork).getInterfaceName(); 395 396 cb.expectOnConnectivityReportAvailable(mTestNetwork, interfaceName); 397 398 runWithShellPermissionIdentity( 399 () -> mConnectivityManager.simulateDataStall( 400 inputDetectionMethod, timestampMillis, mTestNetwork, extras), 401 android.Manifest.permission.MANAGE_TEST_NETWORKS); 402 403 cb.expectOnDataStallSuspected( 404 mTestNetwork, interfaceName, expectedDetectionMethod, timestampMillis, extras); 405 cb.assertNoCallback(); 406 } 407 408 @Test testOnNetworkConnectivityReportedTrue()409 public void testOnNetworkConnectivityReportedTrue() throws Exception { 410 verifyOnNetworkConnectivityReported(true /* hasConnectivity */); 411 } 412 413 @Test testOnNetworkConnectivityReportedFalse()414 public void testOnNetworkConnectivityReportedFalse() throws Exception { 415 verifyOnNetworkConnectivityReported(false /* hasConnectivity */); 416 } 417 verifyOnNetworkConnectivityReported(boolean hasConnectivity)418 private void verifyOnNetworkConnectivityReported(boolean hasConnectivity) throws Exception { 419 mTestNetworkFD = setUpTestNetwork().getFileDescriptor(); 420 mTestNetwork = mTestNetworkCallback.waitForAvailable(); 421 422 final TestConnectivityDiagnosticsCallback cb = 423 createAndRegisterConnectivityDiagnosticsCallback(TEST_NETWORK_REQUEST); 424 425 // onConnectivityReportAvailable always invoked when the test network is established 426 final String interfaceName = 427 mConnectivityManager.getLinkProperties(mTestNetwork).getInterfaceName(); 428 cb.expectOnConnectivityReportAvailable(mTestNetwork, interfaceName); 429 cb.assertNoCallback(); 430 431 mConnectivityManager.reportNetworkConnectivity(mTestNetwork, hasConnectivity); 432 433 cb.expectOnNetworkConnectivityReported(mTestNetwork, hasConnectivity); 434 435 // All calls to #onNetworkConnectivityReported are expected to be accompanied by a call to 436 // #onConnectivityReportAvailable for T+ (for R, ConnectivityReports were only sent when the 437 // Network was re-validated - when reported connectivity != known connectivity). On S, 438 // recent module versions will have the callback, but not the earliest ones. 439 if (!hasConnectivity) { 440 cb.expectOnConnectivityReportAvailable(mTestNetwork, interfaceName); 441 } else if (SdkLevel.isAtLeastS()) { 442 cb.maybeVerifyConnectivityReportAvailable(mTestNetwork, interfaceName, TRANSPORT_TEST, 443 getPossibleDiagnosticsValidationResults(), 444 SdkLevel.isAtLeastT() /* requireCallbackFired */); 445 } 446 447 cb.assertNoCallback(); 448 } 449 createAndRegisterConnectivityDiagnosticsCallback( NetworkRequest request)450 private TestConnectivityDiagnosticsCallback createAndRegisterConnectivityDiagnosticsCallback( 451 NetworkRequest request) { 452 final TestConnectivityDiagnosticsCallback cb = new TestConnectivityDiagnosticsCallback(); 453 mCdm.registerConnectivityDiagnosticsCallback(request, INLINE_EXECUTOR, cb); 454 mRegisteredCallbacks.add(cb); 455 return cb; 456 } 457 458 /** 459 * Registers a test NetworkAgent with ConnectivityService with limited capabilities, which leads 460 * to the Network being validated. 461 */ 462 @NonNull setUpTestNetwork()463 private TestNetworkInterface setUpTestNetwork() throws Exception { 464 final int[] administratorUids = new int[] {Process.myUid()}; 465 return callWithShellPermissionIdentity( 466 () -> { 467 final TestNetworkManager tnm = 468 mContext.getSystemService(TestNetworkManager.class); 469 final TestNetworkInterface tni = tnm.createTunInterface(new LinkAddress[0]); 470 tnm.setupTestNetwork(tni.getInterfaceName(), administratorUids, BINDER); 471 return tni; 472 }); 473 } 474 475 private static class TestConnectivityDiagnosticsCallback 476 extends ConnectivityDiagnosticsCallback { 477 private final ArrayTrackRecord<Object>.ReadHead mHistory = 478 new ArrayTrackRecord<Object>().newReadHead(); 479 480 @Override onConnectivityReportAvailable(ConnectivityReport report)481 public void onConnectivityReportAvailable(ConnectivityReport report) { 482 mHistory.add(report); 483 } 484 485 @Override onDataStallSuspected(DataStallReport report)486 public void onDataStallSuspected(DataStallReport report) { 487 mHistory.add(report); 488 } 489 490 @Override onNetworkConnectivityReported(Network network, boolean hasConnectivity)491 public void onNetworkConnectivityReported(Network network, boolean hasConnectivity) { 492 mHistory.add(new Pair<Network, Boolean>(network, hasConnectivity)); 493 } 494 expectOnConnectivityReportAvailable( @onNull Network network, @NonNull String interfaceName)495 public void expectOnConnectivityReportAvailable( 496 @NonNull Network network, @NonNull String interfaceName) { 497 // Test Networks both do not require validation and are not tested for validation. This 498 // results in the validation result being reported as SKIPPED for S+ (for R, the 499 // platform marked these Networks as VALID). 500 501 maybeVerifyConnectivityReportAvailable(network, interfaceName, TRANSPORT_TEST, 502 getPossibleDiagnosticsValidationResults(), true); 503 } 504 maybeVerifyConnectivityReportAvailable(@onNull Network network, @NonNull String interfaceName, int transportType, int expectedValidationResult)505 public void maybeVerifyConnectivityReportAvailable(@NonNull Network network, 506 @NonNull String interfaceName, int transportType, int expectedValidationResult) { 507 maybeVerifyConnectivityReportAvailable(network, interfaceName, transportType, 508 new ArraySet<>(Collections.singletonList(expectedValidationResult)), true); 509 } 510 maybeVerifyConnectivityReportAvailable(@onNull Network network, @NonNull String interfaceName, int transportType, Set<Integer> possibleValidationResults, boolean requireCallbackFired)511 public void maybeVerifyConnectivityReportAvailable(@NonNull Network network, 512 @NonNull String interfaceName, int transportType, 513 Set<Integer> possibleValidationResults, boolean requireCallbackFired) { 514 final ConnectivityReport result = 515 (ConnectivityReport) mHistory.poll(CALLBACK_TIMEOUT_MILLIS, x -> true); 516 if (!requireCallbackFired && result == null) { 517 return; 518 } 519 assertEquals(network, result.getNetwork()); 520 521 final NetworkCapabilities nc = result.getNetworkCapabilities(); 522 assertNotNull(nc); 523 assertTrue(nc.hasTransport(transportType)); 524 assertNotNull(result.getLinkProperties()); 525 assertEquals(interfaceName, result.getLinkProperties().getInterfaceName()); 526 527 final PersistableBundle extras = result.getAdditionalInfo(); 528 assertTrue(extras.containsKey(KEY_NETWORK_VALIDATION_RESULT)); 529 final int actualValidationResult = extras.getInt(KEY_NETWORK_VALIDATION_RESULT); 530 assertTrue("Network validation result is incorrect: " + actualValidationResult, 531 possibleValidationResults.contains(actualValidationResult)); 532 533 assertTrue(extras.containsKey(KEY_NETWORK_PROBES_SUCCEEDED_BITMASK)); 534 final int probesSucceeded = extras.getInt(KEY_NETWORK_VALIDATION_RESULT); 535 assertTrue("PROBES_SUCCEEDED mask not in expected range", probesSucceeded >= 0); 536 537 assertTrue(extras.containsKey(KEY_NETWORK_PROBES_ATTEMPTED_BITMASK)); 538 final int probesAttempted = extras.getInt(KEY_NETWORK_PROBES_ATTEMPTED_BITMASK); 539 assertTrue("PROBES_ATTEMPTED mask not in expected range", probesAttempted >= 0); 540 } 541 expectOnDataStallSuspected( @onNull Network network, @NonNull String interfaceName, int detectionMethod, long timestampMillis, @NonNull PersistableBundle extras)542 public void expectOnDataStallSuspected( 543 @NonNull Network network, 544 @NonNull String interfaceName, 545 int detectionMethod, 546 long timestampMillis, 547 @NonNull PersistableBundle extras) { 548 final DataStallReport result = 549 (DataStallReport) mHistory.poll(CALLBACK_TIMEOUT_MILLIS, x -> true); 550 assertEquals(network, result.getNetwork()); 551 assertEquals(detectionMethod, result.getDetectionMethod()); 552 assertEquals(timestampMillis, result.getReportTimestamp()); 553 554 final NetworkCapabilities nc = result.getNetworkCapabilities(); 555 assertNotNull(nc); 556 assertTrue(nc.hasTransport(TRANSPORT_TEST)); 557 assertNotNull(result.getLinkProperties()); 558 assertEquals(interfaceName, result.getLinkProperties().getInterfaceName()); 559 560 assertTrue(persistableBundleEquals(extras, result.getStallDetails())); 561 } 562 expectOnNetworkConnectivityReported( @onNull Network network, boolean hasConnectivity)563 public void expectOnNetworkConnectivityReported( 564 @NonNull Network network, boolean hasConnectivity) { 565 final Pair<Network, Boolean> result = 566 (Pair<Network, Boolean>) mHistory.poll(CALLBACK_TIMEOUT_MILLIS, x -> true); 567 assertEquals(network, result.first /* network */); 568 assertEquals(hasConnectivity, result.second /* hasConnectivity */); 569 } 570 assertNoCallback()571 public void assertNoCallback() { 572 // If no more callbacks exist, there should be nothing left in the ReadHead 573 assertNull("Unexpected event in history", 574 mHistory.poll(NO_CALLBACK_INVOKED_TIMEOUT, x -> true)); 575 } 576 } 577 getPossibleDiagnosticsValidationResults()578 private static Set<Integer> getPossibleDiagnosticsValidationResults() { 579 final Set<Integer> possibleValidationResults = new ArraySet<>(); 580 possibleValidationResults.add(NETWORK_VALIDATION_RESULT_SKIPPED); 581 582 // In S, some early module versions will return NETWORK_VALIDATION_RESULT_VALID. 583 // Starting from T, all module versions should only return SKIPPED. For platform < T, 584 // accept both values. 585 if (!SdkLevel.isAtLeastT()) { 586 possibleValidationResults.add(NETWORK_VALIDATION_RESULT_VALID); 587 } 588 return possibleValidationResults; 589 } 590 591 private class CarrierConfigReceiver extends BroadcastReceiver { 592 // CountDownLatch used to wait for this BroadcastReceiver to be notified of a CarrierConfig 593 // change. This latch will be counted down if a broadcast indicates this package has carrier 594 // configs, or if an Exception occurs in #onReceive. 595 private final CountDownLatch mLatch = new CountDownLatch(1); 596 private final int mSubId; 597 598 // #onReceive may encounter Exceptions while running on the Process' main Thread and 599 // #waitForCarrierConfigChanged checks the cached Exception from the test Thread. These 600 // Exceptions must be cached and thrown later, as throwing on the Process' main Thread will 601 // crash the process and cause other tests to fail. 602 private Exception mOnReceiveException; 603 CarrierConfigReceiver(int subId)604 CarrierConfigReceiver(int subId) { 605 mSubId = subId; 606 } 607 608 @Override onReceive(Context context, Intent intent)609 public void onReceive(Context context, Intent intent) { 610 if (!CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED.equals(intent.getAction())) { 611 // Received an incorrect broadcast - ignore 612 return; 613 } 614 615 final int subId = 616 intent.getIntExtra( 617 CarrierConfigManager.EXTRA_SUBSCRIPTION_INDEX, 618 SubscriptionManager.INVALID_SUBSCRIPTION_ID); 619 if (mSubId != subId) { 620 // Received a broadcast for the wrong subId - ignore 621 return; 622 } 623 624 final PersistableBundle carrierConfigs; 625 try { 626 synchronized (mShellPermissionsIdentityLock) { 627 carrierConfigs = callWithShellPermissionIdentity( 628 () -> mCarrierConfigManager.getConfigForSubId(subId), 629 android.Manifest.permission.READ_PHONE_STATE); 630 } 631 } catch (Exception exception) { 632 // callWithShellPermissionIdentity() threw an Exception - cache it and allow 633 // waitForCarrierConfigChanged() to throw it 634 mOnReceiveException = exception; 635 mLatch.countDown(); 636 return; 637 } 638 639 if (!CarrierConfigManager.isConfigForIdentifiedCarrier(carrierConfigs)) { 640 // Configs are not for an identified carrier (meaning they are defaults) - ignore 641 return; 642 } 643 644 final String[] certs = carrierConfigs.getStringArray( 645 CarrierConfigManager.KEY_CARRIER_CERTIFICATE_STRING_ARRAY); 646 try { 647 if (ArrayUtils.contains(certs, getCertHashForThisPackage())) { 648 // Received an update for this package's cert hash - countdown and exit 649 mLatch.countDown(); 650 } 651 // Broadcast is for the right subId, but does not show this package as Carrier 652 // Privileged. Keep waiting for a broadcast that indicates Carrier Privileges. 653 } catch (Exception exception) { 654 // getCertHashForThisPackage() threw an Exception - cache it and allow 655 // waitForCarrierConfigChanged() to throw it 656 mOnReceiveException = exception; 657 mLatch.countDown(); 658 } 659 } 660 661 /** 662 * Waits for the CarrierConfig changed broadcast to reach this CarrierConfigReceiver. 663 * 664 * <p>Must be called from the Test Thread. 665 * 666 * @throws Exception if an Exception occurred during any #onReceive invocation 667 */ waitForCarrierConfigChanged()668 boolean waitForCarrierConfigChanged() throws Exception { 669 final boolean result = mLatch.await(CARRIER_CONFIG_CHANGED_BROADCAST_TIMEOUT, 670 TimeUnit.MILLISECONDS); 671 672 if (mOnReceiveException != null) { 673 throw mOnReceiveException; 674 } 675 676 return result; 677 } 678 } 679 } 680