diff --git a/tests/cts/net/Android.bp b/tests/cts/net/Android.bp index 779d5c4be2..b6ea4afe80 100644 --- a/tests/cts/net/Android.bp +++ b/tests/cts/net/Android.bp @@ -42,6 +42,7 @@ android_test { "FrameworksNetCommonTests", "core-tests-support", "compatibility-device-util-axt", + "cts-net-utils", "ctstestrunner-axt", "ctstestserver", "mockwebserver", diff --git a/tests/cts/net/api23Test/Android.bp b/tests/cts/net/api23Test/Android.bp index 48161cf7e7..ffe854e2e9 100644 --- a/tests/cts/net/api23Test/Android.bp +++ b/tests/cts/net/api23Test/Android.bp @@ -31,6 +31,7 @@ android_test { static_libs: [ "core-tests-support", "compatibility-device-util-axt", + "cts-net-utils", "ctstestrunner-axt", "ctstestserver", "mockwebserver", diff --git a/tests/cts/net/api23Test/src/android/net/cts/api23test/ConnectivityManagerApi23Test.java b/tests/cts/net/api23Test/src/android/net/cts/api23test/ConnectivityManagerApi23Test.java index f38490e60e..cdb66e3d5a 100644 --- a/tests/cts/net/api23Test/src/android/net/cts/api23test/ConnectivityManagerApi23Test.java +++ b/tests/cts/net/api23Test/src/android/net/cts/api23test/ConnectivityManagerApi23Test.java @@ -25,58 +25,33 @@ import android.content.Intent; import android.content.IntentFilter; import android.content.pm.PackageManager; import android.net.ConnectivityManager; -import android.net.Network; -import android.net.NetworkCapabilities; -import android.net.NetworkInfo; -import android.net.NetworkInfo.State; -import android.net.NetworkRequest; -import android.net.wifi.WifiManager; +import android.net.cts.util.CtsNetUtils; import android.os.Looper; -import android.system.Os; -import android.system.OsConstants; import android.test.AndroidTestCase; import android.util.Log; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.net.InetSocketAddress; -import java.net.Socket; -import java.util.concurrent.CountDownLatch; import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.TimeUnit; public class ConnectivityManagerApi23Test extends AndroidTestCase { private static final String TAG = ConnectivityManagerApi23Test.class.getSimpleName(); - - private static final String TEST_HOST = "connectivitycheck.gstatic.com"; - private static final int SOCKET_TIMEOUT_MS = 2000; private static final int SEND_BROADCAST_TIMEOUT = 30000; - private static final int HTTP_PORT = 80; // Intent string to get the number of wifi CONNECTIVITY_ACTION callbacks the test app has seen public static final String GET_WIFI_CONNECTIVITY_ACTION_COUNT = "android.net.cts.appForApi23.getWifiConnectivityActionCount"; // Action sent to ConnectivityActionReceiver when a network callback is sent via PendingIntent. - private static final String NETWORK_CALLBACK_ACTION = - "ConnectivityManagerTest.NetworkCallbackAction"; - private static final String HTTP_REQUEST = - "GET /generate_204 HTTP/1.0\r\n" + - "Host: " + TEST_HOST + "\r\n" + - "Connection: keep-alive\r\n\r\n"; private Context mContext; - private ConnectivityManager mCm; - private WifiManager mWifiManager; private PackageManager mPackageManager; + private CtsNetUtils mCtsNetUtils; @Override protected void setUp() throws Exception { super.setUp(); Looper.prepare(); mContext = getContext(); - mCm = (ConnectivityManager) mContext.getSystemService(Context.CONNECTIVITY_SERVICE); - mWifiManager = (WifiManager) mContext.getSystemService(Context.WIFI_SERVICE); mPackageManager = mContext.getPackageManager(); + mCtsNetUtils = new CtsNetUtils(mContext); } /** @@ -89,7 +64,7 @@ public class ConnectivityManagerApi23Test extends AndroidTestCase { } ConnectivityReceiver.prepare(); - toggleWifi(); + mCtsNetUtils.toggleWifi(); // The connectivity broadcast has been sent; push through a terminal broadcast // to wait for in the receive to confirm it didn't see the connectivity change. @@ -112,7 +87,7 @@ public class ConnectivityManagerApi23Test extends AndroidTestCase { .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)); Thread.sleep(200); - toggleWifi(); + mCtsNetUtils.toggleWifi(); Intent getConnectivityCount = new Intent(GET_WIFI_CONNECTIVITY_ACTION_COUNT); assertEquals(2, sendOrderedBroadcastAndReturnResultCode( @@ -130,7 +105,7 @@ public class ConnectivityManagerApi23Test extends AndroidTestCase { filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION); mContext.registerReceiver(receiver, filter); - toggleWifi(); + mCtsNetUtils.toggleWifi(); Intent finalIntent = new Intent(ConnectivityReceiver.FINAL_ACTION); finalIntent.setClass(mContext, ConnectivityReceiver.class); mContext.sendBroadcast(finalIntent); @@ -138,19 +113,6 @@ public class ConnectivityManagerApi23Test extends AndroidTestCase { assertTrue(ConnectivityReceiver.waitForBroadcast()); } - // Toggle WiFi twice, leaving it in the state it started in - private void toggleWifi() { - if (mWifiManager.isWifiEnabled()) { - Network wifiNetwork = getWifiNetwork(); - disconnectFromWifi(wifiNetwork); - connectToWifi(); - } else { - connectToWifi(); - Network wifiNetwork = getWifiNetwork(); - disconnectFromWifi(wifiNetwork); - } - } - private int sendOrderedBroadcastAndReturnResultCode( Intent intent, int timeoutMs) throws InterruptedException { final LinkedBlockingQueue result = new LinkedBlockingQueue<>(1); @@ -167,233 +129,4 @@ public class ConnectivityManagerApi23Test extends AndroidTestCase { return resultCode; } - private Network getWifiNetwork() { - TestNetworkCallback callback = new TestNetworkCallback(); - mCm.registerNetworkCallback(makeWifiNetworkRequest(), callback); - Network network = null; - try { - network = callback.waitForAvailable(); - } catch (InterruptedException e) { - fail("NetworkCallback wait was interrupted."); - } finally { - mCm.unregisterNetworkCallback(callback); - } - assertNotNull("Cannot find Network for wifi. Is wifi connected?", network); - return network; - } - - /** Disable WiFi and wait for it to become disconnected from the network. */ - private void disconnectFromWifi(Network wifiNetworkToCheck) { - final TestNetworkCallback callback = new TestNetworkCallback(); - mCm.registerNetworkCallback(makeWifiNetworkRequest(), callback); - Network lostWifiNetwork = null; - - ConnectivityActionReceiver receiver = new ConnectivityActionReceiver( - ConnectivityManager.TYPE_WIFI, NetworkInfo.State.DISCONNECTED); - IntentFilter filter = new IntentFilter(); - filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION); - mContext.registerReceiver(receiver, filter); - - // Assert that we can establish a TCP connection on wifi. - Socket wifiBoundSocket = null; - if (wifiNetworkToCheck != null) { - try { - wifiBoundSocket = getBoundSocket(wifiNetworkToCheck, TEST_HOST, HTTP_PORT); - testHttpRequest(wifiBoundSocket); - } catch (IOException e) { - fail("HTTP request before wifi disconnected failed with: " + e); - } - } - - boolean disconnected = false; - try { - assertTrue(mWifiManager.setWifiEnabled(false)); - // Ensure we get both an onLost callback and a CONNECTIVITY_ACTION. - lostWifiNetwork = callback.waitForLost(); - assertNotNull(lostWifiNetwork); - disconnected = receiver.waitForState(); - } catch (InterruptedException ex) { - fail("disconnectFromWifi was interrupted"); - } finally { - mCm.unregisterNetworkCallback(callback); - mContext.unregisterReceiver(receiver); - } - - assertTrue("Wifi failed to reach DISCONNECTED state.", disconnected); - - // Check that the socket is closed when wifi disconnects. - if (wifiBoundSocket != null) { - try { - testHttpRequest(wifiBoundSocket); - fail("HTTP request should not succeed after wifi disconnects"); - } catch (IOException expected) { - assertEquals(Os.strerror(OsConstants.ECONNABORTED), expected.getMessage()); - } - } - } - - /** Enable WiFi and wait for it to become connected to a network. */ - private Network connectToWifi() { - final TestNetworkCallback callback = new TestNetworkCallback(); - mCm.registerNetworkCallback(makeWifiNetworkRequest(), callback); - Network wifiNetwork = null; - - ConnectivityActionReceiver receiver = new ConnectivityActionReceiver( - ConnectivityManager.TYPE_WIFI, NetworkInfo.State.CONNECTED); - IntentFilter filter = new IntentFilter(); - filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION); - mContext.registerReceiver(receiver, filter); - - boolean connected = false; - try { - assertTrue(mWifiManager.setWifiEnabled(true)); - // Ensure we get both an onAvailable callback and a CONNECTIVITY_ACTION. - wifiNetwork = callback.waitForAvailable(); - assertNotNull(wifiNetwork); - connected = receiver.waitForState(); - } catch (InterruptedException ex) { - fail("connectToWifi was interrupted"); - } finally { - mCm.unregisterNetworkCallback(callback); - mContext.unregisterReceiver(receiver); - } - - assertTrue("Wifi must be configured to connect to an access point for this test.", - connected); - return wifiNetwork; - } - - private NetworkRequest makeWifiNetworkRequest() { - return new NetworkRequest.Builder() - .addTransportType(NetworkCapabilities.TRANSPORT_WIFI) - .build(); - } - - private void testHttpRequest(Socket s) throws IOException { - OutputStream out = s.getOutputStream(); - InputStream in = s.getInputStream(); - - final byte[] requestBytes = HTTP_REQUEST.getBytes("UTF-8"); - byte[] responseBytes = new byte[4096]; - out.write(requestBytes); - in.read(responseBytes); - assertTrue(new String(responseBytes, "UTF-8").startsWith("HTTP/1.0 204 No Content\r\n")); - } - - private Socket getBoundSocket(Network network, String host, int port) throws IOException { - InetSocketAddress addr = new InetSocketAddress(host, port); - Socket s = network.getSocketFactory().createSocket(); - try { - s.setSoTimeout(SOCKET_TIMEOUT_MS); - s.connect(addr, SOCKET_TIMEOUT_MS); - } catch (IOException e) { - s.close(); - throw e; - } - return s; - } - - /** - * Receiver that captures the last connectivity change's network type and state. Recognizes - * both {@code CONNECTIVITY_ACTION} and {@code NETWORK_CALLBACK_ACTION} intents. - */ - private class ConnectivityActionReceiver extends BroadcastReceiver { - - private final CountDownLatch mReceiveLatch = new CountDownLatch(1); - - private final int mNetworkType; - private final NetworkInfo.State mNetState; - - ConnectivityActionReceiver(int networkType, NetworkInfo.State netState) { - mNetworkType = networkType; - mNetState = netState; - } - - public void onReceive(Context context, Intent intent) { - String action = intent.getAction(); - NetworkInfo networkInfo = null; - - // When receiving ConnectivityManager.CONNECTIVITY_ACTION, the NetworkInfo parcelable - // is stored in EXTRA_NETWORK_INFO. With a NETWORK_CALLBACK_ACTION, the Network is - // sent in EXTRA_NETWORK and we need to ask the ConnectivityManager for the NetworkInfo. - if (ConnectivityManager.CONNECTIVITY_ACTION.equals(action)) { - networkInfo = intent.getExtras() - .getParcelable(ConnectivityManager.EXTRA_NETWORK_INFO); - assertNotNull("ConnectivityActionReceiver expected EXTRA_NETWORK_INFO", networkInfo); - } else if (NETWORK_CALLBACK_ACTION.equals(action)) { - Network network = intent.getExtras() - .getParcelable(ConnectivityManager.EXTRA_NETWORK); - assertNotNull("ConnectivityActionReceiver expected EXTRA_NETWORK", network); - networkInfo = mCm.getNetworkInfo(network); - if (networkInfo == null) { - // When disconnecting, it seems like we get an intent sent with an invalid - // Network; that is, by the time we call ConnectivityManager.getNetworkInfo(), - // it is invalid. Ignore these. - Log.i(TAG, "ConnectivityActionReceiver NETWORK_CALLBACK_ACTION ignoring " - + "invalid network"); - return; - } - } else { - fail("ConnectivityActionReceiver received unxpected intent action: " + action); - } - - assertNotNull("ConnectivityActionReceiver didn't find NetworkInfo", networkInfo); - int networkType = networkInfo.getType(); - State networkState = networkInfo.getState(); - Log.i(TAG, "Network type: " + networkType + " state: " + networkState); - if (networkType == mNetworkType && networkInfo.getState() == mNetState) { - mReceiveLatch.countDown(); - } - } - - public boolean waitForState() throws InterruptedException { - return mReceiveLatch.await(30, TimeUnit.SECONDS); - } - } - - /** - * Callback used in testRegisterNetworkCallback that allows caller to block on - * {@code onAvailable}. - */ - private static class TestNetworkCallback extends ConnectivityManager.NetworkCallback { - private final CountDownLatch mAvailableLatch = new CountDownLatch(1); - private final CountDownLatch mLostLatch = new CountDownLatch(1); - private final CountDownLatch mUnavailableLatch = new CountDownLatch(1); - - public Network currentNetwork; - public Network lastLostNetwork; - - public Network waitForAvailable() throws InterruptedException { - return mAvailableLatch.await(30, TimeUnit.SECONDS) ? currentNetwork : null; - } - - public Network waitForLost() throws InterruptedException { - return mLostLatch.await(30, TimeUnit.SECONDS) ? lastLostNetwork : null; - } - - public boolean waitForUnavailable() throws InterruptedException { - return mUnavailableLatch.await(2, TimeUnit.SECONDS); - } - - - @Override - public void onAvailable(Network network) { - currentNetwork = network; - mAvailableLatch.countDown(); - } - - @Override - public void onLost(Network network) { - lastLostNetwork = network; - if (network.equals(currentNetwork)) { - currentNetwork = null; - } - mLostLatch.countDown(); - } - - @Override - public void onUnavailable() { - mUnavailableLatch.countDown(); - } - } } \ No newline at end of file diff --git a/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java b/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java index c444445b2a..c3ae793aae 100644 --- a/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java +++ b/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java @@ -21,8 +21,12 @@ import static android.content.pm.PackageManager.FEATURE_WIFI; import static android.net.NetworkCapabilities.NET_CAPABILITY_IMS; import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET; import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_METERED; -import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR; import static android.net.NetworkCapabilities.TRANSPORT_WIFI; +import static android.net.cts.util.CtsNetUtils.ConnectivityActionReceiver; +import static android.net.cts.util.CtsNetUtils.HTTP_PORT; +import static android.net.cts.util.CtsNetUtils.NETWORK_CALLBACK_ACTION; +import static android.net.cts.util.CtsNetUtils.TEST_HOST; +import static android.net.cts.util.CtsNetUtils.TestNetworkCallback; import static android.os.MessageQueue.OnFileDescriptorEventListener.EVENT_INPUT; import static android.provider.Settings.Global.NETWORK_METERED_MULTIPATH_PREFERENCE; import static android.system.OsConstants.AF_INET; @@ -34,7 +38,6 @@ import static com.android.compatibility.common.util.SystemUtil.runShellCommand; import android.app.Instrumentation; import android.app.PendingIntent; import android.app.UiAutomation; -import android.content.BroadcastReceiver; import android.content.ContentResolver; import android.content.Context; import android.content.Intent; @@ -53,6 +56,7 @@ import android.net.NetworkInfo.DetailedState; import android.net.NetworkInfo.State; import android.net.NetworkRequest; import android.net.SocketKeepalive; +import android.net.cts.util.CtsNetUtils; import android.net.util.KeepaliveUtils; import android.net.wifi.WifiManager; import android.os.Looper; @@ -61,15 +65,12 @@ import android.os.SystemClock; import android.os.SystemProperties; import android.platform.test.annotations.AppModeFull; import android.provider.Settings; -import android.system.Os; -import android.system.OsConstants; import android.test.AndroidTestCase; import android.text.TextUtils; import android.util.Log; import androidx.test.InstrumentationRegistry; -import com.android.compatibility.common.util.SystemUtil; import com.android.internal.R; import com.android.internal.telephony.PhoneConstants; @@ -107,8 +108,6 @@ public class ConnectivityManagerTest extends AndroidTestCase { public static final int TYPE_WIFI = ConnectivityManager.TYPE_WIFI; private static final int HOST_ADDRESS = 0x7f000001;// represent ip 127.0.0.1 - private static final String TEST_HOST = "connectivitycheck.gstatic.com"; - private static final int SOCKET_TIMEOUT_MS = 2000; private static final int CONNECT_TIMEOUT_MS = 2000; private static final int KEEPALIVE_CALLBACK_TIMEOUT_MS = 2000; private static final int KEEPALIVE_SOCKET_TIMEOUT_MS = 5000; @@ -116,16 +115,6 @@ public class ConnectivityManagerTest extends AndroidTestCase { private static final int NETWORK_CHANGE_METEREDNESS_TIMEOUT = 5000; private static final int NUM_TRIES_MULTIPATH_PREF_CHECK = 20; private static final long INTERVAL_MULTIPATH_PREF_CHECK_MS = 500; - private static final int HTTP_PORT = 80; - private static final String HTTP_REQUEST = - "GET /generate_204 HTTP/1.0\r\n" + - "Host: " + TEST_HOST + "\r\n" + - "Connection: keep-alive\r\n\r\n"; - - // Action sent to ConnectivityActionReceiver when a network callback is sent via PendingIntent. - private static final String NETWORK_CALLBACK_ACTION = - "ConnectivityManagerTest.NetworkCallbackAction"; - // device could have only one interface: data, wifi. private static final int MIN_NUM_NETWORK_TYPES = 1; @@ -137,8 +126,8 @@ public class ConnectivityManagerTest extends AndroidTestCase { private final HashMap mNetworks = new HashMap(); boolean mWifiConnectAttempted; - private TestNetworkCallback mCellNetworkCallback; private UiAutomation mUiAutomation; + private CtsNetUtils mCtsNetUtils; private boolean mShellPermissionIdentityAdopted; @Override @@ -150,6 +139,7 @@ public class ConnectivityManagerTest extends AndroidTestCase { mCm = (ConnectivityManager) mContext.getSystemService(Context.CONNECTIVITY_SERVICE); mWifiManager = (WifiManager) mContext.getSystemService(Context.WIFI_SERVICE); mPackageManager = mContext.getPackageManager(); + mCtsNetUtils = new CtsNetUtils(mContext); mWifiConnectAttempted = false; // Get com.android.internal.R.array.networkAttributes @@ -174,10 +164,10 @@ public class ConnectivityManagerTest extends AndroidTestCase { protected void tearDown() throws Exception { // Return WiFi to its original disabled state after tests that explicitly connect. if (mWifiConnectAttempted) { - disconnectFromWifi(null); + mCtsNetUtils.disconnectFromWifi(null); } - if (cellConnectAttempted()) { - disconnectFromCell(); + if (mCtsNetUtils.cellConnectAttempted()) { + mCtsNetUtils.disconnectFromCell(); } dropShellPermissionIdentity(); super.tearDown(); @@ -190,10 +180,10 @@ public class ConnectivityManagerTest extends AndroidTestCase { */ private Network ensureWifiConnected() { if (mWifiManager.isWifiEnabled()) { - return getWifiNetwork(); + return mCtsNetUtils.getWifiNetwork(); } mWifiConnectAttempted = true; - return connectToWifi(); + return mCtsNetUtils.connectToWifi(); } public void testIsNetworkTypeValid() { @@ -301,8 +291,8 @@ public class ConnectivityManagerTest extends AndroidTestCase { return; } - Network wifiNetwork = connectToWifi(); - Network cellNetwork = connectToCell(); + Network wifiNetwork = mCtsNetUtils.connectToWifi(); + Network cellNetwork = mCtsNetUtils.connectToCell(); // This server returns the requestor's IP address as the response body. URL url = new URL("http://google-ipv6test.appspot.com/ip.js?fmt=text"); String wifiAddressString = httpGet(wifiNetwork, url); @@ -320,33 +310,6 @@ public class ConnectivityManagerTest extends AndroidTestCase { assertFalse("Unexpectedly equal: " + wifiNetwork, wifiNetwork.equals(cellNetwork)); } - private Network connectToCell() throws InterruptedException { - if (cellConnectAttempted()) { - throw new IllegalStateException("Already connected"); - } - NetworkRequest cellRequest = new NetworkRequest.Builder() - .addTransportType(TRANSPORT_CELLULAR) - .addCapability(NET_CAPABILITY_INTERNET) - .build(); - mCellNetworkCallback = new TestNetworkCallback(); - mCm.requestNetwork(cellRequest, mCellNetworkCallback); - final Network cellNetwork = mCellNetworkCallback.waitForAvailable(); - assertNotNull("Cell network not available within timeout", cellNetwork); - return cellNetwork; - } - - private boolean cellConnectAttempted() { - return mCellNetworkCallback != null; - } - - private void disconnectFromCell() { - if (!cellConnectAttempted()) { - throw new IllegalStateException("Cell connection not attempted"); - } - mCm.unregisterNetworkCallback(mCellNetworkCallback); - mCellNetworkCallback = null; - } - /** * Performs a HTTP GET to the specified URL on the specified Network, and returns * the response body decoded as UTF-8. @@ -508,7 +471,7 @@ public class ConnectivityManagerTest extends AndroidTestCase { filter.addAction(NETWORK_CALLBACK_ACTION); ConnectivityActionReceiver receiver = new ConnectivityActionReceiver( - ConnectivityManager.TYPE_WIFI, NetworkInfo.State.CONNECTED); + mCm, ConnectivityManager.TYPE_WIFI, NetworkInfo.State.CONNECTED); mContext.registerReceiver(receiver, filter); // Create a broadcast PendingIntent for NETWORK_CALLBACK_ACTION. @@ -567,7 +530,7 @@ public class ConnectivityManagerTest extends AndroidTestCase { public void testRequestNetworkCallback_onUnavailable() { final boolean previousWifiEnabledState = mWifiManager.isWifiEnabled(); if (previousWifiEnabledState) { - disconnectFromWifi(null); + mCtsNetUtils.disconnectFromWifi(null); } final TestNetworkCallback callback = new TestNetworkCallback(); @@ -584,42 +547,11 @@ public class ConnectivityManagerTest extends AndroidTestCase { } finally { mCm.unregisterNetworkCallback(callback); if (previousWifiEnabledState) { - connectToWifi(); + mCtsNetUtils.connectToWifi(); } } } - /** Enable WiFi and wait for it to become connected to a network. */ - private Network connectToWifi() { - final TestNetworkCallback callback = new TestNetworkCallback(); - mCm.registerNetworkCallback(makeWifiNetworkRequest(), callback); - Network wifiNetwork = null; - - ConnectivityActionReceiver receiver = new ConnectivityActionReceiver( - ConnectivityManager.TYPE_WIFI, NetworkInfo.State.CONNECTED); - IntentFilter filter = new IntentFilter(); - filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION); - mContext.registerReceiver(receiver, filter); - - boolean connected = false; - try { - SystemUtil.runShellCommand("svc wifi enable"); - // Ensure we get both an onAvailable callback and a CONNECTIVITY_ACTION. - wifiNetwork = callback.waitForAvailable(); - assertNotNull(wifiNetwork); - connected = receiver.waitForState(); - } catch (InterruptedException ex) { - fail("connectToWifi was interrupted"); - } finally { - mCm.unregisterNetworkCallback(callback); - mContext.unregisterReceiver(receiver); - } - - assertTrue("Wifi must be configured to connect to an access point for this test.", - connected); - return wifiNetwork; - } - private InetAddress getFirstV4Address(Network network) { LinkProperties linkProperties = mCm.getLinkProperties(network); for (InetAddress address : linkProperties.getAddresses()) { @@ -630,199 +562,6 @@ public class ConnectivityManagerTest extends AndroidTestCase { return null; } - private Socket getBoundSocket(Network network, String host, int port) throws IOException { - InetSocketAddress addr = new InetSocketAddress(host, port); - Socket s = network.getSocketFactory().createSocket(); - try { - s.setSoTimeout(SOCKET_TIMEOUT_MS); - s.connect(addr, SOCKET_TIMEOUT_MS); - } catch (IOException e) { - s.close(); - throw e; - } - return s; - } - - private void testHttpRequest(Socket s) throws IOException { - OutputStream out = s.getOutputStream(); - InputStream in = s.getInputStream(); - - final byte[] requestBytes = HTTP_REQUEST.getBytes("UTF-8"); - byte[] responseBytes = new byte[4096]; - out.write(requestBytes); - in.read(responseBytes); - assertTrue(new String(responseBytes, "UTF-8").startsWith("HTTP/1.0 204 No Content\r\n")); - } - - /** Disable WiFi and wait for it to become disconnected from the network. */ - private void disconnectFromWifi(Network wifiNetworkToCheck) { - final TestNetworkCallback callback = new TestNetworkCallback(); - mCm.registerNetworkCallback(makeWifiNetworkRequest(), callback); - Network lostWifiNetwork = null; - - ConnectivityActionReceiver receiver = new ConnectivityActionReceiver( - ConnectivityManager.TYPE_WIFI, NetworkInfo.State.DISCONNECTED); - IntentFilter filter = new IntentFilter(); - filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION); - mContext.registerReceiver(receiver, filter); - - // Assert that we can establish a TCP connection on wifi. - Socket wifiBoundSocket = null; - if (wifiNetworkToCheck != null) { - try { - wifiBoundSocket = getBoundSocket(wifiNetworkToCheck, TEST_HOST, HTTP_PORT); - testHttpRequest(wifiBoundSocket); - } catch (IOException e) { - fail("HTTP request before wifi disconnected failed with: " + e); - } - } - - boolean disconnected = false; - try { - SystemUtil.runShellCommand("svc wifi disable"); - // Ensure we get both an onLost callback and a CONNECTIVITY_ACTION. - lostWifiNetwork = callback.waitForLost(); - assertNotNull(lostWifiNetwork); - disconnected = receiver.waitForState(); - } catch (InterruptedException ex) { - fail("disconnectFromWifi was interrupted"); - } finally { - mCm.unregisterNetworkCallback(callback); - mContext.unregisterReceiver(receiver); - } - - assertTrue("Wifi failed to reach DISCONNECTED state.", disconnected); - - // Check that the socket is closed when wifi disconnects. - if (wifiBoundSocket != null) { - try { - testHttpRequest(wifiBoundSocket); - fail("HTTP request should not succeed after wifi disconnects"); - } catch (IOException expected) { - assertEquals(Os.strerror(OsConstants.ECONNABORTED), expected.getMessage()); - } - } - } - - /** - * Receiver that captures the last connectivity change's network type and state. Recognizes - * both {@code CONNECTIVITY_ACTION} and {@code NETWORK_CALLBACK_ACTION} intents. - */ - private class ConnectivityActionReceiver extends BroadcastReceiver { - - private final CountDownLatch mReceiveLatch = new CountDownLatch(1); - - private final int mNetworkType; - private final NetworkInfo.State mNetState; - - ConnectivityActionReceiver(int networkType, NetworkInfo.State netState) { - mNetworkType = networkType; - mNetState = netState; - } - - public void onReceive(Context context, Intent intent) { - String action = intent.getAction(); - NetworkInfo networkInfo = null; - - // When receiving ConnectivityManager.CONNECTIVITY_ACTION, the NetworkInfo parcelable - // is stored in EXTRA_NETWORK_INFO. With a NETWORK_CALLBACK_ACTION, the Network is - // sent in EXTRA_NETWORK and we need to ask the ConnectivityManager for the NetworkInfo. - if (ConnectivityManager.CONNECTIVITY_ACTION.equals(action)) { - networkInfo = intent.getExtras() - .getParcelable(ConnectivityManager.EXTRA_NETWORK_INFO); - assertNotNull("ConnectivityActionReceiver expected EXTRA_NETWORK_INFO", networkInfo); - } else if (NETWORK_CALLBACK_ACTION.equals(action)) { - Network network = intent.getExtras() - .getParcelable(ConnectivityManager.EXTRA_NETWORK); - assertNotNull("ConnectivityActionReceiver expected EXTRA_NETWORK", network); - networkInfo = mCm.getNetworkInfo(network); - if (networkInfo == null) { - // When disconnecting, it seems like we get an intent sent with an invalid - // Network; that is, by the time we call ConnectivityManager.getNetworkInfo(), - // it is invalid. Ignore these. - Log.i(TAG, "ConnectivityActionReceiver NETWORK_CALLBACK_ACTION ignoring " - + "invalid network"); - return; - } - } else { - fail("ConnectivityActionReceiver received unxpected intent action: " + action); - } - - assertNotNull("ConnectivityActionReceiver didn't find NetworkInfo", networkInfo); - int networkType = networkInfo.getType(); - State networkState = networkInfo.getState(); - Log.i(TAG, "Network type: " + networkType + " state: " + networkState); - if (networkType == mNetworkType && networkInfo.getState() == mNetState) { - mReceiveLatch.countDown(); - } - } - - public boolean waitForState() throws InterruptedException { - return mReceiveLatch.await(30, TimeUnit.SECONDS); - } - } - - /** - * Callback used in testRegisterNetworkCallback that allows caller to block on - * {@code onAvailable}. - */ - private static class TestNetworkCallback extends ConnectivityManager.NetworkCallback { - private final CountDownLatch mAvailableLatch = new CountDownLatch(1); - private final CountDownLatch mLostLatch = new CountDownLatch(1); - private final CountDownLatch mUnavailableLatch = new CountDownLatch(1); - - public Network currentNetwork; - public Network lastLostNetwork; - - public Network waitForAvailable() throws InterruptedException { - return mAvailableLatch.await(30, TimeUnit.SECONDS) ? currentNetwork : null; - } - - public Network waitForLost() throws InterruptedException { - return mLostLatch.await(30, TimeUnit.SECONDS) ? lastLostNetwork : null; - } - - public boolean waitForUnavailable() throws InterruptedException { - return mUnavailableLatch.await(2, TimeUnit.SECONDS); - } - - - @Override - public void onAvailable(Network network) { - currentNetwork = network; - mAvailableLatch.countDown(); - } - - @Override - public void onLost(Network network) { - lastLostNetwork = network; - if (network.equals(currentNetwork)) { - currentNetwork = null; - } - mLostLatch.countDown(); - } - - @Override - public void onUnavailable() { - mUnavailableLatch.countDown(); - } - } - - private Network getWifiNetwork() { - TestNetworkCallback callback = new TestNetworkCallback(); - mCm.registerNetworkCallback(makeWifiNetworkRequest(), callback); - Network network = null; - try { - network = callback.waitForAvailable(); - } catch (InterruptedException e) { - fail("NetworkCallback wait was interrupted."); - } finally { - mCm.unregisterNetworkCallback(callback); - } - assertNotNull("Cannot find Network for wifi. Is wifi connected?", network); - return network; - } - /** Verify restricted networks cannot be requested. */ @AppModeFull(reason = "CHANGE_NETWORK_STATE permission can't be granted to instant apps") public void testRestrictedNetworks() { @@ -1151,7 +890,7 @@ public class ConnectivityManagerTest extends AndroidTestCase { if (!isKeepaliveSupported()) return; final Network network = ensureWifiConnected(); - final byte[] requestBytes = HTTP_REQUEST.getBytes("UTF-8"); + final byte[] requestBytes = CtsNetUtils.HTTP_REQUEST.getBytes("UTF-8"); // So far only ipv4 tcp keepalive offload is supported. // TODO: add test case for ipv6 tcp keepalive offload when it is supported. try (Socket s = getConnectedSocket(network, TEST_HOST, HTTP_PORT, diff --git a/tests/cts/net/util/Android.bp b/tests/cts/net/util/Android.bp new file mode 100644 index 0000000000..1f94613ffb --- /dev/null +++ b/tests/cts/net/util/Android.bp @@ -0,0 +1,25 @@ +// +// Copyright (C) 2019 The Android Open Source Project +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +// Common utilities for cts net tests. +java_library { + name: "cts-net-utils", + srcs: ["java/**/*.java", "java/**/*.kt"], + static_libs: [ + "compatibility-device-util-axt", + "junit", + ], +} \ No newline at end of file diff --git a/tests/cts/net/util/java/android/net/cts/util/CtsNetUtils.java b/tests/cts/net/util/java/android/net/cts/util/CtsNetUtils.java new file mode 100644 index 0000000000..e19d2bafb7 --- /dev/null +++ b/tests/cts/net/util/java/android/net/cts/util/CtsNetUtils.java @@ -0,0 +1,353 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.net.cts.util; + +import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET; +import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; + +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.net.ConnectivityManager; +import android.net.ConnectivityManager.NetworkCallback; +import android.net.Network; +import android.net.NetworkCapabilities; +import android.net.NetworkInfo; +import android.net.NetworkInfo.State; +import android.net.NetworkRequest; +import android.net.wifi.WifiManager; +import android.system.Os; +import android.system.OsConstants; +import android.util.Log; + +import com.android.compatibility.common.util.SystemUtil; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.net.InetSocketAddress; +import java.net.Socket; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; + +public final class CtsNetUtils { + private static final String TAG = CtsNetUtils.class.getSimpleName(); + private static final int DURATION = 10000; + private static final int SOCKET_TIMEOUT_MS = 2000; + + public static final int HTTP_PORT = 80; + public static final String TEST_HOST = "connectivitycheck.gstatic.com"; + public static final String HTTP_REQUEST = + "GET /generate_204 HTTP/1.0\r\n" + + "Host: " + TEST_HOST + "\r\n" + + "Connection: keep-alive\r\n\r\n"; + // Action sent to ConnectivityActionReceiver when a network callback is sent via PendingIntent. + public static final String NETWORK_CALLBACK_ACTION = + "ConnectivityManagerTest.NetworkCallbackAction"; + + private Context mContext; + private ConnectivityManager mCm; + private WifiManager mWifiManager; + private TestNetworkCallback mCellNetworkCallback; + + public CtsNetUtils(Context context) { + mContext = context; + mCm = (ConnectivityManager) mContext.getSystemService(Context.CONNECTIVITY_SERVICE); + mWifiManager = (WifiManager) mContext.getSystemService(Context.WIFI_SERVICE); + } + + // Toggle WiFi twice, leaving it in the state it started in + public void toggleWifi() { + if (mWifiManager.isWifiEnabled()) { + Network wifiNetwork = getWifiNetwork(); + disconnectFromWifi(wifiNetwork); + connectToWifi(); + } else { + connectToWifi(); + Network wifiNetwork = getWifiNetwork(); + disconnectFromWifi(wifiNetwork); + } + } + + /** Enable WiFi and wait for it to become connected to a network. */ + public Network connectToWifi() { + final TestNetworkCallback callback = new TestNetworkCallback(); + mCm.registerNetworkCallback(makeWifiNetworkRequest(), callback); + Network wifiNetwork = null; + + ConnectivityActionReceiver receiver = new ConnectivityActionReceiver( + mCm, ConnectivityManager.TYPE_WIFI, NetworkInfo.State.CONNECTED); + IntentFilter filter = new IntentFilter(); + filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION); + mContext.registerReceiver(receiver, filter); + + boolean connected = false; + try { + SystemUtil.runShellCommand("svc wifi enable"); + // Ensure we get both an onAvailable callback and a CONNECTIVITY_ACTION. + wifiNetwork = callback.waitForAvailable(); + assertNotNull(wifiNetwork); + connected = receiver.waitForState(); + } catch (InterruptedException ex) { + fail("connectToWifi was interrupted"); + } finally { + mCm.unregisterNetworkCallback(callback); + mContext.unregisterReceiver(receiver); + } + + assertTrue("Wifi must be configured to connect to an access point for this test.", + connected); + return wifiNetwork; + } + + /** Disable WiFi and wait for it to become disconnected from the network. */ + public void disconnectFromWifi(Network wifiNetworkToCheck) { + final TestNetworkCallback callback = new TestNetworkCallback(); + mCm.registerNetworkCallback(makeWifiNetworkRequest(), callback); + Network lostWifiNetwork = null; + + ConnectivityActionReceiver receiver = new ConnectivityActionReceiver( + mCm, ConnectivityManager.TYPE_WIFI, NetworkInfo.State.DISCONNECTED); + IntentFilter filter = new IntentFilter(); + filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION); + mContext.registerReceiver(receiver, filter); + + // Assert that we can establish a TCP connection on wifi. + Socket wifiBoundSocket = null; + if (wifiNetworkToCheck != null) { + try { + wifiBoundSocket = getBoundSocket(wifiNetworkToCheck, TEST_HOST, HTTP_PORT); + testHttpRequest(wifiBoundSocket); + } catch (IOException e) { + fail("HTTP request before wifi disconnected failed with: " + e); + } + } + + boolean disconnected = false; + try { + SystemUtil.runShellCommand("svc wifi disable"); + // Ensure we get both an onLost callback and a CONNECTIVITY_ACTION. + lostWifiNetwork = callback.waitForLost(); + assertNotNull(lostWifiNetwork); + disconnected = receiver.waitForState(); + } catch (InterruptedException ex) { + fail("disconnectFromWifi was interrupted"); + } finally { + mCm.unregisterNetworkCallback(callback); + mContext.unregisterReceiver(receiver); + } + + assertTrue("Wifi failed to reach DISCONNECTED state.", disconnected); + + // Check that the socket is closed when wifi disconnects. + if (wifiBoundSocket != null) { + try { + testHttpRequest(wifiBoundSocket); + fail("HTTP request should not succeed after wifi disconnects"); + } catch (IOException expected) { + assertEquals(Os.strerror(OsConstants.ECONNABORTED), expected.getMessage()); + } + } + } + + public Network getWifiNetwork() { + TestNetworkCallback callback = new TestNetworkCallback(); + mCm.registerNetworkCallback(makeWifiNetworkRequest(), callback); + Network network = null; + try { + network = callback.waitForAvailable(); + } catch (InterruptedException e) { + fail("NetworkCallback wait was interrupted."); + } finally { + mCm.unregisterNetworkCallback(callback); + } + assertNotNull("Cannot find Network for wifi. Is wifi connected?", network); + return network; + } + + public Network connectToCell() throws InterruptedException { + if (cellConnectAttempted()) { + throw new IllegalStateException("Already connected"); + } + NetworkRequest cellRequest = new NetworkRequest.Builder() + .addTransportType(TRANSPORT_CELLULAR) + .addCapability(NET_CAPABILITY_INTERNET) + .build(); + mCellNetworkCallback = new TestNetworkCallback(); + mCm.requestNetwork(cellRequest, mCellNetworkCallback); + final Network cellNetwork = mCellNetworkCallback.waitForAvailable(); + assertNotNull("Cell network not available. " + + "Please ensure the device has working mobile data.", cellNetwork); + return cellNetwork; + } + + public void disconnectFromCell() { + if (!cellConnectAttempted()) { + throw new IllegalStateException("Cell connection not attempted"); + } + mCm.unregisterNetworkCallback(mCellNetworkCallback); + mCellNetworkCallback = null; + } + + public boolean cellConnectAttempted() { + return mCellNetworkCallback != null; + } + + private NetworkRequest makeWifiNetworkRequest() { + return new NetworkRequest.Builder() + .addTransportType(NetworkCapabilities.TRANSPORT_WIFI) + .build(); + } + + private void testHttpRequest(Socket s) throws IOException { + OutputStream out = s.getOutputStream(); + InputStream in = s.getInputStream(); + + final byte[] requestBytes = HTTP_REQUEST.getBytes("UTF-8"); + byte[] responseBytes = new byte[4096]; + out.write(requestBytes); + in.read(responseBytes); + assertTrue(new String(responseBytes, "UTF-8").startsWith("HTTP/1.0 204 No Content\r\n")); + } + + private Socket getBoundSocket(Network network, String host, int port) throws IOException { + InetSocketAddress addr = new InetSocketAddress(host, port); + Socket s = network.getSocketFactory().createSocket(); + try { + s.setSoTimeout(SOCKET_TIMEOUT_MS); + s.connect(addr, SOCKET_TIMEOUT_MS); + } catch (IOException e) { + s.close(); + throw e; + } + return s; + } + + /** + * Receiver that captures the last connectivity change's network type and state. Recognizes + * both {@code CONNECTIVITY_ACTION} and {@code NETWORK_CALLBACK_ACTION} intents. + */ + public static class ConnectivityActionReceiver extends BroadcastReceiver { + + private final CountDownLatch mReceiveLatch = new CountDownLatch(1); + + private final int mNetworkType; + private final NetworkInfo.State mNetState; + private final ConnectivityManager mCm; + + public ConnectivityActionReceiver(ConnectivityManager cm, int networkType, + NetworkInfo.State netState) { + this.mCm = cm; + mNetworkType = networkType; + mNetState = netState; + } + + public void onReceive(Context context, Intent intent) { + String action = intent.getAction(); + NetworkInfo networkInfo = null; + + // When receiving ConnectivityManager.CONNECTIVITY_ACTION, the NetworkInfo parcelable + // is stored in EXTRA_NETWORK_INFO. With a NETWORK_CALLBACK_ACTION, the Network is + // sent in EXTRA_NETWORK and we need to ask the ConnectivityManager for the NetworkInfo. + if (ConnectivityManager.CONNECTIVITY_ACTION.equals(action)) { + networkInfo = intent.getExtras() + .getParcelable(ConnectivityManager.EXTRA_NETWORK_INFO); + assertNotNull("ConnectivityActionReceiver expected EXTRA_NETWORK_INFO", + networkInfo); + } else if (NETWORK_CALLBACK_ACTION.equals(action)) { + Network network = intent.getExtras() + .getParcelable(ConnectivityManager.EXTRA_NETWORK); + assertNotNull("ConnectivityActionReceiver expected EXTRA_NETWORK", network); + networkInfo = this.mCm.getNetworkInfo(network); + if (networkInfo == null) { + // When disconnecting, it seems like we get an intent sent with an invalid + // Network; that is, by the time we call ConnectivityManager.getNetworkInfo(), + // it is invalid. Ignore these. + Log.i(TAG, "ConnectivityActionReceiver NETWORK_CALLBACK_ACTION ignoring " + + "invalid network"); + return; + } + } else { + fail("ConnectivityActionReceiver received unxpected intent action: " + action); + } + + assertNotNull("ConnectivityActionReceiver didn't find NetworkInfo", networkInfo); + int networkType = networkInfo.getType(); + State networkState = networkInfo.getState(); + Log.i(TAG, "Network type: " + networkType + " state: " + networkState); + if (networkType == mNetworkType && networkInfo.getState() == mNetState) { + mReceiveLatch.countDown(); + } + } + + public boolean waitForState() throws InterruptedException { + return mReceiveLatch.await(30, TimeUnit.SECONDS); + } + } + + /** + * Callback used in testRegisterNetworkCallback that allows caller to block on + * {@code onAvailable}. + */ + public static class TestNetworkCallback extends ConnectivityManager.NetworkCallback { + private final CountDownLatch mAvailableLatch = new CountDownLatch(1); + private final CountDownLatch mLostLatch = new CountDownLatch(1); + private final CountDownLatch mUnavailableLatch = new CountDownLatch(1); + + public Network currentNetwork; + public Network lastLostNetwork; + + public Network waitForAvailable() throws InterruptedException { + return mAvailableLatch.await(30, TimeUnit.SECONDS) ? currentNetwork : null; + } + + public Network waitForLost() throws InterruptedException { + return mLostLatch.await(30, TimeUnit.SECONDS) ? lastLostNetwork : null; + } + + public boolean waitForUnavailable() throws InterruptedException { + return mUnavailableLatch.await(2, TimeUnit.SECONDS); + } + + + @Override + public void onAvailable(Network network) { + currentNetwork = network; + mAvailableLatch.countDown(); + } + + @Override + public void onLost(Network network) { + lastLostNetwork = network; + if (network.equals(currentNetwork)) { + currentNetwork = null; + } + mLostLatch.countDown(); + } + + @Override + public void onUnavailable() { + mUnavailableLatch.countDown(); + } + } +}