diff --git a/tests/cts/net/Android.bp b/tests/cts/net/Android.bp index 2b99a40202..112799b716 100644 --- a/tests/cts/net/Android.bp +++ b/tests/cts/net/Android.bp @@ -36,19 +36,20 @@ java_defaults { "src/**/*.java", "src/**/*.kt", ], - + jarjar_rules: "jarjar-rules-shared.txt", static_libs: [ "FrameworksNetCommonTests", "TestNetworkStackLib", - "core-tests-support", "compatibility-device-util-axt", + "core-tests-support", "cts-net-utils", "ctstestrunner-axt", "ctstestserver", - "mockwebserver", "junit", "junit-params", "libnanohttpd", + "mockwebserver", + "net-utils-framework-common", "truth-prebuilt", ], diff --git a/tests/cts/net/jarjar-rules-shared.txt b/tests/cts/net/jarjar-rules-shared.txt new file mode 100644 index 0000000000..11dba74096 --- /dev/null +++ b/tests/cts/net/jarjar-rules-shared.txt @@ -0,0 +1,2 @@ +# Module library in frameworks/libs/net +rule com.android.net.module.util.** android.net.cts.util.@1 \ No newline at end of file diff --git a/tests/cts/net/src/android/net/cts/ConnectivityDiagnosticsManagerTest.java b/tests/cts/net/src/android/net/cts/ConnectivityDiagnosticsManagerTest.java index d17d8e53ae..a19ba64d7f 100644 --- a/tests/cts/net/src/android/net/cts/ConnectivityDiagnosticsManagerTest.java +++ b/tests/cts/net/src/android/net/cts/ConnectivityDiagnosticsManagerTest.java @@ -16,6 +16,7 @@ package android.net.cts; +import static android.content.pm.PackageManager.FEATURE_TELEPHONY; import static android.net.ConnectivityDiagnosticsManager.ConnectivityDiagnosticsCallback; import static android.net.ConnectivityDiagnosticsManager.ConnectivityReport; import static android.net.ConnectivityDiagnosticsManager.ConnectivityReport.KEY_NETWORK_PROBES_ATTEMPTED_BITMASK; @@ -31,9 +32,11 @@ import static android.net.ConnectivityDiagnosticsManager.DataStallReport.KEY_TCP import static android.net.ConnectivityDiagnosticsManager.persistableBundleEquals; import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VPN; import static android.net.NetworkCapabilities.NET_CAPABILITY_TRUSTED; +import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR; import static android.net.NetworkCapabilities.TRANSPORT_TEST; import static android.net.cts.util.CtsNetUtils.TestNetworkCallback; +import static com.android.compatibility.common.util.SystemUtil.callWithShellPermissionIdentity; import static com.android.compatibility.common.util.SystemUtil.runWithShellPermissionIdentity; import static org.junit.Assert.assertEquals; @@ -41,9 +44,15 @@ import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; +import static org.junit.Assume.assumeTrue; import android.annotation.NonNull; +import android.content.BroadcastReceiver; import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.content.pm.PackageInfo; +import android.content.pm.PackageManager; import android.net.ConnectivityDiagnosticsManager; import android.net.ConnectivityManager; import android.net.LinkAddress; @@ -55,13 +64,19 @@ import android.net.TestNetworkManager; import android.os.Binder; import android.os.Build; import android.os.IBinder; +import android.os.ParcelFileDescriptor; import android.os.PersistableBundle; import android.os.Process; import android.platform.test.annotations.AppModeFull; +import android.telephony.CarrierConfigManager; +import android.telephony.SubscriptionManager; +import android.telephony.TelephonyManager; import android.util.Pair; import androidx.test.InstrumentationRegistry; +import com.android.internal.telephony.uicc.IccUtils; +import com.android.internal.util.ArrayUtils; import com.android.testutils.ArrayTrackRecord; import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo; import com.android.testutils.DevSdkIgnoreRunner; @@ -71,7 +86,12 @@ import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; +import java.security.MessageDigest; +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.CountDownLatch; import java.util.concurrent.Executor; +import java.util.concurrent.TimeUnit; @RunWith(DevSdkIgnoreRunner.class) @IgnoreUpTo(Build.VERSION_CODES.Q) // ConnectivityDiagnosticsManager did not exist in Q @@ -85,6 +105,7 @@ public class ConnectivityDiagnosticsManagerTest { private static final int FAIL_RATE_PERCENTAGE = 100; private static final int UNKNOWN_DETECTION_METHOD = 4; private static final int FILTERED_UNKNOWN_DETECTION_METHOD = 0; + private static final int CARRIER_CONFIG_CHANGED_BROADCAST_TIMEOUT = 5000; private static final Executor INLINE_EXECUTOR = x -> x.run(); @@ -95,44 +116,71 @@ public class ConnectivityDiagnosticsManagerTest { .removeCapability(NET_CAPABILITY_NOT_VPN) .build(); - // Callback used to keep TestNetworks up when there are no other outstanding NetworkRequests - // for it. - private static final TestNetworkCallback TEST_NETWORK_CALLBACK = new TestNetworkCallback(); + private static final String SHA_256 = "SHA-256"; + + private static final NetworkRequest CELLULAR_NETWORK_REQUEST = + new NetworkRequest.Builder().addTransportType(TRANSPORT_CELLULAR).build(); private static final IBinder BINDER = new Binder(); private Context mContext; private ConnectivityManager mConnectivityManager; private ConnectivityDiagnosticsManager mCdm; + private CarrierConfigManager mCarrierConfigManager; + private PackageManager mPackageManager; + private TelephonyManager mTelephonyManager; + + // Callback used to keep TestNetworks up when there are no other outstanding NetworkRequests + // for it. + private TestNetworkCallback mTestNetworkCallback; private Network mTestNetwork; + private ParcelFileDescriptor mTestNetworkFD; + + private List mRegisteredCallbacks; @Before public void setUp() throws Exception { mContext = InstrumentationRegistry.getContext(); mConnectivityManager = mContext.getSystemService(ConnectivityManager.class); mCdm = mContext.getSystemService(ConnectivityDiagnosticsManager.class); + mCarrierConfigManager = mContext.getSystemService(CarrierConfigManager.class); + mPackageManager = mContext.getPackageManager(); + mTelephonyManager = mContext.getSystemService(TelephonyManager.class); - mConnectivityManager.requestNetwork(TEST_NETWORK_REQUEST, TEST_NETWORK_CALLBACK); + mTestNetworkCallback = new TestNetworkCallback(); + mConnectivityManager.requestNetwork(TEST_NETWORK_REQUEST, mTestNetworkCallback); + + mRegisteredCallbacks = new ArrayList<>(); } @After public void tearDown() throws Exception { - mConnectivityManager.unregisterNetworkCallback(TEST_NETWORK_CALLBACK); - + mConnectivityManager.unregisterNetworkCallback(mTestNetworkCallback); if (mTestNetwork != null) { runWithShellPermissionIdentity(() -> { final TestNetworkManager tnm = mContext.getSystemService(TestNetworkManager.class); tnm.teardownTestNetwork(mTestNetwork); }); + mTestNetwork = null; + } + + if (mTestNetworkFD != null) { + mTestNetworkFD.close(); + mTestNetworkFD = null; + } + + for (TestConnectivityDiagnosticsCallback cb : mRegisteredCallbacks) { + mCdm.unregisterConnectivityDiagnosticsCallback(cb); } } @Test public void testRegisterConnectivityDiagnosticsCallback() throws Exception { - mTestNetwork = setUpTestNetwork(); + mTestNetworkFD = setUpTestNetwork().getFileDescriptor(); + mTestNetwork = mTestNetworkCallback.waitForAvailable(); - final TestConnectivityDiagnosticsCallback cb = new TestConnectivityDiagnosticsCallback(); - mCdm.registerConnectivityDiagnosticsCallback(TEST_NETWORK_REQUEST, INLINE_EXECUTOR, cb); + final TestConnectivityDiagnosticsCallback cb = + createAndRegisterConnectivityDiagnosticsCallback(TEST_NETWORK_REQUEST); final String interfaceName = mConnectivityManager.getLinkProperties(mTestNetwork).getInterfaceName(); @@ -141,10 +189,99 @@ public class ConnectivityDiagnosticsManagerTest { cb.assertNoCallback(); } + @Test + public void testRegisterCallbackWithCarrierPrivileges() throws Exception { + assumeTrue(mPackageManager.hasSystemFeature(FEATURE_TELEPHONY)); + + final int subId = SubscriptionManager.getDefaultSubscriptionId(); + if (subId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) { + fail("Need an active subscription. Please ensure that the device has working mobile" + + " data."); + } + + final CarrierConfigReceiver carrierConfigReceiver = new CarrierConfigReceiver(subId); + mContext.registerReceiver( + carrierConfigReceiver, + new IntentFilter(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED)); + + final TestNetworkCallback testNetworkCallback = new TestNetworkCallback(); + + try { + doBroadcastCarrierConfigsAndVerifyOnConnectivityReportAvailable( + subId, carrierConfigReceiver, testNetworkCallback); + } finally { + runWithShellPermissionIdentity( + () -> mCarrierConfigManager.overrideConfig(subId, null), + android.Manifest.permission.MODIFY_PHONE_STATE); + mConnectivityManager.unregisterNetworkCallback(testNetworkCallback); + mContext.unregisterReceiver(carrierConfigReceiver); + } + } + + private String getCertHashForThisPackage() throws Exception { + final PackageInfo pkgInfo = + mPackageManager.getPackageInfo( + mContext.getOpPackageName(), PackageManager.GET_SIGNATURES); + final MessageDigest md = MessageDigest.getInstance(SHA_256); + final byte[] certHash = md.digest(pkgInfo.signatures[0].toByteArray()); + return IccUtils.bytesToHexString(certHash); + } + + private void doBroadcastCarrierConfigsAndVerifyOnConnectivityReportAvailable( + int subId, + @NonNull CarrierConfigReceiver carrierConfigReceiver, + @NonNull TestNetworkCallback testNetworkCallback) + throws Exception { + final PersistableBundle carrierConfigs = new PersistableBundle(); + carrierConfigs.putStringArray( + CarrierConfigManager.KEY_CARRIER_CERTIFICATE_STRING_ARRAY, + new String[] {getCertHashForThisPackage()}); + + runWithShellPermissionIdentity( + () -> { + mCarrierConfigManager.overrideConfig(subId, carrierConfigs); + mCarrierConfigManager.notifyConfigChangedForSubId(subId); + }, + android.Manifest.permission.MODIFY_PHONE_STATE); + + // TODO(b/157779832): This should use android.permission.CHANGE_NETWORK_STATE. However, the + // shell does not have CHANGE_NETWORK_STATE, so use CONNECTIVITY_INTERNAL until the shell + // permissions are updated. + runWithShellPermissionIdentity( + () -> mConnectivityManager.requestNetwork( + CELLULAR_NETWORK_REQUEST, testNetworkCallback), + android.Manifest.permission.CONNECTIVITY_INTERNAL); + + final Network network = testNetworkCallback.waitForAvailable(); + assertNotNull(network); + + assertTrue("Didn't receive broadcast for ACTION_CARRIER_CONFIG_CHANGED for subId=" + subId, + carrierConfigReceiver.waitForCarrierConfigChanged()); + assertTrue("Don't have Carrier Privileges after adding cert for this package", + mTelephonyManager.createForSubscriptionId(subId).hasCarrierPrivileges()); + + // Wait for CarrierPrivilegesTracker to receive the ACTION_CARRIER_CONFIG_CHANGED + // broadcast. CPT then needs to update the corresponding DataConnection, which then + // updates ConnectivityService. Unfortunately, this update to the NetworkCapabilities in + // CS does not trigger NetworkCallback#onCapabilitiesChanged as changing the + // administratorUids is not a publicly visible change. In lieu of a better signal to + // detministically wait for, use Thread#sleep here. + Thread.sleep(500); + + final TestConnectivityDiagnosticsCallback connDiagsCallback = + createAndRegisterConnectivityDiagnosticsCallback(CELLULAR_NETWORK_REQUEST); + + final String interfaceName = + mConnectivityManager.getLinkProperties(network).getInterfaceName(); + connDiagsCallback.expectOnConnectivityReportAvailable( + network, interfaceName, TRANSPORT_CELLULAR); + connDiagsCallback.assertNoCallback(); + } + @Test public void testRegisterDuplicateConnectivityDiagnosticsCallback() { - final TestConnectivityDiagnosticsCallback cb = new TestConnectivityDiagnosticsCallback(); - mCdm.registerConnectivityDiagnosticsCallback(TEST_NETWORK_REQUEST, INLINE_EXECUTOR, cb); + final TestConnectivityDiagnosticsCallback cb = + createAndRegisterConnectivityDiagnosticsCallback(TEST_NETWORK_REQUEST); try { mCdm.registerConnectivityDiagnosticsCallback(TEST_NETWORK_REQUEST, INLINE_EXECUTOR, cb); @@ -168,10 +305,11 @@ public class ConnectivityDiagnosticsManagerTest { @Test public void testOnConnectivityReportAvailable() throws Exception { - mTestNetwork = setUpTestNetwork(); + final TestConnectivityDiagnosticsCallback cb = + createAndRegisterConnectivityDiagnosticsCallback(TEST_NETWORK_REQUEST); - final TestConnectivityDiagnosticsCallback cb = new TestConnectivityDiagnosticsCallback(); - mCdm.registerConnectivityDiagnosticsCallback(TEST_NETWORK_REQUEST, INLINE_EXECUTOR, cb); + mTestNetworkFD = setUpTestNetwork().getFileDescriptor(); + mTestNetwork = mTestNetworkCallback.waitForAvailable(); final String interfaceName = mConnectivityManager.getLinkProperties(mTestNetwork).getInterfaceName(); @@ -219,10 +357,11 @@ public class ConnectivityDiagnosticsManagerTest { long timestampMillis, @NonNull PersistableBundle extras) throws Exception { - mTestNetwork = setUpTestNetwork(); + mTestNetworkFD = setUpTestNetwork().getFileDescriptor(); + mTestNetwork = mTestNetworkCallback.waitForAvailable(); - final TestConnectivityDiagnosticsCallback cb = new TestConnectivityDiagnosticsCallback(); - mCdm.registerConnectivityDiagnosticsCallback(TEST_NETWORK_REQUEST, INLINE_EXECUTOR, cb); + final TestConnectivityDiagnosticsCallback cb = + createAndRegisterConnectivityDiagnosticsCallback(TEST_NETWORK_REQUEST); final String interfaceName = mConnectivityManager.getLinkProperties(mTestNetwork).getInterfaceName(); @@ -250,10 +389,11 @@ public class ConnectivityDiagnosticsManagerTest { } private void verifyOnNetworkConnectivityReported(boolean hasConnectivity) throws Exception { - mTestNetwork = setUpTestNetwork(); + mTestNetworkFD = setUpTestNetwork().getFileDescriptor(); + mTestNetwork = mTestNetworkCallback.waitForAvailable(); - final TestConnectivityDiagnosticsCallback cb = new TestConnectivityDiagnosticsCallback(); - mCdm.registerConnectivityDiagnosticsCallback(TEST_NETWORK_REQUEST, INLINE_EXECUTOR, cb); + final TestConnectivityDiagnosticsCallback cb = + createAndRegisterConnectivityDiagnosticsCallback(TEST_NETWORK_REQUEST); // onConnectivityReportAvailable always invoked when the test network is established final String interfaceName = @@ -274,17 +414,12 @@ public class ConnectivityDiagnosticsManagerTest { cb.assertNoCallback(); } - @NonNull - private Network waitForConnectivityServiceIdleAndGetNetwork() throws InterruptedException { - // Get a new Network. This requires going through the ConnectivityService thread. Once it - // completes, all previously enqueued messages on the ConnectivityService main Handler have - // completed. - final TestNetworkCallback callback = new TestNetworkCallback(); - mConnectivityManager.requestNetwork(TEST_NETWORK_REQUEST, callback); - final Network network = callback.waitForAvailable(); - mConnectivityManager.unregisterNetworkCallback(callback); - assertNotNull(network); - return network; + private TestConnectivityDiagnosticsCallback createAndRegisterConnectivityDiagnosticsCallback( + NetworkRequest request) { + final TestConnectivityDiagnosticsCallback cb = new TestConnectivityDiagnosticsCallback(); + mCdm.registerConnectivityDiagnosticsCallback(request, INLINE_EXECUTOR, cb); + mRegisteredCallbacks.add(cb); + return cb; } /** @@ -292,16 +427,16 @@ public class ConnectivityDiagnosticsManagerTest { * to the Network being validated. */ @NonNull - private Network setUpTestNetwork() throws Exception { + private TestNetworkInterface setUpTestNetwork() throws Exception { final int[] administratorUids = new int[] {Process.myUid()}; - runWithShellPermissionIdentity( + return callWithShellPermissionIdentity( () -> { final TestNetworkManager tnm = mContext.getSystemService(TestNetworkManager.class); final TestNetworkInterface tni = tnm.createTunInterface(new LinkAddress[0]); tnm.setupTestNetwork(tni.getInterfaceName(), administratorUids, BINDER); + return tni; }); - return waitForConnectivityServiceIdleAndGetNetwork(); } private static class TestConnectivityDiagnosticsCallback @@ -326,13 +461,18 @@ public class ConnectivityDiagnosticsManagerTest { public void expectOnConnectivityReportAvailable( @NonNull Network network, @NonNull String interfaceName) { + expectOnConnectivityReportAvailable(network, interfaceName, TRANSPORT_TEST); + } + + public void expectOnConnectivityReportAvailable( + @NonNull Network network, @NonNull String interfaceName, int transportType) { final ConnectivityReport result = (ConnectivityReport) mHistory.poll(CALLBACK_TIMEOUT_MILLIS, x -> true); assertEquals(network, result.getNetwork()); final NetworkCapabilities nc = result.getNetworkCapabilities(); assertNotNull(nc); - assertTrue(nc.hasTransport(TRANSPORT_TEST)); + assertTrue(nc.hasTransport(transportType)); assertNotNull(result.getLinkProperties()); assertEquals(interfaceName, result.getLinkProperties().getInterfaceName()); @@ -386,4 +526,43 @@ public class ConnectivityDiagnosticsManagerTest { mHistory.poll(NO_CALLBACK_INVOKED_TIMEOUT, x -> true)); } } + + private class CarrierConfigReceiver extends BroadcastReceiver { + private final CountDownLatch mLatch = new CountDownLatch(1); + private final int mSubId; + + CarrierConfigReceiver(int subId) { + mSubId = subId; + } + + @Override + public void onReceive(Context context, Intent intent) { + if (!CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED.equals(intent.getAction())) { + return; + } + + final int subId = + intent.getIntExtra( + CarrierConfigManager.EXTRA_SUBSCRIPTION_INDEX, + SubscriptionManager.INVALID_SUBSCRIPTION_ID); + if (mSubId != subId) return; + + final PersistableBundle carrierConfigs = mCarrierConfigManager.getConfigForSubId(subId); + if (!CarrierConfigManager.isConfigForIdentifiedCarrier(carrierConfigs)) return; + + final String[] certs = + carrierConfigs.getStringArray( + CarrierConfigManager.KEY_CARRIER_CERTIFICATE_STRING_ARRAY); + try { + if (ArrayUtils.contains(certs, getCertHashForThisPackage())) { + mLatch.countDown(); + } + } catch (Exception e) { + } + } + + boolean waitForCarrierConfigChanged() throws Exception { + return mLatch.await(CARRIER_CONFIG_CHANGED_BROADCAST_TIMEOUT, TimeUnit.MILLISECONDS); + } + } }