diff --git a/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java b/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java index baf5c2e302..d498ed9885 100644 --- a/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java +++ b/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java @@ -40,6 +40,16 @@ import static android.system.OsConstants.AF_INET6; import static android.system.OsConstants.AF_UNSPEC; import static com.android.compatibility.common.util.SystemUtil.runShellCommand; +import static com.android.compatibility.common.util.SystemUtil.runWithShellPermissionIdentity; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNotSame; +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.app.Instrumentation; @@ -78,17 +88,22 @@ import android.os.SystemProperties; import android.os.VintfRuntimeInfo; import android.platform.test.annotations.AppModeFull; import android.provider.Settings; -import android.test.AndroidTestCase; import android.text.TextUtils; import android.util.Log; import android.util.Pair; import androidx.test.InstrumentationRegistry; +import androidx.test.runner.AndroidJUnit4; import com.android.internal.util.ArrayUtils; import libcore.io.Streams; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; + import java.io.FileDescriptor; import java.io.IOException; import java.io.InputStream; @@ -114,7 +129,8 @@ import java.util.function.Supplier; import java.util.regex.Matcher; import java.util.regex.Pattern; -public class ConnectivityManagerTest extends AndroidTestCase { +@RunWith(AndroidJUnit4.class) +public class ConnectivityManagerTest { private static final String TAG = ConnectivityManagerTest.class.getSimpleName(); @@ -126,7 +142,10 @@ public class ConnectivityManagerTest extends AndroidTestCase { private static final int INTERVAL_KEEPALIVE_RETRY_MS = 500; private static final int MAX_KEEPALIVE_RETRY_COUNT = 3; private static final int MIN_KEEPALIVE_INTERVAL = 10; - private static final int NETWORK_CHANGE_METEREDNESS_TIMEOUT = 5000; + + // Changing meteredness on wifi involves reconnecting, which can take several seconds (involves + // re-associating, DHCP...) + private static final int NETWORK_CHANGE_METEREDNESS_TIMEOUT = 30_000; private static final int NUM_TRIES_MULTIPATH_PREF_CHECK = 20; private static final long INTERVAL_MULTIPATH_PREF_CHECK_MS = 500; // device could have only one interface: data, wifi. @@ -150,22 +169,19 @@ public class ConnectivityManagerTest extends AndroidTestCase { private PackageManager mPackageManager; private final HashMap mNetworks = new HashMap(); - boolean mWifiConnectAttempted; + boolean mWifiWasDisabled; private UiAutomation mUiAutomation; private CtsNetUtils mCtsNetUtils; - private boolean mShellPermissionIdentityAdopted; - @Override - protected void setUp() throws Exception { - super.setUp(); - Looper.prepare(); - mContext = getContext(); + @Before + public void setUp() throws Exception { mInstrumentation = InstrumentationRegistry.getInstrumentation(); + mContext = mInstrumentation.getContext(); mCm = (ConnectivityManager) mContext.getSystemService(Context.CONNECTIVITY_SERVICE); mWifiManager = (WifiManager) mContext.getSystemService(Context.WIFI_SERVICE); mPackageManager = mContext.getPackageManager(); mCtsNetUtils = new CtsNetUtils(mContext); - mWifiConnectAttempted = false; + mWifiWasDisabled = false; // Get com.android.internal.R.array.networkAttributes int resId = mContext.getResources().getIdentifier("networkAttributes", "array", "android"); @@ -182,20 +198,17 @@ public class ConnectivityManagerTest extends AndroidTestCase { } catch (Exception e) {} } mUiAutomation = mInstrumentation.getUiAutomation(); - mShellPermissionIdentityAdopted = false; } - @Override - protected void tearDown() throws Exception { + @After + public void tearDown() throws Exception { // Return WiFi to its original disabled state after tests that explicitly connect. - if (mWifiConnectAttempted) { + if (mWifiWasDisabled) { mCtsNetUtils.disconnectFromWifi(null); } if (mCtsNetUtils.cellConnectAttempted()) { mCtsNetUtils.disconnectFromCell(); } - dropShellPermissionIdentity(); - super.tearDown(); } /** @@ -204,13 +217,12 @@ public class ConnectivityManagerTest extends AndroidTestCase { * automatically in tearDown(). */ private Network ensureWifiConnected() { - if (mWifiManager.isWifiEnabled()) { - return mCtsNetUtils.getWifiNetwork(); - } - mWifiConnectAttempted = true; + mWifiWasDisabled = !mWifiManager.isWifiEnabled(); + // Even if wifi is enabled, the network may not be connected or ready yet return mCtsNetUtils.connectToWifi(); } + @Test public void testIsNetworkTypeValid() { assertTrue(ConnectivityManager.isNetworkTypeValid(ConnectivityManager.TYPE_MOBILE)); assertTrue(ConnectivityManager.isNetworkTypeValid(ConnectivityManager.TYPE_WIFI)); @@ -240,12 +252,14 @@ public class ConnectivityManagerTest extends AndroidTestCase { } + @Test public void testSetNetworkPreference() { // getNetworkPreference() and setNetworkPreference() are both deprecated so they do // not preform any action. Verify they are at least still callable. mCm.setNetworkPreference(mCm.getNetworkPreference()); } + @Test public void testGetActiveNetworkInfo() { NetworkInfo ni = mCm.getActiveNetworkInfo(); @@ -254,6 +268,7 @@ public class ConnectivityManagerTest extends AndroidTestCase { assertTrue(ni.getState() == State.CONNECTED); } + @Test public void testGetActiveNetwork() { Network network = mCm.getActiveNetwork(); assertNotNull("You must have an active network connection to complete CTS", network); @@ -266,6 +281,7 @@ public class ConnectivityManagerTest extends AndroidTestCase { assertTrue(ni.getState() == State.CONNECTED); } + @Test public void testGetNetworkInfo() { for (int type = -1; type <= ConnectivityManager.MAX_NETWORK_TYPE+1; type++) { if (shouldBeSupported(type)) { @@ -284,6 +300,7 @@ public class ConnectivityManagerTest extends AndroidTestCase { } } + @Test public void testGetAllNetworkInfo() { NetworkInfo[] ni = mCm.getAllNetworkInfo(); assertTrue(ni.length >= MIN_NUM_NETWORK_TYPES); @@ -307,6 +324,7 @@ public class ConnectivityManagerTest extends AndroidTestCase { * and that they are made from different IP addresses. */ @AppModeFull(reason = "Cannot get WifiManager in instant app mode") + @Test public void testOpenConnection() throws Exception { boolean canRunTest = mPackageManager.hasSystemFeature(FEATURE_WIFI) && mPackageManager.hasSystemFeature(FEATURE_TELEPHONY); @@ -386,6 +404,7 @@ public class ConnectivityManagerTest extends AndroidTestCase { } catch (UnsupportedOperationException expected) {} } + @Test public void testStartUsingNetworkFeature() { final String invalidateFeature = "invalidateFeature"; @@ -415,6 +434,7 @@ public class ConnectivityManagerTest extends AndroidTestCase { (networkType == ConnectivityManager.TYPE_ETHERNET && shouldEthernetBeSupported()); } + @Test public void testIsNetworkSupported() { for (int type = -1; type <= ConnectivityManager.MAX_NETWORK_TYPE; type++) { boolean supported = mCm.isNetworkSupported(type); @@ -426,12 +446,14 @@ public class ConnectivityManagerTest extends AndroidTestCase { } } + @Test public void testRequestRouteToHost() { for (int type = -1 ; type <= ConnectivityManager.MAX_NETWORK_TYPE; type++) { assertRequestRouteToHostUnsupported(type, HOST_ADDRESS); } } + @Test public void testTest() { mCm.getBackgroundDataSetting(); } @@ -452,6 +474,7 @@ public class ConnectivityManagerTest extends AndroidTestCase { * that it would increase test coverage by much (how many devices have 3G radio but not Wifi?). */ @AppModeFull(reason = "Cannot get WifiManager in instant app mode") + @Test public void testRegisterNetworkCallback() { if (!mPackageManager.hasSystemFeature(FEATURE_WIFI)) { Log.i(TAG, "testRegisterNetworkCallback cannot execute unless device supports WiFi"); @@ -493,6 +516,7 @@ public class ConnectivityManagerTest extends AndroidTestCase { * of a {@code NetworkCallback}. */ @AppModeFull(reason = "Cannot get WifiManager in instant app mode") + @Test public void testRegisterNetworkCallback_withPendingIntent() { if (!mPackageManager.hasSystemFeature(FEATURE_WIFI)) { Log.i(TAG, "testRegisterNetworkCallback cannot execute unless device supports WiFi"); @@ -538,6 +562,7 @@ public class ConnectivityManagerTest extends AndroidTestCase { * see if we get a callback for an INTERNET request. */ @AppModeFull(reason = "CHANGE_NETWORK_STATE permission can't be granted to instant apps") + @Test public void testRequestNetworkCallback() { final TestNetworkCallback callback = new TestNetworkCallback(); mCm.requestNetwork(new NetworkRequest.Builder() @@ -561,6 +586,7 @@ public class ConnectivityManagerTest extends AndroidTestCase { * fail. Use WIFI and switch Wi-Fi off. */ @AppModeFull(reason = "Cannot get WifiManager in instant app mode") + @Test public void testRequestNetworkCallback_onUnavailable() { final boolean previousWifiEnabledState = mWifiManager.isWifiEnabled(); if (previousWifiEnabledState) { @@ -598,6 +624,7 @@ public class ConnectivityManagerTest extends AndroidTestCase { /** Verify restricted networks cannot be requested. */ @AppModeFull(reason = "CHANGE_NETWORK_STATE permission can't be granted to instant apps") + @Test public void testRestrictedNetworks() { // Verify we can request unrestricted networks: NetworkRequest request = new NetworkRequest.Builder() @@ -719,6 +746,7 @@ public class ConnectivityManagerTest extends AndroidTestCase { * for metered and unmetered networks. */ @AppModeFull(reason = "Cannot get WifiManager in instant app mode") + @Test public void testGetMultipathPreference() throws Exception { final ContentResolver resolver = mContext.getContentResolver(); ensureWifiConnected(); @@ -887,18 +915,6 @@ public class ConnectivityManagerTest extends AndroidTestCase { keepalivesPerTransport, nc); } - private void adoptShellPermissionIdentity() { - mUiAutomation.adoptShellPermissionIdentity(); - mShellPermissionIdentityAdopted = true; - } - - private void dropShellPermissionIdentity() { - if (mShellPermissionIdentityAdopted) { - mUiAutomation.dropShellPermissionIdentity(); - mShellPermissionIdentityAdopted = false; - } - } - private static boolean isTcpKeepaliveSupportedByKernel() { final String kVersionString = VintfRuntimeInfo.getKernelVersion(); return compareMajorMinorVersion(kVersionString, "4.8") >= 0; @@ -933,6 +949,7 @@ public class ConnectivityManagerTest extends AndroidTestCase { * Verifies that version string compare logic returns expected result for various cases. * Note that only major and minor number are compared. */ + @Test public void testMajorMinorVersionCompare() { assertEquals(0, compareMajorMinorVersion("4.8.1", "4.8")); assertEquals(1, compareMajorMinorVersion("4.9", "4.8.1")); @@ -952,6 +969,7 @@ public class ConnectivityManagerTest extends AndroidTestCase { * keepalives is set to 0. */ @AppModeFull(reason = "Cannot get WifiManager in instant app mode") + @Test public void testKeepaliveWifiUnsupported() throws Exception { if (!mPackageManager.hasSystemFeature(FEATURE_WIFI)) { Log.i(TAG, "testKeepaliveUnsupported cannot execute unless device" @@ -961,32 +979,36 @@ public class ConnectivityManagerTest extends AndroidTestCase { final Network network = ensureWifiConnected(); if (getSupportedKeepalivesForNet(network) != 0) return; + final InetAddress srcAddr = getFirstV4Address(network); + assumeTrue("This test requires native IPv4", srcAddr != null); - adoptShellPermissionIdentity(); - - assertEquals(0, createConcurrentSocketKeepalives(network, 1, 0)); - assertEquals(0, createConcurrentSocketKeepalives(network, 0, 1)); - - dropShellPermissionIdentity(); + runWithShellPermissionIdentity(() -> { + assertEquals(0, createConcurrentSocketKeepalives(network, srcAddr, 1, 0)); + assertEquals(0, createConcurrentSocketKeepalives(network, srcAddr, 0, 1)); + }); } @AppModeFull(reason = "Cannot get WifiManager in instant app mode") + @Test public void testCreateTcpKeepalive() throws Exception { if (!mPackageManager.hasSystemFeature(FEATURE_WIFI)) { Log.i(TAG, "testCreateTcpKeepalive cannot execute unless device supports WiFi"); return; } - adoptShellPermissionIdentity(); - final Network network = ensureWifiConnected(); if (getSupportedKeepalivesForNet(network) == 0) return; + final InetAddress srcAddr = getFirstV4Address(network); + assumeTrue("This test requires native IPv4", srcAddr != null); + // If kernel < 4.8 then it doesn't support TCP keepalive, but it might still support // NAT-T keepalive. If keepalive limits from resource overlay is not zero, TCP keepalive // needs to be supported except if the kernel doesn't support it. if (!isTcpKeepaliveSupportedByKernel()) { // Sanity check to ensure the callback result is expected. - assertEquals(0, createConcurrentSocketKeepalives(network, 0, 1)); + runWithShellPermissionIdentity(() -> { + assertEquals(0, createConcurrentSocketKeepalives(network, srcAddr, 0, 1)); + }); Log.i(TAG, "testCreateTcpKeepalive is skipped for kernel " + VintfRuntimeInfo.getKernelVersion()); return; @@ -1000,6 +1022,8 @@ public class ConnectivityManagerTest extends AndroidTestCase { // Should able to start keep alive offload when socket is idle. final Executor executor = mContext.getMainExecutor(); final TestSocketKeepaliveCallback callback = new TestSocketKeepaliveCallback(); + + mUiAutomation.adoptShellPermissionIdentity(); try (SocketKeepalive sk = mCm.createSocketKeepalive(network, s, executor, callback)) { sk.start(MIN_KEEPALIVE_INTERVAL); callback.expectStarted(); @@ -1021,6 +1045,8 @@ public class ConnectivityManagerTest extends AndroidTestCase { // Stop. sk.stop(); callback.expectStopped(); + } finally { + mUiAutomation.dropShellPermissionIdentity(); } // Ensure socket is still connected. @@ -1049,9 +1075,12 @@ public class ConnectivityManagerTest extends AndroidTestCase { // Should get ERROR_SOCKET_NOT_IDLE because there is still data in the receive queue // that has not been read. + mUiAutomation.adoptShellPermissionIdentity(); try (SocketKeepalive sk = mCm.createSocketKeepalive(network, s, executor, callback)) { sk.start(MIN_KEEPALIVE_INTERVAL); callback.expectError(SocketKeepalive.ERROR_SOCKET_NOT_IDLE); + } finally { + mUiAutomation.dropShellPermissionIdentity(); } } } @@ -1096,7 +1125,7 @@ public class ConnectivityManagerTest extends AndroidTestCase { } private @NonNull ArrayList createConcurrentNattSocketKeepalives( - @NonNull Network network, int requestCount, + @NonNull Network network, @NonNull InetAddress srcAddr, int requestCount, @NonNull TestSocketKeepaliveCallback callback) throws Exception { final Executor executor = mContext.getMainExecutor(); @@ -1104,7 +1133,6 @@ public class ConnectivityManagerTest extends AndroidTestCase { // Initialize a real NaT-T socket. final IpSecManager mIpSec = (IpSecManager) mContext.getSystemService(Context.IPSEC_SERVICE); final UdpEncapsulationSocket nattSocket = mIpSec.openUdpEncapsulationSocket(); - final InetAddress srcAddr = getFirstV4Address(network); final InetAddress dstAddr = getAddrByName(TEST_HOST, AF_INET); assertNotNull(srcAddr); assertNotNull(dstAddr); @@ -1145,11 +1173,12 @@ public class ConnectivityManagerTest extends AndroidTestCase { * @return the total number of keepalives created. */ private int createConcurrentSocketKeepalives( - @NonNull Network network, int nattCount, int tcpCount) throws Exception { + @NonNull Network network, @NonNull InetAddress srcAddr, int nattCount, int tcpCount) + throws Exception { final ArrayList kalist = new ArrayList<>(); final TestSocketKeepaliveCallback callback = new TestSocketKeepaliveCallback(); - kalist.addAll(createConcurrentNattSocketKeepalives(network, nattCount, callback)); + kalist.addAll(createConcurrentNattSocketKeepalives(network, srcAddr, nattCount, callback)); kalist.addAll(createConcurrentTcpSocketKeepalives(network, tcpCount, callback)); final int ret = kalist.size(); @@ -1169,6 +1198,7 @@ public class ConnectivityManagerTest extends AndroidTestCase { * get leaked after iterations. */ @AppModeFull(reason = "Cannot get WifiManager in instant app mode") + @Test public void testSocketKeepaliveLimitWifi() throws Exception { if (!mPackageManager.hasSystemFeature(FEATURE_WIFI)) { Log.i(TAG, "testSocketKeepaliveLimitWifi cannot execute unless device" @@ -1181,33 +1211,39 @@ public class ConnectivityManagerTest extends AndroidTestCase { if (supported == 0) { return; } + final InetAddress srcAddr = getFirstV4Address(network); + assumeTrue("This test requires native IPv4", srcAddr != null); - adoptShellPermissionIdentity(); + runWithShellPermissionIdentity(() -> { + // Verifies that the supported keepalive slots meet MIN_SUPPORTED_KEEPALIVE_COUNT. + assertGreaterOrEqual(supported, MIN_SUPPORTED_WIFI_KEEPALIVE_COUNT); - // Verifies that the supported keepalive slots meet MIN_SUPPORTED_KEEPALIVE_COUNT. - assertGreaterOrEqual(supported, MIN_SUPPORTED_WIFI_KEEPALIVE_COUNT); - - // Verifies that Nat-T keepalives can be established. - assertEquals(supported, createConcurrentSocketKeepalives(network, supported + 1, 0)); - // Verifies that keepalives don't get leaked in second round. - assertEquals(supported, createConcurrentSocketKeepalives(network, supported, 0)); + // Verifies that Nat-T keepalives can be established. + assertEquals(supported, createConcurrentSocketKeepalives(network, srcAddr, + supported + 1, 0)); + // Verifies that keepalives don't get leaked in second round. + assertEquals(supported, createConcurrentSocketKeepalives(network, srcAddr, supported, + 0)); + }); // If kernel < 4.8 then it doesn't support TCP keepalive, but it might still support // NAT-T keepalive. Test below cases only if TCP keepalive is supported by kernel. - if (isTcpKeepaliveSupportedByKernel()) { - assertEquals(supported, createConcurrentSocketKeepalives(network, 0, supported + 1)); + if (!isTcpKeepaliveSupportedByKernel()) return; + + runWithShellPermissionIdentity(() -> { + assertEquals(supported, createConcurrentSocketKeepalives(network, srcAddr, 0, + supported + 1)); // Verifies that different types can be established at the same time. - assertEquals(supported, createConcurrentSocketKeepalives(network, + assertEquals(supported, createConcurrentSocketKeepalives(network, srcAddr, supported / 2, supported - supported / 2)); // Verifies that keepalives don't get leaked in second round. - assertEquals(supported, createConcurrentSocketKeepalives(network, 0, supported)); - assertEquals(supported, createConcurrentSocketKeepalives(network, + assertEquals(supported, createConcurrentSocketKeepalives(network, srcAddr, 0, + supported)); + assertEquals(supported, createConcurrentSocketKeepalives(network, srcAddr, supported / 2, supported - supported / 2)); - } - - dropShellPermissionIdentity(); + }); } /** @@ -1215,6 +1251,7 @@ public class ConnectivityManagerTest extends AndroidTestCase { * don't get leaked after iterations. */ @AppModeFull(reason = "Cannot request network in instant app mode") + @Test public void testSocketKeepaliveLimitTelephony() throws Exception { if (!mPackageManager.hasSystemFeature(FEATURE_TELEPHONY)) { Log.i(TAG, "testSocketKeepaliveLimitTelephony cannot execute unless device" @@ -1231,18 +1268,19 @@ public class ConnectivityManagerTest extends AndroidTestCase { final Network network = mCtsNetUtils.connectToCell(); final int supported = getSupportedKeepalivesForNet(network); + final InetAddress srcAddr = getFirstV4Address(network); + assumeTrue("This test requires native IPv4", srcAddr != null); - adoptShellPermissionIdentity(); - - // Verifies that the supported keepalive slots meet minimum requirement. - assertGreaterOrEqual(supported, MIN_SUPPORTED_CELLULAR_KEEPALIVE_COUNT); - - // Verifies that Nat-T keepalives can be established. - assertEquals(supported, createConcurrentSocketKeepalives(network, supported + 1, 0)); - // Verifies that keepalives don't get leaked in second round. - assertEquals(supported, createConcurrentSocketKeepalives(network, supported, 0)); - - dropShellPermissionIdentity(); + runWithShellPermissionIdentity(() -> { + // Verifies that the supported keepalive slots meet minimum requirement. + assertGreaterOrEqual(supported, MIN_SUPPORTED_CELLULAR_KEEPALIVE_COUNT); + // Verifies that Nat-T keepalives can be established. + assertEquals(supported, createConcurrentSocketKeepalives(network, srcAddr, + supported + 1, 0)); + // Verifies that keepalives don't get leaked in second round. + assertEquals(supported, createConcurrentSocketKeepalives(network, srcAddr, supported, + 0)); + }); } private int getIntResourceForName(@NonNull String resName) { @@ -1255,6 +1293,7 @@ public class ConnectivityManagerTest extends AndroidTestCase { * Verifies that the keepalive slots are limited as customized for unprivileged requests. */ @AppModeFull(reason = "Cannot get WifiManager in instant app mode") + @Test public void testSocketKeepaliveUnprivileged() throws Exception { if (!mPackageManager.hasSystemFeature(FEATURE_WIFI)) { Log.i(TAG, "testSocketKeepaliveUnprivileged cannot execute unless device" @@ -1267,6 +1306,8 @@ public class ConnectivityManagerTest extends AndroidTestCase { if (supported == 0) { return; } + final InetAddress srcAddr = getFirstV4Address(network); + assumeTrue("This test requires native IPv4", srcAddr != null); // Resource ID might be shifted on devices that compiled with different symbols. // Thus, resolve ID at runtime is needed. @@ -1282,7 +1323,7 @@ public class ConnectivityManagerTest extends AndroidTestCase { final int expectedUnprivileged = Math.min(allowedUnprivilegedPerUid, supported - reservedPrivilegedSlots); assertEquals(expectedUnprivileged, - createConcurrentSocketKeepalives(network, supported + 1, 0)); + createConcurrentSocketKeepalives(network, srcAddr, supported + 1, 0)); } private static void assertGreaterOrEqual(long greater, long lesser) { @@ -1296,6 +1337,7 @@ public class ConnectivityManagerTest extends AndroidTestCase { * See. b/144679405. */ @AppModeFull(reason = "Cannot get WifiManager in instant app mode") + @Test public void testRestrictedNetworkPermission() throws Exception { // Ensure that CONNECTIVITY_USE_RESTRICTED_NETWORKS isn't granted to this package. final PackageInfo app = mPackageManager.getPackageInfo(mContext.getPackageName(),