From 533fed11d81416e60e7a0d973b63163260ad71f2 Mon Sep 17 00:00:00 2001 From: Etan Cohen Date: Thu, 21 Jun 2018 15:22:58 -0700 Subject: [PATCH 01/71] Update OWNERS file - Clean-up without functional change: removed name already inherited from parent directory. - Add OWNERS to p2p CtsVerifier Bug: 110536740 Test: N/A Change-Id: Iebfe7c4401fcb02163f757a3a1c346eb05222925 --- tests/cts/net/src/android/net/wifi/aware/OWNERS | 1 - tests/cts/net/src/android/net/wifi/rtt/OWNERS | 1 - 2 files changed, 2 deletions(-) diff --git a/tests/cts/net/src/android/net/wifi/aware/OWNERS b/tests/cts/net/src/android/net/wifi/aware/OWNERS index 4afc47f43f..cf116f89dd 100644 --- a/tests/cts/net/src/android/net/wifi/aware/OWNERS +++ b/tests/cts/net/src/android/net/wifi/aware/OWNERS @@ -1,2 +1 @@ etancohen@google.com -satk@google.com \ No newline at end of file diff --git a/tests/cts/net/src/android/net/wifi/rtt/OWNERS b/tests/cts/net/src/android/net/wifi/rtt/OWNERS index 4afc47f43f..cf116f89dd 100644 --- a/tests/cts/net/src/android/net/wifi/rtt/OWNERS +++ b/tests/cts/net/src/android/net/wifi/rtt/OWNERS @@ -1,2 +1 @@ etancohen@google.com -satk@google.com \ No newline at end of file From 375ccc286a7e6f1a9964f380d6d60ceca1914912 Mon Sep 17 00:00:00 2001 From: Rebecca Silberstein Date: Fri, 22 Jun 2018 18:19:32 -0700 Subject: [PATCH 02/71] WifiManagerTest: checks for networking permissions Add checks for critical networking permissions: 1 - NETWORK_STACK 2 - NETWORK_SETTINGS 3 - NETWORK_SETUP Bug: 80490622 Test: atest WifiManagerTest Change-Id: Ifdbb2a9e13a781fe9a3568eef362837af175952b --- .../android/net/wifi/cts/WifiManagerTest.java | 121 ++++++++++++++++++ 1 file changed, 121 insertions(+) diff --git a/tests/cts/net/src/android/net/wifi/cts/WifiManagerTest.java b/tests/cts/net/src/android/net/wifi/cts/WifiManagerTest.java index af91fbfb15..ea31fdffd6 100644 --- a/tests/cts/net/src/android/net/wifi/cts/WifiManagerTest.java +++ b/tests/cts/net/src/android/net/wifi/cts/WifiManagerTest.java @@ -21,7 +21,10 @@ 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.content.pm.ResolveInfo; +import android.net.ConnectivityManager; import android.net.NetworkInfo; import android.net.wifi.ScanResult; import android.net.wifi.WifiConfiguration; @@ -32,9 +35,11 @@ import android.net.wifi.WifiManager.WifiLock; import android.net.wifi.hotspot2.PasspointConfiguration; import android.net.wifi.hotspot2.pps.Credential; import android.net.wifi.hotspot2.pps.HomeSp; +import android.os.Process; import android.os.SystemClock; import android.provider.Settings; import android.test.AndroidTestCase; +import android.util.ArraySet; import android.util.Log; import com.android.compatibility.common.util.WifiConfigCreator; @@ -45,6 +50,7 @@ import java.security.MessageDigest; import java.security.cert.X509Certificate; import java.util.HashSet; import java.util.List; +import java.util.Objects; import java.util.Set; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; @@ -951,4 +957,119 @@ public class WifiManagerTest extends AndroidTestCase { stopLocalOnlyHotspot(callback, wifiEnabled); } + + /** + * Verify that the {@link android.Manifest.permission#NETWORK_STACK} permission is never held by + * any package. + *

+ * No apps should ever attempt to acquire this permission, since it would give those + * apps extremely broad access to connectivity functionality. + */ + public void testNetworkStackPermission() { + final PackageManager pm = getContext().getPackageManager(); + + final List holding = pm.getPackagesHoldingPermissions(new String[] { + android.Manifest.permission.NETWORK_STACK + }, PackageManager.MATCH_UNINSTALLED_PACKAGES); + for (PackageInfo pi : holding) { + fail("The NETWORK_STACK permission must not be held by " + pi.packageName + + " and must be revoked for security reasons"); + } + } + + /** + * Verify that the {@link android.Manifest.permission#NETWORK_SETTINGS} permission is + * never held by any package. + *

+ * Only Settings, SysUi and shell apps should ever attempt to acquire this + * permission, since it would give those apps extremely broad access to connectivity + * functionality. The permission is intended to be granted to only those apps with direct user + * access and no others. + */ + public void testNetworkSettingsPermission() { + final PackageManager pm = getContext().getPackageManager(); + + final ArraySet allowedPackages = new ArraySet(); + final ArraySet allowedUIDs = new ArraySet(); + // explicitly add allowed UIDs + allowedUIDs.add(Process.SYSTEM_UID); + allowedUIDs.add(Process.SHELL_UID); + allowedUIDs.add(Process.PHONE_UID); + + // only quick settings is allowed to bind to the BIND_QUICK_SETTINGS_TILE permission, using + // this fact to determined allowed package name for sysui + String validPkg = ""; + final List sysuiPackage = pm.getPackagesHoldingPermissions(new String[] { + android.Manifest.permission.BIND_QUICK_SETTINGS_TILE + }, PackageManager.MATCH_UNINSTALLED_PACKAGES); + + if (sysuiPackage.size() > 1) { + fail("The BIND_QUICK_SETTINGS_TILE permission must only be held by one package"); + } + + if (sysuiPackage.size() == 1) { + validPkg = sysuiPackage.get(0).packageName; + allowedPackages.add(validPkg); + } + + // the captive portal flow also currently holds the NETWORK_SETTINGS permission + final Intent intent = new Intent(ConnectivityManager.ACTION_CAPTIVE_PORTAL_SIGN_IN); + final ResolveInfo ri = pm.resolveActivity(intent, PackageManager.MATCH_DISABLED_COMPONENTS); + if (ri != null) { + allowedPackages.add(ri.activityInfo.packageName); + } + + final List holding = pm.getPackagesHoldingPermissions(new String[] { + android.Manifest.permission.NETWORK_SETTINGS + }, PackageManager.MATCH_UNINSTALLED_PACKAGES); + for (PackageInfo pi : holding) { + String packageName = pi.packageName; + if (allowedPackages.contains(packageName)) { + // this is an explicitly allowed package + } else { + // now check if the packages are from allowed UIDs + boolean allowed = false; + try { + if (allowedUIDs.contains(pm.getPackageUid(packageName, 0))) { + allowed = true; + Log.d(TAG, packageName + " is on an allowed UID"); + } + } catch (PackageManager.NameNotFoundException e) { } + if (!allowed) { + fail("The NETWORK_SETTINGS permission must not be held by " + + packageName + " and must be revoked for security reasons"); + } + } + } + } + + /** + * Verify that the {@link android.Manifest.permission#NETWORK_SETUP_WIZARD} permission is + * only held by the device setup wizard application. + *

+ * Only the SetupWizard app should ever attempt to acquire this + * permission, since it would give those apps extremely broad access to connectivity + * functionality. The permission is intended to be granted to only the device setup wizard. + */ + public void testNetworkSetupWizardPermission() { + final PackageManager pm = getContext().getPackageManager(); + + final Intent intent = new Intent(Intent.ACTION_MAIN); + intent.addCategory(Intent.CATEGORY_SETUP_WIZARD); + final ResolveInfo ri = pm.resolveActivity(intent, PackageManager.MATCH_DISABLED_COMPONENTS); + String validPkg = ""; + if (ri != null) { + validPkg = ri.activityInfo.packageName; + } + + final List holding = pm.getPackagesHoldingPermissions(new String[] { + android.Manifest.permission.NETWORK_SETUP_WIZARD + }, PackageManager.MATCH_UNINSTALLED_PACKAGES); + for (PackageInfo pi : holding) { + if (!Objects.equals(pi.packageName, validPkg)) { + fail("The NETWORK_SETUP_WIZARD permission must not be held by " + pi.packageName + + " and must be revoked for security reasons [" + validPkg +"]"); + } + } + } } From 7f494f69183ac09fc94573e62f6eaa7dbc0ed054 Mon Sep 17 00:00:00 2001 From: xshu Date: Fri, 7 Sep 2018 11:30:10 -0700 Subject: [PATCH 03/71] CTS: Location scan is not disabled at screen off Location Wi-Fi scanning should not be turned off when the screen turns off. Bug: 113876483 Test: Run CTS, manually toggle location Wi-Fi scanning off right after the screen turns on and observe failure. Test: Run CTS with location Wi-Fi scanning initially turned off and observe failure. Test: Run CTS with location Wi-Fi scanning initially turned on and observe success. Change-Id: I092a3854b6365de72c2cfe38a55a0e1cedfcabd9 --- .../android/net/wifi/cts/WifiManagerTest.java | 90 +++++++++++++++++++ 1 file changed, 90 insertions(+) diff --git a/tests/cts/net/src/android/net/wifi/cts/WifiManagerTest.java b/tests/cts/net/src/android/net/wifi/cts/WifiManagerTest.java index ea31fdffd6..3b8ad6ca65 100644 --- a/tests/cts/net/src/android/net/wifi/cts/WifiManagerTest.java +++ b/tests/cts/net/src/android/net/wifi/cts/WifiManagerTest.java @@ -38,6 +38,8 @@ import android.net.wifi.hotspot2.pps.HomeSp; import android.os.Process; import android.os.SystemClock; import android.provider.Settings; +import android.support.test.InstrumentationRegistry; +import android.support.test.uiautomator.UiDevice; import android.test.AndroidTestCase; import android.util.ArraySet; import android.util.Log; @@ -66,6 +68,7 @@ public class WifiManagerTest extends AndroidTestCase { private List mScanResults = null; private NetworkInfo mNetworkInfo; private Object mLOHSLock = new Object(); + private UiDevice mUiDevice; // Please refer to WifiManager private static final int MIN_RSSI = -100; @@ -90,6 +93,7 @@ public class WifiManagerTest extends AndroidTestCase { private static final int TIMEOUT_MSEC = 6000; private static final int WAIT_MSEC = 60; private static final int DURATION = 10000; + private static final int DURATION_SCREEN_TOGGLE = 2000; private static final int WIFI_SCAN_TEST_INTERVAL_MILLIS = 60 * 1000; private static final int WIFI_SCAN_TEST_CACHE_DELAY_MILLIS = 3 * 60 * 1000; private static final int WIFI_SCAN_TEST_ITERATIONS = 5; @@ -162,6 +166,8 @@ public class WifiManagerTest extends AndroidTestCase { mWifiLock.acquire(); if (!mWifiManager.isWifiEnabled()) setWifiEnabled(true); + mUiDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation()); + turnScreenOnNoDelay(); Thread.sleep(DURATION); assertTrue(mWifiManager.isWifiEnabled()); synchronized (mMySync) { @@ -1072,4 +1078,88 @@ public class WifiManagerTest extends AndroidTestCase { } } } + + private void turnScreenOnNoDelay() throws Exception { + mUiDevice.executeShellCommand("input keyevent KEYCODE_WAKEUP"); + mUiDevice.executeShellCommand("wm dismiss-keyguard"); + } + + private void turnScreenOn() throws Exception { + turnScreenOnNoDelay(); + // Since the screen on/off intent is ordered, they will not be sent right now. + Thread.sleep(DURATION_SCREEN_TOGGLE); + } + + private void turnScreenOff() throws Exception { + mUiDevice.executeShellCommand("input keyevent KEYCODE_SLEEP"); + // Since the screen on/off intent is ordered, they will not be sent right now. + Thread.sleep(DURATION_SCREEN_TOGGLE); + } + + /** + * Verify that Wi-Fi scanning is not turned off when the screen turns off while wifi is disabled + * but location is on. + * @throws Exception + */ + public void testScreenOffDoesNotTurnOffWifiScanningWhenWifiDisabled() throws Exception { + if (!WifiFeature.isWifiSupported(getContext())) { + // skip the test if WiFi is not supported + return; + } + if (!hasLocationFeature()) { + // skip the test if location is not supported + return; + } + if (!isLocationEnabled()) { + fail("Please enable location for this test - since Marshmallow WiFi scan results are" + + " empty when location is disabled!"); + } + if(!mWifiManager.isScanAlwaysAvailable()) { + fail("Please enable Wi-Fi scanning for this test!"); + } + setWifiEnabled(false); + turnScreenOn(); + assertWifiScanningIsOn(); + // Toggle screen and verify Wi-Fi scanning is still on. + turnScreenOff(); + assertWifiScanningIsOn(); + turnScreenOn(); + assertWifiScanningIsOn(); + } + + /** + * Verify that Wi-Fi scanning is not turned off when the screen turns off while wifi is enabled. + * @throws Exception + */ + public void testScreenOffDoesNotTurnOffWifiScanningWhenWifiEnabled() throws Exception { + if (!WifiFeature.isWifiSupported(getContext())) { + // skip the test if WiFi is not supported + return; + } + if (!hasLocationFeature()) { + // skip the test if location is not supported + return; + } + if (!isLocationEnabled()) { + fail("Please enable location for this test - since Marshmallow WiFi scan results are" + + " empty when location is disabled!"); + } + if(!mWifiManager.isScanAlwaysAvailable()) { + fail("Please enable Wi-Fi scanning for this test!"); + } + setWifiEnabled(true); + turnScreenOn(); + assertWifiScanningIsOn(); + // Toggle screen and verify Wi-Fi scanning is still on. + turnScreenOff(); + assertWifiScanningIsOn(); + turnScreenOn(); + assertWifiScanningIsOn(); + } + + private void assertWifiScanningIsOn() { + if(!mWifiManager.isScanAlwaysAvailable()) { + fail("Wi-Fi scanning should be on."); + } + } } From c7758c460ce66ae130ad7abfa9eb7bae3d495e95 Mon Sep 17 00:00:00 2001 From: Etan Cohen Date: Mon, 1 Oct 2018 14:02:44 -0700 Subject: [PATCH 04/71] [CTS] Clarify CTS assert message for missing RTT AP support Add a much more verbose message for the common failure case in which the CTS is run without an AP which supports IEEE 802.11mc / RTT. That may help speed up issue resolution. Bug: 116849381 Test: atest WifiRttTest Change-Id: I4ea3fbe17563f0087a013cbf48f7f601fec7e363 --- .../cts/net/src/android/net/wifi/rtt/cts/WifiRttTest.java | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/tests/cts/net/src/android/net/wifi/rtt/cts/WifiRttTest.java b/tests/cts/net/src/android/net/wifi/rtt/cts/WifiRttTest.java index 74a0c3dfbc..20791c068e 100644 --- a/tests/cts/net/src/android/net/wifi/rtt/cts/WifiRttTest.java +++ b/tests/cts/net/src/android/net/wifi/rtt/cts/WifiRttTest.java @@ -16,11 +16,9 @@ package android.net.wifi.rtt.cts; -import android.content.IntentFilter; import android.net.wifi.ScanResult; import android.net.wifi.rtt.RangingRequest; import android.net.wifi.rtt.RangingResult; -import android.net.wifi.rtt.WifiRttManager; import com.android.compatibility.common.util.DeviceReportLog; import com.android.compatibility.common.util.ResultType; @@ -64,7 +62,10 @@ public class WifiRttTest extends TestBase { // Scan for IEEE 802.11mc supporting APs ScanResult testAp = scanForTestAp(NUM_SCANS_SEARCHING_FOR_IEEE80211MC_AP); - assertTrue("Cannot find test AP", testAp != null); + assertTrue( + "Cannot find any test APs which support RTT / IEEE 802.11mc - please verify that " + + "your test setup includes them!", + testAp != null); // Perform RTT operations RangingRequest request = new RangingRequest.Builder().addAccessPoint(testAp).build(); From f99027bf27c683164ff74a325eeb96c8b0624ca3 Mon Sep 17 00:00:00 2001 From: Pavel Maltsev Date: Fri, 5 Oct 2018 10:49:48 -0700 Subject: [PATCH 05/71] CTS to verify local-only hotspot started at 2Ghz The only exception is automotive builds which may start local-only hotspot at 5Ghz Bug:115666270 Test: run cts -m CtsNetTestCases -t android.net.wifi.cts.WifiManagerTest#testStartLocalOnlyHotspotSuccess Change-Id: Ic3df22dab4ee93b531b92e6ed38adfa2b75880c7 --- .../net/src/android/net/wifi/cts/WifiManagerTest.java | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/tests/cts/net/src/android/net/wifi/cts/WifiManagerTest.java b/tests/cts/net/src/android/net/wifi/cts/WifiManagerTest.java index 3b8ad6ca65..b09d4581b9 100644 --- a/tests/cts/net/src/android/net/wifi/cts/WifiManagerTest.java +++ b/tests/cts/net/src/android/net/wifi/cts/WifiManagerTest.java @@ -408,6 +408,10 @@ public class WifiManagerTest extends AndroidTestCase { return getContext().getPackageManager().hasSystemFeature(PackageManager.FEATURE_LOCATION); } + private boolean hasAutomotiveFeature() { + return getContext().getPackageManager().hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE); + } + /** * test point of wifiManager NetWork: * 1.add NetWork @@ -847,6 +851,11 @@ public class WifiManagerTest extends AndroidTestCase { // check if we got the callback assertTrue(callback.onStartedCalled); assertNotNull(callback.reservation.getWifiConfiguration()); + if (!hasAutomotiveFeature()) { + assertEquals( + WifiConfiguration.AP_BAND_2GHZ, + callback.reservation.getWifiConfiguration().apBand); + } assertFalse(callback.onFailedCalled); assertFalse(callback.onStoppedCalled); } From 9d7688dd9e7d0d4007fee8693c65ef0beb56748d Mon Sep 17 00:00:00 2001 From: Roshan Pius Date: Thu, 1 Nov 2018 15:14:44 -0700 Subject: [PATCH 06/71] WifiManagerTest: Remove tests for deprecated API's Remove/Modify tests that are invoking the deprecated API's. Use the shell automator to toggle wifi state. CTS tests for the replacement API surface (i.e NetworkRequest & NetworkSuggestion) will be added later. Bug: 115504728 Test: `atest android.net.wifi.cts.WifiManagerTest` Change-Id: I04b3e1572ddfd31b28639185e5cf54dd70a1ae42 --- .../android/net/wifi/cts/WifiManagerTest.java | 187 +++--------------- 1 file changed, 30 insertions(+), 157 deletions(-) diff --git a/tests/cts/net/src/android/net/wifi/cts/WifiManagerTest.java b/tests/cts/net/src/android/net/wifi/cts/WifiManagerTest.java index b09d4581b9..bfb9970bd3 100644 --- a/tests/cts/net/src/android/net/wifi/cts/WifiManagerTest.java +++ b/tests/cts/net/src/android/net/wifi/cts/WifiManagerTest.java @@ -41,9 +41,11 @@ import android.provider.Settings; import android.support.test.InstrumentationRegistry; import android.support.test.uiautomator.UiDevice; import android.test.AndroidTestCase; +import android.text.TextUtils; import android.util.ArraySet; import android.util.Log; +import com.android.compatibility.common.util.SystemUtil; import com.android.compatibility.common.util.WifiConfigCreator; import java.net.HttpURLConnection; @@ -83,9 +85,6 @@ public class WifiManagerTest extends AndroidTestCase { private static final String TAG = "WifiManagerTest"; private static final String SSID1 = "\"WifiManagerTest\""; - private static final String SSID2 = "\"WifiManagerTestModified\""; - private static final String PROXY_TEST_SSID = "SomeProxyAp"; - private static final String ADD_NETWORK_EXCEPTION_SUBSTR = "addNetwork"; // A full single scan duration is about 6-7 seconds if country code is set // to US. If country code is set to world mode (00), we would expect a scan // duration of roughly 8 seconds. So we set scan timeout as 9 seconds here. @@ -198,8 +197,8 @@ public class WifiManagerTest extends AndroidTestCase { } else { mMySync.expectedState = (enable ? STATE_WIFI_ENABLED : STATE_WIFI_DISABLED); } - // now trigger the change - assertTrue(mWifiManager.setWifiEnabled(enable)); + // now trigger the change using shell commands. + SystemUtil.runShellCommand("svc wifi " + (enable ? "enable" : "disable")); waitForExpectedWifiState(enable); } } @@ -274,20 +273,13 @@ public class WifiManagerTest extends AndroidTestCase { } /** - * test point of wifiManager actions: - * 1.reconnect - * 2.reassociate - * 3.disconnect - * 4.createWifiLock + * Test creation of WifiManager Lock. */ - public void testWifiManagerActions() throws Exception { + public void testWifiManagerLock() throws Exception { if (!WifiFeature.isWifiSupported(getContext())) { // skip the test if WiFi is not supported return; } - assertTrue(mWifiManager.reconnect()); - assertTrue(mWifiManager.reassociate()); - assertTrue(mWifiManager.disconnect()); final String TAG = "Test"; assertNotNull(mWifiManager.createWifiLock(TAG)); assertNotNull(mWifiManager.createWifiLock(WifiManager.WIFI_MODE_FULL, TAG)); @@ -412,125 +404,6 @@ public class WifiManagerTest extends AndroidTestCase { return getContext().getPackageManager().hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE); } - /** - * test point of wifiManager NetWork: - * 1.add NetWork - * 2.update NetWork - * 3.remove NetWork - * 4.enable NetWork - * 5.disable NetWork - * 6.configured Networks - * 7.save configure; - */ - public void testWifiManagerNetWork() throws Exception { - if (!WifiFeature.isWifiSupported(getContext())) { - // skip the test if WiFi is not supported - return; - } - - // store the list of enabled networks, so they can be re-enabled after test completes - Set enabledSsids = getEnabledNetworks(mWifiManager.getConfiguredNetworks()); - try { - WifiConfiguration wifiConfiguration; - // add a WifiConfig - final int notExist = -1; - List wifiConfiguredNetworks = mWifiManager.getConfiguredNetworks(); - int pos = findConfiguredNetworks(SSID1, wifiConfiguredNetworks); - if (notExist != pos) { - wifiConfiguration = wifiConfiguredNetworks.get(pos); - mWifiManager.removeNetwork(wifiConfiguration.networkId); - } - pos = findConfiguredNetworks(SSID1, wifiConfiguredNetworks); - assertEquals(notExist, pos); - final int size = wifiConfiguredNetworks.size(); - - wifiConfiguration = new WifiConfiguration(); - wifiConfiguration.SSID = SSID1; - wifiConfiguration.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE); - int netId = mWifiManager.addNetwork(wifiConfiguration); - assertTrue(existSSID(SSID1)); - - wifiConfiguredNetworks = mWifiManager.getConfiguredNetworks(); - assertEquals(size + 1, wifiConfiguredNetworks.size()); - pos = findConfiguredNetworks(SSID1, wifiConfiguredNetworks); - assertTrue(notExist != pos); - - // Enable & disable network - boolean disableOthers = true; - assertTrue(mWifiManager.enableNetwork(netId, disableOthers)); - wifiConfiguration = mWifiManager.getConfiguredNetworks().get(pos); - assertEquals(Status.ENABLED, wifiConfiguration.status); - - assertTrue(mWifiManager.disableNetwork(netId)); - wifiConfiguration = mWifiManager.getConfiguredNetworks().get(pos); - assertEquals(Status.DISABLED, wifiConfiguration.status); - - // Update a WifiConfig - wifiConfiguration = wifiConfiguredNetworks.get(pos); - wifiConfiguration.SSID = SSID2; - netId = mWifiManager.updateNetwork(wifiConfiguration); - assertFalse(existSSID(SSID1)); - assertTrue(existSSID(SSID2)); - - // Remove a WifiConfig - assertTrue(mWifiManager.removeNetwork(netId)); - assertFalse(mWifiManager.removeNetwork(notExist)); - assertFalse(existSSID(SSID1)); - assertFalse(existSSID(SSID2)); - - assertTrue(mWifiManager.saveConfiguration()); - } finally { - reEnableNetworks(enabledSsids, mWifiManager.getConfiguredNetworks()); - mWifiManager.saveConfiguration(); - } - } - - /** - * Verifies that addNetwork() fails for WifiConfigurations containing a non-null http proxy when - * the caller doesn't have OVERRIDE_WIFI_CONFIG permission, DeviceOwner or ProfileOwner device - * management policies - */ - public void testSetHttpProxy_PermissionFail() throws Exception { - if (!WifiFeature.isWifiSupported(getContext())) { - // skip the test if WiFi is not supported - return; - } - WifiConfigCreator configCreator = new WifiConfigCreator(getContext()); - boolean exceptionThrown = false; - try { - configCreator.addHttpProxyNetworkVerifyAndRemove( - PROXY_TEST_SSID, TEST_PAC_URL); - } catch (IllegalStateException e) { - // addHttpProxyNetworkVerifyAndRemove throws three IllegalStateException, - // expect it to throw for the addNetwork operation - if (e.getMessage().contains(ADD_NETWORK_EXCEPTION_SUBSTR)) { - exceptionThrown = true; - } - } - assertTrue(exceptionThrown); - } - - private Set getEnabledNetworks(List configuredNetworks) { - Set ssids = new HashSet(); - for (WifiConfiguration wifiConfig : configuredNetworks) { - if (Status.ENABLED == wifiConfig.status || Status.CURRENT == wifiConfig.status) { - ssids.add(wifiConfig.SSID); - Log.i(TAG, String.format("remembering enabled network %s", wifiConfig.SSID)); - } - } - return ssids; - } - - private void reEnableNetworks(Set enabledSsids, - List configuredNetworks) { - for (WifiConfiguration wifiConfig : configuredNetworks) { - if (enabledSsids.contains(wifiConfig.SSID)) { - mWifiManager.enableNetwork(wifiConfig.networkId, false); - Log.i(TAG, String.format("re-enabling network %s", wifiConfig.SSID)); - } - } - } - public void testSignal() { if (!WifiFeature.isWifiSupported(getContext())) { // skip the test if WiFi is not supported @@ -902,37 +775,37 @@ public class WifiManagerTest extends AndroidTestCase { } /** - * Verify calls to setWifiEnabled from a non-settings app while softap mode is active do not - * exit softap mode. - * - * This test uses the LocalOnlyHotspot API to enter softap mode. This should also be true when - * tethering is started. - * Note: Location mode must be enabled for this test. + * Verify calls to deprecated API's all fail for non-settings apps targeting >= Q SDK. */ - public void testSetWifiEnabledByAppDoesNotStopHotspot() throws Exception { + public void testDeprecatedApis() throws Exception { if (!WifiFeature.isWifiSupported(getContext())) { // skip the test if WiFi is not supported return; } - // check that softap mode is supported by the device - if (!mWifiManager.isPortableHotspotSupported()) { - return; - } + setWifiEnabled(true); + connectWifi(); // ensures that there is at-least 1 saved network on the device. + + WifiConfiguration wifiConfiguration = new WifiConfiguration(); + wifiConfiguration.SSID = SSID1; + wifiConfiguration.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE); + + assertEquals(WifiConfiguration.INVALID_NETWORK_ID, + mWifiManager.addNetwork(wifiConfiguration)); + assertEquals(WifiConfiguration.INVALID_NETWORK_ID, + mWifiManager.updateNetwork(wifiConfiguration)); + assertFalse(mWifiManager.enableNetwork(0, true)); + assertFalse(mWifiManager.disableNetwork(0)); + assertFalse(mWifiManager.removeNetwork(0)); + assertFalse(mWifiManager.disconnect()); + assertFalse(mWifiManager.reconnect()); + assertFalse(mWifiManager.reassociate()); + assertTrue(mWifiManager.getConfiguredNetworks().isEmpty()); boolean wifiEnabled = mWifiManager.isWifiEnabled(); - - if (wifiEnabled) { - // disable wifi so we have something to turn on (some devices may be able to run - // simultaneous modes) - setWifiEnabled(false); - } - - TestLocalOnlyHotspotCallback callback = startLocalOnlyHotspot(); - - // now we should fail to turn on wifi - assertFalse(mWifiManager.setWifiEnabled(true)); - - stopLocalOnlyHotspot(callback, wifiEnabled); + // now we should fail to toggle wifi state. + assertFalse(mWifiManager.setWifiEnabled(!wifiEnabled)); + Thread.sleep(DURATION); + assertEquals(wifiEnabled, mWifiManager.isWifiEnabled()); } /** From d0a2b9d50a5b438e0e293a5f10176e5b57ed71dd Mon Sep 17 00:00:00 2001 From: Roshan Pius Date: Wed, 14 Nov 2018 14:58:07 -0800 Subject: [PATCH 07/71] WifiManagerTest: Test for new privileged permission Add a new test to ensure that the NETWORK_MANAGED_PROVISIONING is only granted to the correct app. Bug: 115980767 Test: atest WifiManagerTest Change-Id: Ifca1fcd81e201134bbb4173c3f142cca91ed49f9 --- .../android/net/wifi/cts/WifiManagerTest.java | 37 +++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/tests/cts/net/src/android/net/wifi/cts/WifiManagerTest.java b/tests/cts/net/src/android/net/wifi/cts/WifiManagerTest.java index b09d4581b9..40e25ad66c 100644 --- a/tests/cts/net/src/android/net/wifi/cts/WifiManagerTest.java +++ b/tests/cts/net/src/android/net/wifi/cts/WifiManagerTest.java @@ -99,6 +99,8 @@ public class WifiManagerTest extends AndroidTestCase { private static final int WIFI_SCAN_TEST_ITERATIONS = 5; private static final String TEST_PAC_URL = "http://www.example.com/proxy.pac"; + private static final String MANAGED_PROVISIONING_PACKAGE_NAME + = "com.android.managedprovisioning"; private IntentFilter mIntentFilter; private final BroadcastReceiver mReceiver = new BroadcastReceiver() { @@ -1088,6 +1090,41 @@ public class WifiManagerTest extends AndroidTestCase { } } + /** + * Verify that the {@link android.Manifest.permission#NETWORK_MANAGED_PROVISIONING} permission + * is only held by the device managed provisioning application. + *

+ * Only the ManagedProvisioning app should ever attempt to acquire this + * permission, since it would give those apps extremely broad access to connectivity + * functionality. The permission is intended to be granted to only the device managed + * provisioning. + */ + public void testNetworkManagedProvisioningPermission() { + final PackageManager pm = getContext().getPackageManager(); + + // TODO(b/115980767): Using hardcoded package name. Need a better mechanism to find the + // managed provisioning app. + // Ensure that the package exists. + final Intent intent = new Intent(Intent.ACTION_MAIN); + intent.setPackage(MANAGED_PROVISIONING_PACKAGE_NAME); + final ResolveInfo ri = pm.resolveActivity(intent, PackageManager.MATCH_DISABLED_COMPONENTS); + String validPkg = ""; + if (ri != null) { + validPkg = ri.activityInfo.packageName; + } + + final List holding = pm.getPackagesHoldingPermissions(new String[] { + android.Manifest.permission.NETWORK_MANAGED_PROVISIONING + }, PackageManager.MATCH_UNINSTALLED_PACKAGES); + for (PackageInfo pi : holding) { + if (!Objects.equals(pi.packageName, validPkg)) { + fail("The NETWORK_MANAGED_PROVISIONING permission must not be held by " + + pi.packageName + " and must be revoked for security reasons [" + + validPkg +"]"); + } + } + } + private void turnScreenOnNoDelay() throws Exception { mUiDevice.executeShellCommand("input keyevent KEYCODE_WAKEUP"); mUiDevice.executeShellCommand("wm dismiss-keyguard"); From 30897c29ef24b47a6a227d0716c811ee81e7bc59 Mon Sep 17 00:00:00 2001 From: Kweku Adams Date: Mon, 19 Nov 2018 14:53:32 -0800 Subject: [PATCH 08/71] Tests for app idle whitelisting. Ensuring that app idle network whitelisting works as expected and does not override other power saving restrictions. Bug: 117846754 Bug: 111423978 Test: atest CtsHostsideNetworkTests and atest NetworkPolicyManagerServiceTest Change-Id: I09172184e2fe543d6723639e5e62ae6afd5a6087 --- .../net/hostside/AbstractAppIdleTestCase.java | 19 +++++ ...ractRestrictBackgroundNetworkTestCase.java | 22 ++++- .../cts/net/hostside/MixedModesTest.java | 80 +++++++++++++++++++ ...ostsideRestrictBackgroundNetworkTests.java | 25 ++++++ 4 files changed, 142 insertions(+), 4 deletions(-) diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractAppIdleTestCase.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractAppIdleTestCase.java index 0e141c05ad..7bf7bd44f4 100644 --- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractAppIdleTestCase.java +++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractAppIdleTestCase.java @@ -175,6 +175,25 @@ abstract class AbstractAppIdleTestCase extends AbstractRestrictBackgroundNetwork assertBackgroundNetworkAccess(true); } + public void testAppIdleNetworkAccess_idleWhitelisted() throws Exception { + if (!isSupported()) return; + + setAppIdle(true); + assertAppIdle(true); + assertBackgroundNetworkAccess(false); + + addAppIdleWhitelist(mUid); + assertBackgroundNetworkAccess(true); + + removeAppIdleWhitelist(mUid); + assertBackgroundNetworkAccess(false); + + // Make sure whitelisting a random app doesn't affect the tested app. + addAppIdleWhitelist(mUid + 1); + assertBackgroundNetworkAccess(false); + removeAppIdleWhitelist(mUid + 1); + } + public void testAppIdle_toast() throws Exception { if (!isSupported()) return; diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java index 5232372047..ec5a877757 100644 --- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java +++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java @@ -26,10 +26,6 @@ import static android.os.BatteryManager.BATTERY_PLUGGED_WIRELESS; import static com.android.compatibility.common.util.SystemUtil.runShellCommand; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.LinkedBlockingQueue; -import java.util.concurrent.TimeUnit; - import android.app.ActivityManager; import android.app.Instrumentation; import android.app.NotificationManager; @@ -53,6 +49,10 @@ import android.test.InstrumentationTestCase; import android.text.TextUtils; import android.util.Log; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.TimeUnit; + /** * Superclass for tests related to background network restrictions. */ @@ -744,6 +744,20 @@ abstract class AbstractRestrictBackgroundNetworkTestCase extends Instrumentation assertRestrictBackground("restrict-background-blacklist", uid, expected); } + protected void addAppIdleWhitelist(int uid) throws Exception { + executeShellCommand("cmd netpolicy add app-idle-whitelist " + uid); + assertAppIdleWhitelist(uid, true); + } + + protected void removeAppIdleWhitelist(int uid) throws Exception { + executeShellCommand("cmd netpolicy remove app-idle-whitelist " + uid); + assertAppIdleWhitelist(uid, false); + } + + protected void assertAppIdleWhitelist(int uid, boolean expected) throws Exception { + assertRestrictBackground("app-idle-whitelist", uid, expected); + } + private void assertRestrictBackground(String list, int uid, boolean expected) throws Exception { final int maxTries = 5; boolean actual = false; diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/MixedModesTest.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/MixedModesTest.java index 87f9d7738d..74875cd2c9 100644 --- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/MixedModesTest.java +++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/MixedModesTest.java @@ -306,4 +306,84 @@ public class MixedModesTest extends AbstractRestrictBackgroundNetworkTestCase { setBatterySaverMode(false); } } + + /** + * Tests that the app idle whitelist works as expected when doze and appIdle mode are enabled. + */ + public void testDozeAndAppIdle_appIdleWhitelist() throws Exception { + if (!isSupported()) { + return; + } + + setDozeMode(true); + setAppIdle(true); + + try { + assertBackgroundNetworkAccess(false); + + // UID still shouldn't have access because of Doze. + addAppIdleWhitelist(mUid); + assertBackgroundNetworkAccess(false); + + removeAppIdleWhitelist(mUid); + assertBackgroundNetworkAccess(false); + } finally { + setAppIdle(false); + setDozeMode(false); + } + } + + public void testAppIdleAndDoze_tempPowerSaveAndAppIdleWhitelists() throws Exception { + if (!isSupported()) { + return; + } + + setDozeMode(true); + setAppIdle(true); + + try { + assertBackgroundNetworkAccess(false); + + addAppIdleWhitelist(mUid); + assertBackgroundNetworkAccess(false); + + addTempPowerSaveModeWhitelist(TEST_APP2_PKG, TEMP_POWERSAVE_WHITELIST_DURATION_MS); + assertBackgroundNetworkAccess(true); + + // Wait until the whitelist duration is expired. + SystemClock.sleep(TEMP_POWERSAVE_WHITELIST_DURATION_MS); + assertBackgroundNetworkAccess(false); + } finally { + setAppIdle(false); + setDozeMode(false); + removeAppIdleWhitelist(mUid); + } + } + + public void testAppIdleAndBatterySaver_tempPowerSaveAndAppIdleWhitelists() throws Exception { + if (!isSupported()) { + return; + } + + setBatterySaverMode(true); + setAppIdle(true); + + try { + assertBackgroundNetworkAccess(false); + + addAppIdleWhitelist(mUid); + assertBackgroundNetworkAccess(false); + + addTempPowerSaveModeWhitelist(TEST_APP2_PKG, TEMP_POWERSAVE_WHITELIST_DURATION_MS); + assertBackgroundNetworkAccess(true); + + // Wait until the whitelist duration is expired. + SystemClock.sleep(TEMP_POWERSAVE_WHITELIST_DURATION_MS); + assertBackgroundNetworkAccess(false); + } finally { + setAppIdle(false); + setBatterySaverMode(false); + removeAppIdleWhitelist(mUid); + } + } } diff --git a/tests/cts/hostside/src/com/android/cts/net/HostsideRestrictBackgroundNetworkTests.java b/tests/cts/hostside/src/com/android/cts/net/HostsideRestrictBackgroundNetworkTests.java index fe9d36ce1d..5f5ea43d67 100644 --- a/tests/cts/hostside/src/com/android/cts/net/HostsideRestrictBackgroundNetworkTests.java +++ b/tests/cts/hostside/src/com/android/cts/net/HostsideRestrictBackgroundNetworkTests.java @@ -156,6 +156,11 @@ public class HostsideRestrictBackgroundNetworkTests extends HostsideNetworkTestC "testBackgroundNetworkAccess_enabled"); } + public void testAppIdleMetered_idleWhitelisted() throws Exception { + runDeviceTests(TEST_PKG, TEST_PKG + ".AppIdleMeteredTest", + "testAppIdleNetworkAccess_idleWhitelisted"); + } + // TODO: currently power-save mode and idle uses the same whitelist, so this test would be // redundant (as it would be testing the same as testBatterySaverMode_reinstall()) // public void testAppIdle_reinstall() throws Exception { @@ -181,6 +186,11 @@ public class HostsideRestrictBackgroundNetworkTests extends HostsideNetworkTestC "testBackgroundNetworkAccess_enabled"); } + public void testAppIdleNonMetered_idleWhitelisted() throws Exception { + runDeviceTests(TEST_PKG, TEST_PKG + ".AppIdleNonMeteredTest", + "testAppIdleNetworkAccess_idleWhitelisted"); + } + public void testAppIdleNonMetered_whenCharging() throws Exception { runDeviceTests(TEST_PKG, TEST_PKG + ".AppIdleNonMeteredTest", "testAppIdleNetworkAccess_whenCharging"); @@ -281,6 +291,21 @@ public class HostsideRestrictBackgroundNetworkTests extends HostsideNetworkTestC "testAppIdleAndBatterySaver_tempPowerSaveWhitelists"); } + public void testDozeAndAppIdle_appIdleWhitelist() throws Exception { + runDeviceTests(TEST_PKG, TEST_PKG + ".MixedModesTest", + "testDozeAndAppIdle_appIdleWhitelist"); + } + + public void testAppIdleAndDoze_tempPowerSaveAndAppIdleWhitelists() throws Exception { + runDeviceTests(TEST_PKG, TEST_PKG + ".MixedModesTest", + "testAppIdleAndDoze_tempPowerSaveAndAppIdleWhitelists"); + } + + public void testAppIdleAndBatterySaver_tempPowerSaveAndAppIdleWhitelists() throws Exception { + runDeviceTests(TEST_PKG, TEST_PKG + ".MixedModesTest", + "testAppIdleAndBatterySaver_tempPowerSaveAndAppIdleWhitelists"); + } + /******************* * Helper methods. * *******************/ From 4b1386285a7444fbb1d853228a2cac8ea88865f6 Mon Sep 17 00:00:00 2001 From: David Su Date: Wed, 28 Nov 2018 09:25:43 -0800 Subject: [PATCH 09/71] Scan Optimization: Check set device mobility permission is granted to <= 1 app Add a new CTS test to ensure that set device mobility permission is granted to at most 1 app. Bug: 120097108 Test: "atest WifiManagerTest" after installing app with new permission granted Change-Id: Ifda2163da6da9e9365c440d47031d25f92c6c375 --- .../android/net/wifi/cts/WifiManagerTest.java | 25 +++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/tests/cts/net/src/android/net/wifi/cts/WifiManagerTest.java b/tests/cts/net/src/android/net/wifi/cts/WifiManagerTest.java index deaa64421c..8ea72e00e9 100644 --- a/tests/cts/net/src/android/net/wifi/cts/WifiManagerTest.java +++ b/tests/cts/net/src/android/net/wifi/cts/WifiManagerTest.java @@ -58,6 +58,7 @@ import java.util.Objects; import java.util.Set; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; +import java.util.stream.Collectors; public class WifiManagerTest extends AndroidTestCase { private static class MySync { @@ -998,6 +999,30 @@ public class WifiManagerTest extends AndroidTestCase { } } + /** + * Verify that the {@link android.Manifest.permission#WIFI_SET_DEVICE_MOBILITY_STATE} permission + * is held by at most one application. + */ + public void testWifiSetDeviceMobilityStatePermission() { + final PackageManager pm = getContext().getPackageManager(); + + final List holding = pm.getPackagesHoldingPermissions(new String[] { + android.Manifest.permission.WIFI_SET_DEVICE_MOBILITY_STATE + }, PackageManager.MATCH_UNINSTALLED_PACKAGES); + + List uniquePackageNames = holding + .stream() + .map(pi -> pi.packageName) + .distinct() + .collect(Collectors.toList()); + + if (uniquePackageNames.size() > 1) { + fail("The WIFI_SET_DEVICE_MOBILITY_STATE permission must not be held by more than one " + + "application, but is held by " + uniquePackageNames.size() + " applications: " + + String.join(", ", uniquePackageNames)); + } + } + private void turnScreenOnNoDelay() throws Exception { mUiDevice.executeShellCommand("input keyevent KEYCODE_WAKEUP"); mUiDevice.executeShellCommand("wm dismiss-keyguard"); From c2b211f450420c80418b6b0f0cddefc57a765864 Mon Sep 17 00:00:00 2001 From: Julien Desprez Date: Mon, 17 Dec 2018 12:45:11 -0800 Subject: [PATCH 10/71] Tag modules for their sim card required Test: tf/cts unit tests ./cts-tradefed run cts-dev -m CtsNetTestCases --shard-count 2 (with and without sim card) ./cts-tradefed run cts-dev -m CtsCarrierApiTestCases --shard-count 2 (with and without uicc sim card) Bug: 69367250 Change-Id: Idcd35b9345be32658a1fd44027b03e5a47ff7e88 --- tests/cts/net/AndroidTest.xml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/cts/net/AndroidTest.xml b/tests/cts/net/AndroidTest.xml index 1326970462..76ff1674f6 100644 --- a/tests/cts/net/AndroidTest.xml +++ b/tests/cts/net/AndroidTest.xml @@ -15,6 +15,8 @@

- * Only Settings, SysUi and shell apps should ever attempt to acquire this - * permission, since it would give those apps extremely broad access to connectivity + * Only Settings, SysUi, NetworkStack and shell apps should ever attempt to acquire + * this permission, since it would give those apps extremely broad access to connectivity * functionality. The permission is intended to be granted to only those apps with direct user * access and no others. */ @@ -886,6 +886,7 @@ public class WifiManagerTest extends AndroidTestCase { allowedUIDs.add(Process.SYSTEM_UID); allowedUIDs.add(Process.SHELL_UID); allowedUIDs.add(Process.PHONE_UID); + allowedUIDs.add(Process.NETWORK_STACK_UID); // only quick settings is allowed to bind to the BIND_QUICK_SETTINGS_TILE permission, using // this fact to determined allowed package name for sysui From 823149f58f674bb653b0ff00fecf89d46fde572d Mon Sep 17 00:00:00 2001 From: David Su Date: Wed, 6 Feb 2019 11:42:55 -0800 Subject: [PATCH 17/71] Grant CTS test APK ACCESS_BACKGROUND_LOCATION permission Fixed broken CTS tests due to missing permissions. Bug: 123622071 Test: cts-tradefed, run cts -m CtsNetTestCases Change-Id: I6ddd2afbae6f685c018fd53d988e543ddbcfec04 --- tests/cts/net/AndroidManifest.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/cts/net/AndroidManifest.xml b/tests/cts/net/AndroidManifest.xml index 0bfb650882..2a57c101b2 100644 --- a/tests/cts/net/AndroidManifest.xml +++ b/tests/cts/net/AndroidManifest.xml @@ -22,6 +22,7 @@ + From 2186a943d32a9c4433d19d5d97d702b6531ff73d Mon Sep 17 00:00:00 2001 From: Sudheer Shanka Date: Fri, 15 Feb 2019 17:58:15 -0800 Subject: [PATCH 18/71] Add permissions needed for WifiManager.getConnectionInfo().getSSID(). Fixes: 124383293 Test: atest com.android.cts.net.HostsideRestrictBackgroundNetworkTests Change-Id: I3145e4ba1e768b7bb3c89867e36b506a90b87506 --- tests/cts/hostside/app/AndroidManifest.xml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/cts/hostside/app/AndroidManifest.xml b/tests/cts/hostside/app/AndroidManifest.xml index 2553f475aa..b91f39d36e 100644 --- a/tests/cts/hostside/app/AndroidManifest.xml +++ b/tests/cts/hostside/app/AndroidManifest.xml @@ -23,6 +23,8 @@ + + From 54c6488a76a552af10d23790929f8f9be32f5458 Mon Sep 17 00:00:00 2001 From: Jimmy Chen Date: Thu, 14 Feb 2019 17:43:43 +0800 Subject: [PATCH 19/71] p2p: add cts coverage for WifiP2pConfig.Builder Bug: 123780303 Test: cts - atest CtsNetTestCases:android.net.wifi.cts.WifiP2pConfigTest Change-Id: I8529bf725c648e499acd6017ee57fe3db7422fef --- tests/cts/net/src/android/net/wifi/OWNERS | 5 ++ .../cts/net/src/android/net/wifi/aware/OWNERS | 1 - .../net/wifi/p2p/cts/WifiP2pConfigTest.java | 62 +++++++++++++++++++ tests/cts/net/src/android/net/wifi/rtt/OWNERS | 1 - 4 files changed, 67 insertions(+), 2 deletions(-) create mode 100644 tests/cts/net/src/android/net/wifi/OWNERS delete mode 100644 tests/cts/net/src/android/net/wifi/aware/OWNERS create mode 100644 tests/cts/net/src/android/net/wifi/p2p/cts/WifiP2pConfigTest.java delete mode 100644 tests/cts/net/src/android/net/wifi/rtt/OWNERS diff --git a/tests/cts/net/src/android/net/wifi/OWNERS b/tests/cts/net/src/android/net/wifi/OWNERS new file mode 100644 index 0000000000..4a6001bcfe --- /dev/null +++ b/tests/cts/net/src/android/net/wifi/OWNERS @@ -0,0 +1,5 @@ +etancohen@google.com +lorenzo@google.com +mplass@google.com +rpius@google.com +satk@google.com diff --git a/tests/cts/net/src/android/net/wifi/aware/OWNERS b/tests/cts/net/src/android/net/wifi/aware/OWNERS deleted file mode 100644 index cf116f89dd..0000000000 --- a/tests/cts/net/src/android/net/wifi/aware/OWNERS +++ /dev/null @@ -1 +0,0 @@ -etancohen@google.com diff --git a/tests/cts/net/src/android/net/wifi/p2p/cts/WifiP2pConfigTest.java b/tests/cts/net/src/android/net/wifi/p2p/cts/WifiP2pConfigTest.java new file mode 100644 index 0000000000..639db8a7c3 --- /dev/null +++ b/tests/cts/net/src/android/net/wifi/p2p/cts/WifiP2pConfigTest.java @@ -0,0 +1,62 @@ +/* + * 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.wifi.p2p.cts; + +import android.net.MacAddress; +import android.net.wifi.p2p.WifiP2pConfig; +import android.net.wifi.p2p.WifiP2pGroup; +import android.test.AndroidTestCase; + +public class WifiP2pConfigTest extends AndroidTestCase { + static final String TEST_NETWORK_NAME = "DIRECT-xy-Hello"; + static final String TEST_PASSPHRASE = "8etterW0r1d"; + static final int TEST_OWNER_BAND = WifiP2pConfig.GROUP_OWNER_BAND_5GHZ; + static final int TEST_OWNER_FREQ = 2447; + static final String TEST_DEVICE_ADDRESS = "aa:bb:cc:dd:ee:ff"; + + public void testWifiP2pConfigBuilderForPersist() { + WifiP2pConfig.Builder builder = new WifiP2pConfig.Builder(); + builder.setNetworkName(TEST_NETWORK_NAME) + .setPassphrase(TEST_PASSPHRASE) + .setGroupOperatingBand(TEST_OWNER_BAND) + .setDeviceAddress(MacAddress.fromString(TEST_DEVICE_ADDRESS)) + .enablePersistentMode(true); + WifiP2pConfig config = builder.build(); + + assertTrue(config.deviceAddress.equals(TEST_DEVICE_ADDRESS)); + assertTrue(config.networkName.equals(TEST_NETWORK_NAME)); + assertTrue(config.passphrase.equals(TEST_PASSPHRASE)); + assertEquals(config.groupOwnerBand, TEST_OWNER_BAND); + assertEquals(config.netId, WifiP2pGroup.PERSISTENT_NET_ID); + } + + public void testWifiP2pConfigBuilderForNonPersist() { + WifiP2pConfig.Builder builder = new WifiP2pConfig.Builder(); + builder.setNetworkName(TEST_NETWORK_NAME) + .setPassphrase(TEST_PASSPHRASE) + .setGroupOperatingFrequency(TEST_OWNER_FREQ) + .setDeviceAddress(MacAddress.fromString(TEST_DEVICE_ADDRESS)) + .enablePersistentMode(false); + WifiP2pConfig config = builder.build(); + + assertTrue(config.deviceAddress.equals(TEST_DEVICE_ADDRESS)); + assertTrue(config.networkName.equals(TEST_NETWORK_NAME)); + assertTrue(config.passphrase.equals(TEST_PASSPHRASE)); + assertEquals(config.groupOwnerBand, TEST_OWNER_FREQ); + assertEquals(config.netId, WifiP2pGroup.TEMPORARY_NET_ID); + } +} diff --git a/tests/cts/net/src/android/net/wifi/rtt/OWNERS b/tests/cts/net/src/android/net/wifi/rtt/OWNERS deleted file mode 100644 index cf116f89dd..0000000000 --- a/tests/cts/net/src/android/net/wifi/rtt/OWNERS +++ /dev/null @@ -1 +0,0 @@ -etancohen@google.com From db6c9fd35a0eaf441273a1ff937de323dbd6286a Mon Sep 17 00:00:00 2001 From: Jimmy Chen Date: Thu, 14 Feb 2019 14:27:13 +0800 Subject: [PATCH 20/71] p2p: add cts coverage for new WifiP2pManager API Bug: 123781797 Test: cts - atest CtsNetTestCases:android.net.wifi.cts.ConcurrencyTest Change-Id: Id37429c48e6e784bfe1cc6de0378f5213991c241 --- .../android/net/wifi/cts/ConcurrencyTest.java | 320 +++++++++++++++++- 1 file changed, 304 insertions(+), 16 deletions(-) diff --git a/tests/cts/net/src/android/net/wifi/cts/ConcurrencyTest.java b/tests/cts/net/src/android/net/wifi/cts/ConcurrencyTest.java index 5e91366a9d..c80e3720c5 100644 --- a/tests/cts/net/src/android/net/wifi/cts/ConcurrencyTest.java +++ b/tests/cts/net/src/android/net/wifi/cts/ConcurrencyTest.java @@ -16,36 +16,66 @@ package android.net.wifi.cts; +import static org.junit.Assert.assertNotEquals; + import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; +import android.content.pm.PackageManager; import android.net.ConnectivityManager; import android.net.ConnectivityManager.NetworkCallback; import android.net.Network; import android.net.NetworkCapabilities; +import android.net.NetworkInfo; import android.net.NetworkRequest; import android.net.wifi.WifiManager; import android.net.wifi.p2p.WifiP2pManager; -import static android.net.wifi.p2p.WifiP2pManager.WIFI_P2P_STATE_DISABLED; -import static android.net.wifi.p2p.WifiP2pManager.WIFI_P2P_STATE_ENABLED; +import android.provider.Settings; import android.test.AndroidTestCase; +import android.util.Log; import com.android.compatibility.common.util.SystemUtil; +import java.util.Arrays; +import java.util.BitSet; +import java.util.LinkedList; +import java.util.List; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; +import java.util.stream.Collectors; public class ConcurrencyTest extends AndroidTestCase { private class MySync { - int expectedWifiState; - int expectedP2pState; + static final int WIFI_STATE = 0; + static final int P2P_STATE = 1; + static final int DISCOVERY_STATE = 2; + static final int NETWORK_INFO = 3; + + public BitSet pendingSync = new BitSet(); + + public int expectedWifiState; + public int expectedP2pState; + public int expectedDiscoveryState; + public NetworkInfo expectedNetworkInfo; + } + + private class MyResponse { + public boolean valid = false; + + public boolean success; + public int p2pState; + public int discoveryState; + public NetworkInfo networkInfo; } private WifiManager mWifiManager; + private WifiP2pManager mWifiP2pManager; + private WifiP2pManager.Channel mWifiP2pChannel; private MySync mMySync = new MySync(); + private MyResponse mMyResponse = new MyResponse(); - private static final String TAG = "WifiInfoTest"; + private static final String TAG = "ConcurrencyTest"; private static final int TIMEOUT_MSEC = 6000; private static final int WAIT_MSEC = 60; private static final int DURATION = 10000; @@ -56,16 +86,33 @@ public class ConcurrencyTest extends AndroidTestCase { final String action = intent.getAction(); if (action.equals(WifiManager.WIFI_STATE_CHANGED_ACTION)) { synchronized (mMySync) { + mMySync.pendingSync.set(MySync.WIFI_STATE); mMySync.expectedWifiState = intent.getIntExtra(WifiManager.EXTRA_WIFI_STATE, WifiManager.WIFI_STATE_DISABLED); mMySync.notify(); } } else if(action.equals(WifiP2pManager.WIFI_P2P_STATE_CHANGED_ACTION)) { synchronized (mMySync) { + mMySync.pendingSync.set(MySync.P2P_STATE); mMySync.expectedP2pState = intent.getIntExtra(WifiP2pManager.EXTRA_WIFI_STATE, WifiP2pManager.WIFI_P2P_STATE_DISABLED); mMySync.notify(); } + } else if (action.equals(WifiP2pManager.WIFI_P2P_DISCOVERY_CHANGED_ACTION)) { + synchronized (mMySync) { + mMySync.pendingSync.set(MySync.DISCOVERY_STATE); + mMySync.expectedDiscoveryState = intent.getIntExtra( + WifiP2pManager.EXTRA_DISCOVERY_STATE, + WifiP2pManager.WIFI_P2P_DISCOVERY_STOPPED); + mMySync.notify(); + } + } else if (action.equals(WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION)) { + synchronized (mMySync) { + mMySync.pendingSync.set(MySync.NETWORK_INFO); + mMySync.expectedNetworkInfo = (NetworkInfo) intent.getExtra( + WifiP2pManager.EXTRA_NETWORK_INFO, null); + mMySync.notify(); + } } } }; @@ -81,6 +128,8 @@ public class ConcurrencyTest extends AndroidTestCase { mIntentFilter = new IntentFilter(); mIntentFilter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION); mIntentFilter.addAction(WifiP2pManager.WIFI_P2P_STATE_CHANGED_ACTION); + mIntentFilter.addAction(WifiP2pManager.WIFI_P2P_DISCOVERY_CHANGED_ACTION); + mIntentFilter.addAction(WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION); mContext.registerReceiver(mReceiver, mIntentFilter); mWifiManager = (WifiManager) getContext().getSystemService(Context.WIFI_SERVICE); @@ -92,6 +141,8 @@ public class ConcurrencyTest extends AndroidTestCase { assertTrue(!mWifiManager.isWifiEnabled()); mMySync.expectedWifiState = WifiManager.WIFI_STATE_DISABLED; mMySync.expectedP2pState = WifiP2pManager.WIFI_P2P_STATE_DISABLED; + mMySync.expectedDiscoveryState = WifiP2pManager.WIFI_P2P_DISCOVERY_STOPPED; + mMySync.expectedNetworkInfo = null; } @Override @@ -108,16 +159,66 @@ public class ConcurrencyTest extends AndroidTestCase { super.tearDown(); } - private void waitForBroadcasts() { + private boolean waitForBroadcasts(List waitSyncList) { synchronized (mMySync) { long timeout = System.currentTimeMillis() + TIMEOUT_MSEC; - while (System.currentTimeMillis() < timeout - && (mMySync.expectedWifiState != WifiManager.WIFI_STATE_ENABLED || - mMySync.expectedP2pState != WifiP2pManager.WIFI_P2P_STATE_ENABLED)) { + while (System.currentTimeMillis() < timeout) { + List handledSyncList = waitSyncList.stream() + .filter(w -> mMySync.pendingSync.get(w)) + .collect(Collectors.toList()); + handledSyncList.forEach(w -> mMySync.pendingSync.clear(w)); + waitSyncList.removeAll(handledSyncList); + if (waitSyncList.isEmpty()) { + break; + } try { mMySync.wait(WAIT_MSEC); } catch (InterruptedException e) { } } + if (!waitSyncList.isEmpty()) { + Log.i(TAG, "Missing broadcast: " + waitSyncList); + } + return waitSyncList.isEmpty(); + } + } + + private boolean waitForBroadcasts(int waitSingleSync) { + return waitForBroadcasts( + new LinkedList(Arrays.asList(waitSingleSync))); + } + + private boolean waitForServiceResponse(MyResponse waitResponse) { + synchronized (waitResponse) { + long timeout = System.currentTimeMillis() + TIMEOUT_MSEC; + while (System.currentTimeMillis() < timeout) { + try { + waitResponse.wait(WAIT_MSEC); + } catch (InterruptedException e) { } + + if (waitResponse.valid) { + return true; + } + } + return false; + } + } + + // Return true if location is enabled. + private boolean isLocationEnabled() { + return Settings.Secure.getInt(getContext().getContentResolver(), + Settings.Secure.LOCATION_MODE, Settings.Secure.LOCATION_MODE_OFF) + != Settings.Secure.LOCATION_MODE_OFF; + } + + // Returns true if the device has location feature. + private boolean hasLocationFeature() { + return getContext().getPackageManager().hasSystemFeature(PackageManager.FEATURE_LOCATION); + } + + private void resetResponse(MyResponse responseObj) { + synchronized (responseObj) { + responseObj.valid = false; + responseObj.networkInfo = null; } } @@ -148,25 +249,212 @@ public class ConcurrencyTest extends AndroidTestCase { cm.unregisterNetworkCallback(networkCallback); } - public void testConcurrency() { + private boolean setupWifiP2p() { // Cannot support p2p alone if (!WifiFeature.isWifiSupported(getContext())) { assertTrue(!WifiFeature.isP2pSupported(getContext())); - return; + return false; } if (!WifiFeature.isP2pSupported(getContext())) { // skip the test if p2p is not supported + return false; + } + + if (!hasLocationFeature()) { + Log.d(TAG, "Skipping test as location is not supported"); + return false; + } + if (!isLocationEnabled()) { + fail("Please enable location for this test - since P-release WiFi Direct" + + " needs Location enabled."); + } + + long timeout = System.currentTimeMillis() + TIMEOUT_MSEC; + while (!mWifiManager.isWifiEnabled() && System.currentTimeMillis() < timeout) { + try { + enableWifi(); + } catch (InterruptedException e) { } + } + + assertTrue(mWifiManager.isWifiEnabled()); + + assertTrue(waitForBroadcasts( + new LinkedList( + Arrays.asList(MySync.WIFI_STATE, MySync.P2P_STATE)))); + + assertEquals(WifiManager.WIFI_STATE_ENABLED, mMySync.expectedWifiState); + assertEquals(WifiP2pManager.WIFI_P2P_STATE_ENABLED, mMySync.expectedP2pState); + + mWifiP2pManager = + (WifiP2pManager) getContext().getSystemService(Context.WIFI_P2P_SERVICE); + mWifiP2pChannel = mWifiP2pManager.initialize( + getContext(), getContext().getMainLooper(), null); + + assertNotNull(mWifiP2pManager); + assertNotNull(mWifiP2pChannel); + + assertTrue(waitForBroadcasts(MySync.NETWORK_INFO)); + // wait for changing to EnabledState + assertNotNull(mMySync.expectedNetworkInfo); + assertTrue(mMySync.expectedNetworkInfo.isAvailable()); + + return true; + } + + public void testConcurrency() { + if (!setupWifiP2p()) { return; } - // Enable wifi - SystemUtil.runShellCommand("svc wifi enable"); + resetResponse(mMyResponse); + mWifiP2pManager.requestP2pState(mWifiP2pChannel, new WifiP2pManager.P2pStateListener() { + @Override + public void onP2pStateAvailable(int state) { + synchronized (mMyResponse) { + mMyResponse.valid = true; + mMyResponse.p2pState = state; + mMyResponse.notify(); + } + } + }); + assertTrue(waitForServiceResponse(mMyResponse)); + assertEquals(WifiP2pManager.WIFI_P2P_STATE_ENABLED, mMyResponse.p2pState); + } - waitForBroadcasts(); + public void testRequestDiscoveryState() { + if (!setupWifiP2p()) { + return; + } - assertTrue(mMySync.expectedWifiState == WifiManager.WIFI_STATE_ENABLED); - assertTrue(mMySync.expectedP2pState == WifiP2pManager.WIFI_P2P_STATE_ENABLED); + resetResponse(mMyResponse); + mWifiP2pManager.requestDiscoveryState( + mWifiP2pChannel, new WifiP2pManager.DiscoveryStateListener() { + @Override + public void onDiscoveryStateAvailable(int state) { + synchronized (mMyResponse) { + mMyResponse.valid = true; + mMyResponse.discoveryState = state; + mMyResponse.notify(); + } + } + }); + assertTrue(waitForServiceResponse(mMyResponse)); + assertEquals(WifiP2pManager.WIFI_P2P_DISCOVERY_STOPPED, mMyResponse.discoveryState); + + resetResponse(mMyResponse); + mWifiP2pManager.discoverPeers(mWifiP2pChannel, new WifiP2pManager.ActionListener() { + @Override + public void onSuccess() { + synchronized (mMyResponse) { + mMyResponse.valid = true; + mMyResponse.success = true; + mMyResponse.notify(); + } + } + + @Override + public void onFailure(int reason) { + synchronized (mMyResponse) { + Log.d(TAG, "discoveryPeers failure reason: " + reason); + mMyResponse.valid = true; + mMyResponse.success = false; + mMyResponse.notify(); + } + } + }); + assertTrue(waitForServiceResponse(mMyResponse)); + assertTrue(mMyResponse.success); + assertTrue(waitForBroadcasts(MySync.DISCOVERY_STATE)); + + resetResponse(mMyResponse); + mWifiP2pManager.requestDiscoveryState(mWifiP2pChannel, + new WifiP2pManager.DiscoveryStateListener() { + @Override + public void onDiscoveryStateAvailable(int state) { + synchronized (mMyResponse) { + mMyResponse.valid = true; + mMyResponse.discoveryState = state; + mMyResponse.notify(); + } + } + }); + assertTrue(waitForServiceResponse(mMyResponse)); + assertEquals(WifiP2pManager.WIFI_P2P_DISCOVERY_STARTED, mMyResponse.discoveryState); + + mWifiP2pManager.stopPeerDiscovery(mWifiP2pChannel, null); + } + + public void testRequestNetworkInfo() { + if (!setupWifiP2p()) { + return; + } + + resetResponse(mMyResponse); + mWifiP2pManager.requestNetworkInfo(mWifiP2pChannel, + new WifiP2pManager.NetworkInfoListener() { + @Override + public void onNetworkInfoAvailable(NetworkInfo info) { + synchronized (mMyResponse) { + mMyResponse.valid = true; + mMyResponse.networkInfo = info; + mMyResponse.notify(); + } + } + }); + assertTrue(waitForServiceResponse(mMyResponse)); + assertNotNull(mMyResponse.networkInfo); + // The state might be IDLE, DISCONNECTED, FAILED before a connection establishment. + // Just ensure the state is NOT CONNECTED. + assertNotEquals(NetworkInfo.DetailedState.CONNECTED, + mMySync.expectedNetworkInfo.getDetailedState()); + + resetResponse(mMyResponse); + mWifiP2pManager.createGroup(mWifiP2pChannel, new WifiP2pManager.ActionListener() { + @Override + public void onSuccess() { + synchronized (mMyResponse) { + mMyResponse.valid = true; + mMyResponse.success = true; + mMyResponse.notify(); + } + } + + @Override + public void onFailure(int reason) { + synchronized (mMyResponse) { + Log.d(TAG, "createGroup failure reason: " + reason); + mMyResponse.valid = true; + mMyResponse.success = false; + mMyResponse.notify(); + } + } + }); + assertTrue(waitForServiceResponse(mMyResponse)); + assertTrue(mMyResponse.success); + assertTrue(waitForBroadcasts(MySync.NETWORK_INFO)); + assertNotNull(mMySync.expectedNetworkInfo); + assertEquals(NetworkInfo.DetailedState.CONNECTED, + mMySync.expectedNetworkInfo.getDetailedState()); + + resetResponse(mMyResponse); + mWifiP2pManager.requestNetworkInfo(mWifiP2pChannel, + new WifiP2pManager.NetworkInfoListener() { + @Override + public void onNetworkInfoAvailable(NetworkInfo info) { + synchronized (mMyResponse) { + mMyResponse.valid = true; + mMyResponse.networkInfo = info; + mMyResponse.notify(); + } + } + }); + assertTrue(waitForServiceResponse(mMyResponse)); + assertNotNull(mMyResponse.networkInfo); + assertEquals(NetworkInfo.DetailedState.CONNECTED, + mMyResponse.networkInfo.getDetailedState()); + + mWifiP2pManager.removeGroup(mWifiP2pChannel, null); } } From 328a891956b7c0729cb652f79ce1504648da03e0 Mon Sep 17 00:00:00 2001 From: Ricky Wai Date: Wed, 20 Feb 2019 15:46:43 +0000 Subject: [PATCH 21/71] Make net cts not using isolated storage Disabling isolated storage so existing tests can still write files to /sdcard and shell can read it successfully. Bug: 124651276 Test: atest android.net.cts.NetworkWatchlistTest#testGetWatchlistConfigHash Change-Id: I6c40d1ae12fc2cff76c976c11650423df5ce044f --- tests/cts/net/AndroidTest.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/cts/net/AndroidTest.xml b/tests/cts/net/AndroidTest.xml index 76ff1674f6..ff93afc375 100644 --- a/tests/cts/net/AndroidTest.xml +++ b/tests/cts/net/AndroidTest.xml @@ -26,5 +26,6 @@ diff --git a/tests/cts/hostside/src/com/android/cts/net/HostsideNetworkTestCase.java b/tests/cts/hostside/src/com/android/cts/net/HostsideNetworkTestCase.java index 7c9ce8f833..a2443b391a 100644 --- a/tests/cts/hostside/src/com/android/cts/net/HostsideNetworkTestCase.java +++ b/tests/cts/hostside/src/com/android/cts/net/HostsideNetworkTestCase.java @@ -128,7 +128,7 @@ abstract class HostsideNetworkTestCase extends DeviceTestCase implements IAbiRec protected void runDeviceTests(String packageName, String testClassName, String methodName) throws DeviceNotAvailableException { RemoteAndroidTestRunner testRunner = new RemoteAndroidTestRunner(packageName, - "android.support.test.runner.AndroidJUnitRunner", getDevice().getIDevice()); + "androidx.test.runner.AndroidJUnitRunner", getDevice().getIDevice()); if (testClassName != null) { if (methodName != null) { From 0c6f9ef7c80e318e848c94dbd3dee426fa35666c Mon Sep 17 00:00:00 2001 From: Yichun Li Date: Tue, 26 Feb 2019 18:03:52 -0800 Subject: [PATCH 25/71] Backfill OWNERS for CTS module CtsHostsideNetworkTests You're receiving this CL because you're the owner of CtsHostsideNetworkTests as per http://go/cts-test-owners. Please refer to the following doc for more details on why we are backfilling OWNERS file: http://go/backfill-cts-owners. Test: Ignored Bug: 126563878 Change-Id: Ib239888264404f6acd265f9923d8c2c4eb988797 --- tests/cts/hostside/OWNERS | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 tests/cts/hostside/OWNERS diff --git a/tests/cts/hostside/OWNERS b/tests/cts/hostside/OWNERS new file mode 100644 index 0000000000..52c8053323 --- /dev/null +++ b/tests/cts/hostside/OWNERS @@ -0,0 +1,4 @@ +# Bug component: 61373 +sudheersai@google.com +lorenzo@google.com +jchalard@google.com From d87f0affe6219855d34807f104ab456d940b0336 Mon Sep 17 00:00:00 2001 From: Ahmed ElArabawy Date: Wed, 26 Dec 2018 16:08:09 -0800 Subject: [PATCH 26/71] [Wifi] Update CTS test for Wifi Locks This commit adds CTS test cases for High-Perf and Low-Latency wifi locks. Bug: 34905427 Bug: 116512430 Test: atest WifiManager_WifiLockTest Change-Id: I94cb7fc0aa7876d6796eca6ca97b744dc009ef3e --- .../wifi/cts/WifiManager_WifiLockTest.java | 20 ++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/tests/cts/net/src/android/net/wifi/cts/WifiManager_WifiLockTest.java b/tests/cts/net/src/android/net/wifi/cts/WifiManager_WifiLockTest.java index 3cdd56af89..e08a972bd0 100644 --- a/tests/cts/net/src/android/net/wifi/cts/WifiManager_WifiLockTest.java +++ b/tests/cts/net/src/android/net/wifi/cts/WifiManager_WifiLockTest.java @@ -25,13 +25,27 @@ public class WifiManager_WifiLockTest extends AndroidTestCase { private static final String WIFI_TAG = "WifiManager_WifiLockTest"; - public void testWifiLock() { + /** + * Verify acquire and release of High Performance wifi locks + */ + public void testHiPerfWifiLock() { + testWifiLock(WifiManager.WIFI_MODE_FULL_HIGH_PERF); + } + + /** + * Verify acquire and release of Low latency wifi locks + */ + public void testLowLatencyWifiLock() { + testWifiLock(WifiManager.WIFI_MODE_FULL_LOW_LATENCY); + } + + private void testWifiLock(int lockType) { if (!WifiFeature.isWifiSupported(getContext())) { // skip the test if WiFi is not supported return; } WifiManager wm = (WifiManager) getContext().getSystemService(Context.WIFI_SERVICE); - WifiLock wl = wm.createWifiLock(WIFI_TAG); + WifiLock wl = wm.createWifiLock(lockType, WIFI_TAG); wl.setReferenceCounted(true); assertFalse(wl.isHeld()); @@ -55,7 +69,7 @@ public class WifiManager_WifiLockTest extends AndroidTestCase { // expected } - wl = wm.createWifiLock(WIFI_TAG); + wl = wm.createWifiLock(lockType, WIFI_TAG); wl.setReferenceCounted(false); assertFalse(wl.isHeld()); wl.acquire(); From c626be0dc78d8ffa9d30c63455aa48900023ffec Mon Sep 17 00:00:00 2001 From: Brett Chabot Date: Tue, 12 Feb 2019 20:46:59 -0800 Subject: [PATCH 27/71] Migrate cts/tests/tests/net to androidx.test See go/jetpack-test-android-migration This is the internal version of aosp/915793 Exempt-From-Owner-Approval: already reviewed in aosp Test: m -j CtsNetTestCases Change-Id: If102677e4cdc4361b5d93283c4d6140dc477a94a --- tests/cts/net/Android.mk | 4 ++-- tests/cts/net/AndroidManifest.xml | 2 +- .../android/net/cts/ConnectivityManagerTest.java | 15 +++++++-------- .../net/src/android/net/cts/MacAddressTest.java | 6 ++++-- .../src/android/net/cts/NetworkWatchlistTest.java | 8 ++++---- .../src/android/net/wifi/cts/WifiManagerTest.java | 8 ++------ 6 files changed, 20 insertions(+), 23 deletions(-) diff --git a/tests/cts/net/Android.mk b/tests/cts/net/Android.mk index bb1f4c73c4..2084dbc357 100644 --- a/tests/cts/net/Android.mk +++ b/tests/cts/net/Android.mk @@ -40,8 +40,8 @@ LOCAL_PACKAGE_NAME := CtsNetTestCases LOCAL_STATIC_JAVA_LIBRARIES := \ core-tests-support \ - compatibility-device-util \ - ctstestrunner \ + compatibility-device-util-axt \ + ctstestrunner-axt \ ctstestserver \ mockwebserver \ junit \ diff --git a/tests/cts/net/AndroidManifest.xml b/tests/cts/net/AndroidManifest.xml index 2a57c101b2..630de7e08f 100644 --- a/tests/cts/net/AndroidManifest.xml +++ b/tests/cts/net/AndroidManifest.xml @@ -43,7 +43,7 @@ - Date: Tue, 12 Mar 2019 16:41:39 -0700 Subject: [PATCH 28/71] Removed Passpoint tests from WifiManagerTest Passpoint APIs require NETWORK_SETTINGS permission, which the CTS verifier cannot acquire. Bug: 127824266 Test: atest WifiManagerTest Change-Id: I1c69ae748318c0c5431326be77f8b1a942a1f2db --- .../android/net/wifi/cts/WifiManagerTest.java | 158 ------------------ 1 file changed, 158 deletions(-) diff --git a/tests/cts/net/src/android/net/wifi/cts/WifiManagerTest.java b/tests/cts/net/src/android/net/wifi/cts/WifiManagerTest.java index a66fcdb0ba..8e66cb8953 100644 --- a/tests/cts/net/src/android/net/wifi/cts/WifiManagerTest.java +++ b/tests/cts/net/src/android/net/wifi/cts/WifiManagerTest.java @@ -509,164 +509,6 @@ public class WifiManagerTest extends AndroidTestCase { assertTrue(i < 15); } - /** - * Verify Passpoint configuration management APIs (add, remove, get) for a Passpoint - * configuration with an user credential. - * - * @throws Exception - */ - public void testAddPasspointConfigWithUserCredential() throws Exception { - if (!WifiFeature.isWifiSupported(getContext())) { - // skip the test if WiFi is not supported - return; - } - testAddPasspointConfig(generatePasspointConfig(generateUserCredential())); - } - - /** - * Verify Passpoint configuration management APIs (add, remove, get) for a Passpoint - * configuration with a certificate credential. - * - * @throws Exception - */ - public void testAddPasspointConfigWithCertCredential() throws Exception { - if (!WifiFeature.isWifiSupported(getContext())) { - // skip the test if WiFi is not supported - return; - } - testAddPasspointConfig(generatePasspointConfig(generateCertCredential())); - } - - /** - * Verify Passpoint configuration management APIs (add, remove, get) for a Passpoint - * configuration with a SIm credential. - * - * @throws Exception - */ - public void testAddPasspointConfigWithSimCredential() throws Exception { - if (!WifiFeature.isWifiSupported(getContext())) { - // skip the test if WiFi is not supported - return; - } - testAddPasspointConfig(generatePasspointConfig(generateSimCredential())); - } - - /** - * Helper function for generating a {@link PasspointConfiguration} for testing. - * - * @return {@link PasspointConfiguration} - */ - private PasspointConfiguration generatePasspointConfig(Credential credential) { - PasspointConfiguration config = new PasspointConfiguration(); - config.setCredential(credential); - - // Setup HomeSp. - HomeSp homeSp = new HomeSp(); - homeSp.setFqdn("Test.com"); - homeSp.setFriendlyName("Test Provider"); - homeSp.setRoamingConsortiumOis(new long[] {0x11223344}); - config.setHomeSp(homeSp); - - return config; - } - - /** - * Helper function for generating an user credential for testing. - * - * @return {@link Credential} - */ - private Credential generateUserCredential() { - Credential credential = new Credential(); - credential.setRealm("test.net"); - Credential.UserCredential userCred = new Credential.UserCredential(); - userCred.setEapType(21 /* EAP_TTLS */); - userCred.setUsername("username"); - userCred.setPassword("password"); - userCred.setNonEapInnerMethod("PAP"); - credential.setUserCredential(userCred); - credential.setCaCertificate(FakeKeys.CA_PUBLIC_CERT); - return credential; - } - - /** - * Helper function for generating a certificate credential for testing. - * - * @return {@link Credential} - */ - private Credential generateCertCredential() throws Exception { - Credential credential = new Credential(); - credential.setRealm("test.net"); - Credential.CertificateCredential certCredential = new Credential.CertificateCredential(); - certCredential.setCertType("x509v3"); - certCredential.setCertSha256Fingerprint( - MessageDigest.getInstance("SHA-256").digest(FakeKeys.CLIENT_CERT.getEncoded())); - credential.setCertCredential(certCredential); - credential.setCaCertificate(FakeKeys.CA_PUBLIC_CERT); - credential.setClientCertificateChain(new X509Certificate[] {FakeKeys.CLIENT_CERT}); - credential.setClientPrivateKey(FakeKeys.RSA_KEY1); - return credential; - } - - /** - * Helper function for generating a SIM credential for testing. - * - * @return {@link Credential} - */ - private Credential generateSimCredential() throws Exception { - Credential credential = new Credential(); - credential.setRealm("test.net"); - Credential.SimCredential simCredential = new Credential.SimCredential(); - simCredential.setImsi("1234*"); - simCredential.setEapType(18 /* EAP_SIM */); - credential.setSimCredential(simCredential); - return credential; - } - - /** - * Helper function verifying Passpoint configuration management APIs (add, remove, get) for - * a given configuration. - * - * @param config The configuration to test with - */ - private void testAddPasspointConfig(PasspointConfiguration config) throws Exception { - try { - - // obtain number of passpoint networks already present in device (preloaded) - List preConfigList = mWifiManager.getPasspointConfigurations(); - int numOfNetworks = preConfigList.size(); - - // add new (test) configuration - mWifiManager.addOrUpdatePasspointConfiguration(config); - - // Certificates and keys will be set to null after it is installed to the KeyStore by - // WifiManager. Reset them in the expected config so that it can be used to compare - // against the retrieved config. - config.getCredential().setCaCertificate(null); - config.getCredential().setClientCertificateChain(null); - config.getCredential().setClientPrivateKey(null); - - // retrieve the configuration and verify it. The retrieved list may not be in order - - // check all configs to see if any match - List configList = mWifiManager.getPasspointConfigurations(); - assertEquals(numOfNetworks + 1, configList.size()); - - boolean anyMatch = false; - for (PasspointConfiguration passpointConfiguration : configList) { - if (passpointConfiguration.equals(config)) { - anyMatch = true; - break; - } - } - assertTrue(anyMatch); - - // remove the (test) configuration and verify number of installed configurations - mWifiManager.removePasspointConfiguration(config.getHomeSp().getFqdn()); - assertEquals(mWifiManager.getPasspointConfigurations().size(), numOfNetworks); - } catch (UnsupportedOperationException e) { - // Passpoint build config |config_wifi_hotspot2_enabled| is disabled, so noop. - } - } - public class TestLocalOnlyHotspotCallback extends WifiManager.LocalOnlyHotspotCallback { Object hotspotLock; WifiManager.LocalOnlyHotspotReservation reservation = null; From e451659573add8b4479b4553d1d785b0f825bd5c Mon Sep 17 00:00:00 2001 From: Ahmed ElArabawy Date: Wed, 13 Mar 2019 23:58:13 -0700 Subject: [PATCH 29/71] Wifi: Add CTS test for WifiManager.MulticastLock This commit adds the CTS tests for the class WifiManager.MulticastLock Bug: 124017617 Test: atest android.net.wifi.cts Change-Id: I6e7a6e70f350dcd23fe541ef746770e3561d49e6 --- tests/cts/net/AndroidManifest.xml | 1 + .../net/wifi/cts/MulticastLockTest.java | 77 +++++++++++++++++++ 2 files changed, 78 insertions(+) create mode 100644 tests/cts/net/src/android/net/wifi/cts/MulticastLockTest.java diff --git a/tests/cts/net/AndroidManifest.xml b/tests/cts/net/AndroidManifest.xml index 630de7e08f..dbd8fef08e 100644 --- a/tests/cts/net/AndroidManifest.xml +++ b/tests/cts/net/AndroidManifest.xml @@ -31,6 +31,7 @@ + diff --git a/tests/cts/net/src/android/net/wifi/cts/MulticastLockTest.java b/tests/cts/net/src/android/net/wifi/cts/MulticastLockTest.java new file mode 100644 index 0000000000..54fe9c72a9 --- /dev/null +++ b/tests/cts/net/src/android/net/wifi/cts/MulticastLockTest.java @@ -0,0 +1,77 @@ +/* + * 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.wifi.cts; + +import android.content.Context; +import android.net.wifi.WifiManager; +import android.net.wifi.WifiManager.MulticastLock; +import android.test.AndroidTestCase; + +public class MulticastLockTest extends AndroidTestCase { + + private static final String WIFI_TAG = "MulticastLockTest"; + + /** + * Verify acquire and release of Multicast locks + */ + public void testMulticastLock() { + if (!WifiFeature.isWifiSupported(getContext())) { + // skip the test if WiFi is not supported + return; + } + WifiManager wm = (WifiManager) getContext().getSystemService(Context.WIFI_SERVICE); + MulticastLock mcl = wm.createMulticastLock(WIFI_TAG); + + mcl.setReferenceCounted(true); + assertFalse(mcl.isHeld()); + mcl.acquire(); + assertTrue(mcl.isHeld()); + mcl.release(); + assertFalse(mcl.isHeld()); + mcl.acquire(); + mcl.acquire(); + assertTrue(mcl.isHeld()); + mcl.release(); + assertTrue(mcl.isHeld()); + mcl.release(); + assertFalse(mcl.isHeld()); + assertNotNull(mcl.toString()); + try { + mcl.release(); + fail("should throw out exception because release is called" + +" a greater number of times than acquire"); + } catch (RuntimeException e) { + // expected + } + + mcl = wm.createMulticastLock(WIFI_TAG); + mcl.setReferenceCounted(false); + assertFalse(mcl.isHeld()); + mcl.acquire(); + assertTrue(mcl.isHeld()); + mcl.release(); + assertFalse(mcl.isHeld()); + mcl.acquire(); + mcl.acquire(); + assertTrue(mcl.isHeld()); + mcl.release(); + assertFalse(mcl.isHeld()); + assertNotNull(mcl.toString()); + // releasing again after release: but ignored for non-referenced locks + mcl.release(); + } +} From e16d426550b6683e4abf9dc70004d00bad548804 Mon Sep 17 00:00:00 2001 From: Ahmed ElArabawy Date: Thu, 14 Mar 2019 14:31:28 -0700 Subject: [PATCH 30/71] Wifi: Rename class name WifiManager_WifiLockTest This commit renames both the class name and the file name from WifiManager_WifiLockTest into WifiLockTest since WifiManager is implied from the package and directory hierarchy. Bug: 34905427 Test: atest android.net.wifi.cts Change-Id: Iaade2ba98cb1608384c2527eddb29bb6d020bf78 --- .../{WifiManager_WifiLockTest.java => WifiLockTest.java} | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) rename tests/cts/net/src/android/net/wifi/cts/{WifiManager_WifiLockTest.java => WifiLockTest.java} (93%) diff --git a/tests/cts/net/src/android/net/wifi/cts/WifiManager_WifiLockTest.java b/tests/cts/net/src/android/net/wifi/cts/WifiLockTest.java similarity index 93% rename from tests/cts/net/src/android/net/wifi/cts/WifiManager_WifiLockTest.java rename to tests/cts/net/src/android/net/wifi/cts/WifiLockTest.java index e08a972bd0..0703e6096b 100644 --- a/tests/cts/net/src/android/net/wifi/cts/WifiManager_WifiLockTest.java +++ b/tests/cts/net/src/android/net/wifi/cts/WifiLockTest.java @@ -21,9 +21,9 @@ import android.net.wifi.WifiManager; import android.net.wifi.WifiManager.WifiLock; import android.test.AndroidTestCase; -public class WifiManager_WifiLockTest extends AndroidTestCase { +public class WifiLockTest extends AndroidTestCase { - private static final String WIFI_TAG = "WifiManager_WifiLockTest"; + private static final String WIFI_TAG = "WifiLockTest"; /** * Verify acquire and release of High Performance wifi locks @@ -82,7 +82,7 @@ public class WifiManager_WifiLockTest extends AndroidTestCase { wl.release(); assertFalse(wl.isHeld()); assertNotNull(wl.toString()); - // should be ignored + // releasing again after release: but ignored for non-referenced locks wl.release(); } } From 0d952ca8473b208c71b8c86843c17ac3952eb84a Mon Sep 17 00:00:00 2001 From: Roshan Pius Date: Fri, 15 Mar 2019 08:32:54 -0700 Subject: [PATCH 31/71] WifiManagerTest: Enforce a min number of suggestions per app The enforced number is set at 50. Also, removed the usage of a deprecated API in WifiManagerTest. Bug: 126536466 Test: atest WifiManagerTest Change-Id: I3a1ab4150cbbecef1157152c51b1148e1e2360ca --- .../android/net/wifi/cts/WifiManagerTest.java | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/tests/cts/net/src/android/net/wifi/cts/WifiManagerTest.java b/tests/cts/net/src/android/net/wifi/cts/WifiManagerTest.java index 8e66cb8953..93795b2bf0 100644 --- a/tests/cts/net/src/android/net/wifi/cts/WifiManagerTest.java +++ b/tests/cts/net/src/android/net/wifi/cts/WifiManagerTest.java @@ -94,6 +94,8 @@ public class WifiManagerTest extends AndroidTestCase { private static final int WIFI_SCAN_TEST_CACHE_DELAY_MILLIS = 3 * 60 * 1000; private static final int WIFI_SCAN_TEST_ITERATIONS = 5; + private static final int ENFORCED_NUM_NETWORK_SUGGESTIONS_PER_APP = 50; + private static final String TEST_PAC_URL = "http://www.example.com/proxy.pac"; private static final String MANAGED_PROVISIONING_PACKAGE_NAME = "com.android.managedprovisioning"; @@ -246,7 +248,6 @@ public class WifiManagerTest extends AndroidTestCase { private void connectWifi() throws Exception { synchronized (mMySync) { if (mNetworkInfo.getState() == NetworkInfo.State.CONNECTED) return; - assertTrue(mWifiManager.reconnect()); long timeout = System.currentTimeMillis() + TIMEOUT_MSEC; while (System.currentTimeMillis() < timeout && mNetworkInfo.getState() != NetworkInfo.State.CONNECTED) @@ -982,6 +983,19 @@ public class WifiManagerTest extends AndroidTestCase { assertWifiScanningIsOn(); } + /** + * Verify that the platform supports a reasonable number of suggestions per app. + * @throws Exception + */ + public void testMaxNumberOfNetworkSuggestionsPerApp() throws Exception { + if (!WifiFeature.isWifiSupported(getContext())) { + // skip the test if WiFi is not supported + return; + } + assertTrue(mWifiManager.getMaxNumberOfNetworkSuggestionsPerApp() + > ENFORCED_NUM_NETWORK_SUGGESTIONS_PER_APP); + } + private void assertWifiScanningIsOn() { if(!mWifiManager.isScanAlwaysAvailable()) { fail("Wi-Fi scanning should be on."); From 2a0aa641454df76141ed77db7a0cce436bc1e0cc Mon Sep 17 00:00:00 2001 From: Brett Chabot Date: Mon, 25 Mar 2019 11:51:41 -0700 Subject: [PATCH 32/71] DO NOT MERGE - Migrate remaining cts to androidx.test. See go/jetpack-test-android-migration Test: m cts Change-Id: I148ac492524a07edf6142d884d991c3a3487ce06 Exempt-From-Owner-Approval: automated refactoring, has already been reviewed by owners downstream Bug: 127482512 --- tests/cts/hostside/app/Android.mk | 2 +- tests/cts/hostside/app/AndroidManifest.xml | 2 +- .../com/android/cts/net/HostsideNetworkTestCase.java | 2 +- tests/cts/net/Android.mk | 4 ++-- tests/cts/net/AndroidManifest.xml | 2 +- .../src/android/net/cts/ConnectivityManagerTest.java | 12 +++++++----- .../cts/net/src/android/net/cts/MacAddressTest.java | 6 ++++-- .../src/android/net/cts/NetworkWatchlistTest.java | 8 ++++---- 8 files changed, 21 insertions(+), 17 deletions(-) diff --git a/tests/cts/hostside/app/Android.mk b/tests/cts/hostside/app/Android.mk index c03e70bcb0..6d89e58576 100644 --- a/tests/cts/hostside/app/Android.mk +++ b/tests/cts/hostside/app/Android.mk @@ -20,7 +20,7 @@ include $(CLEAR_VARS) LOCAL_MODULE_TAGS := tests LOCAL_SDK_VERSION := current -LOCAL_STATIC_JAVA_LIBRARIES := compatibility-device-util ctstestrunner ub-uiautomator \ +LOCAL_STATIC_JAVA_LIBRARIES := compatibility-device-util-axt ctstestrunner-axt ub-uiautomator \ CtsHostsideNetworkTestsAidl LOCAL_JAVA_LIBRARIES := android.test.runner.stubs android.test.base.stubs diff --git a/tests/cts/hostside/app/AndroidManifest.xml b/tests/cts/hostside/app/AndroidManifest.xml index 2553f475aa..ba0e242ab9 100644 --- a/tests/cts/hostside/app/AndroidManifest.xml +++ b/tests/cts/hostside/app/AndroidManifest.xml @@ -45,7 +45,7 @@ diff --git a/tests/cts/hostside/src/com/android/cts/net/HostsideNetworkTestCase.java b/tests/cts/hostside/src/com/android/cts/net/HostsideNetworkTestCase.java index 7c9ce8f833..a2443b391a 100644 --- a/tests/cts/hostside/src/com/android/cts/net/HostsideNetworkTestCase.java +++ b/tests/cts/hostside/src/com/android/cts/net/HostsideNetworkTestCase.java @@ -128,7 +128,7 @@ abstract class HostsideNetworkTestCase extends DeviceTestCase implements IAbiRec protected void runDeviceTests(String packageName, String testClassName, String methodName) throws DeviceNotAvailableException { RemoteAndroidTestRunner testRunner = new RemoteAndroidTestRunner(packageName, - "android.support.test.runner.AndroidJUnitRunner", getDevice().getIDevice()); + "androidx.test.runner.AndroidJUnitRunner", getDevice().getIDevice()); if (testClassName != null) { if (methodName != null) { diff --git a/tests/cts/net/Android.mk b/tests/cts/net/Android.mk index 1430071997..45941a79e1 100644 --- a/tests/cts/net/Android.mk +++ b/tests/cts/net/Android.mk @@ -41,8 +41,8 @@ LOCAL_PACKAGE_NAME := CtsNetTestCases LOCAL_STATIC_JAVA_LIBRARIES := \ core-tests-support \ - compatibility-device-util \ - ctstestrunner \ + compatibility-device-util-axt \ + ctstestrunner-axt \ ctstestserver \ mockwebserver \ junit \ diff --git a/tests/cts/net/AndroidManifest.xml b/tests/cts/net/AndroidManifest.xml index 0bfb650882..b261b39885 100644 --- a/tests/cts/net/AndroidManifest.xml +++ b/tests/cts/net/AndroidManifest.xml @@ -42,7 +42,7 @@ - Date: Fri, 29 Mar 2019 10:34:39 -0700 Subject: [PATCH 33/71] WifiManagerTest: Test for new privileged permission Add a new test to ensure that the NETWORK_CARRIER_PROVISIONING is only granted to one app. Bug: 129401919 Test: atest WifiManagerTest Change-Id: Id2e722d63b02d9cee718dd3af49e9ef113bd5ffb --- .../android/net/wifi/cts/WifiManagerTest.java | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/tests/cts/net/src/android/net/wifi/cts/WifiManagerTest.java b/tests/cts/net/src/android/net/wifi/cts/WifiManagerTest.java index 93795b2bf0..1d666827fa 100644 --- a/tests/cts/net/src/android/net/wifi/cts/WifiManagerTest.java +++ b/tests/cts/net/src/android/net/wifi/cts/WifiManagerTest.java @@ -881,6 +881,30 @@ public class WifiManagerTest extends AndroidTestCase { } } + /** + * Verify that the {@link android.Manifest.permission#NETWORK_CARRIER_PROVISIONING} permission + * is held by at most one application. + */ + public void testNetworkCarrierProvisioningPermission() { + final PackageManager pm = getContext().getPackageManager(); + + final List holding = pm.getPackagesHoldingPermissions(new String[] { + android.Manifest.permission.NETWORK_CARRIER_PROVISIONING + }, PackageManager.MATCH_UNINSTALLED_PACKAGES); + + List uniquePackageNames = holding + .stream() + .map(pi -> pi.packageName) + .distinct() + .collect(Collectors.toList()); + + if (uniquePackageNames.size() > 1) { + fail("The NETWORK_CARRIER_PROVISIONING permission must not be held by more than one " + + "application, but is held by " + uniquePackageNames.size() + " applications: " + + String.join(", ", uniquePackageNames)); + } + } + /** * Verify that the {@link android.Manifest.permission#WIFI_UPDATE_USABILITY_STATS_SCORE} * permission is held by at most one application. From ef4ac8c021b8cfe108a5b80d8c2cb1806b6cc51f Mon Sep 17 00:00:00 2001 From: Remi NGUYEN VAN Date: Thu, 4 Apr 2019 09:39:20 -0700 Subject: [PATCH 34/71] Add FrameworksNetCommonTests to CTS The common tests include tests that must be both in CTS and unit tests. Bug: 129199908 Test: atest CtsNetTestCases, IpPrefixCommonTest is run and passes. Change-Id: I872fb80e8a0b21144f0b66b33645a320dcd5dcf2 (cherry picked from commit 855e7889d62839fe6449f97086656e860c4db177) --- tests/cts/net/Android.mk | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/cts/net/Android.mk b/tests/cts/net/Android.mk index 2084dbc357..04974702a6 100644 --- a/tests/cts/net/Android.mk +++ b/tests/cts/net/Android.mk @@ -39,6 +39,7 @@ LOCAL_SRC_FILES := $(call all-java-files-under, src) LOCAL_PACKAGE_NAME := CtsNetTestCases LOCAL_STATIC_JAVA_LIBRARIES := \ + FrameworksNetCommonTests \ core-tests-support \ compatibility-device-util-axt \ ctstestrunner-axt \ From 49a2918a964aa1e6f124d838b879417a91220cd7 Mon Sep 17 00:00:00 2001 From: Adam Vartanian Date: Wed, 10 Apr 2019 19:45:06 -0700 Subject: [PATCH 35/71] Add test for SslError.getCertificate() Bug: 129200144 Test: cts -m CtsNetTestCases -t android.net.http.cts Change-Id: I1b23746865a4bffc90847b30384defd2c7d49879 Merged-In: I1b23746865a4bffc90847b30384defd2c7d49879 (cherry picked from commit befb9b0798da57d3f0a9b3ed214377296025bda2) --- tests/cts/net/src/android/net/http/cts/SslErrorTest.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/tests/cts/net/src/android/net/http/cts/SslErrorTest.java b/tests/cts/net/src/android/net/http/cts/SslErrorTest.java index 850a8b61e6..0058c90ac4 100644 --- a/tests/cts/net/src/android/net/http/cts/SslErrorTest.java +++ b/tests/cts/net/src/android/net/http/cts/SslErrorTest.java @@ -77,4 +77,9 @@ public class SslErrorTest extends TestCase { SslError error = new SslError(SslError.SSL_EXPIRED, mCertificate); assertEquals(error.getUrl(), ""); } + + public void testGetCertificate() { + SslError error = new SslError(SslError.SSL_EXPIRED, mCertificate); + assertEquals(mCertificate, error.getCertificate()); + } } From a0e4104e81f4fa32ed61c592297a92d7e57157cc Mon Sep 17 00:00:00 2001 From: Luke Huang Date: Thu, 11 Apr 2019 17:57:03 -0700 Subject: [PATCH 36/71] DnsResolver cts changes to match API council requests Bug: 129261432 Test: atest DnsResolverTest Merged-In: I42df921cc3bb01ea25a671d5a1af678a6d3f5872 (cherry picked from commit 89996844304a2919f8cd000f82a4d1af9de3df01) Change-Id: Ibcb92ac23cf413322234bba9100293ab794cf50e --- .../src/android/net/cts/DnsResolverTest.java | 384 +++++++++--------- 1 file changed, 181 insertions(+), 203 deletions(-) diff --git a/tests/cts/net/src/android/net/cts/DnsResolverTest.java b/tests/cts/net/src/android/net/cts/DnsResolverTest.java index 0ff6cd8bac..40d64cf49b 100644 --- a/tests/cts/net/src/android/net/cts/DnsResolverTest.java +++ b/tests/cts/net/src/android/net/cts/DnsResolverTest.java @@ -39,13 +39,14 @@ import android.system.ErrnoException; import android.test.AndroidTestCase; import android.util.Log; +import java.net.Inet4Address; +import java.net.Inet6Address; import java.net.InetAddress; import java.util.ArrayList; import java.util.List; import java.util.concurrent.CountDownLatch; import java.util.concurrent.Executor; import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicReference; public class DnsResolverTest extends AndroidTestCase { private static final String TAG = "DnsResolverTest"; @@ -53,7 +54,9 @@ public class DnsResolverTest extends AndroidTestCase { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' }; static final int TIMEOUT_MS = 12_000; + static final int CANCEL_TIMEOUT_MS = 3_000; static final int CANCEL_RETRY_TIMES = 5; + static final int NXDOMAIN = 3; private ConnectivityManager mCM; private Executor mExecutor; @@ -94,73 +97,26 @@ public class DnsResolverTest extends AndroidTestCase { return testableNetworks.toArray(new Network[0]); } - public void testQueryWithInetAddressCallback() { - final String dname = "www.google.com"; - final String msg = "Query with InetAddressAnswerCallback " + dname; - for (Network network : getTestableNetworks()) { - final CountDownLatch latch = new CountDownLatch(1); - final AtomicReference> answers = new AtomicReference<>(); - final DnsResolver.InetAddressAnswerCallback callback = - new DnsResolver.InetAddressAnswerCallback() { - @Override - public void onAnswer(@NonNull List answerList) { - answers.set(answerList); - for (InetAddress addr : answerList) { - Log.d(TAG, "Reported addr: " + addr.toString()); - } - latch.countDown(); - } - - @Override - public void onParseException(@NonNull ParseException e) { - fail(msg + e.getMessage()); - } - - @Override - public void onQueryException(@NonNull ErrnoException e) { - fail(msg + e.getMessage()); - } - }; - mDns.query(network, dname, CLASS_IN, TYPE_A, FLAG_NO_CACHE_LOOKUP, - mExecutor, null, callback); - try { - assertTrue(msg + " but no valid answer after " + TIMEOUT_MS + "ms.", - latch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS)); - assertGreaterThan(msg + " returned 0 result", answers.get().size(), 0); - } catch (InterruptedException e) { - fail(msg + " Waiting for DNS lookup was interrupted"); - } - } - } - static private void assertGreaterThan(String msg, int first, int second) { assertTrue(msg + " Excepted " + first + " to be greater than " + second, first > second); } - static private void assertValidAnswer(String msg, @NonNull DnsAnswer ans) { - // Check rcode field.(0, No error condition). - assertTrue(msg + " Response error, rcode: " + ans.getRcode(), ans.getRcode() == 0); - // Check answer counts. - assertGreaterThan(msg + " No answer found", ans.getANCount(), 0); - // Check question counts. - assertGreaterThan(msg + " No question found", ans.getQDCount(), 0); - } + private static class DnsParseException extends Exception { + public DnsParseException(String msg) { + super(msg); + } - static private void assertValidEmptyAnswer(String msg, @NonNull DnsAnswer ans) { - // Check rcode field.(0, No error condition). - assertTrue(msg + " Response error, rcode: " + ans.getRcode(), ans.getRcode() == 0); - // Check answer counts. Expect 0 answer. - assertTrue(msg + " Not an empty answer", ans.getANCount() == 0); - // Check question counts. - assertGreaterThan(msg + " No question found", ans.getQDCount(), 0); + public DnsParseException(String msg, Throwable cause) { + super(msg, cause); + } } private static class DnsAnswer extends DnsPacket { - DnsAnswer(@NonNull byte[] data) throws ParseException { + DnsAnswer(@NonNull byte[] data) throws DnsParseException { super(data); // Check QR field.(query (0), or a response (1)). if ((mHeader.flags & (1 << 15)) == 0) { - throw new ParseException("Not an answer packet"); + throw new DnsParseException("Not an answer packet"); } } @@ -175,63 +131,116 @@ public class DnsResolverTest extends AndroidTestCase { } } - class RawAnswerCallbackImpl extends DnsResolver.RawAnswerCallback { + /** + * A query callback that ensures that the query is cancelled and that onAnswer is never + * called. If the query succeeds before it is cancelled, needRetry will return true so the + * test can retry. + */ + class VerifyCancelCallback implements DnsResolver.Callback { private final CountDownLatch mLatch = new CountDownLatch(1); private final String mMsg; - private final int mTimeout; + private final CancellationSignal mCancelSignal; + private int mRcode; + private DnsAnswer mDnsAnswer; - RawAnswerCallbackImpl(@NonNull String msg, int timeout) { + VerifyCancelCallback(@NonNull String msg, @Nullable CancellationSignal cancel) { this.mMsg = msg; - this.mTimeout = timeout; + this.mCancelSignal = cancel; + this.mDnsAnswer = null; } - RawAnswerCallbackImpl(@NonNull String msg) { - this(msg, TIMEOUT_MS); + VerifyCancelCallback(@NonNull String msg) { + this(msg, null); + } + + public boolean waitForAnswer(int timeout) throws InterruptedException { + return mLatch.await(timeout, TimeUnit.MILLISECONDS); } public boolean waitForAnswer() throws InterruptedException { - return mLatch.await(mTimeout, TimeUnit.MILLISECONDS); + return waitForAnswer(TIMEOUT_MS); + } + + public boolean needRetry() throws InterruptedException { + return mLatch.await(CANCEL_TIMEOUT_MS, TimeUnit.MILLISECONDS); } @Override - public void onAnswer(@NonNull byte[] answer) { + public void onAnswer(@NonNull byte[] answer, int rcode) { + if (mCancelSignal != null && mCancelSignal.isCanceled()) { + fail(mMsg + " should not have returned any answers"); + } + + mRcode = rcode; try { - assertValidAnswer(mMsg, new DnsAnswer(answer)); - Log.d(TAG, "Reported blob: " + byteArrayToHexString(answer)); - mLatch.countDown(); - } catch (ParseException e) { + mDnsAnswer = new DnsAnswer(answer); + } catch (DnsParseException e) { fail(mMsg + e.getMessage()); } + Log.d(TAG, "Reported blob: " + byteArrayToHexString(answer)); + mLatch.countDown(); } @Override - public void onParseException(@NonNull ParseException e) { - fail(mMsg + e.getMessage()); + public void onError(@NonNull DnsResolver.DnsException error) { + fail(mMsg + error.getMessage()); } - @Override - public void onQueryException(@NonNull ErrnoException e) { - fail(mMsg + e.getMessage()); + private void assertValidAnswer() { + assertTrue(mMsg + "No valid answer", mDnsAnswer != null); + assertTrue(mMsg + " Unexpected error: reported rcode" + mRcode + + " blob's rcode " + mDnsAnswer.getRcode(), mRcode == mDnsAnswer.getRcode()); + } + + public void assertHasAnswer() { + assertValidAnswer(); + // Check rcode field.(0, No error condition). + assertTrue(mMsg + " Response error, rcode: " + mRcode, mRcode == 0); + // Check answer counts. + assertGreaterThan(mMsg + " No answer found", mDnsAnswer.getANCount(), 0); + // Check question counts. + assertGreaterThan(mMsg + " No question found", mDnsAnswer.getQDCount(), 0); + } + + public void assertNXDomain() { + assertValidAnswer(); + // Check rcode field.(3, NXDomain). + assertTrue(mMsg + " Unexpected rcode: " + mRcode, mRcode == NXDOMAIN); + // Check answer counts. Expect 0 answer. + assertTrue(mMsg + " Not an empty answer", mDnsAnswer.getANCount() == 0); + // Check question counts. + assertGreaterThan(mMsg + " No question found", mDnsAnswer.getQDCount(), 0); + } + + public void assertEmptyAnswer() { + assertValidAnswer(); + // Check rcode field.(0, No error condition). + assertTrue(mMsg + " Response error, rcode: " + mRcode, mRcode == 0); + // Check answer counts. Expect 0 answer. + assertTrue(mMsg + " Not an empty answer", mDnsAnswer.getANCount() == 0); + // Check question counts. + assertGreaterThan(mMsg + " No question found", mDnsAnswer.getQDCount(), 0); } } - public void testQueryWithRawAnswerCallback() { + public void testRawQuery() { final String dname = "www.google.com"; - final String msg = "Query with RawAnswerCallback " + dname; + final String msg = "RawQuery " + dname; for (Network network : getTestableNetworks()) { - final RawAnswerCallbackImpl callback = new RawAnswerCallbackImpl(msg); - mDns.query(network, dname, CLASS_IN, TYPE_AAAA, FLAG_NO_CACHE_LOOKUP, + final VerifyCancelCallback callback = new VerifyCancelCallback(msg); + mDns.rawQuery(network, dname, CLASS_IN, TYPE_AAAA, FLAG_NO_CACHE_LOOKUP, mExecutor, null, callback); try { assertTrue(msg + " but no answer after " + TIMEOUT_MS + "ms.", callback.waitForAnswer()); + callback.assertHasAnswer(); } catch (InterruptedException e) { fail(msg + " Waiting for DNS lookup was interrupted"); } } } - public void testQueryBlobWithRawAnswerCallback() { + public void testRawQueryBlob() { final byte[] blob = new byte[]{ /* Header */ 0x55, 0x66, /* Transaction ID */ @@ -246,137 +255,58 @@ public class DnsResolverTest extends AndroidTestCase { 0x00, 0x01, /* Type */ 0x00, 0x01 /* Class */ }; - final String msg = "Query with RawAnswerCallback " + byteArrayToHexString(blob); + final String msg = "RawQuery blob " + byteArrayToHexString(blob); for (Network network : getTestableNetworks()) { - final RawAnswerCallbackImpl callback = new RawAnswerCallbackImpl(msg); - mDns.query(network, blob, FLAG_NO_CACHE_LOOKUP, mExecutor, null, callback); + final VerifyCancelCallback callback = new VerifyCancelCallback(msg); + mDns.rawQuery(network, blob, FLAG_NO_CACHE_LOOKUP, mExecutor, null, callback); try { assertTrue(msg + " but no answer after " + TIMEOUT_MS + "ms.", callback.waitForAnswer()); + callback.assertHasAnswer(); } catch (InterruptedException e) { fail(msg + " Waiting for DNS lookup was interrupted"); } } } - public void testQueryRoot() { + public void testRawQueryRoot() { final String dname = ""; - final String msg = "Query with RawAnswerCallback empty dname(ROOT) "; + final String msg = "RawQuery empty dname(ROOT) "; for (Network network : getTestableNetworks()) { - final CountDownLatch latch = new CountDownLatch(1); - final DnsResolver.RawAnswerCallback callback = new DnsResolver.RawAnswerCallback() { - @Override - public void onAnswer(@NonNull byte[] answer) { - try { - // Except no answer record because of querying with empty dname(ROOT) - assertValidEmptyAnswer(msg, new DnsAnswer(answer)); - latch.countDown(); - } catch (ParseException e) { - fail(msg + e.getMessage()); - } - } - - @Override - public void onParseException(@NonNull ParseException e) { - fail(msg + e.getMessage()); - } - - @Override - public void onQueryException(@NonNull ErrnoException e) { - fail(msg + e.getMessage()); - } - }; - mDns.query(network, dname, CLASS_IN, TYPE_AAAA, FLAG_NO_CACHE_LOOKUP, + final VerifyCancelCallback callback = new VerifyCancelCallback(msg); + mDns.rawQuery(network, dname, CLASS_IN, TYPE_AAAA, FLAG_NO_CACHE_LOOKUP, mExecutor, null, callback); try { - assertTrue(msg + "but no answer after " + TIMEOUT_MS + "ms.", - latch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS)); + assertTrue(msg + " but no answer after " + TIMEOUT_MS + "ms.", + callback.waitForAnswer()); + // Except no answer record because of querying with empty dname(ROOT) + callback.assertEmptyAnswer(); } catch (InterruptedException e) { fail(msg + "Waiting for DNS lookup was interrupted"); } } } - public void testQueryNXDomain() { + public void testRawQueryNXDomain() { final String dname = "test1-nx.metric.gstatic.com"; - final String msg = "Query with InetAddressAnswerCallback " + dname; + final String msg = "RawQuery " + dname; for (Network network : getTestableNetworks()) { - final CountDownLatch latch = new CountDownLatch(1); - final DnsResolver.InetAddressAnswerCallback callback = - new DnsResolver.InetAddressAnswerCallback() { - @Override - public void onAnswer(@NonNull List answerList) { - if (answerList.size() == 0) { - latch.countDown(); - return; - } - fail(msg + " but get valid answers"); - } - - @Override - public void onParseException(@NonNull ParseException e) { - fail(msg + e.getMessage()); - } - - @Override - public void onQueryException(@NonNull ErrnoException e) { - fail(msg + e.getMessage()); - } - }; - mDns.query(network, dname, CLASS_IN, TYPE_AAAA, FLAG_NO_CACHE_LOOKUP, + final VerifyCancelCallback callback = new VerifyCancelCallback(msg); + mDns.rawQuery(network, dname, CLASS_IN, TYPE_AAAA, FLAG_NO_CACHE_LOOKUP, mExecutor, null, callback); try { assertTrue(msg + " but no answer after " + TIMEOUT_MS + "ms.", - latch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS)); + callback.waitForAnswer()); + callback.assertNXDomain(); } catch (InterruptedException e) { fail(msg + " Waiting for DNS lookup was interrupted"); } } } - /** - * A query callback that ensures that the query is cancelled and that onAnswer is never - * called. If the query succeeds before it is cancelled, needRetry will return true so the - * test can retry. - */ - class VerifyCancelCallback extends DnsResolver.RawAnswerCallback { - private static final int CANCEL_TIMEOUT = 3_000; - - private final CountDownLatch mLatch = new CountDownLatch(1); - private final String mMsg; - private final CancellationSignal mCancelSignal; - - VerifyCancelCallback(@NonNull String msg, @NonNull CancellationSignal cancelSignal) { - this.mMsg = msg; - this.mCancelSignal = cancelSignal; - } - - public boolean needRetry() throws InterruptedException { - return mLatch.await(CANCEL_TIMEOUT, TimeUnit.MILLISECONDS); - } - - @Override - public void onAnswer(@NonNull byte[] answer) { - if (mCancelSignal.isCanceled()) { - fail(mMsg + " should not have returned any answers"); - } - mLatch.countDown(); - } - - @Override - public void onParseException(@NonNull ParseException e) { - fail(mMsg + e.getMessage()); - } - - @Override - public void onQueryException(@NonNull ErrnoException e) { - fail(mMsg + e.getMessage()); - } - } - - public void testQueryCancel() throws ErrnoException { + public void testRawQueryCancel() throws ErrnoException { final String dname = "www.google.com"; - final String msg = "Test cancel query " + dname; + final String msg = "Test cancel RawQuery " + dname; // Start a DNS query and the cancel it immediately. Use VerifyCancelCallback to expect // that the query is cancelled before it succeeds. If it is not cancelled before it // succeeds, retry the test until it is. @@ -390,7 +320,7 @@ public class DnsResolverTest extends AndroidTestCase { final CountDownLatch latch = new CountDownLatch(1); final CancellationSignal cancelSignal = new CancellationSignal(); final VerifyCancelCallback callback = new VerifyCancelCallback(msg, cancelSignal); - mDns.query(network, dname, CLASS_IN, TYPE_AAAA, FLAG_EMPTY, + mDns.rawQuery(network, dname, CLASS_IN, TYPE_AAAA, FLAG_EMPTY, mExecutor, cancelSignal, callback); mExecutor.execute(() -> { cancelSignal.cancel(); @@ -399,7 +329,7 @@ public class DnsResolverTest extends AndroidTestCase { try { retry = callback.needRetry(); assertTrue(msg + " query was not cancelled", - latch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS)); + latch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS)); } catch (InterruptedException e) { fail(msg + "Waiting for DNS lookup was interrupted"); } @@ -407,7 +337,7 @@ public class DnsResolverTest extends AndroidTestCase { } } - public void testQueryBlobCancel() throws ErrnoException { + public void testRawQueryBlobCancel() throws ErrnoException { final byte[] blob = new byte[]{ /* Header */ 0x55, 0x66, /* Transaction ID */ @@ -422,7 +352,7 @@ public class DnsResolverTest extends AndroidTestCase { 0x00, 0x01, /* Type */ 0x00, 0x01 /* Class */ }; - final String msg = "Test cancel raw Query " + byteArrayToHexString(blob); + final String msg = "Test cancel RawQuery blob " + byteArrayToHexString(blob); // Start a DNS query and the cancel it immediately. Use VerifyCancelCallback to expect // that the query is cancelled before it succeeds. If it is not cancelled before it // succeeds, retry the test until it is. @@ -436,7 +366,7 @@ public class DnsResolverTest extends AndroidTestCase { final CountDownLatch latch = new CountDownLatch(1); final CancellationSignal cancelSignal = new CancellationSignal(); final VerifyCancelCallback callback = new VerifyCancelCallback(msg, cancelSignal); - mDns.query(network, blob, FLAG_EMPTY, mExecutor, cancelSignal, callback); + mDns.rawQuery(network, blob, FLAG_EMPTY, mExecutor, cancelSignal, callback); mExecutor.execute(() -> { cancelSignal.cancel(); latch.countDown(); @@ -444,7 +374,7 @@ public class DnsResolverTest extends AndroidTestCase { try { retry = callback.needRetry(); assertTrue(msg + " cancel is not done", - latch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS)); + latch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS)); } catch (InterruptedException e) { fail(msg + " Waiting for DNS lookup was interrupted"); } @@ -454,16 +384,16 @@ public class DnsResolverTest extends AndroidTestCase { public void testCancelBeforeQuery() throws ErrnoException { final String dname = "www.google.com"; - final String msg = "Test cancelled query " + dname; + final String msg = "Test cancelled RawQuery " + dname; for (Network network : getTestableNetworks()) { - final RawAnswerCallbackImpl callback = new RawAnswerCallbackImpl(msg, 3_000); + final VerifyCancelCallback callback = new VerifyCancelCallback(msg); final CancellationSignal cancelSignal = new CancellationSignal(); cancelSignal.cancel(); - mDns.query(network, dname, CLASS_IN, TYPE_AAAA, FLAG_EMPTY, + mDns.rawQuery(network, dname, CLASS_IN, TYPE_AAAA, FLAG_EMPTY, mExecutor, cancelSignal, callback); try { assertTrue(msg + " should not return any answers", - !callback.waitForAnswer()); + !callback.waitForAnswer(CANCEL_TIMEOUT_MS)); } catch (InterruptedException e) { fail(msg + " Waiting for DNS lookup was interrupted"); } @@ -476,9 +406,7 @@ public class DnsResolverTest extends AndroidTestCase { * before it is cancelled, needRetry will return true so the * test can retry. */ - class VerifyCancelInetAddressCallback extends DnsResolver.InetAddressAnswerCallback { - private static final int CANCEL_TIMEOUT = 3_000; - + class VerifyCancelInetAddressCallback implements DnsResolver.Callback> { private final CountDownLatch mLatch = new CountDownLatch(1); private final String mMsg; private final List mAnswers; @@ -495,31 +423,43 @@ public class DnsResolverTest extends AndroidTestCase { } public boolean needRetry() throws InterruptedException { - return mLatch.await(CANCEL_TIMEOUT, TimeUnit.MILLISECONDS); + return mLatch.await(CANCEL_TIMEOUT_MS, TimeUnit.MILLISECONDS); } public boolean isAnswerEmpty() { return mAnswers.isEmpty(); } + public boolean hasIpv6Answer() { + for (InetAddress answer : mAnswers) { + if (answer instanceof Inet6Address) return true; + } + return false; + } + + public boolean hasIpv4Answer() { + for (InetAddress answer : mAnswers) { + if (answer instanceof Inet4Address) return true; + } + return false; + } + @Override - public void onAnswer(@NonNull List answerList) { + public void onAnswer(@NonNull List answerList, int rcode) { if (mCancelSignal != null && mCancelSignal.isCanceled()) { fail(mMsg + " should not have returned any answers"); } + for (InetAddress addr : answerList) { + Log.d(TAG, "Reported addr: " + addr.toString()); + } mAnswers.clear(); mAnswers.addAll(answerList); mLatch.countDown(); } @Override - public void onParseException(@NonNull ParseException e) { - fail(mMsg + e.getMessage()); - } - - @Override - public void onQueryException(@NonNull ErrnoException e) { - fail(mMsg + e.getMessage()); + public void onError(@NonNull DnsResolver.DnsException error) { + fail(mMsg + error.getMessage()); } } @@ -544,8 +484,8 @@ public class DnsResolverTest extends AndroidTestCase { public void testQueryCancelForInetAddress() throws ErrnoException { final String dname = "www.google.com"; final String msg = "Test cancel query for InetAddress " + dname; - // Start a DNS query and the cancel it immediately. Use VerifyCancelCallback to expect - // that the query is cancelled before it succeeds. If it is not cancelled before it + // Start a DNS query and the cancel it immediately. Use VerifyCancelInetAddressCallback to + // expect that the query is cancelled before it succeeds. If it is not cancelled before it // succeeds, retry the test until it is. for (Network network : getTestableNetworks()) { boolean retry = false; @@ -566,11 +506,49 @@ public class DnsResolverTest extends AndroidTestCase { try { retry = callback.needRetry(); assertTrue(msg + " query was not cancelled", - latch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS)); + latch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS)); } catch (InterruptedException e) { fail(msg + "Waiting for DNS lookup was interrupted"); } } while (retry); } } + + public void testQueryForInetAddressIpv4() { + final String dname = "www.google.com"; + final String msg = "Test query for IPv4 InetAddress " + dname; + for (Network network : getTestableNetworks()) { + final VerifyCancelInetAddressCallback callback = + new VerifyCancelInetAddressCallback(msg, null); + mDns.query(network, dname, TYPE_A, FLAG_NO_CACHE_LOOKUP, + mExecutor, null, callback); + try { + assertTrue(msg + " but no answer after " + TIMEOUT_MS + "ms.", + callback.waitForAnswer()); + assertTrue(msg + " returned 0 results", !callback.isAnswerEmpty()); + assertTrue(msg + " returned Ipv6 results", !callback.hasIpv6Answer()); + } catch (InterruptedException e) { + fail(msg + " Waiting for DNS lookup was interrupted"); + } + } + } + + public void testQueryForInetAddressIpv6() { + final String dname = "www.google.com"; + final String msg = "Test query for IPv6 InetAddress " + dname; + for (Network network : getTestableNetworks()) { + final VerifyCancelInetAddressCallback callback = + new VerifyCancelInetAddressCallback(msg, null); + mDns.query(network, dname, TYPE_AAAA, FLAG_NO_CACHE_LOOKUP, + mExecutor, null, callback); + try { + assertTrue(msg + " but no answer after " + TIMEOUT_MS + "ms.", + callback.waitForAnswer()); + assertTrue(msg + " returned 0 results", !callback.isAnswerEmpty()); + assertTrue(msg + " returned Ipv4 results", !callback.hasIpv4Answer()); + } catch (InterruptedException e) { + fail(msg + " Waiting for DNS lookup was interrupted"); + } + } + } } From 5d3ac8f9e1de786c05f3091549bd4eec3fda42a6 Mon Sep 17 00:00:00 2001 From: Varun Anand Date: Tue, 12 Mar 2019 16:02:32 -0700 Subject: [PATCH 37/71] CTS tests related to VPN meteredness. (cherry picked from commit d1008aa730886a52e39ddb9c384fd563806a1501) Tests cover scenarios related to whether VPN has explicitly declared its underlying networks plus whether it is an always metered VPN. For each of these scenarios, we ensure VPN meteredness based on its capabilities and ConnectivityManager#isActiveNetworkMetered matches. Bug: 123727651 Test: atest HostsideVpnTests Change-Id: I2dea70c1c432d05b1a22c945f1e3e17166e4132d Merged-In: I3030e5468a55bbc32be2a753f098dcf7f0256af8 --- .../cts/net/hostside/MyVpnService.java | 14 ++ .../com/android/cts/net/hostside/VpnTest.java | 175 ++++++++++++++++-- .../com/android/cts/net/HostsideVpnTests.java | 27 +++ 3 files changed, 205 insertions(+), 11 deletions(-) diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/MyVpnService.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/MyVpnService.java index 7d91574c82..7d3d4fce74 100644 --- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/MyVpnService.java +++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/MyVpnService.java @@ -17,6 +17,7 @@ package com.android.cts.net.hostside; import android.content.Intent; +import android.net.Network; import android.net.ProxyInfo; import android.net.VpnService; import android.os.ParcelFileDescriptor; @@ -27,6 +28,7 @@ import android.util.Log; import java.io.IOException; import java.net.InetAddress; import java.net.UnknownHostException; +import java.util.ArrayList; public class MyVpnService extends VpnService { @@ -118,6 +120,18 @@ public class MyVpnService extends VpnService { } } + ArrayList underlyingNetworks = + intent.getParcelableArrayListExtra(packageName + ".underlyingNetworks"); + if (underlyingNetworks == null) { + // VPN tracks default network + builder.setUnderlyingNetworks(null); + } else { + builder.setUnderlyingNetworks(underlyingNetworks.toArray(new Network[0])); + } + + boolean isAlwaysMetered = intent.getBooleanExtra(packageName + ".isAlwaysMetered", false); + builder.setMetered(isAlwaysMetered); + ProxyInfo vpnProxy = intent.getParcelableExtra(packageName + ".httpProxy"); builder.setHttpProxy(vpnProxy); builder.setMtu(MTU); diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/VpnTest.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/VpnTest.java index 17e13478b0..2fc85f6e3e 100755 --- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/VpnTest.java +++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/VpnTest.java @@ -19,6 +19,7 @@ package com.android.cts.net.hostside; import static android.os.Process.INVALID_UID; import static android.system.OsConstants.*; +import android.annotation.Nullable; import android.content.Context; import android.content.Intent; import android.content.pm.PackageManager; @@ -31,6 +32,7 @@ import android.net.NetworkRequest; import android.net.Proxy; import android.net.ProxyInfo; import android.net.VpnService; +import android.net.wifi.WifiManager; import android.os.ParcelFileDescriptor; import android.os.Process; import android.os.SystemProperties; @@ -61,7 +63,9 @@ import java.net.InetSocketAddress; import java.net.ServerSocket; import java.net.Socket; import java.nio.charset.StandardCharsets; +import java.util.ArrayList; import java.util.Random; +import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; /** @@ -100,6 +104,7 @@ public class VpnTest extends InstrumentationTestCase { private MyActivity mActivity; private String mPackageName; private ConnectivityManager mCM; + private WifiManager mWifiManager; private RemoteSocketFactoryClient mRemoteSocketFactoryClient; Network mNetwork; @@ -123,7 +128,8 @@ public class VpnTest extends InstrumentationTestCase { mActivity = launchActivity(getInstrumentation().getTargetContext().getPackageName(), MyActivity.class, null); mPackageName = mActivity.getPackageName(); - mCM = (ConnectivityManager) mActivity.getSystemService(mActivity.CONNECTIVITY_SERVICE); + mCM = (ConnectivityManager) mActivity.getSystemService(Context.CONNECTIVITY_SERVICE); + mWifiManager = (WifiManager) mActivity.getSystemService(Context.WIFI_SERVICE); mRemoteSocketFactoryClient = new RemoteSocketFactoryClient(mActivity); mRemoteSocketFactoryClient.bind(); mDevice.waitForIdle(); @@ -192,9 +198,11 @@ public class VpnTest extends InstrumentationTestCase { } } + // TODO: Consider replacing arguments with a Builder. private void startVpn( String[] addresses, String[] routes, String allowedApplications, - String disallowedApplications, ProxyInfo proxyInfo) throws Exception { + String disallowedApplications, @Nullable ProxyInfo proxyInfo, + @Nullable ArrayList underlyingNetworks, boolean isAlwaysMetered) throws Exception { prepareVpn(); // Register a callback so we will be notified when our VPN comes up. @@ -221,7 +229,10 @@ public class VpnTest extends InstrumentationTestCase { .putExtra(mPackageName + ".routes", TextUtils.join(",", routes)) .putExtra(mPackageName + ".allowedapplications", allowedApplications) .putExtra(mPackageName + ".disallowedapplications", disallowedApplications) - .putExtra(mPackageName + ".httpProxy", proxyInfo); + .putExtra(mPackageName + ".httpProxy", proxyInfo) + .putParcelableArrayListExtra( + mPackageName + ".underlyingNetworks", underlyingNetworks) + .putExtra(mPackageName + ".isAlwaysMetered", isAlwaysMetered); mActivity.startService(intent); synchronized (mLock) { @@ -251,7 +262,8 @@ public class VpnTest extends InstrumentationTestCase { mCallback = new NetworkCallback() { public void onLost(Network network) { synchronized (mLockShutdown) { - Log.i(TAG, "Got lost callback for network=" + network + ",mNetwork = " + mNetwork); + Log.i(TAG, "Got lost callback for network=" + network + + ",mNetwork = " + mNetwork); if( mNetwork == network){ mLockShutdown.notify(); } @@ -574,7 +586,7 @@ public class VpnTest extends InstrumentationTestCase { startVpn(new String[] {"192.0.2.2/32", "2001:db8:1:2::ffe/128"}, new String[] {"0.0.0.0/0", "::/0"}, - "", "", null); + "", "", null, null /* underlyingNetworks */, false /* isAlwaysMetered */); final Intent intent = receiver.awaitForBroadcast(TimeUnit.MINUTES.toMillis(1)); assertNotNull("Failed to receive broadcast from VPN service", intent); @@ -598,7 +610,7 @@ public class VpnTest extends InstrumentationTestCase { String allowedApps = mRemoteSocketFactoryClient.getPackageName() + "," + mPackageName; startVpn(new String[] {"192.0.2.2/32", "2001:db8:1:2::ffe/128"}, new String[] {"192.0.2.0/24", "2001:db8::/32"}, - allowedApps, "", null); + allowedApps, "", null, null /* underlyingNetworks */, false /* isAlwaysMetered */); assertSocketClosed(fd, TEST_HOST); @@ -620,7 +632,8 @@ public class VpnTest extends InstrumentationTestCase { Log.i(TAG, "Append shell app to disallowedApps: " + disallowedApps); startVpn(new String[] {"192.0.2.2/32", "2001:db8:1:2::ffe/128"}, new String[] {"192.0.2.0/24", "2001:db8::/32"}, - "", disallowedApps, null); + "", disallowedApps, null, null /* underlyingNetworks */, + false /* isAlwaysMetered */); assertSocketStillOpen(localFd, TEST_HOST); assertSocketStillOpen(remoteFd, TEST_HOST); @@ -657,7 +670,7 @@ public class VpnTest extends InstrumentationTestCase { ProxyInfo testProxyInfo = ProxyInfo.buildDirectProxy("10.0.0.1", 8888); startVpn(new String[] {"192.0.2.2/32", "2001:db8:1:2::ffe/128"}, new String[] {"0.0.0.0/0", "::/0"}, allowedApps, "", - testProxyInfo); + testProxyInfo, null /* underlyingNetworks */, false /* isAlwaysMetered */); // Check that the proxy change broadcast is received try { @@ -697,7 +710,7 @@ public class VpnTest extends InstrumentationTestCase { ProxyInfo testProxyInfo = ProxyInfo.buildDirectProxy("10.0.0.1", 8888); startVpn(new String[] {"192.0.2.2/32", "2001:db8:1:2::ffe/128"}, new String[] {"0.0.0.0/0", "::/0"}, "", disallowedApps, - testProxyInfo); + testProxyInfo, null /* underlyingNetworks */, false /* isAlwaysMetered */); // The disallowed app does has the proxy configs of the default network. assertNetworkHasExpectedProxy(initialProxy, mCM.getActiveNetwork()); @@ -711,7 +724,8 @@ public class VpnTest extends InstrumentationTestCase { proxyBroadcastReceiver.register(); String allowedApps = mPackageName; startVpn(new String[] {"192.0.2.2/32", "2001:db8:1:2::ffe/128"}, - new String[] {"0.0.0.0/0", "::/0"}, allowedApps, "", null); + new String[] {"0.0.0.0/0", "::/0"}, allowedApps, "", null, + null /* underlyingNetworks */, false /* isAlwaysMetered */); try { assertNotNull("No proxy change was broadcast.", @@ -748,7 +762,7 @@ public class VpnTest extends InstrumentationTestCase { proxyBroadcastReceiver.register(); startVpn(new String[] {"192.0.2.2/32", "2001:db8:1:2::ffe/128"}, new String[] {"0.0.0.0/0", "::/0"}, allowedApps, "", - testProxyInfo); + testProxyInfo, null /* underlyingNetworks */, false /* isAlwaysMetered */); assertDefaultProxy(testProxyInfo); mCM.bindProcessToNetwork(initialNetwork); @@ -761,6 +775,145 @@ public class VpnTest extends InstrumentationTestCase { assertDefaultProxy(initialProxy); } + public void testVpnMeterednessWithNoUnderlyingNetwork() throws Exception { + if (!supportedHardware()) { + return; + } + // VPN is not routing any traffic i.e. its underlying networks is an empty array. + ArrayList underlyingNetworks = new ArrayList<>(); + String allowedApps = mPackageName; + + startVpn(new String[] {"192.0.2.2/32", "2001:db8:1:2::ffe/128"}, + new String[] {"0.0.0.0/0", "::/0"}, allowedApps, "", null, + underlyingNetworks, false /* isAlwaysMetered */); + + // VPN should now be the active network. + assertEquals(mNetwork, mCM.getActiveNetwork()); + assertVpnTransportContains(NetworkCapabilities.TRANSPORT_VPN); + // VPN with no underlying networks should be metered by default. + assertTrue(isNetworkMetered(mNetwork)); + assertTrue(mCM.isActiveNetworkMetered()); + } + + public void testVpnMeterednessWithNullUnderlyingNetwork() throws Exception { + if (!supportedHardware()) { + return; + } + Network underlyingNetwork = mCM.getActiveNetwork(); + if (underlyingNetwork == null) { + Log.i(TAG, "testVpnMeterednessWithNullUnderlyingNetwork cannot execute" + + " unless there is an active network"); + return; + } + // VPN tracks platform default. + ArrayList underlyingNetworks = null; + String allowedApps = mPackageName; + + startVpn(new String[] {"192.0.2.2/32", "2001:db8:1:2::ffe/128"}, + new String[] {"0.0.0.0/0", "::/0"}, allowedApps, "", null, + underlyingNetworks, false /*isAlwaysMetered */); + + // Ensure VPN transports contains underlying network's transports. + assertVpnTransportContains(underlyingNetwork); + // Its meteredness should be same as that of underlying network. + assertEquals(isNetworkMetered(underlyingNetwork), isNetworkMetered(mNetwork)); + // Meteredness based on VPN capabilities and CM#isActiveNetworkMetered should be in sync. + assertEquals(isNetworkMetered(mNetwork), mCM.isActiveNetworkMetered()); + } + + public void testVpnMeterednessWithNonNullUnderlyingNetwork() throws Exception { + if (!supportedHardware()) { + return; + } + Network underlyingNetwork = mCM.getActiveNetwork(); + if (underlyingNetwork == null) { + Log.i(TAG, "testVpnMeterednessWithNonNullUnderlyingNetwork cannot execute" + + " unless there is an active network"); + return; + } + // VPN explicitly declares WiFi to be its underlying network. + ArrayList underlyingNetworks = new ArrayList<>(1); + underlyingNetworks.add(underlyingNetwork); + String allowedApps = mPackageName; + + startVpn(new String[] {"192.0.2.2/32", "2001:db8:1:2::ffe/128"}, + new String[] {"0.0.0.0/0", "::/0"}, allowedApps, "", null, + underlyingNetworks, false /* isAlwaysMetered */); + + // Ensure VPN transports contains underlying network's transports. + assertVpnTransportContains(underlyingNetwork); + // Its meteredness should be same as that of underlying network. + assertEquals(isNetworkMetered(underlyingNetwork), isNetworkMetered(mNetwork)); + // Meteredness based on VPN capabilities and CM#isActiveNetworkMetered should be in sync. + assertEquals(isNetworkMetered(mNetwork), mCM.isActiveNetworkMetered()); + } + + public void testAlwaysMeteredVpnWithNullUnderlyingNetwork() throws Exception { + if (!supportedHardware()) { + return; + } + Network underlyingNetwork = mCM.getActiveNetwork(); + if (underlyingNetwork == null) { + Log.i(TAG, "testAlwaysMeteredVpnWithNullUnderlyingNetwork cannot execute" + + " unless there is an active network"); + return; + } + // VPN tracks platform default. + ArrayList underlyingNetworks = null; + String allowedApps = mPackageName; + boolean isAlwaysMetered = true; + + startVpn(new String[] {"192.0.2.2/32", "2001:db8:1:2::ffe/128"}, + new String[] {"0.0.0.0/0", "::/0"}, allowedApps, "", null, + underlyingNetworks, isAlwaysMetered); + + // VPN's meteredness does not depend on underlying network since it is always metered. + assertTrue(isNetworkMetered(mNetwork)); + assertTrue(mCM.isActiveNetworkMetered()); + } + + public void testAlwaysMeteredVpnWithNonNullUnderlyingNetwork() throws Exception { + if (!supportedHardware()) { + return; + } + Network underlyingNetwork = mCM.getActiveNetwork(); + if (underlyingNetwork == null) { + Log.i(TAG, "testAlwaysMeteredVpnWithNonNullUnderlyingNetwork cannot execute" + + " unless there is an active network"); + return; + } + // VPN explicitly declares its underlying network. + ArrayList underlyingNetworks = new ArrayList<>(1); + underlyingNetworks.add(underlyingNetwork); + String allowedApps = mPackageName; + boolean isAlwaysMetered = true; + + startVpn(new String[] {"192.0.2.2/32", "2001:db8:1:2::ffe/128"}, + new String[] {"0.0.0.0/0", "::/0"}, allowedApps, "", null, + underlyingNetworks, isAlwaysMetered); + + // VPN's meteredness does not depend on underlying network since it is always metered. + assertTrue(isNetworkMetered(mNetwork)); + assertTrue(mCM.isActiveNetworkMetered()); + } + + private boolean isNetworkMetered(Network network) { + NetworkCapabilities nc = mCM.getNetworkCapabilities(network); + return !nc.hasCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED); + } + + private void assertVpnTransportContains(Network underlyingNetwork) { + int[] transports = mCM.getNetworkCapabilities(underlyingNetwork).getTransportTypes(); + assertVpnTransportContains(transports); + } + + private void assertVpnTransportContains(int... transports) { + NetworkCapabilities vpnCaps = mCM.getNetworkCapabilities(mNetwork); + for (int transport : transports) { + assertTrue(vpnCaps.hasTransport(transport)); + } + } + private void assertDefaultProxy(ProxyInfo expected) { assertEquals("Incorrect proxy config.", expected, mCM.getDefaultProxy()); String expectedHost = expected == null ? null : expected.getHost(); diff --git a/tests/cts/hostside/src/com/android/cts/net/HostsideVpnTests.java b/tests/cts/hostside/src/com/android/cts/net/HostsideVpnTests.java index e34ee89897..6e37a24c68 100644 --- a/tests/cts/hostside/src/com/android/cts/net/HostsideVpnTests.java +++ b/tests/cts/hostside/src/com/android/cts/net/HostsideVpnTests.java @@ -64,4 +64,31 @@ public class HostsideVpnTests extends HostsideNetworkTestCase { public void testBindToNetworkWithProxy() throws Exception { runDeviceTests(TEST_PKG, TEST_PKG + ".VpnTest", "testBindToNetworkWithProxy"); } + + public void testVpnMeterednessWithNoUnderlyingNetwork() throws Exception { + runDeviceTests( + TEST_PKG, TEST_PKG + ".VpnTest", "testVpnMeterednessWithNoUnderlyingNetwork"); + } + + public void testVpnMeterednessWithNullUnderlyingNetwork() throws Exception { + runDeviceTests( + TEST_PKG, TEST_PKG + ".VpnTest", "testVpnMeterednessWithNullUnderlyingNetwork"); + } + + public void testVpnMeterednessWithNonNullUnderlyingNetwork() throws Exception { + runDeviceTests( + TEST_PKG, TEST_PKG + ".VpnTest", "testVpnMeterednessWithNonNullUnderlyingNetwork"); + } + + public void testAlwaysMeteredVpnWithNullUnderlyingNetwork() throws Exception { + runDeviceTests( + TEST_PKG, TEST_PKG + ".VpnTest", "testAlwaysMeteredVpnWithNullUnderlyingNetwork"); + } + + public void testAlwaysMeteredVpnWithNonNullUnderlyingNetwork() throws Exception { + runDeviceTests( + TEST_PKG, + TEST_PKG + ".VpnTest", + "testAlwaysMeteredVpnWithNonNullUnderlyingNetwork"); + } } From a59e8b6407a4cf582f4e7f9061b6d1b1c264998f Mon Sep 17 00:00:00 2001 From: Luke Huang Date: Fri, 12 Apr 2019 13:19:52 -0700 Subject: [PATCH 38/71] Minor changes for DnsResolverTest Done for code-style nits from aosp/940128. Bug: 129395490 Test: atest DnsResolverTest Merged-In: Ibe5b5396d7d7563643eae14940934786903a4f64 (cherry picked from commit a2f73df47b32924dbf2c26e976bd217ac98ff38c) Change-Id: I0fe6c4b651e23e3018070174d7f18b9b328a2cfc --- .../src/android/net/cts/DnsResolverTest.java | 29 +++++++++---------- 1 file changed, 14 insertions(+), 15 deletions(-) diff --git a/tests/cts/net/src/android/net/cts/DnsResolverTest.java b/tests/cts/net/src/android/net/cts/DnsResolverTest.java index 40d64cf49b..945f51dbc8 100644 --- a/tests/cts/net/src/android/net/cts/DnsResolverTest.java +++ b/tests/cts/net/src/android/net/cts/DnsResolverTest.java @@ -144,9 +144,8 @@ public class DnsResolverTest extends AndroidTestCase { private DnsAnswer mDnsAnswer; VerifyCancelCallback(@NonNull String msg, @Nullable CancellationSignal cancel) { - this.mMsg = msg; - this.mCancelSignal = cancel; - this.mDnsAnswer = null; + mMsg = msg; + mCancelSignal = cancel; } VerifyCancelCallback(@NonNull String msg) { @@ -187,15 +186,15 @@ public class DnsResolverTest extends AndroidTestCase { } private void assertValidAnswer() { - assertTrue(mMsg + "No valid answer", mDnsAnswer != null); - assertTrue(mMsg + " Unexpected error: reported rcode" + mRcode + - " blob's rcode " + mDnsAnswer.getRcode(), mRcode == mDnsAnswer.getRcode()); + assertNotNull(mMsg + " No valid answer", mDnsAnswer); + assertEquals(mMsg + " Unexpected error: reported rcode" + mRcode + + " blob's rcode " + mDnsAnswer.getRcode(), mRcode, mDnsAnswer.getRcode()); } public void assertHasAnswer() { assertValidAnswer(); // Check rcode field.(0, No error condition). - assertTrue(mMsg + " Response error, rcode: " + mRcode, mRcode == 0); + assertEquals(mMsg + " Response error, rcode: " + mRcode, mRcode, 0); // Check answer counts. assertGreaterThan(mMsg + " No answer found", mDnsAnswer.getANCount(), 0); // Check question counts. @@ -205,9 +204,9 @@ public class DnsResolverTest extends AndroidTestCase { public void assertNXDomain() { assertValidAnswer(); // Check rcode field.(3, NXDomain). - assertTrue(mMsg + " Unexpected rcode: " + mRcode, mRcode == NXDOMAIN); + assertEquals(mMsg + " Unexpected rcode: " + mRcode, mRcode, NXDOMAIN); // Check answer counts. Expect 0 answer. - assertTrue(mMsg + " Not an empty answer", mDnsAnswer.getANCount() == 0); + assertEquals(mMsg + " Not an empty answer", mDnsAnswer.getANCount(), 0); // Check question counts. assertGreaterThan(mMsg + " No question found", mDnsAnswer.getQDCount(), 0); } @@ -215,9 +214,9 @@ public class DnsResolverTest extends AndroidTestCase { public void assertEmptyAnswer() { assertValidAnswer(); // Check rcode field.(0, No error condition). - assertTrue(mMsg + " Response error, rcode: " + mRcode, mRcode == 0); + assertEquals(mMsg + " Response error, rcode: " + mRcode, mRcode, 0); // Check answer counts. Expect 0 answer. - assertTrue(mMsg + " Not an empty answer", mDnsAnswer.getANCount() == 0); + assertEquals(mMsg + " Not an empty answer", mDnsAnswer.getANCount(), 0); // Check question counts. assertGreaterThan(mMsg + " No question found", mDnsAnswer.getQDCount(), 0); } @@ -279,10 +278,10 @@ public class DnsResolverTest extends AndroidTestCase { try { assertTrue(msg + " but no answer after " + TIMEOUT_MS + "ms.", callback.waitForAnswer()); - // Except no answer record because of querying with empty dname(ROOT) + // Except no answer record because the root does not have AAAA records. callback.assertEmptyAnswer(); } catch (InterruptedException e) { - fail(msg + "Waiting for DNS lookup was interrupted"); + fail(msg + " Waiting for DNS lookup was interrupted"); } } } @@ -331,7 +330,7 @@ public class DnsResolverTest extends AndroidTestCase { assertTrue(msg + " query was not cancelled", latch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS)); } catch (InterruptedException e) { - fail(msg + "Waiting for DNS lookup was interrupted"); + fail(msg + " Waiting for DNS lookup was interrupted"); } } while (retry); } @@ -508,7 +507,7 @@ public class DnsResolverTest extends AndroidTestCase { assertTrue(msg + " query was not cancelled", latch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS)); } catch (InterruptedException e) { - fail(msg + "Waiting for DNS lookup was interrupted"); + fail(msg + " Waiting for DNS lookup was interrupted"); } } while (retry); } From 221ac7cdb2ccdd6171d68f921466727ffaae49d3 Mon Sep 17 00:00:00 2001 From: Chalard Jean Date: Fri, 19 Apr 2019 14:59:56 +0900 Subject: [PATCH 39/71] Add a test for a bugfix in UrlQuerySanitizer ...so this does not happen again. This is a test for the fix in Ic91660d974dce21f2affdcacaeffe9accf8451ac Bug: 1866121 Test: This Change-Id: Ib7ee866f65baf99b46a31e2115355a42a829421e (cherry picked from commit d60c09fd4db5deb81900af5208cc9306e2f77b3b) Merged-In: Iba7ed3fe8cb23d7d14a29f2259a08e9c833db146 Merged-In: I10882b8d9a62766acfff6ec18afb3d813c631fd3 --- .../cts/net/src/android/net/cts/UrlQuerySanitizerTest.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/tests/cts/net/src/android/net/cts/UrlQuerySanitizerTest.java b/tests/cts/net/src/android/net/cts/UrlQuerySanitizerTest.java index 7076ea2990..2d615bbe86 100644 --- a/tests/cts/net/src/android/net/cts/UrlQuerySanitizerTest.java +++ b/tests/cts/net/src/android/net/cts/UrlQuerySanitizerTest.java @@ -170,6 +170,12 @@ public class UrlQuerySanitizerTest extends AndroidTestCase { String initialPercentSign = "title=%B5"; assertEquals(expectedPlus, uqs.unescape(initialPlus)); assertEquals(expectedPercentSignHex, uqs.unescape(initialPercentSign)); + String expectedPlusThenPercentSign = "Joe Random, User"; + String plusThenPercentSign = "Joe+Random%2C%20User"; + assertEquals(expectedPlusThenPercentSign, uqs.unescape(plusThenPercentSign)); + String expectedPercentSignThenPlus = "Joe, Random User"; + String percentSignThenPlus = "Joe%2C+Random+User"; + assertEquals(expectedPercentSignThenPlus, uqs.unescape(percentSignThenPlus)); assertTrue(uqs.decodeHexDigit('0') >= 0); assertTrue(uqs.decodeHexDigit('b') >= 0); From 7457cd272850a6d3e1c00f11cdf60d7c7f1fe02b Mon Sep 17 00:00:00 2001 From: Jack Yu Date: Fri, 26 Apr 2019 11:49:45 +0800 Subject: [PATCH 40/71] Allow NFC to grant NETWORK_SETTINGS permission There is use cases in NFC that need this permission. Bug:131195124 Test: Cts pass after NFC app add NETWORK_SETTINGS permission Change-Id: Iec5a08721da43767cfd0ced51e73a1b757b0d97a --- tests/cts/net/src/android/net/wifi/cts/WifiManagerTest.java | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/cts/net/src/android/net/wifi/cts/WifiManagerTest.java b/tests/cts/net/src/android/net/wifi/cts/WifiManagerTest.java index 1d666827fa..cbc92aad85 100644 --- a/tests/cts/net/src/android/net/wifi/cts/WifiManagerTest.java +++ b/tests/cts/net/src/android/net/wifi/cts/WifiManagerTest.java @@ -744,6 +744,7 @@ public class WifiManagerTest extends AndroidTestCase { allowedUIDs.add(Process.SHELL_UID); allowedUIDs.add(Process.PHONE_UID); allowedUIDs.add(Process.NETWORK_STACK_UID); + allowedUIDs.add(Process.NFC_UID); // only quick settings is allowed to bind to the BIND_QUICK_SETTINGS_TILE permission, using // this fact to determined allowed package name for sysui From 5abd1ff34694db6303fbbee695c9bc21f3657050 Mon Sep 17 00:00:00 2001 From: Lorenzo Colitti Date: Mon, 25 Mar 2019 21:12:51 +0900 Subject: [PATCH 41/71] Add instant and ABI XML tags for hostside networking tests. These are not multi-ABI because the behaviour does not depend on the ABI of the app. Some of the APIs are ultimately backed by JNI code in the system server, but that only depends on the system server's ABI, not the app's. Enable instant mode because these applications are subject to the same network restrictions as other apps. Fix: 123364589 Test: atest CtsHostsideNetworkTests Test: cts-tradefed run commandAndExit cts --enable-parameterized-modules --module-parameter instant_app -m CtsHostsideNetworkTests Change-Id: Ib3c4cd365ffe95889d51a236f035ea84516f0abd (cherry picked from commit ad17ee9e9273a53e3bb141f750c09eb27e76372e) --- tests/cts/hostside/AndroidTest.xml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tests/cts/hostside/AndroidTest.xml b/tests/cts/hostside/AndroidTest.xml index 0656cae3ca..c7cab7b0ba 100644 --- a/tests/cts/hostside/AndroidTest.xml +++ b/tests/cts/hostside/AndroidTest.xml @@ -16,6 +16,9 @@

Only checks for known plaintext bytes to prevent triggering on ICMP/RA packets or the like + * + * @param plaintext the plaintext bytes to check for + * @param startIndex the index in the list to check for + */ + public boolean hasPlaintextPacket(byte[] plaintext, int startIndex) { + Predicate verifier = + (pkt) -> { + return Collections.indexOfSubList(Arrays.asList(pkt), Arrays.asList(plaintext)) + != -1; + }; + return getFirstMatchingPacket(verifier, startIndex) != null; + } + + public byte[] getEspPacket(int spi, boolean encap, int startIndex) { + return getFirstMatchingPacket( + (pkt) -> { + return isEsp(pkt, spi, encap); + }, + startIndex); + } + + public byte[] awaitEspPacketNoPlaintext( + int spi, byte[] plaintext, boolean useEncap, int expectedPacketSize) throws Exception { + long endTime = System.currentTimeMillis() + TIMEOUT; + int startIndex = 0; + + synchronized (mPackets) { + while (System.currentTimeMillis() < endTime) { + byte[] espPkt = getEspPacket(spi, useEncap, startIndex); + if (espPkt != null) { + // Validate packet size + assertEquals(expectedPacketSize, espPkt.length); + + // Always check plaintext from start + assertFalse(hasPlaintextPacket(plaintext, 0)); + return espPkt; // We've found the packet we're looking for. + } + + startIndex = mPackets.size(); + + // Try to prevent waiting too long. If waitTimeout <= 0, we've already hit timeout + long waitTimeout = endTime - System.currentTimeMillis(); + if (waitTimeout > 0) { + mPackets.wait(waitTimeout); + } + } + + fail("No such ESP packet found with SPI " + spi); + } + return null; + } + + private static boolean isSpiEqual(byte[] pkt, int espOffset, int spi) { + // Check SPI byte by byte. + return pkt[espOffset] == (byte) ((spi >>> 24) & 0xff) + && pkt[espOffset + 1] == (byte) ((spi >>> 16) & 0xff) + && pkt[espOffset + 2] == (byte) ((spi >>> 8) & 0xff) + && pkt[espOffset + 3] == (byte) (spi & 0xff); + } + + private static boolean isEsp(byte[] pkt, int spi, boolean encap) { + if (isIpv6(pkt)) { + // IPv6 UDP encap not supported by kernels; assume non-encap. + return pkt[IP6_PROTO_OFFSET] == IPPROTO_ESP + && isSpiEqual(pkt, IpSecBaseTest.IP6_HDRLEN, spi); + } else { + // Use default IPv4 header length (assuming no options) + if (encap) { + return pkt[IP4_PROTO_OFFSET] == IPPROTO_UDP + && isSpiEqual( + pkt, IpSecBaseTest.IP4_HDRLEN + IpSecBaseTest.UDP_HDRLEN, spi); + } else { + return pkt[IP4_PROTO_OFFSET] == IPPROTO_ESP + && isSpiEqual(pkt, IpSecBaseTest.IP4_HDRLEN, spi); + } + } + } + + private static boolean isIpv6(byte[] pkt) { + // First nibble shows IP version. 0x60 for IPv6 + return (pkt[0] & (byte) 0xF0) == (byte) 0x60; + } + + private static byte[] getReflectedPacket(byte[] pkt) { + byte[] reflected = Arrays.copyOf(pkt, pkt.length); + + if (isIpv6(pkt)) { + // Set reflected packet's dst to that of the original's src + System.arraycopy( + pkt, // src + IP6_ADDR_OFFSET + IP6_ADDR_LEN, // src offset + reflected, // dst + IP6_ADDR_OFFSET, // dst offset + IP6_ADDR_LEN); // len + // Set reflected packet's src IP to that of the original's dst IP + System.arraycopy( + pkt, // src + IP6_ADDR_OFFSET, // src offset + reflected, // dst + IP6_ADDR_OFFSET + IP6_ADDR_LEN, // dst offset + IP6_ADDR_LEN); // len + } else { + // Set reflected packet's dst to that of the original's src + System.arraycopy( + pkt, // src + IP4_ADDR_OFFSET + IP4_ADDR_LEN, // src offset + reflected, // dst + IP4_ADDR_OFFSET, // dst offset + IP4_ADDR_LEN); // len + // Set reflected packet's src IP to that of the original's dst IP + System.arraycopy( + pkt, // src + IP4_ADDR_OFFSET, // src offset + reflected, // dst + IP4_ADDR_OFFSET + IP4_ADDR_LEN, // dst offset + IP4_ADDR_LEN); // len + } + return reflected; + } + + /** Takes all captured packets, flips the src/dst, and re-injects them. */ + public void reflectPackets() throws IOException { + synchronized (mPackets) { + for (byte[] pkt : mPackets) { + injectPacket(getReflectedPacket(pkt)); + } + } + } + + public void injectPacket(byte[] pkt) throws IOException { + FileOutputStream out = new FileOutputStream(mTunFd.getFileDescriptor()); + out.write(pkt); + out.flush(); + } +} From 2d2a1ab8f7341ba056e622afd98cbcd00501256d Mon Sep 17 00:00:00 2001 From: Benedict Wong Date: Thu, 4 Apr 2019 17:20:38 -0700 Subject: [PATCH 47/71] Add utilities to generate packets This change adds utility methods to generate packets incrementally. It supports UDP, ESP, IPv4, IPv6 packet generation. For ESP, it exclusively does AES-CBC, HMAC-SHA256. Bug: 72950854 Test: This Change-Id: Icffeed2ebb2005d79faf04f48fd5126d1d6fb175 Merged-In: Icffeed2ebb2005d79faf04f48fd5126d1d6fb175 (cherry picked from commit 0e4743d56553d698ac45ae548f31019ea6e91541) --- .../src/android/net/cts/IpSecBaseTest.java | 11 - .../src/android/net/cts/IpSecManagerTest.java | 37 +- .../net/src/android/net/cts/PacketUtils.java | 460 ++++++++++++++++++ .../cts/net/src/android/net/cts/TunUtils.java | 16 +- 4 files changed, 483 insertions(+), 41 deletions(-) create mode 100644 tests/cts/net/src/android/net/cts/PacketUtils.java diff --git a/tests/cts/net/src/android/net/cts/IpSecBaseTest.java b/tests/cts/net/src/android/net/cts/IpSecBaseTest.java index cbb9c195d0..35d0f485e0 100644 --- a/tests/cts/net/src/android/net/cts/IpSecBaseTest.java +++ b/tests/cts/net/src/android/net/cts/IpSecBaseTest.java @@ -52,17 +52,6 @@ public class IpSecBaseTest extends AndroidTestCase { protected static final int[] DIRECTIONS = new int[] {IpSecManager.DIRECTION_IN, IpSecManager.DIRECTION_OUT}; - protected static final int TCP_HDRLEN_WITH_OPTIONS = 32; - protected static final int UDP_HDRLEN = 8; - protected static final int IP4_HDRLEN = 20; - protected static final int IP6_HDRLEN = 40; - - // Encryption parameters - protected static final int AES_GCM_IV_LEN = 8; - protected static final int AES_CBC_IV_LEN = 16; - protected static final int AES_GCM_BLK_SIZE = 4; - protected static final int AES_CBC_BLK_SIZE = 16; - protected static final byte[] TEST_DATA = "Best test data ever!".getBytes(); protected static final int DATA_BUFFER_LEN = 4096; protected static final int SOCK_TIMEOUT = 500; diff --git a/tests/cts/net/src/android/net/cts/IpSecManagerTest.java b/tests/cts/net/src/android/net/cts/IpSecManagerTest.java index e788d9602f..60d1c03ee2 100644 --- a/tests/cts/net/src/android/net/cts/IpSecManagerTest.java +++ b/tests/cts/net/src/android/net/cts/IpSecManagerTest.java @@ -16,6 +16,14 @@ package android.net.cts; +import static android.net.cts.PacketUtils.AES_CBC_BLK_SIZE; +import static android.net.cts.PacketUtils.AES_CBC_IV_LEN; +import static android.net.cts.PacketUtils.AES_GCM_BLK_SIZE; +import static android.net.cts.PacketUtils.AES_GCM_IV_LEN; +import static android.net.cts.PacketUtils.IP4_HDRLEN; +import static android.net.cts.PacketUtils.IP6_HDRLEN; +import static android.net.cts.PacketUtils.TCP_HDRLEN_WITH_TIMESTAMP_OPT; +import static android.net.cts.PacketUtils.UDP_HDRLEN; import static android.system.OsConstants.IPPROTO_TCP; import static android.system.OsConstants.IPPROTO_UDP; import static org.junit.Assert.assertArrayEquals; @@ -421,19 +429,6 @@ public class IpSecManagerTest extends IpSecBaseTest { } } - /** Helper function to calculate expected ESP packet size. */ - private int calculateEspPacketSize( - int payloadLen, int cryptIvLength, int cryptBlockSize, int authTruncLen) { - final int ESP_HDRLEN = 4 + 4; // SPI + Seq# - final int ICV_LEN = authTruncLen / 8; // Auth trailer; based on truncation length - payloadLen += cryptIvLength; // Initialization Vector - payloadLen += 2; // ESP trailer - - // Align to block size of encryption algorithm - payloadLen += (cryptBlockSize - (payloadLen % cryptBlockSize)) % cryptBlockSize; - return payloadLen + ESP_HDRLEN + ICV_LEN; - } - public void checkTransform( int protocol, String localAddress, @@ -474,7 +469,7 @@ public class IpSecManagerTest extends IpSecBaseTest { try (IpSecTransform transform = transformBuilder.buildTransportModeTransform(local, spi)) { if (protocol == IPPROTO_TCP) { - transportHdrLen = TCP_HDRLEN_WITH_OPTIONS; + transportHdrLen = TCP_HDRLEN_WITH_TIMESTAMP_OPT; checkTcp(transform, local, sendCount, useJavaSockets); } else if (protocol == IPPROTO_UDP) { transportHdrLen = UDP_HDRLEN; @@ -511,7 +506,7 @@ public class IpSecManagerTest extends IpSecBaseTest { int innerPacketSize = TEST_DATA.length + transportHdrLen + ipHdrLen; int outerPacketSize = - calculateEspPacketSize( + PacketUtils.calculateEspPacketSize( TEST_DATA.length + transportHdrLen, ivLen, blkSize, truncLenBits) + udpEncapLen + ipHdrLen; @@ -529,13 +524,13 @@ public class IpSecManagerTest extends IpSecBaseTest { // Add TCP ACKs for data packets if (protocol == IPPROTO_TCP) { int encryptedTcpPktSize = - calculateEspPacketSize(TCP_HDRLEN_WITH_OPTIONS, ivLen, blkSize, truncLenBits); + PacketUtils.calculateEspPacketSize( + TCP_HDRLEN_WITH_TIMESTAMP_OPT, ivLen, blkSize, truncLenBits); - - // Add data packet ACKs - expectedOuterBytes += (encryptedTcpPktSize + udpEncapLen + ipHdrLen) * (sendCount); - expectedInnerBytes += (TCP_HDRLEN_WITH_OPTIONS + ipHdrLen) * (sendCount); - expectedPackets += sendCount; + // Add data packet ACKs + expectedOuterBytes += (encryptedTcpPktSize + udpEncapLen + ipHdrLen) * (sendCount); + expectedInnerBytes += (TCP_HDRLEN_WITH_TIMESTAMP_OPT + ipHdrLen) * (sendCount); + expectedPackets += sendCount; } StatsChecker.waitForNumPackets(expectedPackets); diff --git a/tests/cts/net/src/android/net/cts/PacketUtils.java b/tests/cts/net/src/android/net/cts/PacketUtils.java new file mode 100644 index 0000000000..6177827ba6 --- /dev/null +++ b/tests/cts/net/src/android/net/cts/PacketUtils.java @@ -0,0 +1,460 @@ +/* + * Copyright (C) 2018 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; + +import static android.system.OsConstants.IPPROTO_IPV6; +import static android.system.OsConstants.IPPROTO_UDP; + +import java.net.Inet4Address; +import java.net.Inet6Address; +import java.net.InetAddress; +import java.nio.ByteBuffer; +import java.nio.ShortBuffer; +import java.security.GeneralSecurityException; +import java.security.SecureRandom; +import java.util.Arrays; +import javax.crypto.Cipher; +import javax.crypto.Mac; +import javax.crypto.spec.IvParameterSpec; +import javax.crypto.spec.SecretKeySpec; + +public class PacketUtils { + private static final String TAG = PacketUtils.class.getSimpleName(); + + private static final int DATA_BUFFER_LEN = 4096; + + static final int IP4_HDRLEN = 20; + static final int IP6_HDRLEN = 40; + static final int UDP_HDRLEN = 8; + static final int TCP_HDRLEN = 20; + static final int TCP_HDRLEN_WITH_TIMESTAMP_OPT = TCP_HDRLEN + 12; + + // Not defined in OsConstants + static final int IPPROTO_IPV4 = 4; + static final int IPPROTO_ESP = 50; + + // Encryption parameters + static final int AES_GCM_IV_LEN = 8; + static final int AES_CBC_IV_LEN = 16; + static final int AES_GCM_BLK_SIZE = 4; + static final int AES_CBC_BLK_SIZE = 16; + + // Encryption algorithms + static final String AES = "AES"; + static final String AES_CBC = "AES/CBC/NoPadding"; + static final String HMAC_SHA_256 = "HmacSHA256"; + + public interface Payload { + byte[] getPacketBytes(IpHeader header) throws Exception; + + void addPacketBytes(IpHeader header, ByteBuffer resultBuffer) throws Exception; + + short length(); + + int getProtocolId(); + } + + public abstract static class IpHeader { + + public final byte proto; + public final InetAddress srcAddr; + public final InetAddress dstAddr; + public final Payload payload; + + public IpHeader(int proto, InetAddress src, InetAddress dst, Payload payload) { + this.proto = (byte) proto; + this.srcAddr = src; + this.dstAddr = dst; + this.payload = payload; + } + + public abstract byte[] getPacketBytes() throws Exception; + + public abstract int getProtocolId(); + } + + public static class Ip4Header extends IpHeader { + private short checksum; + + public Ip4Header(int proto, Inet4Address src, Inet4Address dst, Payload payload) { + super(proto, src, dst, payload); + } + + public byte[] getPacketBytes() throws Exception { + ByteBuffer resultBuffer = buildHeader(); + payload.addPacketBytes(this, resultBuffer); + + return getByteArrayFromBuffer(resultBuffer); + } + + public ByteBuffer buildHeader() { + ByteBuffer bb = ByteBuffer.allocate(DATA_BUFFER_LEN); + + // Version, IHL + bb.put((byte) (0x45)); + + // DCSP, ECN + bb.put((byte) 0); + + // Total Length + bb.putShort((short) (IP4_HDRLEN + payload.length())); + + // Empty for Identification, Flags and Fragment Offset + bb.putShort((short) 0); + bb.put((byte) 0x40); + bb.put((byte) 0x00); + + // TTL + bb.put((byte) 64); + + // Protocol + bb.put(proto); + + // Header Checksum + final int ipChecksumOffset = bb.position(); + bb.putShort((short) 0); + + // Src/Dst addresses + bb.put(srcAddr.getAddress()); + bb.put(dstAddr.getAddress()); + + bb.putShort(ipChecksumOffset, calculateChecksum(bb)); + + return bb; + } + + private short calculateChecksum(ByteBuffer bb) { + int checksum = 0; + + // Calculate sum of 16-bit values, excluding checksum. IPv4 headers are always 32-bit + // aligned, so no special cases needed for unaligned values. + ShortBuffer shortBuffer = ByteBuffer.wrap(getByteArrayFromBuffer(bb)).asShortBuffer(); + while (shortBuffer.hasRemaining()) { + short val = shortBuffer.get(); + + // Wrap as needed + checksum = addAndWrapForChecksum(checksum, val); + } + + return onesComplement(checksum); + } + + public int getProtocolId() { + return IPPROTO_IPV4; + } + } + + public static class Ip6Header extends IpHeader { + public Ip6Header(int nextHeader, Inet6Address src, Inet6Address dst, Payload payload) { + super(nextHeader, src, dst, payload); + } + + public byte[] getPacketBytes() throws Exception { + ByteBuffer bb = ByteBuffer.allocate(DATA_BUFFER_LEN); + + // Version | Traffic Class (First 4 bits) + bb.put((byte) 0x60); + + // Traffic class (Last 4 bits), Flow Label + bb.put((byte) 0); + bb.put((byte) 0); + bb.put((byte) 0); + + // Payload Length + bb.putShort((short) payload.length()); + + // Next Header + bb.put(proto); + + // Hop Limit + bb.put((byte) 64); + + // Src/Dst addresses + bb.put(srcAddr.getAddress()); + bb.put(dstAddr.getAddress()); + + // Payload + payload.addPacketBytes(this, bb); + + return getByteArrayFromBuffer(bb); + } + + public int getProtocolId() { + return IPPROTO_IPV6; + } + } + + public static class BytePayload implements Payload { + public final byte[] payload; + + public BytePayload(byte[] payload) { + this.payload = payload; + } + + public int getProtocolId() { + return -1; + } + + public byte[] getPacketBytes(IpHeader header) { + ByteBuffer bb = ByteBuffer.allocate(DATA_BUFFER_LEN); + + addPacketBytes(header, bb); + return getByteArrayFromBuffer(bb); + } + + public void addPacketBytes(IpHeader header, ByteBuffer resultBuffer) { + resultBuffer.put(payload); + } + + public short length() { + return (short) payload.length; + } + } + + public static class UdpHeader implements Payload { + + public final short srcPort; + public final short dstPort; + public final Payload payload; + + public UdpHeader(int srcPort, int dstPort, Payload payload) { + this.srcPort = (short) srcPort; + this.dstPort = (short) dstPort; + this.payload = payload; + } + + public int getProtocolId() { + return IPPROTO_UDP; + } + + public short length() { + return (short) (payload.length() + 8); + } + + public byte[] getPacketBytes(IpHeader header) throws Exception { + ByteBuffer bb = ByteBuffer.allocate(DATA_BUFFER_LEN); + + addPacketBytes(header, bb); + return getByteArrayFromBuffer(bb); + } + + public void addPacketBytes(IpHeader header, ByteBuffer resultBuffer) throws Exception { + // Source, Destination port + resultBuffer.putShort(srcPort); + resultBuffer.putShort(dstPort); + + // Payload Length + resultBuffer.putShort(length()); + + // Get payload bytes for checksum + payload + ByteBuffer payloadBuffer = ByteBuffer.allocate(DATA_BUFFER_LEN); + payload.addPacketBytes(header, payloadBuffer); + byte[] payloadBytes = getByteArrayFromBuffer(payloadBuffer); + + // Checksum + resultBuffer.putShort(calculateChecksum(header, payloadBytes)); + + // Payload + resultBuffer.put(payloadBytes); + } + + private short calculateChecksum(IpHeader header, byte[] payloadBytes) throws Exception { + int newChecksum = 0; + ShortBuffer srcBuffer = ByteBuffer.wrap(header.srcAddr.getAddress()).asShortBuffer(); + ShortBuffer dstBuffer = ByteBuffer.wrap(header.dstAddr.getAddress()).asShortBuffer(); + + while (srcBuffer.hasRemaining() || dstBuffer.hasRemaining()) { + short val = srcBuffer.hasRemaining() ? srcBuffer.get() : dstBuffer.get(); + + // Wrap as needed + newChecksum = addAndWrapForChecksum(newChecksum, val); + } + + // Add pseudo-header values. Proto is 0-padded, so just use the byte. + newChecksum = addAndWrapForChecksum(newChecksum, header.proto); + newChecksum = addAndWrapForChecksum(newChecksum, length()); + newChecksum = addAndWrapForChecksum(newChecksum, srcPort); + newChecksum = addAndWrapForChecksum(newChecksum, dstPort); + newChecksum = addAndWrapForChecksum(newChecksum, length()); + + ShortBuffer payloadShortBuffer = ByteBuffer.wrap(payloadBytes).asShortBuffer(); + while (payloadShortBuffer.hasRemaining()) { + newChecksum = addAndWrapForChecksum(newChecksum, payloadShortBuffer.get()); + } + if (payload.length() % 2 != 0) { + newChecksum = + addAndWrapForChecksum( + newChecksum, (payloadBytes[payloadBytes.length - 1] << 8)); + } + + return onesComplement(newChecksum); + } + } + + public static class EspHeader implements Payload { + public final int nextHeader; + public final int spi; + public final int seqNum; + public final byte[] key; + public final byte[] payload; + + /** + * Generic constructor for ESP headers. + * + *

For Tunnel mode, payload will be a full IP header + attached payloads + * + *

For Transport mode, payload will be only the attached payloads, but with the checksum + * calculated using the pre-encryption IP header + */ + public EspHeader(int nextHeader, int spi, int seqNum, byte[] key, byte[] payload) { + this.nextHeader = nextHeader; + this.spi = spi; + this.seqNum = seqNum; + this.key = key; + this.payload = payload; + } + + public int getProtocolId() { + return IPPROTO_ESP; + } + + public short length() { + // ALWAYS uses AES-CBC, HMAC-SHA256 (128b trunc len) + return (short) + calculateEspPacketSize(payload.length, AES_CBC_IV_LEN, AES_CBC_BLK_SIZE, 128); + } + + public byte[] getPacketBytes(IpHeader header) throws Exception { + ByteBuffer bb = ByteBuffer.allocate(DATA_BUFFER_LEN); + + addPacketBytes(header, bb); + return getByteArrayFromBuffer(bb); + } + + public void addPacketBytes(IpHeader header, ByteBuffer resultBuffer) throws Exception { + ByteBuffer espPayloadBuffer = ByteBuffer.allocate(DATA_BUFFER_LEN); + espPayloadBuffer.putInt(spi); + espPayloadBuffer.putInt(seqNum); + espPayloadBuffer.put(getCiphertext(key)); + + espPayloadBuffer.put(getIcv(getByteArrayFromBuffer(espPayloadBuffer)), 0, 16); + resultBuffer.put(getByteArrayFromBuffer(espPayloadBuffer)); + } + + private byte[] getIcv(byte[] authenticatedSection) throws GeneralSecurityException { + Mac sha256HMAC = Mac.getInstance(HMAC_SHA_256); + SecretKeySpec authKey = new SecretKeySpec(key, HMAC_SHA_256); + sha256HMAC.init(authKey); + + return sha256HMAC.doFinal(authenticatedSection); + } + + /** + * Encrypts and builds ciphertext block. Includes the IV, Padding and Next-Header blocks + * + *

The ciphertext does NOT include the SPI/Sequence numbers, or the ICV. + */ + private byte[] getCiphertext(byte[] key) throws GeneralSecurityException { + int paddedLen = calculateEspEncryptedLength(payload.length, AES_CBC_BLK_SIZE); + ByteBuffer paddedPayload = ByteBuffer.allocate(paddedLen); + paddedPayload.put(payload); + + // Add padding - consecutive integers from 0x01 + int pad = 1; + while (paddedPayload.position() < paddedPayload.limit()) { + paddedPayload.put((byte) pad++); + } + + paddedPayload.position(paddedPayload.limit() - 2); + paddedPayload.put((byte) (paddedLen - 2 - payload.length)); // Pad length + paddedPayload.put((byte) nextHeader); + + // Generate Initialization Vector + byte[] iv = new byte[AES_CBC_IV_LEN]; + new SecureRandom().nextBytes(iv); + IvParameterSpec ivParameterSpec = new IvParameterSpec(iv); + SecretKeySpec secretKeySpec = new SecretKeySpec(key, AES); + + // Encrypt payload + Cipher cipher = Cipher.getInstance(AES_CBC); + cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec, ivParameterSpec); + byte[] encrypted = cipher.doFinal(getByteArrayFromBuffer(paddedPayload)); + + // Build ciphertext + ByteBuffer cipherText = ByteBuffer.allocate(AES_CBC_IV_LEN + encrypted.length); + cipherText.put(iv); + cipherText.put(encrypted); + + return getByteArrayFromBuffer(cipherText); + } + } + + private static int addAndWrapForChecksum(int currentChecksum, int value) { + currentChecksum += value & 0x0000ffff; + + // Wrap anything beyond the first 16 bits, and add to lower order bits + return (currentChecksum >>> 16) + (currentChecksum & 0x0000ffff); + } + + private static short onesComplement(int val) { + val = (val >>> 16) + (val & 0xffff); + + if (val == 0) return 0; + return (short) ((~val) & 0xffff); + } + + public static int calculateEspPacketSize( + int payloadLen, int cryptIvLength, int cryptBlockSize, int authTruncLen) { + final int ESP_HDRLEN = 4 + 4; // SPI + Seq# + final int ICV_LEN = authTruncLen / 8; // Auth trailer; based on truncation length + payloadLen += cryptIvLength; // Initialization Vector + + // Align to block size of encryption algorithm + payloadLen = calculateEspEncryptedLength(payloadLen, cryptBlockSize); + return payloadLen + ESP_HDRLEN + ICV_LEN; + } + + private static int calculateEspEncryptedLength(int payloadLen, int cryptBlockSize) { + payloadLen += 2; // ESP trailer + + // Align to block size of encryption algorithm + return payloadLen + calculateEspPadLen(payloadLen, cryptBlockSize); + } + + private static int calculateEspPadLen(int payloadLen, int cryptBlockSize) { + return (cryptBlockSize - (payloadLen % cryptBlockSize)) % cryptBlockSize; + } + + private static byte[] getByteArrayFromBuffer(ByteBuffer buffer) { + return Arrays.copyOfRange(buffer.array(), 0, buffer.position()); + } + + /* + * Debug printing + */ + private static final char[] hexArray = "0123456789ABCDEF".toCharArray(); + + public static String bytesToHex(byte[] bytes) { + StringBuilder sb = new StringBuilder(); + for (byte b : bytes) { + sb.append(hexArray[b >>> 4]); + sb.append(hexArray[b & 0x0F]); + sb.append(' '); + } + return sb.toString(); + } +} diff --git a/tests/cts/net/src/android/net/cts/TunUtils.java b/tests/cts/net/src/android/net/cts/TunUtils.java index ca233ce1e8..4d5533fc62 100644 --- a/tests/cts/net/src/android/net/cts/TunUtils.java +++ b/tests/cts/net/src/android/net/cts/TunUtils.java @@ -16,6 +16,10 @@ package android.net.cts; +import static android.net.cts.PacketUtils.IP4_HDRLEN; +import static android.net.cts.PacketUtils.IP6_HDRLEN; +import static android.net.cts.PacketUtils.IPPROTO_ESP; +import static android.net.cts.PacketUtils.UDP_HDRLEN; import static android.system.OsConstants.IPPROTO_UDP; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; @@ -46,9 +50,6 @@ public class TunUtils { private static final int IP6_ADDR_OFFSET = 8; private static final int IP6_ADDR_LEN = 16; - // Not defined in OsConstants - private static final int IPPROTO_ESP = 50; - private final ParcelFileDescriptor mTunFd; private final List mPackets = new ArrayList<>(); private final Thread mReaderThread; @@ -178,17 +179,14 @@ public class TunUtils { private static boolean isEsp(byte[] pkt, int spi, boolean encap) { if (isIpv6(pkt)) { // IPv6 UDP encap not supported by kernels; assume non-encap. - return pkt[IP6_PROTO_OFFSET] == IPPROTO_ESP - && isSpiEqual(pkt, IpSecBaseTest.IP6_HDRLEN, spi); + return pkt[IP6_PROTO_OFFSET] == IPPROTO_ESP && isSpiEqual(pkt, IP6_HDRLEN, spi); } else { // Use default IPv4 header length (assuming no options) if (encap) { return pkt[IP4_PROTO_OFFSET] == IPPROTO_UDP - && isSpiEqual( - pkt, IpSecBaseTest.IP4_HDRLEN + IpSecBaseTest.UDP_HDRLEN, spi); + && isSpiEqual(pkt, IP4_HDRLEN + UDP_HDRLEN, spi); } else { - return pkt[IP4_PROTO_OFFSET] == IPPROTO_ESP - && isSpiEqual(pkt, IpSecBaseTest.IP4_HDRLEN, spi); + return pkt[IP4_PROTO_OFFSET] == IPPROTO_ESP && isSpiEqual(pkt, IP4_HDRLEN, spi); } } } From 817d192bc4399ab5f457eaf8c604977e9017ec25 Mon Sep 17 00:00:00 2001 From: Benedict Wong Date: Mon, 8 Apr 2019 10:15:26 -0700 Subject: [PATCH 48/71] Add IPsec Tunnel mode data tests This change adds single-direction tests for the IPsec Tunnel Mode API. In the outbound direction, TUNs are used to capture outgoing packets, and values are inspected. In the inbound direction, packets are built manually, using the PacketUtils framework. Additional testing for end-to-end integration tests will follow in aosp/941021 using packet reflection via the TUN. Bug: 72950854 Test: This; passing Change-Id: Ic4181fc857fa880db5553314efa914f870dbe87c Merged-In: Ic4181fc857fa880db5553314efa914f870dbe87c (cherry picked from commit d708a4c217f13c9028427d98031394f0933482bf) --- .../src/android/net/cts/IpSecBaseTest.java | 43 +- .../net/cts/IpSecManagerTunnelTest.java | 694 ++++++++++++++++-- .../cts/net/src/android/net/cts/TunUtils.java | 7 + 3 files changed, 661 insertions(+), 83 deletions(-) diff --git a/tests/cts/net/src/android/net/cts/IpSecBaseTest.java b/tests/cts/net/src/android/net/cts/IpSecBaseTest.java index 35d0f485e0..087dbdaec3 100644 --- a/tests/cts/net/src/android/net/cts/IpSecBaseTest.java +++ b/tests/cts/net/src/android/net/cts/IpSecBaseTest.java @@ -28,11 +28,12 @@ import android.system.OsConstants; import android.test.AndroidTestCase; import android.util.Log; +import androidx.test.InstrumentationRegistry; + import java.io.FileDescriptor; import java.io.IOException; import java.net.DatagramPacket; import java.net.DatagramSocket; -import java.net.Inet4Address; import java.net.Inet6Address; import java.net.InetAddress; import java.net.InetSocketAddress; @@ -72,8 +73,14 @@ public class IpSecBaseTest extends AndroidTestCase { protected void setUp() throws Exception { super.setUp(); - mISM = (IpSecManager) getContext().getSystemService(Context.IPSEC_SERVICE); - mCM = (ConnectivityManager) getContext().getSystemService(Context.CONNECTIVITY_SERVICE); + mISM = + (IpSecManager) + InstrumentationRegistry.getContext() + .getSystemService(Context.IPSEC_SERVICE); + mCM = + (ConnectivityManager) + InstrumentationRegistry.getContext() + .getSystemService(Context.CONNECTIVITY_SERVICE); } protected static byte[] getKey(int bitLength) { @@ -195,6 +202,17 @@ public class IpSecBaseTest extends AndroidTestCase { public static class JavaUdpSocket implements GenericUdpSocket { public final DatagramSocket mSocket; + public JavaUdpSocket(InetAddress localAddr, int port) { + try { + mSocket = new DatagramSocket(port, localAddr); + mSocket.setSoTimeout(SOCK_TIMEOUT); + } catch (SocketException e) { + // Fail loudly if we can't set up sockets properly. And without the timeout, we + // could easily end up in an endless wait. + throw new RuntimeException(e); + } + } + public JavaUdpSocket(InetAddress localAddr) { try { mSocket = new DatagramSocket(0, localAddr); @@ -425,26 +443,25 @@ public class IpSecBaseTest extends AndroidTestCase { } protected static IpSecTransform buildIpSecTransform( - Context mContext, + Context context, IpSecManager.SecurityParameterIndex spi, IpSecManager.UdpEncapsulationSocket encapSocket, InetAddress remoteAddr) throws Exception { - String localAddr = (remoteAddr instanceof Inet4Address) ? IPV4_LOOPBACK : IPV6_LOOPBACK; IpSecTransform.Builder builder = - new IpSecTransform.Builder(mContext) - .setEncryption(new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY)) - .setAuthentication( - new IpSecAlgorithm( - IpSecAlgorithm.AUTH_HMAC_SHA256, - AUTH_KEY, - AUTH_KEY.length * 4)); + new IpSecTransform.Builder(context) + .setEncryption(new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY)) + .setAuthentication( + new IpSecAlgorithm( + IpSecAlgorithm.AUTH_HMAC_SHA256, + AUTH_KEY, + AUTH_KEY.length * 4)); if (encapSocket != null) { builder.setIpv4Encapsulation(encapSocket, encapSocket.getPort()); } - return builder.buildTransportModeTransform(InetAddress.getByName(localAddr), spi); + return builder.buildTransportModeTransform(remoteAddr, spi); } private IpSecTransform buildDefaultTransform(InetAddress localAddr) throws Exception { diff --git a/tests/cts/net/src/android/net/cts/IpSecManagerTunnelTest.java b/tests/cts/net/src/android/net/cts/IpSecManagerTunnelTest.java index c8c99f4a37..e8c0a7a4b2 100644 --- a/tests/cts/net/src/android/net/cts/IpSecManagerTunnelTest.java +++ b/tests/cts/net/src/android/net/cts/IpSecManagerTunnelTest.java @@ -16,174 +16,728 @@ package android.net.cts; +import static android.app.AppOpsManager.OP_MANAGE_IPSEC_TUNNELS; +import static android.net.IpSecManager.UdpEncapsulationSocket; +import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VPN; +import static android.net.NetworkCapabilities.NET_CAPABILITY_TRUSTED; +import static android.net.NetworkCapabilities.TRANSPORT_TEST; +import static android.net.cts.PacketUtils.AES_CBC_BLK_SIZE; +import static android.net.cts.PacketUtils.AES_CBC_IV_LEN; +import static android.net.cts.PacketUtils.BytePayload; +import static android.net.cts.PacketUtils.EspHeader; +import static android.net.cts.PacketUtils.IP4_HDRLEN; +import static android.net.cts.PacketUtils.IP6_HDRLEN; +import static android.net.cts.PacketUtils.Ip4Header; +import static android.net.cts.PacketUtils.Ip6Header; +import static android.net.cts.PacketUtils.IpHeader; +import static android.net.cts.PacketUtils.UDP_HDRLEN; +import static android.net.cts.PacketUtils.UdpHeader; +import static android.system.OsConstants.AF_INET; +import static android.system.OsConstants.AF_INET6; + +import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; +import android.app.AppOpsManager; +import android.content.Context; import android.content.pm.PackageManager; +import android.net.ConnectivityManager; import android.net.IpSecAlgorithm; import android.net.IpSecManager; import android.net.IpSecTransform; +import android.net.LinkAddress; import android.net.Network; +import android.net.NetworkRequest; +import android.net.TestNetworkInterface; +import android.net.TestNetworkManager; +import android.net.cts.PacketUtils.Payload; +import android.os.Binder; +import android.os.IBinder; +import android.os.ParcelFileDescriptor; + +import androidx.test.InstrumentationRegistry; +import androidx.test.runner.AndroidJUnit4; import com.android.compatibility.common.util.SystemUtil; +import java.net.Inet4Address; import java.net.Inet6Address; import java.net.InetAddress; import java.net.InterfaceAddress; import java.net.NetworkInterface; +import java.util.List; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.TimeUnit; +import org.junit.AfterClass; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; +import org.junit.runner.RunWith; + +@RunWith(AndroidJUnit4.class) public class IpSecManagerTunnelTest extends IpSecBaseTest { - private static final String TAG = IpSecManagerTunnelTest.class.getSimpleName(); - private static final int IP4_PREFIX_LEN = 24; - private static final int IP6_PREFIX_LEN = 48; - private static final InetAddress OUTER_ADDR4 = InetAddress.parseNumericAddress("192.0.2.0"); - private static final InetAddress OUTER_ADDR6 = - InetAddress.parseNumericAddress("2001:db8:f00d::1"); - private static final InetAddress INNER_ADDR4 = InetAddress.parseNumericAddress("10.0.0.1"); - private static final InetAddress INNER_ADDR6 = - InetAddress.parseNumericAddress("2001:db8:d00d::1"); - private Network mUnderlyingNetwork; - private Network mIpSecNetwork; + private static final InetAddress LOCAL_OUTER_4 = InetAddress.parseNumericAddress("192.0.2.1"); + private static final InetAddress REMOTE_OUTER_4 = InetAddress.parseNumericAddress("192.0.2.2"); + private static final InetAddress LOCAL_OUTER_6 = + InetAddress.parseNumericAddress("2001:db8:1::1"); + private static final InetAddress REMOTE_OUTER_6 = + InetAddress.parseNumericAddress("2001:db8:1::2"); - protected void setUp() throws Exception { + private static final InetAddress LOCAL_INNER_4 = + InetAddress.parseNumericAddress("198.51.100.1"); + private static final InetAddress REMOTE_INNER_4 = + InetAddress.parseNumericAddress("198.51.100.2"); + private static final InetAddress LOCAL_INNER_6 = + InetAddress.parseNumericAddress("2001:db8:2::1"); + private static final InetAddress REMOTE_INNER_6 = + InetAddress.parseNumericAddress("2001:db8:2::2"); + + private static final int IP4_PREFIX_LEN = 32; + private static final int IP6_PREFIX_LEN = 128; + + private static final int TIMEOUT_MS = 500; + + // Static state to reduce setup/teardown + private static ConnectivityManager sCM; + private static TestNetworkManager sTNM; + private static ParcelFileDescriptor sTunFd; + private static TestNetworkCallback sTunNetworkCallback; + private static Network sTunNetwork; + private static TunUtils sTunUtils; + + private static Context sContext = InstrumentationRegistry.getContext(); + private static IBinder sBinder = new Binder(); + + @BeforeClass + public static void setUpBeforeClass() throws Exception { + InstrumentationRegistry.getInstrumentation() + .getUiAutomation() + .adoptShellPermissionIdentity(); + sCM = (ConnectivityManager) sContext.getSystemService(Context.CONNECTIVITY_SERVICE); + sTNM = (TestNetworkManager) sContext.getSystemService(Context.TEST_NETWORK_SERVICE); + + // Under normal circumstances, the MANAGE_IPSEC_TUNNELS appop would be auto-granted, and + // a standard permission is insufficient. So we shell out the appop, to give us the + // right appop permissions. + setAppop(OP_MANAGE_IPSEC_TUNNELS, true); + + TestNetworkInterface testIntf = + sTNM.createTunInterface( + new LinkAddress[] { + new LinkAddress(LOCAL_OUTER_4, IP4_PREFIX_LEN), + new LinkAddress(LOCAL_OUTER_6, IP6_PREFIX_LEN) + }); + + sTunFd = testIntf.getFileDescriptor(); + sTunNetworkCallback = setupAndGetTestNetwork(testIntf.getInterfaceName()); + sTunNetwork = sTunNetworkCallback.getNetworkBlocking(); + + sTunUtils = new TunUtils(sTunFd); + } + + @Before + public void setUp() throws Exception { super.setUp(); + + // Set to true before every run; some tests flip this. + setAppop(OP_MANAGE_IPSEC_TUNNELS, true); + + // Clear sTunUtils state + sTunUtils.reset(); } - protected void tearDown() { - setAppop(false); + @AfterClass + public static void tearDownAfterClass() throws Exception { + setAppop(OP_MANAGE_IPSEC_TUNNELS, false); + + sCM.unregisterNetworkCallback(sTunNetworkCallback); + + sTNM.teardownTestNetwork(sTunNetwork); + sTunFd.close(); + + InstrumentationRegistry.getInstrumentation() + .getUiAutomation() + .dropShellPermissionIdentity(); } - private boolean hasTunnelsFeature() { - return getContext() - .getPackageManager() - .hasSystemFeature(PackageManager.FEATURE_IPSEC_TUNNELS); + private static boolean hasTunnelsFeature() { + return sContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_IPSEC_TUNNELS); } - private void setAppop(boolean allow) { - // Under normal circumstances, the MANAGE_IPSEC_TUNNELS appop would be auto-granted by the - // telephony framework, and the only permission that is sufficient is NETWORK_STACK. So we - // shell out the appop manager, to give us the right appop permissions. - String cmd = - "appops set " - + mContext.getPackageName() - + " MANAGE_IPSEC_TUNNELS " - + (allow ? "allow" : "deny"); - SystemUtil.runShellCommand(cmd); + private static void setAppop(int appop, boolean allow) { + String opName = AppOpsManager.opToName(appop); + for (String pkg : new String[] {"com.android.shell", sContext.getPackageName()}) { + String cmd = + String.format( + "appops set %s %s %s", + pkg, // Package name + opName, // Appop + (allow ? "allow" : "deny")); // Action + SystemUtil.runShellCommand(cmd); + } } - public void testSecurityExceptionsCreateTunnelInterface() throws Exception { + private static TestNetworkCallback setupAndGetTestNetwork(String ifname) throws Exception { + // Build a network request + NetworkRequest nr = + new NetworkRequest.Builder() + .addTransportType(TRANSPORT_TEST) + .removeCapability(NET_CAPABILITY_TRUSTED) + .removeCapability(NET_CAPABILITY_NOT_VPN) + .setNetworkSpecifier(ifname) + .build(); + + TestNetworkCallback cb = new TestNetworkCallback(); + sCM.requestNetwork(nr, cb); + + // Setup the test network after network request is filed to prevent Network from being + // reaped due to no requests matching it. + sTNM.setupTestNetwork(ifname, sBinder); + + return cb; + } + + @Test + public void testSecurityExceptionCreateTunnelInterfaceWithoutAppop() throws Exception { if (!hasTunnelsFeature()) return; // Ensure we don't have the appop. Permission is not requested in the Manifest - setAppop(false); + setAppop(OP_MANAGE_IPSEC_TUNNELS, false); // Security exceptions are thrown regardless of IPv4/IPv6. Just test one try { - mISM.createIpSecTunnelInterface(OUTER_ADDR6, OUTER_ADDR6, mUnderlyingNetwork); + mISM.createIpSecTunnelInterface(LOCAL_INNER_6, REMOTE_INNER_6, sTunNetwork); fail("Did not throw SecurityException for Tunnel creation without appop"); } catch (SecurityException expected) { } } - public void testSecurityExceptionsBuildTunnelTransform() throws Exception { + @Test + public void testSecurityExceptionBuildTunnelTransformWithoutAppop() throws Exception { if (!hasTunnelsFeature()) return; // Ensure we don't have the appop. Permission is not requested in the Manifest - setAppop(false); + setAppop(OP_MANAGE_IPSEC_TUNNELS, false); // Security exceptions are thrown regardless of IPv4/IPv6. Just test one try (IpSecManager.SecurityParameterIndex spi = - mISM.allocateSecurityParameterIndex(OUTER_ADDR4); + mISM.allocateSecurityParameterIndex(LOCAL_INNER_4); IpSecTransform transform = - new IpSecTransform.Builder(mContext) - .buildTunnelModeTransform(OUTER_ADDR4, spi)) { + new IpSecTransform.Builder(sContext) + .buildTunnelModeTransform(REMOTE_INNER_4, spi)) { fail("Did not throw SecurityException for Transform creation without appop"); } catch (SecurityException expected) { } } - private void checkTunnel(InetAddress inner, InetAddress outer, boolean useEncap) + /* Test runnables for callbacks after IPsec tunnels are set up. */ + private interface TestRunnable { + void run(Network ipsecNetwork) throws Exception; + } + + private static class TestNetworkCallback extends ConnectivityManager.NetworkCallback { + private final CompletableFuture futureNetwork = new CompletableFuture<>(); + + @Override + public void onAvailable(Network network) { + futureNetwork.complete(network); + } + + public Network getNetworkBlocking() throws Exception { + return futureNetwork.get(TIMEOUT_MS, TimeUnit.MILLISECONDS); + } + } + + private int getPacketSize( + int innerFamily, int outerFamily, boolean useEncap, boolean transportInTunnelMode) { + int expectedPacketSize = TEST_DATA.length + UDP_HDRLEN; + + // Inner Transport mode packet size + if (transportInTunnelMode) { + expectedPacketSize = + PacketUtils.calculateEspPacketSize( + expectedPacketSize, + AES_CBC_IV_LEN, + AES_CBC_BLK_SIZE, + AUTH_KEY.length * 4); + } + + // Inner IP Header + expectedPacketSize += innerFamily == AF_INET ? IP4_HDRLEN : IP6_HDRLEN; + + // Tunnel mode transform size + expectedPacketSize = + PacketUtils.calculateEspPacketSize( + expectedPacketSize, AES_CBC_IV_LEN, AES_CBC_BLK_SIZE, AUTH_KEY.length * 4); + + // UDP encap size + expectedPacketSize += useEncap ? UDP_HDRLEN : 0; + + // Outer IP Header + expectedPacketSize += outerFamily == AF_INET ? IP4_HDRLEN : IP6_HDRLEN; + + return expectedPacketSize; + } + + private interface TestRunnableFactory { + TestRunnable getTestRunnable( + boolean transportInTunnelMode, + int spi, + InetAddress localInner, + InetAddress remoteInner, + InetAddress localOuter, + InetAddress remoteOuter, + IpSecTransform inTransportTransform, + IpSecTransform outTransportTransform, + int encapPort, + int expectedPacketSize) + throws Exception; + } + + private class OutputTestRunnableFactory implements TestRunnableFactory { + public TestRunnable getTestRunnable( + boolean transportInTunnelMode, + int spi, + InetAddress localInner, + InetAddress remoteInner, + InetAddress localOuter, + InetAddress remoteOuter, + IpSecTransform inTransportTransform, + IpSecTransform outTransportTransform, + int encapPort, + int expectedPacketSize) { + return new TestRunnable() { + @Override + public void run(Network ipsecNetwork) throws Exception { + // Build a socket and send traffic + JavaUdpSocket socket = new JavaUdpSocket(localInner); + ipsecNetwork.bindSocket(socket.mSocket); + + // For Transport-In-Tunnel mode, apply transform to socket + if (transportInTunnelMode) { + mISM.applyTransportModeTransform( + socket.mSocket, IpSecManager.DIRECTION_IN, inTransportTransform); + mISM.applyTransportModeTransform( + socket.mSocket, IpSecManager.DIRECTION_OUT, outTransportTransform); + } + + socket.sendTo(TEST_DATA, remoteInner, socket.getPort()); + + // Verify that an encrypted packet is sent. As of right now, checking encrypted + // body is not possible, due to our not knowing some of the fields of the + // inner IP header (flow label, flags, etc) + sTunUtils.awaitEspPacketNoPlaintext( + spi, TEST_DATA, encapPort != 0, expectedPacketSize); + + socket.close(); + } + }; + } + } + + private class InputPacketGeneratorTestRunnableFactory implements TestRunnableFactory { + public TestRunnable getTestRunnable( + boolean transportInTunnelMode, + int spi, + InetAddress localInner, + InetAddress remoteInner, + InetAddress localOuter, + InetAddress remoteOuter, + IpSecTransform inTransportTransform, + IpSecTransform outTransportTransform, + int encapPort, + int expectedPacketSize) + throws Exception { + return new TestRunnable() { + @Override + public void run(Network ipsecNetwork) throws Exception { + // Build a socket and receive traffic + JavaUdpSocket socket = new JavaUdpSocket(localInner); + // JavaUdpSocket socket = new JavaUdpSocket(localInner, socketPort.get()); + ipsecNetwork.bindSocket(socket.mSocket); + + // For Transport-In-Tunnel mode, apply transform to socket + if (transportInTunnelMode) { + mISM.applyTransportModeTransform( + socket.mSocket, IpSecManager.DIRECTION_IN, outTransportTransform); + mISM.applyTransportModeTransform( + socket.mSocket, IpSecManager.DIRECTION_OUT, inTransportTransform); + } + + byte[] pkt; + if (transportInTunnelMode) { + pkt = + getTransportInTunnelModePacket( + spi, + spi, + remoteInner, + localInner, + remoteOuter, + localOuter, + socket.getPort(), + encapPort); + } else { + pkt = + getTunnelModePacket( + spi, + remoteInner, + localInner, + remoteOuter, + localOuter, + socket.getPort(), + encapPort); + } + sTunUtils.injectPacket(pkt); + + // Receive packet from socket, and validate + receiveAndValidatePacket(socket); + + socket.close(); + } + }; + } + } + + private void checkTunnelOutput( + int innerFamily, int outerFamily, boolean useEncap, boolean transportInTunnelMode) + throws Exception { + checkTunnel( + innerFamily, + outerFamily, + useEncap, + transportInTunnelMode, + new OutputTestRunnableFactory()); + } + + private void checkTunnelInput( + int innerFamily, int outerFamily, boolean useEncap, boolean transportInTunnelMode) + throws Exception { + checkTunnel( + innerFamily, + outerFamily, + useEncap, + transportInTunnelMode, + new InputPacketGeneratorTestRunnableFactory()); + } + + public void checkTunnel( + int innerFamily, + int outerFamily, + boolean useEncap, + boolean transportInTunnelMode, + TestRunnableFactory factory) throws Exception { if (!hasTunnelsFeature()) return; - setAppop(true); - int innerPrefixLen = inner instanceof Inet6Address ? IP6_PREFIX_LEN : IP4_PREFIX_LEN; + InetAddress localInner = innerFamily == AF_INET ? LOCAL_INNER_4 : LOCAL_INNER_6; + InetAddress remoteInner = innerFamily == AF_INET ? REMOTE_INNER_4 : REMOTE_INNER_6; - try (IpSecManager.SecurityParameterIndex spi = mISM.allocateSecurityParameterIndex(outer); + InetAddress localOuter = outerFamily == AF_INET ? LOCAL_OUTER_4 : LOCAL_OUTER_6; + InetAddress remoteOuter = outerFamily == AF_INET ? REMOTE_OUTER_4 : REMOTE_OUTER_6; + + // Preselect both SPI and encap port, to be used for both inbound and outbound tunnels. + // Re-uses the same SPI to ensure that even in cases of symmetric SPIs shared across tunnel + // and transport mode, packets are encrypted/decrypted properly based on the src/dst. + int spi = getRandomSpi(localOuter, remoteOuter); + int expectedPacketSize = + getPacketSize(innerFamily, outerFamily, useEncap, transportInTunnelMode); + + try (IpSecManager.SecurityParameterIndex inTransportSpi = + mISM.allocateSecurityParameterIndex(localInner, spi); + IpSecManager.SecurityParameterIndex outTransportSpi = + mISM.allocateSecurityParameterIndex(remoteInner, spi); + IpSecTransform inTransportTransform = + buildIpSecTransform(sContext, inTransportSpi, null, remoteInner); + IpSecTransform outTransportTransform = + buildIpSecTransform(sContext, outTransportSpi, null, localInner); + UdpEncapsulationSocket encapSocket = mISM.openUdpEncapsulationSocket()) { + + buildTunnelAndNetwork( + localInner, + remoteInner, + localOuter, + remoteOuter, + spi, + useEncap ? encapSocket : null, + factory.getTestRunnable( + transportInTunnelMode, + spi, + localInner, + remoteInner, + localOuter, + remoteOuter, + inTransportTransform, + outTransportTransform, + useEncap ? encapSocket.getPort() : 0, + expectedPacketSize)); + } + } + + private void buildTunnelAndNetwork( + InetAddress localInner, + InetAddress remoteInner, + InetAddress localOuter, + InetAddress remoteOuter, + int spi, + UdpEncapsulationSocket encapSocket, + TestRunnable test) + throws Exception { + int innerPrefixLen = localInner instanceof Inet6Address ? IP6_PREFIX_LEN : IP4_PREFIX_LEN; + TestNetworkCallback testNetworkCb = null; + + try (IpSecManager.SecurityParameterIndex inSpi = + mISM.allocateSecurityParameterIndex(localOuter, spi); + IpSecManager.SecurityParameterIndex outSpi = + mISM.allocateSecurityParameterIndex(remoteOuter, spi); IpSecManager.IpSecTunnelInterface tunnelIntf = - mISM.createIpSecTunnelInterface(outer, outer, mCM.getActiveNetwork()); - IpSecManager.UdpEncapsulationSocket encapSocket = - mISM.openUdpEncapsulationSocket()) { + mISM.createIpSecTunnelInterface(localOuter, remoteOuter, sTunNetwork)) { + // Build the test network + tunnelIntf.addAddress(localInner, innerPrefixLen); + testNetworkCb = setupAndGetTestNetwork(tunnelIntf.getInterfaceName()); + Network testNetwork = testNetworkCb.getNetworkBlocking(); - IpSecTransform.Builder transformBuilder = new IpSecTransform.Builder(mContext); + // Check interface was created + NetworkInterface netIntf = NetworkInterface.getByName(tunnelIntf.getInterfaceName()); + assertNotNull(netIntf); + + // Check addresses + List intfAddrs = netIntf.getInterfaceAddresses(); + assertEquals(1, intfAddrs.size()); + assertEquals(localInner, intfAddrs.get(0).getAddress()); + assertEquals(innerPrefixLen, intfAddrs.get(0).getNetworkPrefixLength()); + + // Configure Transform parameters + IpSecTransform.Builder transformBuilder = new IpSecTransform.Builder(sContext); transformBuilder.setEncryption( new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY)); transformBuilder.setAuthentication( new IpSecAlgorithm( IpSecAlgorithm.AUTH_HMAC_SHA256, AUTH_KEY, AUTH_KEY.length * 4)); - if (useEncap) { + if (encapSocket != null) { transformBuilder.setIpv4Encapsulation(encapSocket, encapSocket.getPort()); } - // Check transform application - try (IpSecTransform transform = transformBuilder.buildTunnelModeTransform(outer, spi)) { - mISM.applyTunnelModeTransform(tunnelIntf, IpSecManager.DIRECTION_IN, transform); - mISM.applyTunnelModeTransform(tunnelIntf, IpSecManager.DIRECTION_OUT, transform); + // Apply transform and check that traffic is properly encrypted + try (IpSecTransform inTransform = + transformBuilder.buildTunnelModeTransform(remoteOuter, inSpi); + IpSecTransform outTransform = + transformBuilder.buildTunnelModeTransform(localOuter, outSpi)) { + mISM.applyTunnelModeTransform(tunnelIntf, IpSecManager.DIRECTION_IN, inTransform); + mISM.applyTunnelModeTransform(tunnelIntf, IpSecManager.DIRECTION_OUT, outTransform); - // TODO: Test to ensure that send/receive works with these transforms. + test.run(testNetwork); } - // Check interface was created - NetworkInterface netIntf = NetworkInterface.getByName(tunnelIntf.getInterfaceName()); - assertNotNull(netIntf); - - // Add addresses and check - tunnelIntf.addAddress(inner, innerPrefixLen); - for (InterfaceAddress intfAddr : netIntf.getInterfaceAddresses()) { - assertEquals(intfAddr.getAddress(), inner); - assertEquals(intfAddr.getNetworkPrefixLength(), innerPrefixLen); - } + // Teardown the test network + sTNM.teardownTestNetwork(testNetwork); // Remove addresses and check - tunnelIntf.removeAddress(inner, innerPrefixLen); + tunnelIntf.removeAddress(localInner, innerPrefixLen); + netIntf = NetworkInterface.getByName(tunnelIntf.getInterfaceName()); assertTrue(netIntf.getInterfaceAddresses().isEmpty()); // Check interface was cleaned up tunnelIntf.close(); netIntf = NetworkInterface.getByName(tunnelIntf.getInterfaceName()); assertNull(netIntf); + } finally { + if (testNetworkCb != null) { + sCM.unregisterNetworkCallback(testNetworkCb); + } } } - /* - * Create, add and remove addresses, then teardown tunnel - */ + private static void receiveAndValidatePacket(JavaUdpSocket socket) throws Exception { + byte[] socketResponseBytes = socket.receive(); + assertArrayEquals(TEST_DATA, socketResponseBytes); + } + + private int getRandomSpi(InetAddress localOuter, InetAddress remoteOuter) throws Exception { + // Try to allocate both in and out SPIs using the same requested SPI value. + try (IpSecManager.SecurityParameterIndex inSpi = + mISM.allocateSecurityParameterIndex(localOuter); + IpSecManager.SecurityParameterIndex outSpi = + mISM.allocateSecurityParameterIndex(remoteOuter, inSpi.getSpi()); ) { + return inSpi.getSpi(); + } + } + + private IpHeader getIpHeader(int protocol, InetAddress src, InetAddress dst, Payload payload) { + if ((src instanceof Inet6Address) != (dst instanceof Inet6Address)) { + throw new IllegalArgumentException("Invalid src/dst address combination"); + } + + if (src instanceof Inet6Address) { + return new Ip6Header(protocol, (Inet6Address) src, (Inet6Address) dst, payload); + } else { + return new Ip4Header(protocol, (Inet4Address) src, (Inet4Address) dst, payload); + } + } + + private EspHeader buildTransportModeEspPacket( + int spi, InetAddress src, InetAddress dst, int port, Payload payload) throws Exception { + IpHeader preEspIpHeader = getIpHeader(payload.getProtocolId(), src, dst, payload); + + return new EspHeader( + payload.getProtocolId(), + spi, + 1, // sequence number + CRYPT_KEY, // Same key for auth and crypt + payload.getPacketBytes(preEspIpHeader)); + } + + private EspHeader buildTunnelModeEspPacket( + int spi, + InetAddress srcInner, + InetAddress dstInner, + InetAddress srcOuter, + InetAddress dstOuter, + int port, + int encapPort, + Payload payload) + throws Exception { + IpHeader innerIp = getIpHeader(payload.getProtocolId(), srcInner, dstInner, payload); + return new EspHeader( + innerIp.getProtocolId(), + spi, + 1, // sequence number + CRYPT_KEY, // Same key for auth and crypt + innerIp.getPacketBytes()); + } + + private IpHeader maybeEncapPacket( + InetAddress src, InetAddress dst, int encapPort, EspHeader espPayload) + throws Exception { + + Payload payload = espPayload; + if (encapPort != 0) { + payload = new UdpHeader(encapPort, encapPort, espPayload); + } + + return getIpHeader(payload.getProtocolId(), src, dst, payload); + } + + private byte[] getTunnelModePacket( + int spi, + InetAddress srcInner, + InetAddress dstInner, + InetAddress srcOuter, + InetAddress dstOuter, + int port, + int encapPort) + throws Exception { + UdpHeader udp = new UdpHeader(port, port, new BytePayload(TEST_DATA)); + + EspHeader espPayload = + buildTunnelModeEspPacket( + spi, srcInner, dstInner, srcOuter, dstOuter, port, encapPort, udp); + return maybeEncapPacket(srcOuter, dstOuter, encapPort, espPayload).getPacketBytes(); + } + + private byte[] getTransportInTunnelModePacket( + int spiInner, + int spiOuter, + InetAddress srcInner, + InetAddress dstInner, + InetAddress srcOuter, + InetAddress dstOuter, + int port, + int encapPort) + throws Exception { + UdpHeader udp = new UdpHeader(port, port, new BytePayload(TEST_DATA)); + + EspHeader espPayload = buildTransportModeEspPacket(spiInner, srcInner, dstInner, port, udp); + espPayload = + buildTunnelModeEspPacket( + spiOuter, + srcInner, + dstInner, + srcOuter, + dstOuter, + port, + encapPort, + espPayload); + return maybeEncapPacket(srcOuter, dstOuter, encapPort, espPayload).getPacketBytes(); + } + + // Transport-in-Tunnel mode tests + @Test + public void testTransportInTunnelModeV4InV4() throws Exception { + checkTunnelOutput(AF_INET, AF_INET, false, true); + checkTunnelInput(AF_INET, AF_INET, false, true); + } + + @Test + public void testTransportInTunnelModeV4InV4UdpEncap() throws Exception { + checkTunnelOutput(AF_INET, AF_INET, true, true); + checkTunnelInput(AF_INET, AF_INET, true, true); + } + + @Test + public void testTransportInTunnelModeV4InV6() throws Exception { + checkTunnelOutput(AF_INET, AF_INET6, false, true); + checkTunnelInput(AF_INET, AF_INET6, false, true); + } + + @Test + public void testTransportInTunnelModeV6InV4() throws Exception { + checkTunnelOutput(AF_INET6, AF_INET, false, true); + checkTunnelInput(AF_INET6, AF_INET, false, true); + } + + @Test + public void testTransportInTunnelModeV6InV4UdpEncap() throws Exception { + checkTunnelOutput(AF_INET6, AF_INET, true, true); + checkTunnelInput(AF_INET6, AF_INET, true, true); + } + + @Test + public void testTransportInTunnelModeV6InV6() throws Exception { + checkTunnelOutput(AF_INET, AF_INET6, false, true); + checkTunnelInput(AF_INET, AF_INET6, false, true); + } + + // Tunnel mode tests + @Test public void testTunnelV4InV4() throws Exception { - checkTunnel(INNER_ADDR4, OUTER_ADDR4, false); + checkTunnelOutput(AF_INET, AF_INET, false, false); + checkTunnelInput(AF_INET, AF_INET, false, false); } + @Test public void testTunnelV4InV4UdpEncap() throws Exception { - checkTunnel(INNER_ADDR4, OUTER_ADDR4, true); + checkTunnelOutput(AF_INET, AF_INET, true, false); + checkTunnelInput(AF_INET, AF_INET, true, false); } + @Test public void testTunnelV4InV6() throws Exception { - checkTunnel(INNER_ADDR4, OUTER_ADDR6, false); + checkTunnelOutput(AF_INET, AF_INET6, false, false); + checkTunnelInput(AF_INET, AF_INET6, false, false); } + @Test public void testTunnelV6InV4() throws Exception { - checkTunnel(INNER_ADDR6, OUTER_ADDR4, false); + checkTunnelOutput(AF_INET6, AF_INET, false, false); + checkTunnelInput(AF_INET6, AF_INET, false, false); } + @Test public void testTunnelV6InV4UdpEncap() throws Exception { - checkTunnel(INNER_ADDR6, OUTER_ADDR4, true); + checkTunnelOutput(AF_INET6, AF_INET, true, false); + checkTunnelInput(AF_INET6, AF_INET, true, false); } + @Test public void testTunnelV6InV6() throws Exception { - checkTunnel(INNER_ADDR6, OUTER_ADDR6, false); + checkTunnelOutput(AF_INET6, AF_INET6, false, false); + checkTunnelInput(AF_INET6, AF_INET6, false, false); } } diff --git a/tests/cts/net/src/android/net/cts/TunUtils.java b/tests/cts/net/src/android/net/cts/TunUtils.java index 4d5533fc62..a0307137a5 100644 --- a/tests/cts/net/src/android/net/cts/TunUtils.java +++ b/tests/cts/net/src/android/net/cts/TunUtils.java @@ -247,4 +247,11 @@ public class TunUtils { out.write(pkt); out.flush(); } + + /** Resets the intercepted packets. */ + public void reset() throws IOException { + synchronized (mPackets) { + mPackets.clear(); + } + } } From fbbb9c9c04c7323ba25142501885e24a705f8931 Mon Sep 17 00:00:00 2001 From: Benedict Wong Date: Fri, 10 May 2019 11:05:43 -0700 Subject: [PATCH 49/71] Enforce IPsec Tunnel mode for Android Q This commit adds a second condition to whether the device is expected to have the tunnel mode feature. If a device's first API/launch version is Q or above, require IPsec tunnels Bug: 72950854 Test: Ran on device with first API level < Q and == Q. Merged-In: I545444bb483b0f5de45d00a07dc45aeb9e9cbdf7 Change-Id: I7b849ad24a04b6b7899a80f1856236b5ceb5a839 (cherry picked from commit d2465991d92ff4d8425c0f620ab8032609312049) --- .../cts/net/src/android/net/cts/IpSecManagerTunnelTest.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/tests/cts/net/src/android/net/cts/IpSecManagerTunnelTest.java b/tests/cts/net/src/android/net/cts/IpSecManagerTunnelTest.java index e8c0a7a4b2..6e96682b68 100644 --- a/tests/cts/net/src/android/net/cts/IpSecManagerTunnelTest.java +++ b/tests/cts/net/src/android/net/cts/IpSecManagerTunnelTest.java @@ -55,8 +55,10 @@ import android.net.TestNetworkInterface; import android.net.TestNetworkManager; import android.net.cts.PacketUtils.Payload; import android.os.Binder; +import android.os.Build; import android.os.IBinder; import android.os.ParcelFileDescriptor; +import android.os.SystemProperties; import androidx.test.InstrumentationRegistry; import androidx.test.runner.AndroidJUnit4; @@ -167,7 +169,9 @@ public class IpSecManagerTunnelTest extends IpSecBaseTest { } private static boolean hasTunnelsFeature() { - return sContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_IPSEC_TUNNELS); + return sContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_IPSEC_TUNNELS) + || SystemProperties.getInt("ro.product.first_api_level", 0) + >= Build.VERSION_CODES.Q; } private static void setAppop(int appop, boolean allow) { From 0d08e91fe7c2112f44bc12c4d0d00b386e9bebd7 Mon Sep 17 00:00:00 2001 From: Benedict Wong Date: Fri, 10 May 2019 12:41:42 -0700 Subject: [PATCH 50/71] Convert IPsec tests to JUnit4 This patch fixes an incompatibility where some tests in the same hierarchy were using Junit3, and other Junit4 No functional test changes made Bug: 72950854 Test: Ran on devices, working Change-Id: I79d231e202ba25ad5f57b44b387bebd7f012aa95 --- .../src/android/net/cts/IpSecBaseTest.java | 21 ++++- .../src/android/net/cts/IpSecManagerTest.java | 81 ++++++++++++++++++- .../net/cts/IpSecManagerTunnelTest.java | 2 + 3 files changed, 99 insertions(+), 5 deletions(-) diff --git a/tests/cts/net/src/android/net/cts/IpSecBaseTest.java b/tests/cts/net/src/android/net/cts/IpSecBaseTest.java index 087dbdaec3..858891f82b 100644 --- a/tests/cts/net/src/android/net/cts/IpSecBaseTest.java +++ b/tests/cts/net/src/android/net/cts/IpSecBaseTest.java @@ -25,10 +25,10 @@ import android.net.IpSecManager; import android.net.IpSecTransform; import android.system.Os; import android.system.OsConstants; -import android.test.AndroidTestCase; import android.util.Log; import androidx.test.InstrumentationRegistry; +import androidx.test.runner.AndroidJUnit4; import java.io.FileDescriptor; import java.io.IOException; @@ -43,7 +43,12 @@ import java.net.SocketException; import java.util.Arrays; import java.util.concurrent.atomic.AtomicInteger; -public class IpSecBaseTest extends AndroidTestCase { +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; + +@RunWith(AndroidJUnit4.class) +public class IpSecBaseTest { private static final String TAG = IpSecBaseTest.class.getSimpleName(); @@ -70,9 +75,11 @@ public class IpSecBaseTest extends AndroidTestCase { protected ConnectivityManager mCM; protected IpSecManager mISM; + protected Context mContext; - protected void setUp() throws Exception { - super.setUp(); + @Before + public void setUp() throws Exception { + mContext = InstrumentationRegistry.getContext(); mISM = (IpSecManager) InstrumentationRegistry.getContext() @@ -471,6 +478,7 @@ public class IpSecBaseTest extends AndroidTestCase { } } + @Test public void testJavaTcpSocketPair() throws Exception { for (String addr : LOOPBACK_ADDRS) { InetAddress local = InetAddress.getByName(addr); @@ -481,6 +489,7 @@ public class IpSecBaseTest extends AndroidTestCase { } } + @Test public void testJavaUdpSocketPair() throws Exception { for (String addr : LOOPBACK_ADDRS) { InetAddress local = InetAddress.getByName(addr); @@ -492,6 +501,7 @@ public class IpSecBaseTest extends AndroidTestCase { } } + @Test public void testJavaUdpSocketPairUnconnected() throws Exception { for (String addr : LOOPBACK_ADDRS) { InetAddress local = InetAddress.getByName(addr); @@ -503,6 +513,7 @@ public class IpSecBaseTest extends AndroidTestCase { } } + @Test public void testNativeTcpSocketPair() throws Exception { for (String addr : LOOPBACK_ADDRS) { InetAddress local = InetAddress.getByName(addr); @@ -514,6 +525,7 @@ public class IpSecBaseTest extends AndroidTestCase { } } + @Test public void testNativeUdpSocketPair() throws Exception { for (String addr : LOOPBACK_ADDRS) { InetAddress local = InetAddress.getByName(addr); @@ -525,6 +537,7 @@ public class IpSecBaseTest extends AndroidTestCase { } } + @Test public void testNativeUdpSocketPairUnconnected() throws Exception { for (String addr : LOOPBACK_ADDRS) { InetAddress local = InetAddress.getByName(addr); diff --git a/tests/cts/net/src/android/net/cts/IpSecManagerTest.java b/tests/cts/net/src/android/net/cts/IpSecManagerTest.java index 60d1c03ee2..8d5a0684a1 100644 --- a/tests/cts/net/src/android/net/cts/IpSecManagerTest.java +++ b/tests/cts/net/src/android/net/cts/IpSecManagerTest.java @@ -27,7 +27,9 @@ import static android.net.cts.PacketUtils.UDP_HDRLEN; import static android.system.OsConstants.IPPROTO_TCP; import static android.system.OsConstants.IPPROTO_UDP; import static org.junit.Assert.assertArrayEquals; +import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; import android.net.IpSecAlgorithm; import android.net.IpSecManager; @@ -37,6 +39,8 @@ import android.system.ErrnoException; import android.system.Os; import android.system.OsConstants; +import androidx.test.runner.AndroidJUnit4; + import java.io.FileDescriptor; import java.io.IOException; import java.net.DatagramPacket; @@ -45,6 +49,11 @@ import java.net.Inet6Address; import java.net.InetAddress; import java.util.Arrays; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; + +@RunWith(AndroidJUnit4.class) public class IpSecManagerTest extends IpSecBaseTest { private static final String TAG = IpSecManagerTest.class.getSimpleName(); @@ -61,7 +70,9 @@ public class IpSecManagerTest extends IpSecBaseTest { private static final byte[] AEAD_KEY = getKey(288); - protected void setUp() throws Exception { + @Before + @Override + public void setUp() throws Exception { super.setUp(); } @@ -71,6 +82,7 @@ public class IpSecManagerTest extends IpSecBaseTest { * Realloc the same SPI that was specifically created (expect SpiUnavailable) * Close SPIs */ + @Test public void testAllocSpi() throws Exception { for (InetAddress addr : GOOGLE_DNS_LIST) { IpSecManager.SecurityParameterIndex randomSpi = null, droidSpi = null; @@ -222,6 +234,7 @@ public class IpSecManagerTest extends IpSecBaseTest { * release transform * send data (expect exception) */ + @Test public void testCreateTransform() throws Exception { InetAddress localAddr = InetAddress.getByName(IPV4_LOOPBACK); IpSecManager.SecurityParameterIndex spi = @@ -591,6 +604,7 @@ public class IpSecManagerTest extends IpSecBaseTest { } } + @Test public void testIkeOverUdpEncapSocket() throws Exception { // IPv6 not supported for UDP-encap-ESP InetAddress local = InetAddress.getByName(IPV4_LOOPBACK); @@ -649,24 +663,28 @@ public class IpSecManagerTest extends IpSecBaseTest { // checkTransform(IPPROTO_TCP, IPV4_LOOPBACK, crypt, auth, true, 1000); // } + @Test public void testInterfaceCountersUdp4() throws Exception { IpSecAlgorithm crypt = new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY); IpSecAlgorithm auth = new IpSecAlgorithm(IpSecAlgorithm.AUTH_HMAC_MD5, getKey(128), 96); checkTransform(IPPROTO_UDP, IPV4_LOOPBACK, crypt, auth, null, false, 1000, false); } + @Test public void testInterfaceCountersUdp6() throws Exception { IpSecAlgorithm crypt = new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY); IpSecAlgorithm auth = new IpSecAlgorithm(IpSecAlgorithm.AUTH_HMAC_MD5, getKey(128), 96); checkTransform(IPPROTO_UDP, IPV6_LOOPBACK, crypt, auth, null, false, 1000, false); } + @Test public void testInterfaceCountersUdp4UdpEncap() throws Exception { IpSecAlgorithm crypt = new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY); IpSecAlgorithm auth = new IpSecAlgorithm(IpSecAlgorithm.AUTH_HMAC_MD5, getKey(128), 96); checkTransform(IPPROTO_UDP, IPV4_LOOPBACK, crypt, auth, null, true, 1000, false); } + @Test public void testAesCbcHmacMd5Tcp4() throws Exception { IpSecAlgorithm crypt = new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY); IpSecAlgorithm auth = new IpSecAlgorithm(IpSecAlgorithm.AUTH_HMAC_MD5, getKey(128), 96); @@ -674,6 +692,7 @@ public class IpSecManagerTest extends IpSecBaseTest { checkTransform(IPPROTO_TCP, IPV4_LOOPBACK, crypt, auth, null, false, 1, true); } + @Test public void testAesCbcHmacMd5Tcp6() throws Exception { IpSecAlgorithm crypt = new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY); IpSecAlgorithm auth = new IpSecAlgorithm(IpSecAlgorithm.AUTH_HMAC_MD5, getKey(128), 96); @@ -681,6 +700,7 @@ public class IpSecManagerTest extends IpSecBaseTest { checkTransform(IPPROTO_TCP, IPV6_LOOPBACK, crypt, auth, null, false, 1, true); } + @Test public void testAesCbcHmacMd5Udp4() throws Exception { IpSecAlgorithm crypt = new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY); IpSecAlgorithm auth = new IpSecAlgorithm(IpSecAlgorithm.AUTH_HMAC_MD5, getKey(128), 96); @@ -688,6 +708,7 @@ public class IpSecManagerTest extends IpSecBaseTest { checkTransform(IPPROTO_UDP, IPV4_LOOPBACK, crypt, auth, null, false, 1, true); } + @Test public void testAesCbcHmacMd5Udp6() throws Exception { IpSecAlgorithm crypt = new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY); IpSecAlgorithm auth = new IpSecAlgorithm(IpSecAlgorithm.AUTH_HMAC_MD5, getKey(128), 96); @@ -695,6 +716,7 @@ public class IpSecManagerTest extends IpSecBaseTest { checkTransform(IPPROTO_UDP, IPV6_LOOPBACK, crypt, auth, null, false, 1, true); } + @Test public void testAesCbcHmacSha1Tcp4() throws Exception { IpSecAlgorithm crypt = new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY); IpSecAlgorithm auth = new IpSecAlgorithm(IpSecAlgorithm.AUTH_HMAC_SHA1, getKey(160), 96); @@ -702,6 +724,7 @@ public class IpSecManagerTest extends IpSecBaseTest { checkTransform(IPPROTO_TCP, IPV4_LOOPBACK, crypt, auth, null, false, 1, true); } + @Test public void testAesCbcHmacSha1Tcp6() throws Exception { IpSecAlgorithm crypt = new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY); IpSecAlgorithm auth = new IpSecAlgorithm(IpSecAlgorithm.AUTH_HMAC_SHA1, getKey(160), 96); @@ -709,6 +732,7 @@ public class IpSecManagerTest extends IpSecBaseTest { checkTransform(IPPROTO_TCP, IPV6_LOOPBACK, crypt, auth, null, false, 1, true); } + @Test public void testAesCbcHmacSha1Udp4() throws Exception { IpSecAlgorithm crypt = new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY); IpSecAlgorithm auth = new IpSecAlgorithm(IpSecAlgorithm.AUTH_HMAC_SHA1, getKey(160), 96); @@ -716,6 +740,7 @@ public class IpSecManagerTest extends IpSecBaseTest { checkTransform(IPPROTO_UDP, IPV4_LOOPBACK, crypt, auth, null, false, 1, true); } + @Test public void testAesCbcHmacSha1Udp6() throws Exception { IpSecAlgorithm crypt = new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY); IpSecAlgorithm auth = new IpSecAlgorithm(IpSecAlgorithm.AUTH_HMAC_SHA1, getKey(160), 96); @@ -723,6 +748,7 @@ public class IpSecManagerTest extends IpSecBaseTest { checkTransform(IPPROTO_UDP, IPV6_LOOPBACK, crypt, auth, null, false, 1, true); } + @Test public void testAesCbcHmacSha256Tcp4() throws Exception { IpSecAlgorithm crypt = new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY); IpSecAlgorithm auth = new IpSecAlgorithm(IpSecAlgorithm.AUTH_HMAC_SHA256, getKey(256), 128); @@ -730,6 +756,7 @@ public class IpSecManagerTest extends IpSecBaseTest { checkTransform(IPPROTO_TCP, IPV4_LOOPBACK, crypt, auth, null, false, 1, true); } + @Test public void testAesCbcHmacSha256Tcp6() throws Exception { IpSecAlgorithm crypt = new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY); IpSecAlgorithm auth = new IpSecAlgorithm(IpSecAlgorithm.AUTH_HMAC_SHA256, getKey(256), 128); @@ -737,6 +764,7 @@ public class IpSecManagerTest extends IpSecBaseTest { checkTransform(IPPROTO_TCP, IPV6_LOOPBACK, crypt, auth, null, false, 1, true); } + @Test public void testAesCbcHmacSha256Udp4() throws Exception { IpSecAlgorithm crypt = new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY); IpSecAlgorithm auth = new IpSecAlgorithm(IpSecAlgorithm.AUTH_HMAC_SHA256, getKey(256), 128); @@ -744,6 +772,7 @@ public class IpSecManagerTest extends IpSecBaseTest { checkTransform(IPPROTO_UDP, IPV4_LOOPBACK, crypt, auth, null, false, 1, true); } + @Test public void testAesCbcHmacSha256Udp6() throws Exception { IpSecAlgorithm crypt = new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY); IpSecAlgorithm auth = new IpSecAlgorithm(IpSecAlgorithm.AUTH_HMAC_SHA256, getKey(256), 128); @@ -751,6 +780,7 @@ public class IpSecManagerTest extends IpSecBaseTest { checkTransform(IPPROTO_UDP, IPV6_LOOPBACK, crypt, auth, null, false, 1, true); } + @Test public void testAesCbcHmacSha384Tcp4() throws Exception { IpSecAlgorithm crypt = new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY); IpSecAlgorithm auth = new IpSecAlgorithm(IpSecAlgorithm.AUTH_HMAC_SHA384, getKey(384), 192); @@ -758,6 +788,7 @@ public class IpSecManagerTest extends IpSecBaseTest { checkTransform(IPPROTO_TCP, IPV4_LOOPBACK, crypt, auth, null, false, 1, true); } + @Test public void testAesCbcHmacSha384Tcp6() throws Exception { IpSecAlgorithm crypt = new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY); IpSecAlgorithm auth = new IpSecAlgorithm(IpSecAlgorithm.AUTH_HMAC_SHA384, getKey(384), 192); @@ -765,6 +796,7 @@ public class IpSecManagerTest extends IpSecBaseTest { checkTransform(IPPROTO_TCP, IPV6_LOOPBACK, crypt, auth, null, false, 1, true); } + @Test public void testAesCbcHmacSha384Udp4() throws Exception { IpSecAlgorithm crypt = new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY); IpSecAlgorithm auth = new IpSecAlgorithm(IpSecAlgorithm.AUTH_HMAC_SHA384, getKey(384), 192); @@ -772,6 +804,7 @@ public class IpSecManagerTest extends IpSecBaseTest { checkTransform(IPPROTO_UDP, IPV4_LOOPBACK, crypt, auth, null, false, 1, true); } + @Test public void testAesCbcHmacSha384Udp6() throws Exception { IpSecAlgorithm crypt = new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY); IpSecAlgorithm auth = new IpSecAlgorithm(IpSecAlgorithm.AUTH_HMAC_SHA384, getKey(384), 192); @@ -779,6 +812,7 @@ public class IpSecManagerTest extends IpSecBaseTest { checkTransform(IPPROTO_UDP, IPV6_LOOPBACK, crypt, auth, null, false, 1, true); } + @Test public void testAesCbcHmacSha512Tcp4() throws Exception { IpSecAlgorithm crypt = new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY); IpSecAlgorithm auth = new IpSecAlgorithm(IpSecAlgorithm.AUTH_HMAC_SHA512, getKey(512), 256); @@ -786,6 +820,7 @@ public class IpSecManagerTest extends IpSecBaseTest { checkTransform(IPPROTO_TCP, IPV4_LOOPBACK, crypt, auth, null, false, 1, true); } + @Test public void testAesCbcHmacSha512Tcp6() throws Exception { IpSecAlgorithm crypt = new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY); IpSecAlgorithm auth = new IpSecAlgorithm(IpSecAlgorithm.AUTH_HMAC_SHA512, getKey(512), 256); @@ -793,6 +828,7 @@ public class IpSecManagerTest extends IpSecBaseTest { checkTransform(IPPROTO_TCP, IPV6_LOOPBACK, crypt, auth, null, false, 1, true); } + @Test public void testAesCbcHmacSha512Udp4() throws Exception { IpSecAlgorithm crypt = new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY); IpSecAlgorithm auth = new IpSecAlgorithm(IpSecAlgorithm.AUTH_HMAC_SHA512, getKey(512), 256); @@ -800,6 +836,7 @@ public class IpSecManagerTest extends IpSecBaseTest { checkTransform(IPPROTO_UDP, IPV4_LOOPBACK, crypt, auth, null, false, 1, true); } + @Test public void testAesCbcHmacSha512Udp6() throws Exception { IpSecAlgorithm crypt = new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY); IpSecAlgorithm auth = new IpSecAlgorithm(IpSecAlgorithm.AUTH_HMAC_SHA512, getKey(512), 256); @@ -807,6 +844,7 @@ public class IpSecManagerTest extends IpSecBaseTest { checkTransform(IPPROTO_UDP, IPV6_LOOPBACK, crypt, auth, null, false, 1, true); } + @Test public void testAesGcm64Tcp4() throws Exception { IpSecAlgorithm authCrypt = new IpSecAlgorithm(IpSecAlgorithm.AUTH_CRYPT_AES_GCM, AEAD_KEY, 64); @@ -814,6 +852,7 @@ public class IpSecManagerTest extends IpSecBaseTest { checkTransform(IPPROTO_TCP, IPV4_LOOPBACK, null, null, authCrypt, false, 1, true); } + @Test public void testAesGcm64Tcp6() throws Exception { IpSecAlgorithm authCrypt = new IpSecAlgorithm(IpSecAlgorithm.AUTH_CRYPT_AES_GCM, AEAD_KEY, 64); @@ -821,6 +860,7 @@ public class IpSecManagerTest extends IpSecBaseTest { checkTransform(IPPROTO_TCP, IPV6_LOOPBACK, null, null, authCrypt, false, 1, true); } + @Test public void testAesGcm64Udp4() throws Exception { IpSecAlgorithm authCrypt = new IpSecAlgorithm(IpSecAlgorithm.AUTH_CRYPT_AES_GCM, AEAD_KEY, 64); @@ -828,6 +868,7 @@ public class IpSecManagerTest extends IpSecBaseTest { checkTransform(IPPROTO_UDP, IPV4_LOOPBACK, null, null, authCrypt, false, 1, true); } + @Test public void testAesGcm64Udp6() throws Exception { IpSecAlgorithm authCrypt = new IpSecAlgorithm(IpSecAlgorithm.AUTH_CRYPT_AES_GCM, AEAD_KEY, 64); @@ -835,6 +876,7 @@ public class IpSecManagerTest extends IpSecBaseTest { checkTransform(IPPROTO_UDP, IPV6_LOOPBACK, null, null, authCrypt, false, 1, true); } + @Test public void testAesGcm96Tcp4() throws Exception { IpSecAlgorithm authCrypt = new IpSecAlgorithm(IpSecAlgorithm.AUTH_CRYPT_AES_GCM, AEAD_KEY, 96); @@ -842,6 +884,7 @@ public class IpSecManagerTest extends IpSecBaseTest { checkTransform(IPPROTO_TCP, IPV4_LOOPBACK, null, null, authCrypt, false, 1, true); } + @Test public void testAesGcm96Tcp6() throws Exception { IpSecAlgorithm authCrypt = new IpSecAlgorithm(IpSecAlgorithm.AUTH_CRYPT_AES_GCM, AEAD_KEY, 96); @@ -849,6 +892,7 @@ public class IpSecManagerTest extends IpSecBaseTest { checkTransform(IPPROTO_TCP, IPV6_LOOPBACK, null, null, authCrypt, false, 1, true); } + @Test public void testAesGcm96Udp4() throws Exception { IpSecAlgorithm authCrypt = new IpSecAlgorithm(IpSecAlgorithm.AUTH_CRYPT_AES_GCM, AEAD_KEY, 96); @@ -856,6 +900,7 @@ public class IpSecManagerTest extends IpSecBaseTest { checkTransform(IPPROTO_UDP, IPV4_LOOPBACK, null, null, authCrypt, false, 1, true); } + @Test public void testAesGcm96Udp6() throws Exception { IpSecAlgorithm authCrypt = new IpSecAlgorithm(IpSecAlgorithm.AUTH_CRYPT_AES_GCM, AEAD_KEY, 96); @@ -863,6 +908,7 @@ public class IpSecManagerTest extends IpSecBaseTest { checkTransform(IPPROTO_UDP, IPV6_LOOPBACK, null, null, authCrypt, false, 1, true); } + @Test public void testAesGcm128Tcp4() throws Exception { IpSecAlgorithm authCrypt = new IpSecAlgorithm(IpSecAlgorithm.AUTH_CRYPT_AES_GCM, AEAD_KEY, 128); @@ -870,6 +916,7 @@ public class IpSecManagerTest extends IpSecBaseTest { checkTransform(IPPROTO_TCP, IPV4_LOOPBACK, null, null, authCrypt, false, 1, true); } + @Test public void testAesGcm128Tcp6() throws Exception { IpSecAlgorithm authCrypt = new IpSecAlgorithm(IpSecAlgorithm.AUTH_CRYPT_AES_GCM, AEAD_KEY, 128); @@ -877,6 +924,7 @@ public class IpSecManagerTest extends IpSecBaseTest { checkTransform(IPPROTO_TCP, IPV6_LOOPBACK, null, null, authCrypt, false, 1, true); } + @Test public void testAesGcm128Udp4() throws Exception { IpSecAlgorithm authCrypt = new IpSecAlgorithm(IpSecAlgorithm.AUTH_CRYPT_AES_GCM, AEAD_KEY, 128); @@ -884,6 +932,7 @@ public class IpSecManagerTest extends IpSecBaseTest { checkTransform(IPPROTO_UDP, IPV4_LOOPBACK, null, null, authCrypt, false, 1, true); } + @Test public void testAesGcm128Udp6() throws Exception { IpSecAlgorithm authCrypt = new IpSecAlgorithm(IpSecAlgorithm.AUTH_CRYPT_AES_GCM, AEAD_KEY, 128); @@ -891,6 +940,7 @@ public class IpSecManagerTest extends IpSecBaseTest { checkTransform(IPPROTO_UDP, IPV6_LOOPBACK, null, null, authCrypt, false, 1, true); } + @Test public void testAesCbcHmacMd5Tcp4UdpEncap() throws Exception { IpSecAlgorithm crypt = new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY); IpSecAlgorithm auth = new IpSecAlgorithm(IpSecAlgorithm.AUTH_HMAC_MD5, getKey(128), 96); @@ -898,6 +948,7 @@ public class IpSecManagerTest extends IpSecBaseTest { checkTransform(IPPROTO_TCP, IPV4_LOOPBACK, crypt, auth, null, true, 1, true); } + @Test public void testAesCbcHmacMd5Udp4UdpEncap() throws Exception { IpSecAlgorithm crypt = new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY); IpSecAlgorithm auth = new IpSecAlgorithm(IpSecAlgorithm.AUTH_HMAC_MD5, getKey(128), 96); @@ -905,6 +956,7 @@ public class IpSecManagerTest extends IpSecBaseTest { checkTransform(IPPROTO_UDP, IPV4_LOOPBACK, crypt, auth, null, true, 1, true); } + @Test public void testAesCbcHmacSha1Tcp4UdpEncap() throws Exception { IpSecAlgorithm crypt = new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY); IpSecAlgorithm auth = new IpSecAlgorithm(IpSecAlgorithm.AUTH_HMAC_SHA1, getKey(160), 96); @@ -912,6 +964,7 @@ public class IpSecManagerTest extends IpSecBaseTest { checkTransform(IPPROTO_TCP, IPV4_LOOPBACK, crypt, auth, null, true, 1, true); } + @Test public void testAesCbcHmacSha1Udp4UdpEncap() throws Exception { IpSecAlgorithm crypt = new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY); IpSecAlgorithm auth = new IpSecAlgorithm(IpSecAlgorithm.AUTH_HMAC_SHA1, getKey(160), 96); @@ -919,6 +972,7 @@ public class IpSecManagerTest extends IpSecBaseTest { checkTransform(IPPROTO_UDP, IPV4_LOOPBACK, crypt, auth, null, true, 1, true); } + @Test public void testAesCbcHmacSha256Tcp4UdpEncap() throws Exception { IpSecAlgorithm crypt = new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY); IpSecAlgorithm auth = new IpSecAlgorithm(IpSecAlgorithm.AUTH_HMAC_SHA256, getKey(256), 128); @@ -926,6 +980,7 @@ public class IpSecManagerTest extends IpSecBaseTest { checkTransform(IPPROTO_TCP, IPV4_LOOPBACK, crypt, auth, null, true, 1, true); } + @Test public void testAesCbcHmacSha256Udp4UdpEncap() throws Exception { IpSecAlgorithm crypt = new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY); IpSecAlgorithm auth = new IpSecAlgorithm(IpSecAlgorithm.AUTH_HMAC_SHA256, getKey(256), 128); @@ -933,6 +988,7 @@ public class IpSecManagerTest extends IpSecBaseTest { checkTransform(IPPROTO_UDP, IPV4_LOOPBACK, crypt, auth, null, true, 1, true); } + @Test public void testAesCbcHmacSha384Tcp4UdpEncap() throws Exception { IpSecAlgorithm crypt = new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY); IpSecAlgorithm auth = new IpSecAlgorithm(IpSecAlgorithm.AUTH_HMAC_SHA384, getKey(384), 192); @@ -940,6 +996,7 @@ public class IpSecManagerTest extends IpSecBaseTest { checkTransform(IPPROTO_TCP, IPV4_LOOPBACK, crypt, auth, null, true, 1, true); } + @Test public void testAesCbcHmacSha384Udp4UdpEncap() throws Exception { IpSecAlgorithm crypt = new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY); IpSecAlgorithm auth = new IpSecAlgorithm(IpSecAlgorithm.AUTH_HMAC_SHA384, getKey(384), 192); @@ -947,6 +1004,7 @@ public class IpSecManagerTest extends IpSecBaseTest { checkTransform(IPPROTO_UDP, IPV4_LOOPBACK, crypt, auth, null, true, 1, true); } + @Test public void testAesCbcHmacSha512Tcp4UdpEncap() throws Exception { IpSecAlgorithm crypt = new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY); IpSecAlgorithm auth = new IpSecAlgorithm(IpSecAlgorithm.AUTH_HMAC_SHA512, getKey(512), 256); @@ -954,6 +1012,7 @@ public class IpSecManagerTest extends IpSecBaseTest { checkTransform(IPPROTO_TCP, IPV4_LOOPBACK, crypt, auth, null, true, 1, true); } + @Test public void testAesCbcHmacSha512Udp4UdpEncap() throws Exception { IpSecAlgorithm crypt = new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY); IpSecAlgorithm auth = new IpSecAlgorithm(IpSecAlgorithm.AUTH_HMAC_SHA512, getKey(512), 256); @@ -961,6 +1020,7 @@ public class IpSecManagerTest extends IpSecBaseTest { checkTransform(IPPROTO_UDP, IPV4_LOOPBACK, crypt, auth, null, true, 1, true); } + @Test public void testAesGcm64Tcp4UdpEncap() throws Exception { IpSecAlgorithm authCrypt = new IpSecAlgorithm(IpSecAlgorithm.AUTH_CRYPT_AES_GCM, AEAD_KEY, 64); @@ -968,6 +1028,7 @@ public class IpSecManagerTest extends IpSecBaseTest { checkTransform(IPPROTO_TCP, IPV4_LOOPBACK, null, null, authCrypt, true, 1, true); } + @Test public void testAesGcm64Udp4UdpEncap() throws Exception { IpSecAlgorithm authCrypt = new IpSecAlgorithm(IpSecAlgorithm.AUTH_CRYPT_AES_GCM, AEAD_KEY, 64); @@ -975,6 +1036,7 @@ public class IpSecManagerTest extends IpSecBaseTest { checkTransform(IPPROTO_UDP, IPV4_LOOPBACK, null, null, authCrypt, true, 1, true); } + @Test public void testAesGcm96Tcp4UdpEncap() throws Exception { IpSecAlgorithm authCrypt = new IpSecAlgorithm(IpSecAlgorithm.AUTH_CRYPT_AES_GCM, AEAD_KEY, 96); @@ -982,6 +1044,7 @@ public class IpSecManagerTest extends IpSecBaseTest { checkTransform(IPPROTO_TCP, IPV4_LOOPBACK, null, null, authCrypt, true, 1, true); } + @Test public void testAesGcm96Udp4UdpEncap() throws Exception { IpSecAlgorithm authCrypt = new IpSecAlgorithm(IpSecAlgorithm.AUTH_CRYPT_AES_GCM, AEAD_KEY, 96); @@ -989,6 +1052,7 @@ public class IpSecManagerTest extends IpSecBaseTest { checkTransform(IPPROTO_UDP, IPV4_LOOPBACK, null, null, authCrypt, true, 1, true); } + @Test public void testAesGcm128Tcp4UdpEncap() throws Exception { IpSecAlgorithm authCrypt = new IpSecAlgorithm(IpSecAlgorithm.AUTH_CRYPT_AES_GCM, AEAD_KEY, 128); @@ -996,6 +1060,7 @@ public class IpSecManagerTest extends IpSecBaseTest { checkTransform(IPPROTO_TCP, IPV4_LOOPBACK, null, null, authCrypt, true, 1, true); } + @Test public void testAesGcm128Udp4UdpEncap() throws Exception { IpSecAlgorithm authCrypt = new IpSecAlgorithm(IpSecAlgorithm.AUTH_CRYPT_AES_GCM, AEAD_KEY, 128); @@ -1003,78 +1068,91 @@ public class IpSecManagerTest extends IpSecBaseTest { checkTransform(IPPROTO_UDP, IPV4_LOOPBACK, null, null, authCrypt, true, 1, true); } + @Test public void testCryptUdp4() throws Exception { IpSecAlgorithm crypt = new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY); checkTransform(IPPROTO_UDP, IPV4_LOOPBACK, crypt, null, null, false, 1, false); checkTransform(IPPROTO_UDP, IPV4_LOOPBACK, crypt, null, null, false, 1, true); } + @Test public void testAuthUdp4() throws Exception { IpSecAlgorithm auth = new IpSecAlgorithm(IpSecAlgorithm.AUTH_HMAC_SHA256, getKey(256), 128); checkTransform(IPPROTO_UDP, IPV4_LOOPBACK, null, auth, null, false, 1, false); checkTransform(IPPROTO_UDP, IPV4_LOOPBACK, null, auth, null, false, 1, true); } + @Test public void testCryptUdp6() throws Exception { IpSecAlgorithm crypt = new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY); checkTransform(IPPROTO_UDP, IPV6_LOOPBACK, crypt, null, null, false, 1, false); checkTransform(IPPROTO_UDP, IPV6_LOOPBACK, crypt, null, null, false, 1, true); } + @Test public void testAuthUdp6() throws Exception { IpSecAlgorithm auth = new IpSecAlgorithm(IpSecAlgorithm.AUTH_HMAC_SHA256, getKey(256), 128); checkTransform(IPPROTO_UDP, IPV6_LOOPBACK, null, auth, null, false, 1, false); checkTransform(IPPROTO_UDP, IPV6_LOOPBACK, null, auth, null, false, 1, true); } + @Test public void testCryptTcp4() throws Exception { IpSecAlgorithm crypt = new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY); checkTransform(IPPROTO_TCP, IPV4_LOOPBACK, crypt, null, null, false, 1, false); checkTransform(IPPROTO_TCP, IPV4_LOOPBACK, crypt, null, null, false, 1, true); } + @Test public void testAuthTcp4() throws Exception { IpSecAlgorithm auth = new IpSecAlgorithm(IpSecAlgorithm.AUTH_HMAC_SHA256, getKey(256), 128); checkTransform(IPPROTO_TCP, IPV4_LOOPBACK, null, auth, null, false, 1, false); checkTransform(IPPROTO_TCP, IPV4_LOOPBACK, null, auth, null, false, 1, true); } + @Test public void testCryptTcp6() throws Exception { IpSecAlgorithm crypt = new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY); checkTransform(IPPROTO_TCP, IPV6_LOOPBACK, crypt, null, null, false, 1, false); checkTransform(IPPROTO_TCP, IPV6_LOOPBACK, crypt, null, null, false, 1, true); } + @Test public void testAuthTcp6() throws Exception { IpSecAlgorithm auth = new IpSecAlgorithm(IpSecAlgorithm.AUTH_HMAC_SHA256, getKey(256), 128); checkTransform(IPPROTO_TCP, IPV6_LOOPBACK, null, auth, null, false, 1, false); checkTransform(IPPROTO_TCP, IPV6_LOOPBACK, null, auth, null, false, 1, true); } + @Test public void testCryptUdp4UdpEncap() throws Exception { IpSecAlgorithm crypt = new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY); checkTransform(IPPROTO_UDP, IPV4_LOOPBACK, crypt, null, null, true, 1, false); checkTransform(IPPROTO_UDP, IPV4_LOOPBACK, crypt, null, null, true, 1, true); } + @Test public void testAuthUdp4UdpEncap() throws Exception { IpSecAlgorithm auth = new IpSecAlgorithm(IpSecAlgorithm.AUTH_HMAC_SHA256, getKey(256), 128); checkTransform(IPPROTO_UDP, IPV4_LOOPBACK, null, auth, null, true, 1, false); checkTransform(IPPROTO_UDP, IPV4_LOOPBACK, null, auth, null, true, 1, true); } + @Test public void testCryptTcp4UdpEncap() throws Exception { IpSecAlgorithm crypt = new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY); checkTransform(IPPROTO_TCP, IPV4_LOOPBACK, crypt, null, null, true, 1, false); checkTransform(IPPROTO_TCP, IPV4_LOOPBACK, crypt, null, null, true, 1, true); } + @Test public void testAuthTcp4UdpEncap() throws Exception { IpSecAlgorithm auth = new IpSecAlgorithm(IpSecAlgorithm.AUTH_HMAC_SHA256, getKey(256), 128); checkTransform(IPPROTO_TCP, IPV4_LOOPBACK, null, auth, null, true, 1, false); checkTransform(IPPROTO_TCP, IPV4_LOOPBACK, null, auth, null, true, 1, true); } + @Test public void testOpenUdpEncapSocketSpecificPort() throws Exception { IpSecManager.UdpEncapsulationSocket encapSocket = null; int port = -1; @@ -1103,6 +1181,7 @@ public class IpSecManagerTest extends IpSecBaseTest { assertTrue("Returned invalid port", encapSocket.getPort() == port); } + @Test public void testOpenUdpEncapSocketRandomPort() throws Exception { try (IpSecManager.UdpEncapsulationSocket encapSocket = mISM.openUdpEncapsulationSocket()) { assertTrue("Returned invalid port", encapSocket.getPort() != 0); diff --git a/tests/cts/net/src/android/net/cts/IpSecManagerTunnelTest.java b/tests/cts/net/src/android/net/cts/IpSecManagerTunnelTest.java index e8c0a7a4b2..9c94dc993a 100644 --- a/tests/cts/net/src/android/net/cts/IpSecManagerTunnelTest.java +++ b/tests/cts/net/src/android/net/cts/IpSecManagerTunnelTest.java @@ -40,6 +40,7 @@ import static org.junit.Assert.assertEquals; 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 android.app.AppOpsManager; import android.content.Context; @@ -142,6 +143,7 @@ public class IpSecManagerTunnelTest extends IpSecBaseTest { } @Before + @Override public void setUp() throws Exception { super.setUp(); From ad4c047f6d6e9b3dc0df58fd80f6511b7351a872 Mon Sep 17 00:00:00 2001 From: junyulai Date: Tue, 2 Apr 2019 11:36:14 +0800 Subject: [PATCH 51/71] [KA14] add cts for keepalive limit test. Per SDK requirement, OEM is required to support minimum number of concurrent keepalives. Implement CTS to verify this. Bug: 129371366 Test: atest android.net.cts .ConnectivityManagerTest#testSocketKeepaliveLimit --generate-new-metrics 10 (Clean cherry-pick of aosp/937026) Change-Id: I8be89116bed5c4dedb2ca42b6d633aa9e8c6a49a Merged-In: I8be89116bed5c4dedb2ca42b6d633aa9e8c6a49a --- .../net/cts/ConnectivityManagerTest.java | 135 ++++++++++++++++++ 1 file changed, 135 insertions(+) diff --git a/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java b/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java index cb1aa09599..f702042f77 100644 --- a/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java +++ b/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java @@ -43,6 +43,8 @@ import android.content.IntentFilter; import android.content.pm.PackageManager; import android.net.ConnectivityManager; import android.net.ConnectivityManager.NetworkCallback; +import android.net.IpSecManager; +import android.net.IpSecManager.UdpEncapsulationSocket; import android.net.LinkProperties; import android.net.Network; import android.net.NetworkCapabilities; @@ -52,6 +54,7 @@ import android.net.NetworkInfo.DetailedState; import android.net.NetworkInfo.State; import android.net.NetworkRequest; import android.net.SocketKeepalive; +import android.net.util.KeepaliveUtils; import android.net.wifi.WifiManager; import android.os.Looper; import android.os.MessageQueue; @@ -86,6 +89,7 @@ import java.net.Socket; import java.net.URL; import java.net.UnknownHostException; import java.nio.charset.StandardCharsets; +import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.concurrent.CountDownLatch; @@ -705,6 +709,16 @@ public class ConnectivityManagerTest extends AndroidTestCase { return wifiNetwork; } + private InetAddress getFirstV4Address(Network network) { + LinkProperties linkProperties = mCm.getLinkProperties(network); + for (InetAddress address : linkProperties.getAddresses()) { + if (address instanceof Inet4Address) { + return address; + } + } + return null; + } + private Socket getBoundSocket(Network network, String host, int port) throws IOException { InetSocketAddress addr = new InetSocketAddress(host, port); Socket s = network.getSocketFactory().createSocket(); @@ -1278,4 +1292,125 @@ public class ConnectivityManagerTest extends AndroidTestCase { } } + + private int createConcurrentSocketKeepalives(int nattCount, int tcpCount) throws Exception { + if (!isKeepaliveSupported()) return 0; + + final Network network = ensureWifiConnected(); + + final ArrayList kalist = new ArrayList<>(); + final TestSocketKeepaliveCallback callback = new TestSocketKeepaliveCallback(); + final Executor executor = mContext.getMainExecutor(); + + // Create concurrent TCP keepalives. + for (int i = 0; i < tcpCount; i++) { + // Assert that TCP connections can be established on wifi. The file descriptor of tcp + // sockets will be duplicated and kept valid in service side if the keepalives are + // successfully started. + try (Socket tcpSocket = getConnectedSocket(network, TEST_HOST, HTTP_PORT, + 0 /* Unused */, AF_INET)) { + final SocketKeepalive ka = mCm.createSocketKeepalive(network, tcpSocket, executor, + callback); + ka.start(MIN_KEEPALIVE_INTERVAL); + TestSocketKeepaliveCallback.CallbackValue cv = callback.pollCallback(); + assertNotNull(cv); + if (cv.callbackType == TestSocketKeepaliveCallback.CallbackType.ON_ERROR + && cv.error == SocketKeepalive.ERROR_INSUFFICIENT_RESOURCES) { + // Limit reached. + break; + } + if (cv.callbackType == TestSocketKeepaliveCallback.CallbackType.ON_STARTED) { + kalist.add(ka); + } else { + fail("Unexpected error when creating " + (i + 1) + " TCP keepalives: " + cv); + } + } + } + + // Assert that a Nat-T socket can be created. + 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); + + // Test concurrent Nat-T keepalives. + for (int i = 0; i < nattCount; i++) { + final SocketKeepalive ka = mCm.createSocketKeepalive(network, nattSocket, + srcAddr, dstAddr, executor, callback); + ka.start(MIN_KEEPALIVE_INTERVAL); + TestSocketKeepaliveCallback.CallbackValue cv = callback.pollCallback(); + assertNotNull(cv); + if (cv.callbackType == TestSocketKeepaliveCallback.CallbackType.ON_ERROR + && cv.error == SocketKeepalive.ERROR_INSUFFICIENT_RESOURCES) { + // Limit reached. + break; + } + if (cv.callbackType == TestSocketKeepaliveCallback.CallbackType.ON_STARTED) { + kalist.add(ka); + } else { + fail("Unexpected error when creating " + (i + 1) + " Nat-T keepalives: " + cv); + } + } + + final int ret = kalist.size(); + + // Clean up. + for (final SocketKeepalive ka : kalist) { + ka.stop(); + callback.expectStopped(); + } + kalist.clear(); + nattSocket.close(); + + return ret; + } + + /** + * Verifies that the concurrent keepalive slots meet the minimum requirement, and don't + * get leaked after iterations. + */ + public void testSocketKeepaliveLimit() throws Exception { + adoptShellPermissionIdentity(); + + final Network network = ensureWifiConnected(); + final NetworkCapabilities nc = mCm.getNetworkCapabilities(network); + + // Get number of supported concurrent keepalives for testing network. + final int[] keepalivesPerTransport = KeepaliveUtils.getSupportedKeepalives(mContext); + final int supported = KeepaliveUtils.getSupportedKeepalivesForNetworkCapabilities( + keepalivesPerTransport, nc); + + // Sanity check. + if (!isKeepaliveSupported()) { + assertEquals(0, supported); + return; + } + + // Verifies that the supported keepalive slots meet MIN_SUPPORTED_KEEPALIVE_COUNT. + assertGreaterOrEqual(supported, KeepaliveUtils.MIN_SUPPORTED_KEEPALIVE_COUNT); + + // Verifies that different types of keepalives can be established. + assertEquals(supported, createConcurrentSocketKeepalives(supported + 1, 0)); + assertEquals(supported, createConcurrentSocketKeepalives(0, supported + 1)); + + // Verifies that different types can be established at the same time. + assertEquals(supported, createConcurrentSocketKeepalives( + supported / 2, supported - supported / 2)); + + // Verifies that keepalives don't get leaked in second round. + assertEquals(supported, createConcurrentSocketKeepalives(supported + 1, 0)); + assertEquals(supported, createConcurrentSocketKeepalives(0, supported + 1)); + assertEquals(supported, createConcurrentSocketKeepalives( + supported / 2, supported - supported / 2)); + + dropShellPermissionIdentity(); + } + + private static void assertGreaterOrEqual(long greater, long lesser) { + assertTrue("" + greater + " expected to be greater than or equal to " + lesser, + greater >= lesser); + } } From bbf160a93d10af0d521ec96c69be38c9e71803c0 Mon Sep 17 00:00:00 2001 From: junyulai Date: Wed, 8 May 2019 11:46:25 +0800 Subject: [PATCH 52/71] add cts for unprivileged keepalive slots Currently, unprivileged Nat-T keepalives are limited to 1 slot per uid. Add CTS to verify that the keepalive slots are limited as customized for unprivileged requests. Bug: 129371366 Test: atest android.net.cts .ConnectivityManagerTest#testSocketKeepaliveUnprivileged --generate-new-metrics 10 (Clean cherry-pick of aosp/957205) Change-Id: I60b9e9ae9cf2b63490493ced9738cd2f402c3f9b Merged-In: I60b9e9ae9cf2b63490493ced9738cd2f402c3f9b --- .../net/cts/ConnectivityManagerTest.java | 51 +++++++++++++++---- 1 file changed, 42 insertions(+), 9 deletions(-) diff --git a/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java b/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java index f702042f77..606d3fc772 100644 --- a/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java +++ b/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java @@ -1185,6 +1185,16 @@ public class ConnectivityManagerTest extends AndroidTestCase { return s; } + private int getSupportedKeepalivesFromRes() throws Exception { + final Network network = ensureWifiConnected(); + final NetworkCapabilities nc = mCm.getNetworkCapabilities(network); + + // Get number of supported concurrent keepalives for testing network. + final int[] keepalivesPerTransport = KeepaliveUtils.getSupportedKeepalives(mContext); + return KeepaliveUtils.getSupportedKeepalivesForNetworkCapabilities( + keepalivesPerTransport, nc); + } + private boolean isKeepaliveSupported() throws Exception { final Network network = ensureWifiConnected(); final Executor executor = mContext.getMainExecutor(); @@ -1294,7 +1304,8 @@ public class ConnectivityManagerTest extends AndroidTestCase { } private int createConcurrentSocketKeepalives(int nattCount, int tcpCount) throws Exception { - if (!isKeepaliveSupported()) return 0; + // Use customization value in resource to prevent the need of privilege. + if (getSupportedKeepalivesFromRes() == 0) return 0; final Network network = ensureWifiConnected(); @@ -1375,16 +1386,10 @@ public class ConnectivityManagerTest extends AndroidTestCase { public void testSocketKeepaliveLimit() throws Exception { adoptShellPermissionIdentity(); - final Network network = ensureWifiConnected(); - final NetworkCapabilities nc = mCm.getNetworkCapabilities(network); + final int supported = getSupportedKeepalivesFromRes(); - // Get number of supported concurrent keepalives for testing network. - final int[] keepalivesPerTransport = KeepaliveUtils.getSupportedKeepalives(mContext); - final int supported = KeepaliveUtils.getSupportedKeepalivesForNetworkCapabilities( - keepalivesPerTransport, nc); - - // Sanity check. if (!isKeepaliveSupported()) { + // Sanity check. assertEquals(0, supported); return; } @@ -1409,6 +1414,34 @@ public class ConnectivityManagerTest extends AndroidTestCase { dropShellPermissionIdentity(); } + /** + * Verifies that the keepalive slots are limited as customized for unprivileged requests. + */ + public void testSocketKeepaliveUnprivileged() throws Exception { + final int supported = getSupportedKeepalivesFromRes(); + + adoptShellPermissionIdentity(); + if (!isKeepaliveSupported()) { + // Sanity check. + assertEquals(0, supported); + return; + } + dropShellPermissionIdentity(); + + final int allowedUnprivilegedPerUid = mContext.getResources().getInteger( + R.integer.config_allowedUnprivilegedKeepalivePerUid); + final int reservedPrivilegedSlots = mContext.getResources().getInteger( + R.integer.config_reservedPrivilegedKeepaliveSlots); + // Verifies that unprivileged request per uid cannot exceed the limit customized in the + // resource. Currently, unprivileged keepalive slots are limited to Nat-T only, this test + // does not apply to TCP. + assertGreaterOrEqual(supported, reservedPrivilegedSlots); + assertGreaterOrEqual(supported, allowedUnprivilegedPerUid); + final int expectedUnprivileged = + Math.min(allowedUnprivilegedPerUid, supported - reservedPrivilegedSlots); + assertEquals(expectedUnprivileged, createConcurrentSocketKeepalives(supported + 1, 0)); + } + private static void assertGreaterOrEqual(long greater, long lesser) { assertTrue("" + greater + " expected to be greater than or equal to " + lesser, greater >= lesser); From 4af108aacfe7977484d844cefce83a75ac1cafc9 Mon Sep 17 00:00:00 2001 From: Benedict Wong Date: Wed, 15 May 2019 00:26:09 -0700 Subject: [PATCH 53/71] Fix IPsec CTS tests for interface address checking Fixes two potentially device/kernel specific, or flaky bugs: 1. Java interface checking by name seems to cache the lookup, resulting in interface address checks occasionally failing (on delete). 2. Link-local addresses appear to be added on all links for some set of kernels and devices. This patch addresses both by only checking that the requested address was added via a address-based NetworkInterface lookup. Bug: 72950854 Test: Ran on sargo-eng on qt-dev/HEAD Test: Manually verified that the addresses are indeed added/removed Change-Id: I3babc72dfe72337c4d68facb1695aec15e504c90 --- .../net/cts/IpSecManagerTunnelTest.java | 21 +++++++------------ 1 file changed, 8 insertions(+), 13 deletions(-) diff --git a/tests/cts/net/src/android/net/cts/IpSecManagerTunnelTest.java b/tests/cts/net/src/android/net/cts/IpSecManagerTunnelTest.java index 66141960c8..93638ac3b5 100644 --- a/tests/cts/net/src/android/net/cts/IpSecManagerTunnelTest.java +++ b/tests/cts/net/src/android/net/cts/IpSecManagerTunnelTest.java @@ -39,7 +39,6 @@ import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertEquals; 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 android.app.AppOpsManager; @@ -69,9 +68,7 @@ import com.android.compatibility.common.util.SystemUtil; import java.net.Inet4Address; import java.net.Inet6Address; import java.net.InetAddress; -import java.net.InterfaceAddress; import java.net.NetworkInterface; -import java.util.List; import java.util.concurrent.CompletableFuture; import java.util.concurrent.TimeUnit; @@ -512,11 +509,10 @@ public class IpSecManagerTunnelTest extends IpSecBaseTest { NetworkInterface netIntf = NetworkInterface.getByName(tunnelIntf.getInterfaceName()); assertNotNull(netIntf); - // Check addresses - List intfAddrs = netIntf.getInterfaceAddresses(); - assertEquals(1, intfAddrs.size()); - assertEquals(localInner, intfAddrs.get(0).getAddress()); - assertEquals(innerPrefixLen, intfAddrs.get(0).getNetworkPrefixLength()); + // Verify address was added + netIntf = NetworkInterface.getByInetAddress(localInner); + assertNotNull(netIntf); + assertEquals(tunnelIntf.getInterfaceName(), netIntf.getDisplayName()); // Configure Transform parameters IpSecTransform.Builder transformBuilder = new IpSecTransform.Builder(sContext); @@ -544,15 +540,14 @@ public class IpSecManagerTunnelTest extends IpSecBaseTest { // Teardown the test network sTNM.teardownTestNetwork(testNetwork); - // Remove addresses and check + // Remove addresses and check that interface is still present, but fails lookup-by-addr tunnelIntf.removeAddress(localInner, innerPrefixLen); - netIntf = NetworkInterface.getByName(tunnelIntf.getInterfaceName()); - assertTrue(netIntf.getInterfaceAddresses().isEmpty()); + assertNotNull(NetworkInterface.getByName(tunnelIntf.getInterfaceName())); + assertNull(NetworkInterface.getByInetAddress(localInner)); // Check interface was cleaned up tunnelIntf.close(); - netIntf = NetworkInterface.getByName(tunnelIntf.getInterfaceName()); - assertNull(netIntf); + assertNull(NetworkInterface.getByName(tunnelIntf.getInterfaceName())); } finally { if (testNetworkCb != null) { sCM.unregisterNetworkCallback(testNetworkCb); From 78e4a184a10c12978391a039f00e155d0dbff276 Mon Sep 17 00:00:00 2001 From: paulhu Date: Fri, 3 May 2019 16:30:46 +0800 Subject: [PATCH 54/71] Enable instant app mode for CtsNetTestCases 1. Indicating CtsNetTestCases support instant app mode but ignore some tests that cannot run in instant app mode. 2. Move some tests which need to test on API 23 into CtsNetApi23TestCases module due to instant app package must target at least API 26. Bug: 123366918 Test: atest CtsNetTestCases --instant Test: atest CtsNetApi23TestCases Test: atest FrameworksNetTests Change-Id: I4e828cbc48143e36c1be38b91c3c698122d4be5a --- tests/cts/net/AndroidManifest.xml | 9 +- tests/cts/net/AndroidTest.xml | 3 +- tests/cts/net/api23Test/Android.bp | 51 +++ tests/cts/net/api23Test/AndroidManifest.xml | 42 ++ tests/cts/net/api23Test/AndroidTest.xml | 30 ++ .../ConnectivityManagerApi23Test.java | 399 ++++++++++++++++++ .../cts/api23test}/ConnectivityReceiver.java | 2 +- .../src/android/net/cts/AirplaneModeTest.java | 3 +- .../net/cts/ConnectivityManagerTest.java | 106 +---- .../src/android/net/cts/IpSecBaseTest.java | 7 + .../src/android/net/cts/IpSecManagerTest.java | 3 + .../android/net/cts/NetworkWatchlistTest.java | 2 + .../cts/SSLCertificateSocketFactoryTest.java | 4 + .../src/android/net/cts/TheaterModeTest.java | 4 +- .../src/android/net/cts/TrafficStatsTest.java | 2 + .../src/android/net/cts/VpnServiceTest.java | 4 + .../net/http/cts/ApacheHttpClientTest.java | 2 + .../net/http/cts/HttpResponseCacheTest.java | 2 + .../android/net/rtp/cts/AudioGroupTest.java | 3 +- .../android/net/rtp/cts/AudioStreamTest.java | 2 + .../net/wifi/aware/cts/SingleDeviceTest.java | 2 + .../android/net/wifi/cts/ConcurrencyTest.java | 2 + .../net/wifi/cts/MulticastLockTest.java | 2 + .../android/net/wifi/cts/NsdManagerTest.java | 2 + .../android/net/wifi/cts/ScanResultTest.java | 2 + .../net/wifi/cts/WifiConfigurationTest.java | 2 + .../wifi/cts/WifiEnterpriseConfigTest.java | 2 + .../android/net/wifi/cts/WifiInfoTest.java | 2 + .../android/net/wifi/cts/WifiLockTest.java | 2 + .../android/net/wifi/cts/WifiManagerTest.java | 2 + .../android/net/wifi/rtt/cts/WifiRttTest.java | 2 + 31 files changed, 594 insertions(+), 108 deletions(-) create mode 100644 tests/cts/net/api23Test/Android.bp create mode 100644 tests/cts/net/api23Test/AndroidManifest.xml create mode 100644 tests/cts/net/api23Test/AndroidTest.xml create mode 100644 tests/cts/net/api23Test/src/android/net/cts/api23test/ConnectivityManagerApi23Test.java rename tests/cts/net/{src/android/net/cts => api23Test/src/android/net/cts/api23test}/ConnectivityReceiver.java (98%) diff --git a/tests/cts/net/AndroidManifest.xml b/tests/cts/net/AndroidManifest.xml index dbd8fef08e..44a00ef619 100644 --- a/tests/cts/net/AndroidManifest.xml +++ b/tests/cts/net/AndroidManifest.xml @@ -16,7 +16,8 @@ --> + package="android.net.cts" + android:targetSandboxVersion="2"> @@ -36,12 +37,6 @@ - - - - - -

This test takes an outbound IPsec packet, reflects it (by flipping IP src/dst), and + * injects it back into the TUN. This test then verifies that a packet with the correct payload + * is found on the specified socket/port. + */ + public void checkTunnelReflected( + int innerFamily, int outerFamily, boolean useEncap, boolean transportInTunnelMode) + throws Exception { + if (!hasTunnelsFeature()) return; + + InetAddress localInner = innerFamily == AF_INET ? LOCAL_INNER_4 : LOCAL_INNER_6; + InetAddress remoteInner = innerFamily == AF_INET ? REMOTE_INNER_4 : REMOTE_INNER_6; + + InetAddress localOuter = outerFamily == AF_INET ? LOCAL_OUTER_4 : LOCAL_OUTER_6; + InetAddress remoteOuter = outerFamily == AF_INET ? REMOTE_OUTER_4 : REMOTE_OUTER_6; + + // Preselect both SPI and encap port, to be used for both inbound and outbound tunnels. + int spi = getRandomSpi(localOuter, remoteOuter); + int expectedPacketSize = + getPacketSize(innerFamily, outerFamily, useEncap, transportInTunnelMode); + + try (IpSecManager.SecurityParameterIndex inTransportSpi = + mISM.allocateSecurityParameterIndex(localInner, spi); + IpSecManager.SecurityParameterIndex outTransportSpi = + mISM.allocateSecurityParameterIndex(remoteInner, spi); + IpSecTransform inTransportTransform = + buildIpSecTransform(sContext, inTransportSpi, null, remoteInner); + IpSecTransform outTransportTransform = + buildIpSecTransform(sContext, outTransportSpi, null, localInner); + UdpEncapsulationSocket encapSocket = mISM.openUdpEncapsulationSocket()) { + + // Run output direction tests + IpSecTunnelTestRunnable outputIpSecTunnelTestRunnable = + new OutputIpSecTunnelTestRunnableFactory() + .getIpSecTunnelTestRunnable( + transportInTunnelMode, + spi, + localInner, + remoteInner, + localOuter, + remoteOuter, + inTransportTransform, + outTransportTransform, + useEncap ? encapSocket.getPort() : 0, + 0, + expectedPacketSize); + int innerSocketPort = + buildTunnelNetworkAndRunTests( + localInner, + remoteInner, + localOuter, + remoteOuter, + spi, + useEncap ? encapSocket : null, + outputIpSecTunnelTestRunnable); + + // Input direction tests, with matching inner socket ports. + IpSecTunnelTestRunnable inputIpSecTunnelTestRunnable = + new InputReflectedIpSecTunnelTestRunnableFactory() + .getIpSecTunnelTestRunnable( + transportInTunnelMode, + spi, + remoteInner, + localInner, + localOuter, + remoteOuter, + inTransportTransform, + outTransportTransform, + useEncap ? encapSocket.getPort() : 0, + innerSocketPort, + expectedPacketSize); + buildTunnelNetworkAndRunTests( + remoteInner, + localInner, + localOuter, + remoteOuter, + spi, + useEncap ? encapSocket : null, + inputIpSecTunnelTestRunnable); + } } public void checkTunnel( @@ -434,7 +577,7 @@ public class IpSecManagerTunnelTest extends IpSecBaseTest { int outerFamily, boolean useEncap, boolean transportInTunnelMode, - TestRunnableFactory factory) + IpSecTunnelTestRunnableFactory factory) throws Exception { if (!hasTunnelsFeature()) return; @@ -461,14 +604,14 @@ public class IpSecManagerTunnelTest extends IpSecBaseTest { buildIpSecTransform(sContext, outTransportSpi, null, localInner); UdpEncapsulationSocket encapSocket = mISM.openUdpEncapsulationSocket()) { - buildTunnelAndNetwork( + buildTunnelNetworkAndRunTests( localInner, remoteInner, localOuter, remoteOuter, spi, useEncap ? encapSocket : null, - factory.getTestRunnable( + factory.getIpSecTunnelTestRunnable( transportInTunnelMode, spi, localInner, @@ -478,21 +621,23 @@ public class IpSecManagerTunnelTest extends IpSecBaseTest { inTransportTransform, outTransportTransform, useEncap ? encapSocket.getPort() : 0, + 0, expectedPacketSize)); } } - private void buildTunnelAndNetwork( + private int buildTunnelNetworkAndRunTests( InetAddress localInner, InetAddress remoteInner, InetAddress localOuter, InetAddress remoteOuter, int spi, UdpEncapsulationSocket encapSocket, - TestRunnable test) + IpSecTunnelTestRunnable test) throws Exception { int innerPrefixLen = localInner instanceof Inet6Address ? IP6_PREFIX_LEN : IP4_PREFIX_LEN; TestNetworkCallback testNetworkCb = null; + int innerSocketPort; try (IpSecManager.SecurityParameterIndex inSpi = mISM.allocateSecurityParameterIndex(localOuter, spi); @@ -534,7 +679,7 @@ public class IpSecManagerTunnelTest extends IpSecBaseTest { mISM.applyTunnelModeTransform( tunnelIface, IpSecManager.DIRECTION_OUT, outTransform); - test.run(testNetwork); + innerSocketPort = test.run(testNetwork); } // Teardown the test network @@ -553,6 +698,8 @@ public class IpSecManagerTunnelTest extends IpSecBaseTest { sCM.unregisterNetworkCallback(testNetworkCb); } } + + return innerSocketPort; } private static void receiveAndValidatePacket(JavaUdpSocket socket) throws Exception { @@ -675,36 +822,66 @@ public class IpSecManagerTunnelTest extends IpSecBaseTest { checkTunnelInput(AF_INET, AF_INET, false, true); } + @Test + public void testTransportInTunnelModeV4InV4Reflected() throws Exception { + checkTunnelReflected(AF_INET, AF_INET, false, true); + } + @Test public void testTransportInTunnelModeV4InV4UdpEncap() throws Exception { checkTunnelOutput(AF_INET, AF_INET, true, true); checkTunnelInput(AF_INET, AF_INET, true, true); } + @Test + public void testTransportInTunnelModeV4InV4UdpEncapReflected() throws Exception { + checkTunnelReflected(AF_INET, AF_INET, false, true); + } + @Test public void testTransportInTunnelModeV4InV6() throws Exception { checkTunnelOutput(AF_INET, AF_INET6, false, true); checkTunnelInput(AF_INET, AF_INET6, false, true); } + @Test + public void testTransportInTunnelModeV4InV6Reflected() throws Exception { + checkTunnelReflected(AF_INET, AF_INET, false, true); + } + @Test public void testTransportInTunnelModeV6InV4() throws Exception { checkTunnelOutput(AF_INET6, AF_INET, false, true); checkTunnelInput(AF_INET6, AF_INET, false, true); } + @Test + public void testTransportInTunnelModeV6InV4Reflected() throws Exception { + checkTunnelReflected(AF_INET, AF_INET, false, true); + } + @Test public void testTransportInTunnelModeV6InV4UdpEncap() throws Exception { checkTunnelOutput(AF_INET6, AF_INET, true, true); checkTunnelInput(AF_INET6, AF_INET, true, true); } + @Test + public void testTransportInTunnelModeV6InV4UdpEncapReflected() throws Exception { + checkTunnelReflected(AF_INET, AF_INET, false, true); + } + @Test public void testTransportInTunnelModeV6InV6() throws Exception { checkTunnelOutput(AF_INET, AF_INET6, false, true); checkTunnelInput(AF_INET, AF_INET6, false, true); } + @Test + public void testTransportInTunnelModeV6InV6Reflected() throws Exception { + checkTunnelReflected(AF_INET, AF_INET, false, true); + } + // Tunnel mode tests @Test public void testTunnelV4InV4() throws Exception { @@ -712,33 +889,63 @@ public class IpSecManagerTunnelTest extends IpSecBaseTest { checkTunnelInput(AF_INET, AF_INET, false, false); } + @Test + public void testTunnelV4InV4Reflected() throws Exception { + checkTunnelReflected(AF_INET, AF_INET, false, false); + } + @Test public void testTunnelV4InV4UdpEncap() throws Exception { checkTunnelOutput(AF_INET, AF_INET, true, false); checkTunnelInput(AF_INET, AF_INET, true, false); } + @Test + public void testTunnelV4InV4UdpEncapReflected() throws Exception { + checkTunnelReflected(AF_INET, AF_INET, true, false); + } + @Test public void testTunnelV4InV6() throws Exception { checkTunnelOutput(AF_INET, AF_INET6, false, false); checkTunnelInput(AF_INET, AF_INET6, false, false); } + @Test + public void testTunnelV4InV6Reflected() throws Exception { + checkTunnelReflected(AF_INET, AF_INET6, false, false); + } + @Test public void testTunnelV6InV4() throws Exception { checkTunnelOutput(AF_INET6, AF_INET, false, false); checkTunnelInput(AF_INET6, AF_INET, false, false); } + @Test + public void testTunnelV6InV4Reflected() throws Exception { + checkTunnelReflected(AF_INET6, AF_INET, false, false); + } + @Test public void testTunnelV6InV4UdpEncap() throws Exception { checkTunnelOutput(AF_INET6, AF_INET, true, false); checkTunnelInput(AF_INET6, AF_INET, true, false); } + @Test + public void testTunnelV6InV4UdpEncapReflected() throws Exception { + checkTunnelReflected(AF_INET6, AF_INET, true, false); + } + @Test public void testTunnelV6InV6() throws Exception { checkTunnelOutput(AF_INET6, AF_INET6, false, false); checkTunnelInput(AF_INET6, AF_INET6, false, false); } + + @Test + public void testTunnelV6InV6Reflected() throws Exception { + checkTunnelReflected(AF_INET6, AF_INET6, false, false); + } } From d8a36dd745f358a242b4a494c1c8a1e7725af47a Mon Sep 17 00:00:00 2001 From: Benedict Wong Date: Mon, 20 May 2019 11:58:26 -0700 Subject: [PATCH 63/71] Remove mContext from IpSecBaseTest This commit removes the mContext from IpSecBaseTest, and replaces it with InstrumentationRegistry.getContext(). Bug: 72950854 Test: Ran on devices, passing. Merged-In: If6fa359825aa9d1f7d4c8d49aba7a34925c073ed Change-Id: If6fa359825aa9d1f7d4c8d49aba7a34925c073ed (cherry picked from commit 69760fb5b62ae0e36c2a88bb20502dead3d7589b) --- tests/cts/net/src/android/net/cts/IpSecBaseTest.java | 4 +--- tests/cts/net/src/android/net/cts/IpSecManagerTest.java | 8 +++++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/tests/cts/net/src/android/net/cts/IpSecBaseTest.java b/tests/cts/net/src/android/net/cts/IpSecBaseTest.java index 26049cc174..10e43e7b6a 100644 --- a/tests/cts/net/src/android/net/cts/IpSecBaseTest.java +++ b/tests/cts/net/src/android/net/cts/IpSecBaseTest.java @@ -76,11 +76,9 @@ public class IpSecBaseTest { protected ConnectivityManager mCM; protected IpSecManager mISM; - protected Context mContext; @Before public void setUp() throws Exception { - mContext = InstrumentationRegistry.getContext(); mISM = (IpSecManager) InstrumentationRegistry.getContext() @@ -475,7 +473,7 @@ public class IpSecBaseTest { private IpSecTransform buildDefaultTransform(InetAddress localAddr) throws Exception { try (IpSecManager.SecurityParameterIndex spi = mISM.allocateSecurityParameterIndex(localAddr)) { - return buildIpSecTransform(mContext, spi, null, localAddr); + return buildIpSecTransform(InstrumentationRegistry.getContext(), spi, null, localAddr); } } diff --git a/tests/cts/net/src/android/net/cts/IpSecManagerTest.java b/tests/cts/net/src/android/net/cts/IpSecManagerTest.java index d6b8a968d2..355b496829 100644 --- a/tests/cts/net/src/android/net/cts/IpSecManagerTest.java +++ b/tests/cts/net/src/android/net/cts/IpSecManagerTest.java @@ -41,6 +41,7 @@ import android.system.ErrnoException; import android.system.Os; import android.system.OsConstants; +import androidx.test.InstrumentationRegistry; import androidx.test.runner.AndroidJUnit4; import java.io.FileDescriptor; @@ -238,7 +239,7 @@ public class IpSecManagerTest extends IpSecBaseTest { mISM.allocateSecurityParameterIndex(localAddr); IpSecTransform transform = - new IpSecTransform.Builder(mContext) + new IpSecTransform.Builder(InstrumentationRegistry.getContext()) .setEncryption(new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY)) .setAuthentication( new IpSecAlgorithm( @@ -456,7 +457,8 @@ public class IpSecManagerTest extends IpSecBaseTest { IpSecManager.SecurityParameterIndex spi = mISM.allocateSecurityParameterIndex(local)) { - IpSecTransform.Builder transformBuilder = new IpSecTransform.Builder(mContext); + IpSecTransform.Builder transformBuilder = + new IpSecTransform.Builder(InstrumentationRegistry.getContext()); if (crypt != null) { transformBuilder.setEncryption(crypt); } @@ -617,7 +619,7 @@ public class IpSecManagerTest extends IpSecBaseTest { try (IpSecManager.SecurityParameterIndex spi = mISM.allocateSecurityParameterIndex(local); IpSecTransform transform = - new IpSecTransform.Builder(mContext) + new IpSecTransform.Builder(InstrumentationRegistry.getContext()) .setEncryption(crypt) .setAuthentication(auth) .setIpv4Encapsulation(encapSocket, encapSocket.getPort()) From 66fe5244ad2916c4ec9c7eda977df234fb88d572 Mon Sep 17 00:00:00 2001 From: Tomasz Wasilczyk Date: Fri, 31 May 2019 15:13:31 -0700 Subject: [PATCH 64/71] Fix testNetworkSettingsPermission for headless User 0 This test fails on devices with headless user 0 when it tries to verify apps with android:sharedUserId="android.uid.system" (and without explicit ask for NETWORK_SETTINGS). Such apps get this permission by default, but when running on user 1 they get UID 1001000, what doesn't match SYSTEM_UID=1000. By the chance of modifying this code, let's also add more verbose error message (with UID), simplify it and reduce indentation count. Bug: 120143468 Test: atest android.net.wifi.cts.WifiManagerTest#testNetworkSettingsPermission Change-Id: Ifc09320cf738a518003126fad1ce31f5e38a3aff --- tests/cts/net/AndroidManifest.xml | 1 + .../android/net/wifi/cts/WifiManagerTest.java | 30 +++++++++---------- 2 files changed, 16 insertions(+), 15 deletions(-) diff --git a/tests/cts/net/AndroidManifest.xml b/tests/cts/net/AndroidManifest.xml index 44a00ef619..c2b3bf77ad 100644 --- a/tests/cts/net/AndroidManifest.xml +++ b/tests/cts/net/AndroidManifest.xml @@ -27,6 +27,7 @@ + diff --git a/tests/cts/net/src/android/net/wifi/cts/WifiManagerTest.java b/tests/cts/net/src/android/net/wifi/cts/WifiManagerTest.java index 75764508c8..fbf1abd3b8 100644 --- a/tests/cts/net/src/android/net/wifi/cts/WifiManagerTest.java +++ b/tests/cts/net/src/android/net/wifi/cts/WifiManagerTest.java @@ -36,6 +36,7 @@ import android.net.wifi.hotspot2.pps.Credential; import android.net.wifi.hotspot2.pps.HomeSp; import android.os.Process; import android.os.SystemClock; +import android.os.UserHandle; import android.platform.test.annotations.AppModeFull; import android.provider.Settings; import android.support.test.uiautomator.UiDevice; @@ -770,21 +771,20 @@ public class WifiManagerTest extends AndroidTestCase { }, PackageManager.MATCH_UNINSTALLED_PACKAGES); for (PackageInfo pi : holding) { String packageName = pi.packageName; - if (allowedPackages.contains(packageName)) { - // this is an explicitly allowed package - } else { - // now check if the packages are from allowed UIDs - boolean allowed = false; - try { - if (allowedUIDs.contains(pm.getPackageUid(packageName, 0))) { - allowed = true; - Log.d(TAG, packageName + " is on an allowed UID"); - } - } catch (PackageManager.NameNotFoundException e) { } - if (!allowed) { - fail("The NETWORK_SETTINGS permission must not be held by " - + packageName + " and must be revoked for security reasons"); - } + + // this is an explicitly allowed package + if (allowedPackages.contains(packageName)) continue; + + // now check if the packages are from allowed UIDs + int uid = -1; + try { + uid = pm.getPackageUidAsUser(packageName, UserHandle.USER_SYSTEM); + } catch (PackageManager.NameNotFoundException e) { + continue; + } + if (!allowedUIDs.contains(uid)) { + fail("The NETWORK_SETTINGS permission must not be held by " + packageName + + ":" + uid + " and must be revoked for security reasons"); } } } From 802549c8de99517e1fa4a174abbf7c06078526dc Mon Sep 17 00:00:00 2001 From: Sudheer Shanka Date: Wed, 5 Jun 2019 18:27:40 -0700 Subject: [PATCH 65/71] Skip battery saver related tests on unsupported devices. Bug: 133761301 Test: atest com.android.cts.net.HostsideRestrictBackgroundNetworkTests Change-Id: Ifec84425febf38d732367fae6b43fa80c427c79f --- .../net/hostside/AbstractAppIdleTestCase.java | 5 ++++ .../AbstractBatterySaverModeTestCase.java | 18 +++++++++---- ...ractRestrictBackgroundNetworkTestCase.java | 8 ++++++ .../cts/net/hostside/MixedModesTest.java | 25 +++++++++++++++++++ 4 files changed, 51 insertions(+), 5 deletions(-) diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractAppIdleTestCase.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractAppIdleTestCase.java index 7bf7bd44f4..55bd406c64 100644 --- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractAppIdleTestCase.java +++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractAppIdleTestCase.java @@ -150,6 +150,11 @@ abstract class AbstractAppIdleTestCase extends AbstractRestrictBackgroundNetwork } public void testAppIdleNetworkAccess_whenCharging() throws Exception { + if (!isBatterySaverSupported()) { + Log.i(TAG, "Skipping " + getClass() + "." + getName() + + "() because device does not support Battery saver mode"); + return; + } if (!isSupported()) return; // Check that app is paroled when charging diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractBatterySaverModeTestCase.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractBatterySaverModeTestCase.java index 28175b8784..931376b9fe 100644 --- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractBatterySaverModeTestCase.java +++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractBatterySaverModeTestCase.java @@ -16,6 +16,7 @@ package com.android.cts.net.hostside; +import android.text.TextUtils; import android.util.Log; /** @@ -52,12 +53,19 @@ abstract class AbstractBatterySaverModeTestCase extends AbstractRestrictBackgrou @Override protected boolean isSupported() throws Exception { - boolean supported = isDozeModeEnabled(); - if (!supported) { - Log.i(TAG, "Skipping " + getClass() + "." + getName() - + "() because device does not support Doze Mode"); + String unSupported = ""; + if (!isDozeModeEnabled()) { + unSupported += "Doze mode,"; } - return supported; + if (!isBatterySaverSupported()) { + unSupported += "Battery saver mode,"; + } + if (!TextUtils.isEmpty(unSupported)) { + Log.i(TAG, "Skipping " + getClass() + "." + getName() + + "() because device does not support " + unSupported); + return false; + } + return true; } /** diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java index 6dfa2f3aef..40d7e34fcc 100644 --- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java +++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java @@ -34,6 +34,7 @@ import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; +import android.content.pm.PackageManager; import android.net.ConnectivityManager; import android.net.NetworkInfo; import android.net.NetworkInfo.DetailedState; @@ -43,12 +44,15 @@ import android.os.BatteryManager; import android.os.Binder; import android.os.Bundle; import android.os.SystemClock; +import android.os.SystemProperties; import android.provider.Settings; import android.service.notification.NotificationListenerService; import android.test.InstrumentationTestCase; import android.text.TextUtils; import android.util.Log; +import com.android.compatibility.common.util.BatteryUtils; + import java.util.concurrent.CountDownLatch; import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.TimeUnit; @@ -311,6 +315,10 @@ abstract class AbstractRestrictBackgroundNetworkTestCase extends Instrumentation return mSupported; } + protected boolean isBatterySaverSupported() { + return BatteryUtils.isBatterySaverSupported(); + } + /** * Asserts that an app always have access while on foreground or running a foreground service. * diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/MixedModesTest.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/MixedModesTest.java index 74875cd2c9..b1a21867b3 100644 --- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/MixedModesTest.java +++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/MixedModesTest.java @@ -71,6 +71,11 @@ public class MixedModesTest extends AbstractRestrictBackgroundNetworkTestCase { * Tests all DS ON and BS ON scenarios from network-policy-restrictions.md on metered networks. */ public void testDataAndBatterySaverModes_meteredNetwork() throws Exception { + if (!isBatterySaverSupported()) { + Log.i(TAG, "Skipping " + getClass() + "." + getName() + + "() because device does not support Battery saver mode"); + return; + } if (!isSupported()) return; Log.i(TAG, "testDataAndBatterySaverModes_meteredNetwork() tests"); @@ -141,6 +146,11 @@ public class MixedModesTest extends AbstractRestrictBackgroundNetworkTestCase { * networks. */ public void testDataAndBatterySaverModes_nonMeteredNetwork() throws Exception { + if (!isBatterySaverSupported()) { + Log.i(TAG, "Skipping " + getClass() + "." + getName() + + "() because device does not support Battery saver mode"); + return; + } if (!isSupported()) return; if (!setUnmeteredNetwork()) { @@ -206,6 +216,11 @@ public class MixedModesTest extends AbstractRestrictBackgroundNetworkTestCase { * are enabled. */ public void testDozeAndBatterySaverMode_powerSaveWhitelists() throws Exception { + if (!isBatterySaverSupported()) { + Log.i(TAG, "Skipping " + getClass() + "." + getName() + + "() because device does not support Battery saver mode"); + return; + } if (!isSupported()) { return; } @@ -285,6 +300,11 @@ public class MixedModesTest extends AbstractRestrictBackgroundNetworkTestCase { } public void testAppIdleAndBatterySaver_tempPowerSaveWhitelists() throws Exception { + if (!isBatterySaverSupported()) { + Log.i(TAG, "Skipping " + getClass() + "." + getName() + + "() because device does not support Battery saver mode"); + return; + } if (!isSupported()) { return; } @@ -361,6 +381,11 @@ public class MixedModesTest extends AbstractRestrictBackgroundNetworkTestCase { } public void testAppIdleAndBatterySaver_tempPowerSaveAndAppIdleWhitelists() throws Exception { + if (!isBatterySaverSupported()) { + Log.i(TAG, "Skipping " + getClass() + "." + getName() + + "() because device does not support Battery saver mode"); + return; + } if (!isSupported()) { return; } From 8371c77499889e22437eafeece7ac022069e5d64 Mon Sep 17 00:00:00 2001 From: Sudheer Shanka Date: Wed, 5 Jun 2019 18:27:40 -0700 Subject: [PATCH 66/71] Skip battery saver related tests on unsupported devices. Bug: 133761301 Test: atest com.android.cts.net.HostsideRestrictBackgroundNetworkTests Change-Id: Ifec84425febf38d732367fae6b43fa80c427c79f Merged-In: Ifec84425febf38d732367fae6b43fa80c427c79f --- .../net/hostside/AbstractAppIdleTestCase.java | 5 +++++ .../AbstractBatterySaverModeTestCase.java | 18 ++++++++++++----- ...ractRestrictBackgroundNetworkTestCase.java | 7 +++++++ .../cts/net/hostside/MixedModesTest.java | 20 +++++++++++++++++++ 4 files changed, 45 insertions(+), 5 deletions(-) diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractAppIdleTestCase.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractAppIdleTestCase.java index 0e141c05ad..1f5984a704 100644 --- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractAppIdleTestCase.java +++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractAppIdleTestCase.java @@ -150,6 +150,11 @@ abstract class AbstractAppIdleTestCase extends AbstractRestrictBackgroundNetwork } public void testAppIdleNetworkAccess_whenCharging() throws Exception { + if (!isBatterySaverSupported()) { + Log.i(TAG, "Skipping " + getClass() + "." + getName() + + "() because device does not support Battery saver mode"); + return; + } if (!isSupported()) return; // Check that app is paroled when charging diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractBatterySaverModeTestCase.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractBatterySaverModeTestCase.java index 28175b8784..931376b9fe 100644 --- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractBatterySaverModeTestCase.java +++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractBatterySaverModeTestCase.java @@ -16,6 +16,7 @@ package com.android.cts.net.hostside; +import android.text.TextUtils; import android.util.Log; /** @@ -52,12 +53,19 @@ abstract class AbstractBatterySaverModeTestCase extends AbstractRestrictBackgrou @Override protected boolean isSupported() throws Exception { - boolean supported = isDozeModeEnabled(); - if (!supported) { - Log.i(TAG, "Skipping " + getClass() + "." + getName() - + "() because device does not support Doze Mode"); + String unSupported = ""; + if (!isDozeModeEnabled()) { + unSupported += "Doze mode,"; } - return supported; + if (!isBatterySaverSupported()) { + unSupported += "Battery saver mode,"; + } + if (!TextUtils.isEmpty(unSupported)) { + Log.i(TAG, "Skipping " + getClass() + "." + getName() + + "() because device does not support " + unSupported); + return false; + } + return true; } /** diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java index 5232372047..1844878f64 100644 --- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java +++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java @@ -38,6 +38,7 @@ import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; +import android.content.pm.PackageManager; import android.net.ConnectivityManager; import android.net.NetworkInfo; import android.net.NetworkInfo.DetailedState; @@ -53,6 +54,8 @@ import android.test.InstrumentationTestCase; import android.text.TextUtils; import android.util.Log; +import com.android.compatibility.common.util.BatteryUtils; + /** * Superclass for tests related to background network restrictions. */ @@ -301,6 +304,10 @@ abstract class AbstractRestrictBackgroundNetworkTestCase extends Instrumentation return mSupported; } + protected boolean isBatterySaverSupported() throws Exception { + return BatteryUtils.isBatterySaverSupported(); + } + /** * Asserts that an app always have access while on foreground or running a foreground service. * diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/MixedModesTest.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/MixedModesTest.java index 87f9d7738d..7f65b55b48 100644 --- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/MixedModesTest.java +++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/MixedModesTest.java @@ -71,6 +71,11 @@ public class MixedModesTest extends AbstractRestrictBackgroundNetworkTestCase { * Tests all DS ON and BS ON scenarios from network-policy-restrictions.md on metered networks. */ public void testDataAndBatterySaverModes_meteredNetwork() throws Exception { + if (!isBatterySaverSupported()) { + Log.i(TAG, "Skipping " + getClass() + "." + getName() + + "() because device does not support Battery saver mode"); + return; + } if (!isSupported()) return; Log.i(TAG, "testDataAndBatterySaverModes_meteredNetwork() tests"); @@ -141,6 +146,11 @@ public class MixedModesTest extends AbstractRestrictBackgroundNetworkTestCase { * networks. */ public void testDataAndBatterySaverModes_nonMeteredNetwork() throws Exception { + if (!isBatterySaverSupported()) { + Log.i(TAG, "Skipping " + getClass() + "." + getName() + + "() because device does not support Battery saver mode"); + return; + } if (!isSupported()) return; if (!setUnmeteredNetwork()) { @@ -206,6 +216,11 @@ public class MixedModesTest extends AbstractRestrictBackgroundNetworkTestCase { * are enabled. */ public void testDozeAndBatterySaverMode_powerSaveWhitelists() throws Exception { + if (!isBatterySaverSupported()) { + Log.i(TAG, "Skipping " + getClass() + "." + getName() + + "() because device does not support Battery saver mode"); + return; + } if (!isSupported()) { return; } @@ -285,6 +300,11 @@ public class MixedModesTest extends AbstractRestrictBackgroundNetworkTestCase { } public void testAppIdleAndBatterySaver_tempPowerSaveWhitelists() throws Exception { + if (!isBatterySaverSupported()) { + Log.i(TAG, "Skipping " + getClass() + "." + getName() + + "() because device does not support Battery saver mode"); + return; + } if (!isSupported()) { return; } From 50795d03cddf9ad6f8e3c7f5926b82c60ffe21d6 Mon Sep 17 00:00:00 2001 From: Pete Bentley Date: Fri, 7 Jun 2019 18:41:48 +0100 Subject: [PATCH 67/71] Update test host used for TLS host verification. Temporary fix, this is still brittle to certificate changes on the test host. Bug: 134532880 Test: atest android.net.cts.SSLCertificateSocketFactoryTest Change-Id: I6e8c8757963ef46009767925bfa512127d9daba7 Merged-In: I6e8c8757963ef46009767925bfa512127d9daba7 (cherry picked from commit 166e7121b173f2a4e3d6a9ded213e4c8679a9cfb) --- .../src/android/net/cts/SSLCertificateSocketFactoryTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/cts/net/src/android/net/cts/SSLCertificateSocketFactoryTest.java b/tests/cts/net/src/android/net/cts/SSLCertificateSocketFactoryTest.java index 525045057b..01ac3fda08 100644 --- a/tests/cts/net/src/android/net/cts/SSLCertificateSocketFactoryTest.java +++ b/tests/cts/net/src/android/net/cts/SSLCertificateSocketFactoryTest.java @@ -92,7 +92,7 @@ public class SSLCertificateSocketFactoryTest extends AndroidTestCase { // a host and port that are expected to be available but have // a cert with a different CN, in this case CN=mail.google.com - private static String TEST_CREATE_SOCKET_HOST = "googlemail.com"; + private static String TEST_CREATE_SOCKET_HOST = "www3.l.google.com"; private static int TEST_CREATE_SOCKET_PORT = 443; /** From d3b7dec47352efcd4342bbc1adf82687bb442efe Mon Sep 17 00:00:00 2001 From: Luke Huang Date: Mon, 10 Jun 2019 14:16:41 +0800 Subject: [PATCH 68/71] Fix DnsResolverTest for instant mode add AppModeFull@ to DnsResolverTest since WRITE_SECURE_SETTINGS could not be ganted in instant mode. Bug: 134897744 Test: atest DnsResolverTest atest DnsResolverTest --instant Change-Id: I267c19af1a1c5544ca752a364335ec728a478bb2 (cherry picked from commit 2af244f4127883ed967089f550f2cfe07936416d) --- tests/cts/net/src/android/net/cts/DnsResolverTest.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/cts/net/src/android/net/cts/DnsResolverTest.java b/tests/cts/net/src/android/net/cts/DnsResolverTest.java index e16fce09bf..1ff2090bc5 100644 --- a/tests/cts/net/src/android/net/cts/DnsResolverTest.java +++ b/tests/cts/net/src/android/net/cts/DnsResolverTest.java @@ -39,6 +39,7 @@ import android.net.ParseException; import android.os.CancellationSignal; import android.os.Handler; import android.os.Looper; +import android.platform.test.annotations.AppModeFull; import android.provider.Settings; import android.system.ErrnoException; import android.test.AndroidTestCase; @@ -53,6 +54,7 @@ import java.util.concurrent.CountDownLatch; import java.util.concurrent.Executor; import java.util.concurrent.TimeUnit; +@AppModeFull(reason = "WRITE_SECURE_SETTINGS permission can't be granted to instant apps") public class DnsResolverTest extends AndroidTestCase { private static final String TAG = "DnsResolverTest"; private static final char[] HEX_CHARS = { From 5e43421294d03f6ae69527ee4de9c05dd0a8c877 Mon Sep 17 00:00:00 2001 From: Luke Huang Date: Tue, 11 Jun 2019 15:49:08 +0800 Subject: [PATCH 69/71] Add test with inline executor for DnsResolverTest Makes general query test cases also take inline executor. The new added test case testSequentialQuery with inline executor will only pass after aosp/980686. Bug: 134310704 Test: atest DnsResolverTest atest DnsResolverTest --instant Change-Id: I135358fe45652277ed795a2f359f44f4db787c08 (cherry picked from commit 04596294eea3e5db4fd487cf6f8ef598daac606a) --- .../src/android/net/cts/DnsResolverTest.java | 115 +++++++++++++++--- 1 file changed, 101 insertions(+), 14 deletions(-) diff --git a/tests/cts/net/src/android/net/cts/DnsResolverTest.java b/tests/cts/net/src/android/net/cts/DnsResolverTest.java index 1ff2090bc5..ef8badd32a 100644 --- a/tests/cts/net/src/android/net/cts/DnsResolverTest.java +++ b/tests/cts/net/src/android/net/cts/DnsResolverTest.java @@ -80,12 +80,14 @@ public class DnsResolverTest extends AndroidTestCase { static final int TIMEOUT_MS = 12_000; static final int CANCEL_TIMEOUT_MS = 3_000; static final int CANCEL_RETRY_TIMES = 5; + static final int QUERY_TIMES = 10; static final int NXDOMAIN = 3; static final int PRIVATE_DNS_SETTING_TIMEOUT_MS = 2_000; private ContentResolver mCR; private ConnectivityManager mCM; private Executor mExecutor; + private Executor mExecutorInline; private DnsResolver mDns; private String mOldMode; @@ -97,6 +99,7 @@ public class DnsResolverTest extends AndroidTestCase { mCM = (ConnectivityManager) getContext().getSystemService(Context.CONNECTIVITY_SERVICE); mDns = DnsResolver.getInstance(); mExecutor = new Handler(Looper.getMainLooper())::post; + mExecutorInline = (Runnable r) -> r.run(); mCR = getContext().getContentResolver(); storePrivateDnsSetting(); } @@ -274,12 +277,44 @@ public class DnsResolverTest extends AndroidTestCase { } } - public void testRawQuery() throws InterruptedException { + public void testRawQuery() throws Exception { + doTestRawQuery(mExecutor); + } + + public void testRawQueryInline() throws Exception { + doTestRawQuery(mExecutorInline); + } + + public void testRawQueryBlob() throws Exception { + doTestRawQueryBlob(mExecutor); + } + + public void testRawQueryBlobInline() throws Exception { + doTestRawQueryBlob(mExecutorInline); + } + + public void testRawQueryRoot() throws Exception { + doTestRawQueryRoot(mExecutor); + } + + public void testRawQueryRootInline() throws Exception { + doTestRawQueryRoot(mExecutorInline); + } + + public void testRawQueryNXDomain() throws Exception { + doTestRawQueryNXDomain(mExecutor); + } + + public void testRawQueryNXDomainInline() throws Exception { + doTestRawQueryNXDomain(mExecutorInline); + } + + public void doTestRawQuery(Executor executor) throws InterruptedException { final String msg = "RawQuery " + TEST_DOMAIN; for (Network network : getTestableNetworks()) { final VerifyCancelCallback callback = new VerifyCancelCallback(msg); mDns.rawQuery(network, TEST_DOMAIN, CLASS_IN, TYPE_AAAA, FLAG_NO_CACHE_LOOKUP, - mExecutor, null, callback); + executor, null, callback); assertTrue(msg + " but no answer after " + TIMEOUT_MS + "ms.", callback.waitForAnswer()); @@ -287,7 +322,7 @@ public class DnsResolverTest extends AndroidTestCase { } } - public void testRawQueryBlob() throws InterruptedException { + public void doTestRawQueryBlob(Executor executor) throws InterruptedException { final byte[] blob = new byte[]{ /* Header */ 0x55, 0x66, /* Transaction ID */ @@ -305,7 +340,7 @@ public class DnsResolverTest extends AndroidTestCase { final String msg = "RawQuery blob " + byteArrayToHexString(blob); for (Network network : getTestableNetworks()) { final VerifyCancelCallback callback = new VerifyCancelCallback(msg); - mDns.rawQuery(network, blob, FLAG_NO_CACHE_LOOKUP, mExecutor, null, callback); + mDns.rawQuery(network, blob, FLAG_NO_CACHE_LOOKUP, executor, null, callback); assertTrue(msg + " but no answer after " + TIMEOUT_MS + "ms.", callback.waitForAnswer()); @@ -313,13 +348,13 @@ public class DnsResolverTest extends AndroidTestCase { } } - public void testRawQueryRoot() throws InterruptedException { + public void doTestRawQueryRoot(Executor executor) throws InterruptedException { final String dname = ""; final String msg = "RawQuery empty dname(ROOT) "; for (Network network : getTestableNetworks()) { final VerifyCancelCallback callback = new VerifyCancelCallback(msg); mDns.rawQuery(network, dname, CLASS_IN, TYPE_AAAA, FLAG_NO_CACHE_LOOKUP, - mExecutor, null, callback); + executor, null, callback); assertTrue(msg + " but no answer after " + TIMEOUT_MS + "ms.", callback.waitForAnswer()); @@ -328,13 +363,13 @@ public class DnsResolverTest extends AndroidTestCase { } } - public void testRawQueryNXDomain() throws InterruptedException { + public void doTestRawQueryNXDomain(Executor executor) throws InterruptedException { final String dname = "test1-nx.metric.gstatic.com"; final String msg = "RawQuery " + dname; for (Network network : getTestableNetworks()) { final VerifyCancelCallback callback = new VerifyCancelCallback(msg); mDns.rawQuery(network, dname, CLASS_IN, TYPE_AAAA, FLAG_NO_CACHE_LOOKUP, - mExecutor, null, callback); + executor, null, callback); assertTrue(msg + " but no answer after " + TIMEOUT_MS + "ms.", callback.waitForAnswer()); @@ -476,12 +511,44 @@ public class DnsResolverTest extends AndroidTestCase { } } - public void testQueryForInetAddress() throws InterruptedException { + public void testQueryForInetAddress() throws Exception { + doTestQueryForInetAddress(mExecutor); + } + + public void testQueryForInetAddressInline() throws Exception { + doTestQueryForInetAddress(mExecutorInline); + } + + public void testQueryForInetAddressIpv4() throws Exception { + doTestQueryForInetAddressIpv4(mExecutor); + } + + public void testQueryForInetAddressIpv4Inline() throws Exception { + doTestQueryForInetAddressIpv4(mExecutorInline); + } + + public void testQueryForInetAddressIpv6() throws Exception { + doTestQueryForInetAddressIpv6(mExecutor); + } + + public void testQueryForInetAddressIpv6Inline() throws Exception { + doTestQueryForInetAddressIpv6(mExecutorInline); + } + + public void testContinuousQueries() throws Exception { + doTestContinuousQueries(mExecutor); + } + + public void testContinuousQueriesInline() throws Exception { + doTestContinuousQueries(mExecutorInline); + } + + public void doTestQueryForInetAddress(Executor executor) throws InterruptedException { final String msg = "Test query for InetAddress " + TEST_DOMAIN; for (Network network : getTestableNetworks()) { final VerifyCancelInetAddressCallback callback = new VerifyCancelInetAddressCallback(msg, null); - mDns.query(network, TEST_DOMAIN, FLAG_NO_CACHE_LOOKUP, mExecutor, null, callback); + mDns.query(network, TEST_DOMAIN, FLAG_NO_CACHE_LOOKUP, executor, null, callback); assertTrue(msg + " but no answer after " + TIMEOUT_MS + "ms.", callback.waitForAnswer()); @@ -518,13 +585,13 @@ public class DnsResolverTest extends AndroidTestCase { } } - public void testQueryForInetAddressIpv4() throws InterruptedException { + public void doTestQueryForInetAddressIpv4(Executor executor) throws InterruptedException { final String msg = "Test query for IPv4 InetAddress " + TEST_DOMAIN; for (Network network : getTestableNetworks()) { final VerifyCancelInetAddressCallback callback = new VerifyCancelInetAddressCallback(msg, null); mDns.query(network, TEST_DOMAIN, TYPE_A, FLAG_NO_CACHE_LOOKUP, - mExecutor, null, callback); + executor, null, callback); assertTrue(msg + " but no answer after " + TIMEOUT_MS + "ms.", callback.waitForAnswer()); @@ -533,13 +600,13 @@ public class DnsResolverTest extends AndroidTestCase { } } - public void testQueryForInetAddressIpv6() throws InterruptedException { + public void doTestQueryForInetAddressIpv6(Executor executor) throws InterruptedException { final String msg = "Test query for IPv6 InetAddress " + TEST_DOMAIN; for (Network network : getTestableNetworks()) { final VerifyCancelInetAddressCallback callback = new VerifyCancelInetAddressCallback(msg, null); mDns.query(network, TEST_DOMAIN, TYPE_AAAA, FLAG_NO_CACHE_LOOKUP, - mExecutor, null, callback); + executor, null, callback); assertTrue(msg + " but no answer after " + TIMEOUT_MS + "ms.", callback.waitForAnswer()); @@ -632,4 +699,24 @@ public class DnsResolverTest extends AndroidTestCase { mCM.bindProcessToNetwork(null); } } + + public void doTestContinuousQueries(Executor executor) throws InterruptedException { + final String msg = "Test continuous " + QUERY_TIMES + " queries " + TEST_DOMAIN; + for (Network network : getTestableNetworks()) { + for (int i = 0; i < QUERY_TIMES ; ++i) { + final VerifyCancelInetAddressCallback callback = + new VerifyCancelInetAddressCallback(msg, null); + // query v6/v4 in turn + boolean queryV6 = (i % 2 == 0); + mDns.query(network, TEST_DOMAIN, queryV6 ? TYPE_AAAA : TYPE_A, + FLAG_NO_CACHE_LOOKUP, executor, null, callback); + + assertTrue(msg + " but no answer after " + TIMEOUT_MS + "ms.", + callback.waitForAnswer()); + assertTrue(msg + " returned 0 results", !callback.isAnswerEmpty()); + assertTrue(msg + " returned " + (queryV6 ? "Ipv4" : "Ipv6") + " results", + queryV6 ? !callback.hasIpv4Answer() : !callback.hasIpv6Answer()); + } + } + } } From d51ae5760d7850d28911557e08e5110559d78bed Mon Sep 17 00:00:00 2001 From: markchien Date: Wed, 21 Nov 2018 22:56:31 +0800 Subject: [PATCH 70/71] Exempt adb socket for hostside VpnTest Vpn test would destroy socket. If adb run over network, adb socket would be killed during Vpn test. Then, test stop due to adb disconnect. Bug: 119382723 Bug: 135225500 Test: - build pass Change-Id: I91b4ab018a9e7fc73dcb7969e4a6520d6b27d629 Merged-In: I91b4ab018a9e7fc73dcb7969e4a6520d6b27d629 Merged-In: Id6f986aacc3cadf713ebbc8305ca535b861390fc (cherry picked from commit de0f268f789222dd17d3c28c0f07656f2c168d81) --- tests/cts/hostside/app/Android.mk | 5 ++++- .../com/android/cts/net/hostside/VpnTest.java | 16 ++++++++++++++++ 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/tests/cts/hostside/app/Android.mk b/tests/cts/hostside/app/Android.mk index 1c1a798fab..b1a4494d25 100644 --- a/tests/cts/hostside/app/Android.mk +++ b/tests/cts/hostside/app/Android.mk @@ -19,10 +19,13 @@ LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) LOCAL_MODULE_TAGS := tests -LOCAL_SDK_VERSION := current +#LOCAL_SDK_VERSION := current +LOCAL_PRIVATE_PLATFORM_APIS := true LOCAL_STATIC_JAVA_LIBRARIES := compatibility-device-util ctstestrunner ub-uiautomator \ CtsHostsideNetworkTestsAidl +LOCAL_JAVA_LIBRARIES := android.test.runner + LOCAL_SRC_FILES := $(call all-java-files-under, src) LOCAL_PACKAGE_NAME := CtsHostsideNetworkTestsApp diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/VpnTest.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/VpnTest.java index bc982cec78..b3f61c486d 100755 --- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/VpnTest.java +++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/VpnTest.java @@ -29,6 +29,7 @@ import android.net.NetworkRequest; import android.net.VpnService; import android.os.ParcelFileDescriptor; import android.os.Process; +import android.os.SystemProperties; import android.support.test.uiautomator.UiDevice; import android.support.test.uiautomator.UiObject; import android.support.test.uiautomator.UiObjectNotFoundException; @@ -537,6 +538,14 @@ public class VpnTest extends InstrumentationTestCase { public void testDefault() throws Exception { if (!supportedHardware()) return; + // If adb TCP port opened, this test may running by adb over network. + // All of socket would be destroyed in this test. So this test don't + // support adb over network, see b/119382723. + if (SystemProperties.getInt("persist.adb.tcp.port", -1) > -1 + || SystemProperties.getInt("service.adb.tcp.port", -1) > -1) { + Log.i(TAG, "adb is running over the network, so skip this test"); + return; + } FileDescriptor fd = openSocketFdInOtherApp(TEST_HOST, 80, TIMEOUT_MS); @@ -554,6 +563,7 @@ public class VpnTest extends InstrumentationTestCase { FileDescriptor fd = openSocketFdInOtherApp(TEST_HOST, 80, TIMEOUT_MS); + // Shell app must not be put in here or it would kill the ADB-over-network use case String allowedApps = mRemoteSocketFactoryClient.getPackageName() + "," + mPackageName; startVpn(new String[] {"192.0.2.2/32", "2001:db8:1:2::ffe/128"}, new String[] {"192.0.2.0/24", "2001:db8::/32"}, @@ -571,6 +581,12 @@ public class VpnTest extends InstrumentationTestCase { FileDescriptor remoteFd = openSocketFdInOtherApp(TEST_HOST, 80, TIMEOUT_MS); String disallowedApps = mRemoteSocketFactoryClient.getPackageName() + "," + mPackageName; + // If adb TCP port opened, this test may running by adb over TCP. + // Add com.android.shell appllication into blacklist to exclude adb socket for VPN test, + // see b/119382723. + // Note: The test don't support running adb over network for root device + disallowedApps = disallowedApps + ",com.android.shell"; + Log.i(TAG, "Append shell app to disallowedApps: " + disallowedApps); startVpn(new String[] {"192.0.2.2/32", "2001:db8:1:2::ffe/128"}, new String[] {"192.0.2.0/24", "2001:db8::/32"}, "", disallowedApps); From 2419976be43f2284c538a67f1911a8027a7f9596 Mon Sep 17 00:00:00 2001 From: Junyu Lai Date: Wed, 19 Jun 2019 07:29:02 -0700 Subject: [PATCH 71/71] Add CTS for creating keepalive offloads on cellular Bug: 134352656 Test: atest android.net.cts.ConnectivityManagerTest (--instant) Merged-In: Ia7b1111abe687efad032a8c9205990c97a769fcd Change-Id: Ib6b01356d785c5b7684520eef9f9d1fe48187582 (cherry picked from commit 8550488c7cf0c0ab2af06189aca5ad50c39e5276) --- .../net/cts/ConnectivityManagerTest.java | 245 ++++++++++++------ 1 file changed, 168 insertions(+), 77 deletions(-) diff --git a/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java b/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java index 8c9bf6ee21..e9deec9f1e 100644 --- a/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java +++ b/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java @@ -35,6 +35,7 @@ import static android.system.OsConstants.AF_UNSPEC; import static com.android.compatibility.common.util.SystemUtil.runShellCommand; +import android.annotation.NonNull; import android.app.Instrumentation; import android.app.PendingIntent; import android.app.UiAutomation; @@ -59,6 +60,7 @@ import android.net.SocketKeepalive; import android.net.cts.util.CtsNetUtils; import android.net.util.KeepaliveUtils; import android.net.wifi.WifiManager; +import android.os.Build; import android.os.Looper; import android.os.MessageQueue; import android.os.SystemClock; @@ -99,6 +101,7 @@ import java.util.concurrent.CountDownLatch; import java.util.concurrent.Executor; import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.TimeUnit; +import java.util.function.Supplier; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -113,6 +116,8 @@ public class ConnectivityManagerTest extends AndroidTestCase { 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; + 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; private static final int NUM_TRIES_MULTIPATH_PREF_CHECK = 20; @@ -120,6 +125,10 @@ public class ConnectivityManagerTest extends AndroidTestCase { // device could have only one interface: data, wifi. private static final int MIN_NUM_NETWORK_TYPES = 1; + // Minimum supported keepalive counts for wifi and cellular. + public static final int MIN_SUPPORTED_CELLULAR_KEEPALIVE_COUNT = 1; + public static final int MIN_SUPPORTED_WIFI_KEEPALIVE_COUNT = 3; + private Context mContext; private Instrumentation mInstrumentation; private ConnectivityManager mCm; @@ -839,8 +848,7 @@ public class ConnectivityManagerTest extends AndroidTestCase { return s; } - private int getSupportedKeepalivesFromRes() throws Exception { - final Network network = ensureWifiConnected(); + private int getSupportedKeepalivesForNet(@NonNull Network network) throws Exception { final NetworkCapabilities nc = mCm.getNetworkCapabilities(network); // Get number of supported concurrent keepalives for testing network. @@ -914,34 +922,46 @@ public class ConnectivityManagerTest extends AndroidTestCase { * keepalives is set to 0. */ @AppModeFull(reason = "Cannot get WifiManager in instant app mode") - public void testKeepaliveUnsupported() throws Exception { - if (getSupportedKeepalivesFromRes() != 0) return; + public void testKeepaliveWifiUnsupported() throws Exception { + if (!mPackageManager.hasSystemFeature(FEATURE_WIFI)) { + Log.i(TAG, "testKeepaliveUnsupported cannot execute unless device" + + " supports WiFi"); + return; + } + + final Network network = ensureWifiConnected(); + if (getSupportedKeepalivesForNet(network) != 0) return; adoptShellPermissionIdentity(); - assertEquals(0, createConcurrentSocketKeepalives(1, 0)); - assertEquals(0, createConcurrentSocketKeepalives(0, 1)); + assertEquals(0, createConcurrentSocketKeepalives(network, 1, 0)); + assertEquals(0, createConcurrentSocketKeepalives(network, 0, 1)); dropShellPermissionIdentity(); } @AppModeFull(reason = "Cannot get WifiManager in instant app mode") public void testCreateTcpKeepalive() throws Exception { + if (!mPackageManager.hasSystemFeature(FEATURE_WIFI)) { + Log.i(TAG, "testCreateTcpKeepalive cannot execute unless device supports WiFi"); + return; + } + adoptShellPermissionIdentity(); - if (getSupportedKeepalivesFromRes() == 0) return; + final Network network = ensureWifiConnected(); + if (getSupportedKeepalivesForNet(network) == 0) return; // 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(0, 1)); + assertEquals(0, createConcurrentSocketKeepalives(network, 0, 1)); Log.i(TAG, "testCreateTcpKeepalive is skipped for kernel " + VintfRuntimeInfo.getKernelVersion()); return; } - final Network network = ensureWifiConnected(); 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. @@ -1007,80 +1027,102 @@ public class ConnectivityManagerTest extends AndroidTestCase { } } - /** - * Creates concurrent keepalives until the specified counts of each type of keepalives are - * reached or the expected error callbacks are received for each type of keepalives. - * - * @return the total number of keepalives created. - */ - private int createConcurrentSocketKeepalives(int nattCount, int tcpCount) throws Exception { - final Network network = ensureWifiConnected(); - + private ArrayList createConcurrentKeepalivesOfType( + int requestCount, @NonNull TestSocketKeepaliveCallback callback, + Supplier kaFactory) { final ArrayList kalist = new ArrayList<>(); - final TestSocketKeepaliveCallback callback = new TestSocketKeepaliveCallback(); - final Executor executor = mContext.getMainExecutor(); - // Create concurrent TCP keepalives. - for (int i = 0; i < tcpCount; i++) { - // Assert that TCP connections can be established on wifi. The file descriptor of tcp - // sockets will be duplicated and kept valid in service side if the keepalives are - // successfully started. - try (Socket tcpSocket = getConnectedSocket(network, TEST_HOST, HTTP_PORT, - 0 /* Unused */, AF_INET)) { - final SocketKeepalive ka = mCm.createSocketKeepalive(network, tcpSocket, executor, - callback); - ka.start(MIN_KEEPALIVE_INTERVAL); - TestSocketKeepaliveCallback.CallbackValue cv = callback.pollCallback(); - assertNotNull(cv); - if (cv.callbackType == TestSocketKeepaliveCallback.CallbackType.ON_ERROR) { - if (i == 0 && cv.error == SocketKeepalive.ERROR_UNSUPPORTED) { - // Unsupported. - break; - } else if (i != 0 && cv.error == SocketKeepalive.ERROR_INSUFFICIENT_RESOURCES) { - // Limit reached. - break; - } - } - if (cv.callbackType == TestSocketKeepaliveCallback.CallbackType.ON_STARTED) { - kalist.add(ka); - } else { - fail("Unexpected error when creating " + (i + 1) + " TCP keepalives: " + cv); - } - } - } + int remainingRetries = MAX_KEEPALIVE_RETRY_COUNT; - // Assert that a Nat-T socket can be created. - 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); - - // Test concurrent Nat-T keepalives. - for (int i = 0; i < nattCount; i++) { - final SocketKeepalive ka = mCm.createSocketKeepalive(network, nattSocket, - srcAddr, dstAddr, executor, callback); + // Test concurrent keepalives with the given supplier. + while (kalist.size() < requestCount) { + final SocketKeepalive ka = kaFactory.get(); ka.start(MIN_KEEPALIVE_INTERVAL); TestSocketKeepaliveCallback.CallbackValue cv = callback.pollCallback(); assertNotNull(cv); if (cv.callbackType == TestSocketKeepaliveCallback.CallbackType.ON_ERROR) { - if (i == 0 && cv.error == SocketKeepalive.ERROR_UNSUPPORTED) { + if (kalist.size() == 0 && cv.error == SocketKeepalive.ERROR_UNSUPPORTED) { // Unsupported. break; - } else if (i != 0 && cv.error == SocketKeepalive.ERROR_INSUFFICIENT_RESOURCES) { - // Limit reached. + } else if (cv.error == SocketKeepalive.ERROR_INSUFFICIENT_RESOURCES) { + // Limit reached or temporary unavailable due to stopped slot is not yet + // released. + if (remainingRetries > 0) { + SystemClock.sleep(INTERVAL_KEEPALIVE_RETRY_MS); + remainingRetries--; + continue; + } break; } } if (cv.callbackType == TestSocketKeepaliveCallback.CallbackType.ON_STARTED) { kalist.add(ka); } else { - fail("Unexpected error when creating " + (i + 1) + " Nat-T keepalives: " + cv); + fail("Unexpected error when creating " + (kalist.size() + 1) + " " + + ka.getClass().getSimpleName() + ": " + cv); } } + return kalist; + } + + private @NonNull ArrayList createConcurrentNattSocketKeepalives( + @NonNull Network network, int requestCount, + @NonNull TestSocketKeepaliveCallback callback) throws Exception { + + final Executor executor = mContext.getMainExecutor(); + + // 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); + + // Test concurrent Nat-T keepalives. + final ArrayList result = createConcurrentKeepalivesOfType(requestCount, + callback, () -> mCm.createSocketKeepalive(network, nattSocket, + srcAddr, dstAddr, executor, callback)); + + nattSocket.close(); + return result; + } + + private @NonNull ArrayList createConcurrentTcpSocketKeepalives( + @NonNull Network network, int requestCount, + @NonNull TestSocketKeepaliveCallback callback) { + final Executor executor = mContext.getMainExecutor(); + + // Create concurrent TCP keepalives. + return createConcurrentKeepalivesOfType(requestCount, callback, () -> { + // Assert that TCP connections can be established. The file descriptor of tcp + // sockets will be duplicated and kept valid in service side if the keepalives are + // successfully started. + try (Socket tcpSocket = getConnectedSocket(network, TEST_HOST, HTTP_PORT, + 0 /* Unused */, AF_INET)) { + return mCm.createSocketKeepalive(network, tcpSocket, executor, callback); + } catch (Exception e) { + fail("Unexpected error when creating TCP socket: " + e); + } + return null; + }); + } + + /** + * Creates concurrent keepalives until the specified counts of each type of keepalives are + * reached or the expected error callbacks are received for each type of keepalives. + * + * @return the total number of keepalives created. + */ + private int createConcurrentSocketKeepalives( + @NonNull Network network, int nattCount, int tcpCount) throws Exception { + final ArrayList kalist = new ArrayList<>(); + final TestSocketKeepaliveCallback callback = new TestSocketKeepaliveCallback(); + + kalist.addAll(createConcurrentNattSocketKeepalives(network, nattCount, callback)); + kalist.addAll(createConcurrentTcpSocketKeepalives(network, tcpCount, callback)); + final int ret = kalist.size(); // Clean up. @@ -1089,7 +1131,6 @@ public class ConnectivityManagerTest extends AndroidTestCase { callback.expectStopped(); } kalist.clear(); - nattSocket.close(); return ret; } @@ -1099,8 +1140,15 @@ public class ConnectivityManagerTest extends AndroidTestCase { * get leaked after iterations. */ @AppModeFull(reason = "Cannot get WifiManager in instant app mode") - public void testSocketKeepaliveLimit() throws Exception { - final int supported = getSupportedKeepalivesFromRes(); + public void testSocketKeepaliveLimitWifi() throws Exception { + if (!mPackageManager.hasSystemFeature(FEATURE_WIFI)) { + Log.i(TAG, "testSocketKeepaliveLimitWifi cannot execute unless device" + + " supports WiFi"); + return; + } + + final Network network = ensureWifiConnected(); + final int supported = getSupportedKeepalivesForNet(network); if (supported == 0) { return; } @@ -1108,37 +1156,79 @@ public class ConnectivityManagerTest extends AndroidTestCase { adoptShellPermissionIdentity(); // Verifies that the supported keepalive slots meet MIN_SUPPORTED_KEEPALIVE_COUNT. - assertGreaterOrEqual(supported, KeepaliveUtils.MIN_SUPPORTED_KEEPALIVE_COUNT); + assertGreaterOrEqual(supported, MIN_SUPPORTED_WIFI_KEEPALIVE_COUNT); // Verifies that Nat-T keepalives can be established. - assertEquals(supported, createConcurrentSocketKeepalives(supported + 1, 0)); + assertEquals(supported, createConcurrentSocketKeepalives(network, supported + 1, 0)); // Verifies that keepalives don't get leaked in second round. - assertEquals(supported, createConcurrentSocketKeepalives(supported + 1, 0)); + assertEquals(supported, createConcurrentSocketKeepalives(network, 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(0, supported + 1)); + assertEquals(supported, createConcurrentSocketKeepalives(network, 0, supported + 1)); // Verifies that different types can be established at the same time. - assertEquals(supported, createConcurrentSocketKeepalives( + assertEquals(supported, createConcurrentSocketKeepalives(network, supported / 2, supported - supported / 2)); // Verifies that keepalives don't get leaked in second round. - assertEquals(supported, createConcurrentSocketKeepalives(0, supported + 1)); - assertEquals(supported, createConcurrentSocketKeepalives( + assertEquals(supported, createConcurrentSocketKeepalives(network, 0, supported)); + assertEquals(supported, createConcurrentSocketKeepalives(network, supported / 2, supported - supported / 2)); } dropShellPermissionIdentity(); } + /** + * Verifies that the concurrent keepalive slots meet the minimum telephony requirement, and + * don't get leaked after iterations. + */ + @AppModeFull(reason = "Cannot request network in instant app mode") + public void testSocketKeepaliveLimitTelephony() throws Exception { + if (!mPackageManager.hasSystemFeature(FEATURE_TELEPHONY)) { + Log.i(TAG, "testSocketKeepaliveLimitTelephony cannot execute unless device" + + " supports telephony"); + return; + } + + final int firstSdk = Build.VERSION.FIRST_SDK_INT; + if (firstSdk < Build.VERSION_CODES.Q) { + Log.i(TAG, "testSocketKeepaliveLimitTelephony: skip test for devices launching" + + " before Q: " + firstSdk); + return; + } + + final Network network = mCtsNetUtils.connectToCell(); + final int supported = getSupportedKeepalivesForNet(network); + + 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(); + } + /** * Verifies that the keepalive slots are limited as customized for unprivileged requests. */ @AppModeFull(reason = "Cannot get WifiManager in instant app mode") public void testSocketKeepaliveUnprivileged() throws Exception { - final int supported = getSupportedKeepalivesFromRes(); + if (!mPackageManager.hasSystemFeature(FEATURE_WIFI)) { + Log.i(TAG, "testSocketKeepaliveUnprivileged cannot execute unless device" + + " supports WiFi"); + return; + } + + final Network network = ensureWifiConnected(); + final int supported = getSupportedKeepalivesForNet(network); if (supported == 0) { return; } @@ -1154,7 +1244,8 @@ public class ConnectivityManagerTest extends AndroidTestCase { assertGreaterOrEqual(supported, allowedUnprivilegedPerUid); final int expectedUnprivileged = Math.min(allowedUnprivilegedPerUid, supported - reservedPrivilegedSlots); - assertEquals(expectedUnprivileged, createConcurrentSocketKeepalives(supported + 1, 0)); + assertEquals(expectedUnprivileged, + createConcurrentSocketKeepalives(network, supported + 1, 0)); } private static void assertGreaterOrEqual(long greater, long lesser) {