Merge mainline-release 6664920 to master - DO NOT MERGE
Merged-In: I583836eeeaf604391ed9b1196d4b41e872dc635d
Change-Id: Ifd90a94f57f27c2477c0bc52efaea91870080501
diff --git a/tests/cts/hostside/app/Android.bp b/tests/cts/hostside/app/Android.bp
index 7a11456..e129be7 100644
--- a/tests/cts/hostside/app/Android.bp
+++ b/tests/cts/hostside/app/Android.bp
@@ -28,8 +28,8 @@
"CtsHostsideNetworkTestsAidl",
],
libs: [
- "android.test.runner.stubs",
- "android.test.base.stubs",
+ "android.test.runner",
+ "android.test.base",
],
srcs: ["src/**/*.java"],
// Tag this module as a cts test artifact
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 5fe4573..bb492a1 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
@@ -67,7 +67,7 @@
setAppIdle(true);
launchComponentAndAssertNetworkAccess(TYPE_COMPONENT_ACTIVTIY);
finishActivity();
- assertAppIdle(false); // Sanity check - not idle anymore, since activity was launched...
+ assertAppIdle(false); // verify - not idle anymore, since activity was launched...
assertBackgroundNetworkAccess(true);
setAppIdle(true);
assertBackgroundNetworkAccess(false);
@@ -86,24 +86,29 @@
assertBackgroundNetworkAccess(false);
addPowerSaveModeWhitelist(TEST_APP2_PKG);
- assertAppIdle(false); // Sanity check - not idle anymore, since whitelisted
+ assertAppIdle(false); // verify - not idle anymore, since whitelisted
assertBackgroundNetworkAccess(true);
+ setAppIdleNoAssert(true);
+ assertAppIdle(false); // app is still whitelisted
removePowerSaveModeWhitelist(TEST_APP2_PKG);
- assertAppIdle(true); // Sanity check - idle again, once whitelisted was removed
+ assertAppIdle(true); // verify - idle again, once whitelisted was removed
assertBackgroundNetworkAccess(false);
+ setAppIdle(true);
addPowerSaveModeExceptIdleWhitelist(TEST_APP2_PKG);
- assertAppIdle(false); // Sanity check - not idle anymore, since whitelisted
+ assertAppIdle(false); // verify - not idle anymore, since whitelisted
assertBackgroundNetworkAccess(true);
+ setAppIdleNoAssert(true);
+ assertAppIdle(false); // app is still whitelisted
removePowerSaveModeExceptIdleWhitelist(TEST_APP2_PKG);
- assertAppIdle(true); // Sanity check - idle again, once whitelisted was removed
+ assertAppIdle(true); // verify - idle again, once whitelisted was removed
assertBackgroundNetworkAccess(false);
assertsForegroundAlwaysHasNetworkAccess();
- // Sanity check - no whitelist, no access!
+ // verify - no whitelist, no access!
setAppIdle(true);
assertBackgroundNetworkAccess(false);
}
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 2072db3..71f6f2f 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
@@ -229,12 +229,12 @@
}
protected void assertBackgroundNetworkAccess(boolean expectAllowed) throws Exception {
- assertBackgroundState(); // Sanity check.
+ assertBackgroundState();
assertNetworkAccess(expectAllowed /* expectAvailable */, false /* needScreenOn */);
}
protected void assertForegroundNetworkAccess() throws Exception {
- assertForegroundState(); // Sanity check.
+ assertForegroundState();
// We verified that app is in foreground state but if the screen turns-off while
// verifying for network access, the app will go into background state (in case app's
// foreground status was due to top activity). So, turn the screen on when verifying
@@ -243,7 +243,7 @@
}
protected void assertForegroundServiceNetworkAccess() throws Exception {
- assertForegroundServiceState(); // Sanity check.
+ assertForegroundServiceState();
assertNetworkAccess(true /* expectAvailable */, false /* needScreenOn */);
}
@@ -374,7 +374,7 @@
}
// Network status format is described on MyBroadcastReceiver.checkNetworkStatus()
final String[] parts = resultData.split(NETWORK_STATUS_SEPARATOR);
- assertEquals("Wrong network status: " + resultData, 5, parts.length); // Sanity check
+ assertEquals("Wrong network status: " + resultData, 5, parts.length);
final State state = parts[0].equals("null") ? null : State.valueOf(parts[0]);
final DetailedState detailedState = parts[1].equals("null")
? null : DetailedState.valueOf(parts[1]);
@@ -547,7 +547,7 @@
// TODO: currently the power-save mode is behaving like idle, but once it changes, we'll
// need to use netpolicy for whitelisting
executeShellCommand("dumpsys deviceidle whitelist +" + packageName);
- assertPowerSaveModeWhitelist(packageName, true); // Sanity check
+ assertPowerSaveModeWhitelist(packageName, true);
}
protected void removePowerSaveModeWhitelist(String packageName) throws Exception {
@@ -555,7 +555,7 @@
// TODO: currently the power-save mode is behaving like idle, but once it changes, we'll
// need to use netpolicy for whitelisting
executeShellCommand("dumpsys deviceidle whitelist -" + packageName);
- assertPowerSaveModeWhitelist(packageName, false); // Sanity check
+ assertPowerSaveModeWhitelist(packageName, false);
}
protected void assertPowerSaveModeExceptIdleWhitelist(String packageName, boolean expected)
@@ -571,7 +571,7 @@
// TODO: currently the power-save mode is behaving like idle, but once it changes, we'll
// need to use netpolicy for whitelisting
executeShellCommand("dumpsys deviceidle except-idle-whitelist +" + packageName);
- assertPowerSaveModeExceptIdleWhitelist(packageName, true); // Sanity check
+ assertPowerSaveModeExceptIdleWhitelist(packageName, true);
}
protected void removePowerSaveModeExceptIdleWhitelist(String packageName) throws Exception {
@@ -580,7 +580,7 @@
// TODO: currently the power-save mode is behaving like idle, but once it changes, we'll
// need to use netpolicy for whitelisting
executeShellCommand("dumpsys deviceidle except-idle-whitelist reset");
- assertPowerSaveModeExceptIdleWhitelist(packageName, false); // Sanity check
+ assertPowerSaveModeExceptIdleWhitelist(packageName, false);
}
protected void turnBatteryOn() throws Exception {
@@ -635,7 +635,7 @@
}
protected void setDozeMode(boolean enabled) throws Exception {
- // Sanity check, since tests should check beforehand....
+ // Check doze mode is supported.
assertTrue("Device does not support Doze Mode", isDozeModeSupported());
Log.i(TAG, "Setting Doze Mode to " + enabled);
@@ -648,7 +648,6 @@
turnBatteryOff();
executeShellCommand("dumpsys deviceidle unforce");
}
- // Sanity check.
assertDozeMode(enabled);
}
@@ -659,7 +658,12 @@
protected void setAppIdle(boolean enabled) throws Exception {
Log.i(TAG, "Setting app idle to " + enabled);
executeSilentShellCommand("am set-inactive " + TEST_APP2_PKG + " " + enabled );
- assertAppIdle(enabled); // Sanity check
+ assertAppIdle(enabled);
+ }
+
+ protected void setAppIdleNoAssert(boolean enabled) throws Exception {
+ Log.i(TAG, "Setting app idle to " + enabled);
+ executeSilentShellCommand("am set-inactive " + TEST_APP2_PKG + " " + enabled );
}
protected void assertAppIdle(boolean enabled) throws Exception {
diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/DataSaverModeTest.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/DataSaverModeTest.java
index aa2c914..604a0b6 100644
--- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/DataSaverModeTest.java
+++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/DataSaverModeTest.java
@@ -67,7 +67,7 @@
public void testGetRestrictBackgroundStatus_disabled() throws Exception {
assertDataSaverStatusOnBackground(RESTRICT_BACKGROUND_STATUS_DISABLED);
- // Sanity check: make sure status is always disabled, never whitelisted
+ // Verify status is always disabled, never whitelisted
addRestrictBackgroundWhitelist(mUid);
assertRestrictBackgroundChangedReceived(0);
assertDataSaverStatusOnBackground(RESTRICT_BACKGROUND_STATUS_DISABLED);
diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/NetworkCallbackTest.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/NetworkCallbackTest.java
index aa59959..2ac29e7 100644
--- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/NetworkCallbackTest.java
+++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/NetworkCallbackTest.java
@@ -17,7 +17,9 @@
package com.android.cts.net.hostside;
import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_METERED;
+import static com.android.cts.net.hostside.NetworkPolicyTestUtils.canChangeActiveNetworkMeteredness;
import static com.android.cts.net.hostside.NetworkPolicyTestUtils.setRestrictBackground;
+import static com.android.cts.net.hostside.NetworkPolicyTestUtils.isActiveNetworkMetered;
import static com.android.cts.net.hostside.Property.BATTERY_SAVER_MODE;
import static com.android.cts.net.hostside.Property.DATA_SAVER_MODE;
@@ -26,9 +28,11 @@
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
+import static org.junit.Assume.assumeTrue;
import android.net.Network;
import android.net.NetworkCapabilities;
+import android.util.Log;
import org.junit.After;
import org.junit.Before;
@@ -141,15 +145,16 @@
}
public void expectBlockedStatusCallback(Network expectedNetwork, boolean expectBlocked) {
- expectCallback(CallbackState.BLOCKED_STATUS, expectedNetwork,
- expectBlocked);
+ expectCallback(CallbackState.BLOCKED_STATUS, expectedNetwork, expectBlocked);
}
- public void waitBlockedStatusCallback(Network expectedNetwork, boolean expectBlocked) {
+ public void expectBlockedStatusCallbackEventually(Network expectedNetwork,
+ boolean expectBlocked) {
final long deadline = System.currentTimeMillis() + TEST_CALLBACK_TIMEOUT_MS;
do {
final CallbackInfo cb = nextCallback((int) (deadline - System.currentTimeMillis()));
- if (cb.state == CallbackState.BLOCKED_STATUS) {
+ if (cb.state == CallbackState.BLOCKED_STATUS
+ && cb.network.equals(expectedNetwork)) {
assertEquals(expectBlocked, cb.arg);
return;
}
@@ -157,17 +162,23 @@
fail("Didn't receive onBlockedStatusChanged()");
}
- public void expectCapabilitiesCallback(Network expectedNetwork, boolean hasCapability,
- int capability) {
- final CallbackInfo cb = nextCallback(TEST_CALLBACK_TIMEOUT_MS);
- final NetworkCapabilities cap = (NetworkCapabilities) cb.arg;
- assertEquals(expectedNetwork, cb.network);
- assertEquals(CallbackState.CAPABILITIES, cb.state);
- if (hasCapability != cap.hasCapability(capability)) {
- fail("NetworkCapabilities callback "
- + (hasCapability ? "missing expected" : "has unexpected")
- + " capability. " + cb);
- }
+ public void expectCapabilitiesCallbackEventually(Network expectedNetwork, boolean hasCap,
+ int cap) {
+ final long deadline = System.currentTimeMillis() + TEST_CALLBACK_TIMEOUT_MS;
+ do {
+ final CallbackInfo cb = nextCallback((int) (deadline - System.currentTimeMillis()));
+ if (cb.state != CallbackState.CAPABILITIES
+ || !expectedNetwork.equals(cb.network)
+ || (hasCap != ((NetworkCapabilities) cb.arg).hasCapability(cap))) {
+ Log.i("NetworkCallbackTest#expectCapabilitiesCallback",
+ "Ignoring non-matching callback : " + cb);
+ continue;
+ }
+ // Found a match, return
+ return;
+ } while (System.currentTimeMillis() <= deadline);
+ fail("Didn't receive the expected callback to onCapabilitiesChanged(). Check the "
+ + "log for a list of received callbacks, if any.");
}
}
@@ -175,6 +186,8 @@
public void setUp() throws Exception {
super.setUp();
+ assumeTrue(isActiveNetworkMetered(true) || canChangeActiveNetworkMeteredness());
+
registerBroadcastReceiver();
removeRestrictBackgroundWhitelist(mUid);
@@ -194,8 +207,8 @@
// callback to ensure wifi is connected before the test and store the default network.
mNetwork = mTestNetworkCallback.expectAvailableCallbackAndGetNetwork();
// Check that the network is metered.
- mTestNetworkCallback.expectCapabilitiesCallback(mNetwork, false /* hasCapability */,
- NET_CAPABILITY_NOT_METERED);
+ mTestNetworkCallback.expectCapabilitiesCallbackEventually(mNetwork,
+ false /* hasCapability */, NET_CAPABILITY_NOT_METERED);
mTestNetworkCallback.expectBlockedStatusCallback(mNetwork, false);
}
@@ -215,28 +228,28 @@
// Enable restrict background
setRestrictBackground(true);
assertBackgroundNetworkAccess(false);
- mTestNetworkCallback.waitBlockedStatusCallback(mNetwork, true);
+ mTestNetworkCallback.expectBlockedStatusCallbackEventually(mNetwork, true);
// Add to whitelist
addRestrictBackgroundWhitelist(mUid);
assertBackgroundNetworkAccess(true);
- mTestNetworkCallback.waitBlockedStatusCallback(mNetwork, false);
+ mTestNetworkCallback.expectBlockedStatusCallbackEventually(mNetwork, false);
// Remove from whitelist
removeRestrictBackgroundWhitelist(mUid);
assertBackgroundNetworkAccess(false);
- mTestNetworkCallback.waitBlockedStatusCallback(mNetwork, true);
+ mTestNetworkCallback.expectBlockedStatusCallbackEventually(mNetwork, true);
} finally {
mMeterednessConfiguration.resetNetworkMeteredness();
}
// Set to non-metered network
mMeterednessConfiguration.configureNetworkMeteredness(false);
- mTestNetworkCallback.expectCapabilitiesCallback(mNetwork, true /* hasCapability */,
- NET_CAPABILITY_NOT_METERED);
+ mTestNetworkCallback.expectCapabilitiesCallbackEventually(mNetwork,
+ true /* hasCapability */, NET_CAPABILITY_NOT_METERED);
try {
assertBackgroundNetworkAccess(true);
- mTestNetworkCallback.waitBlockedStatusCallback(mNetwork, false);
+ mTestNetworkCallback.expectBlockedStatusCallbackEventually(mNetwork, false);
// Disable restrict background, should not trigger callback
setRestrictBackground(false);
@@ -253,30 +266,30 @@
// Enable Power Saver
setBatterySaverMode(true);
assertBackgroundNetworkAccess(false);
- mTestNetworkCallback.waitBlockedStatusCallback(mNetwork, true);
+ mTestNetworkCallback.expectBlockedStatusCallbackEventually(mNetwork, true);
// Disable Power Saver
setBatterySaverMode(false);
assertBackgroundNetworkAccess(true);
- mTestNetworkCallback.waitBlockedStatusCallback(mNetwork, false);
+ mTestNetworkCallback.expectBlockedStatusCallbackEventually(mNetwork, false);
} finally {
mMeterednessConfiguration.resetNetworkMeteredness();
}
// Set to non-metered network
mMeterednessConfiguration.configureNetworkMeteredness(false);
- mTestNetworkCallback.expectCapabilitiesCallback(mNetwork, true /* hasCapability */,
- NET_CAPABILITY_NOT_METERED);
+ mTestNetworkCallback.expectCapabilitiesCallbackEventually(mNetwork,
+ true /* hasCapability */, NET_CAPABILITY_NOT_METERED);
try {
// Enable Power Saver
setBatterySaverMode(true);
assertBackgroundNetworkAccess(false);
- mTestNetworkCallback.waitBlockedStatusCallback(mNetwork, true);
+ mTestNetworkCallback.expectBlockedStatusCallbackEventually(mNetwork, true);
// Disable Power Saver
setBatterySaverMode(false);
assertBackgroundNetworkAccess(true);
- mTestNetworkCallback.waitBlockedStatusCallback(mNetwork, false);
+ mTestNetworkCallback.expectBlockedStatusCallbackEventually(mNetwork, false);
} finally {
mMeterednessConfiguration.resetNetworkMeteredness();
}
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 4598c39..ac28c7a 100644
--- a/tests/cts/hostside/src/com/android/cts/net/HostsideRestrictBackgroundNetworkTests.java
+++ b/tests/cts/hostside/src/com/android/cts/net/HostsideRestrictBackgroundNetworkTests.java
@@ -367,7 +367,7 @@
// TODO: currently the power-save mode is behaving like idle, but once it changes, we'll
// need to use netpolicy for whitelisting
runCommand("dumpsys deviceidle whitelist +" + packageName);
- assertPowerSaveModeWhitelist(packageName, true); // Sanity check
+ assertPowerSaveModeWhitelist(packageName, true);
}
protected boolean isDozeModeEnabled() throws Exception {
diff --git a/tests/cts/net/Android.bp b/tests/cts/net/Android.bp
index 112799b..4c00428 100644
--- a/tests/cts/net/Android.bp
+++ b/tests/cts/net/Android.bp
@@ -22,7 +22,7 @@
libs: [
"voip-common",
"org.apache.http.legacy",
- "android.test.base.stubs",
+ "android.test.base",
],
jni_libs: [
@@ -47,7 +47,6 @@
"ctstestserver",
"junit",
"junit-params",
- "libnanohttpd",
"mockwebserver",
"net-utils-framework-common",
"truth-prebuilt",
@@ -83,7 +82,7 @@
min_sdk_version: "29",
target_sdk_version: "30",
test_suites: [
- "device-tests",
+ "general-tests",
"mts",
],
test_config_template: "AndroidTestTemplate.xml",
diff --git a/tests/cts/net/AndroidTestTemplate.xml b/tests/cts/net/AndroidTestTemplate.xml
index 1f75da1..4e93751 100644
--- a/tests/cts/net/AndroidTestTemplate.xml
+++ b/tests/cts/net/AndroidTestTemplate.xml
@@ -19,6 +19,8 @@
<option name="config-descriptor:metadata" key="parameter" value="instant_app" />
<option name="config-descriptor:metadata" key="parameter" value="not_multi_abi" />
<option name="config-descriptor:metadata" key="parameter" value="secondary_user" />
+
+ <option name="config-descriptor:metadata" key="mainline-param" value="CaptivePortalLoginGoogle.apk+NetworkStackGoogle.apk" />
<option name="not-shardable" value="true" />
<target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
<option name="cleanup-apks" value="true" />
diff --git a/tests/cts/net/TEST_MAPPING b/tests/cts/net/TEST_MAPPING
index e2a9c75..3162e22 100644
--- a/tests/cts/net/TEST_MAPPING
+++ b/tests/cts/net/TEST_MAPPING
@@ -9,5 +9,15 @@
}
]
}
+ ],
+ "mainline-presubmit": [
+ {
+ "name": "CtsNetTestCasesLatestSdk[CaptivePortalLoginGoogle.apk+NetworkStackGoogle.apk]",
+ "options": [
+ {
+ "exclude-annotation": "com.android.testutils.SkipPresubmit"
+ }
+ ]
+ }
]
}
diff --git a/tests/cts/net/api23Test/Android.bp b/tests/cts/net/api23Test/Android.bp
index ffeef48..0ce9826 100644
--- a/tests/cts/net/api23Test/Android.bp
+++ b/tests/cts/net/api23Test/Android.bp
@@ -20,7 +20,7 @@
compile_multilib: "both",
libs: [
- "android.test.base.stubs",
+ "android.test.base",
],
srcs: [
diff --git a/tests/cts/net/ipsec/Android.bp b/tests/cts/net/ipsec/Android.bp
index 124e93c..948cc05 100644
--- a/tests/cts/net/ipsec/Android.bp
+++ b/tests/cts/net/ipsec/Android.bp
@@ -21,7 +21,7 @@
libs: [
"android.net.ipsec.ike.stubs.system",
- "android.test.base.stubs",
+ "android.test.base",
],
srcs: [
diff --git a/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeSessionTestBase.java b/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeSessionTestBase.java
index a81063b..6264cea 100644
--- a/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeSessionTestBase.java
+++ b/tests/cts/net/ipsec/src/android/net/ipsec/ike/cts/IkeSessionTestBase.java
@@ -56,7 +56,7 @@
import androidx.test.ext.junit.runners.AndroidJUnit4;
import com.android.compatibility.common.util.SystemUtil;
-import com.android.testutils.ArrayTrackRecord;
+import com.android.net.module.util.ArrayTrackRecord;
import org.junit.After;
import org.junit.AfterClass;
diff --git a/tests/cts/net/src/android/net/cts/CaptivePortalTest.kt b/tests/cts/net/src/android/net/cts/CaptivePortalTest.kt
index 4a7d38a..12a966f 100644
--- a/tests/cts/net/src/android/net/cts/CaptivePortalTest.kt
+++ b/tests/cts/net/src/android/net/cts/CaptivePortalTest.kt
@@ -19,7 +19,6 @@
import android.Manifest.permission.CONNECTIVITY_INTERNAL
import android.Manifest.permission.NETWORK_SETTINGS
import android.Manifest.permission.READ_DEVICE_CONFIG
-import android.Manifest.permission.WRITE_DEVICE_CONFIG
import android.content.pm.PackageManager.FEATURE_TELEPHONY
import android.content.pm.PackageManager.FEATURE_WIFI
import android.net.ConnectivityManager
@@ -30,20 +29,25 @@
import android.net.NetworkCapabilities.TRANSPORT_WIFI
import android.net.NetworkRequest
import android.net.Uri
+import android.net.cts.NetworkValidationTestUtil.clearValidationTestUrlsDeviceConfig
+import android.net.cts.NetworkValidationTestUtil.runAsShell
+import android.net.cts.NetworkValidationTestUtil.setHttpUrlDeviceConfig
+import android.net.cts.NetworkValidationTestUtil.setHttpsUrlDeviceConfig
+import android.net.cts.NetworkValidationTestUtil.setUrlExpirationDeviceConfig
+import com.android.testutils.TestHttpServer.Request
import android.net.cts.util.CtsNetUtils
+import android.net.util.NetworkStackUtils.TEST_CAPTIVE_PORTAL_HTTPS_URL
+import android.net.util.NetworkStackUtils.TEST_CAPTIVE_PORTAL_HTTP_URL
import android.net.wifi.WifiManager
import android.os.Build
-import android.os.ConditionVariable
import android.platform.test.annotations.AppModeFull
import android.provider.DeviceConfig
import android.provider.DeviceConfig.NAMESPACE_CONNECTIVITY
import android.text.TextUtils
import androidx.test.platform.app.InstrumentationRegistry.getInstrumentation
import androidx.test.runner.AndroidJUnit4
-import com.android.compatibility.common.util.SystemUtil
+import com.android.testutils.TestHttpServer
import com.android.testutils.isDevSdkInRange
-import fi.iki.elonen.NanoHTTPD
-import fi.iki.elonen.NanoHTTPD.Response.IStatus
import fi.iki.elonen.NanoHTTPD.Response.Status
import junit.framework.AssertionFailedError
import org.junit.After
@@ -55,15 +59,12 @@
import java.util.concurrent.TimeoutException
import kotlin.test.Test
import kotlin.test.assertNotEquals
+import kotlin.test.assertNotNull
import kotlin.test.assertTrue
-private const val TEST_CAPTIVE_PORTAL_HTTPS_URL_SETTING = "test_captive_portal_https_url"
-private const val TEST_CAPTIVE_PORTAL_HTTP_URL_SETTING = "test_captive_portal_http_url"
-private const val TEST_URL_EXPIRATION_TIME = "test_url_expiration_time"
-
-private const val TEST_HTTPS_URL_PATH = "https_path"
-private const val TEST_HTTP_URL_PATH = "http_path"
-private const val TEST_PORTAL_URL_PATH = "portal_path"
+private const val TEST_HTTPS_URL_PATH = "/https_path"
+private const val TEST_HTTP_URL_PATH = "/http_path"
+private const val TEST_PORTAL_URL_PATH = "/portal_path"
private const val LOCALHOST_HOSTNAME = "localhost"
@@ -88,24 +89,24 @@
private val pm by lazy { context.packageManager }
private val utils by lazy { CtsNetUtils(context) }
- private val server = HttpServer()
+ private val server = TestHttpServer("localhost")
@Before
fun setUp() {
- doAsShell(READ_DEVICE_CONFIG) {
+ runAsShell(READ_DEVICE_CONFIG) {
// Verify that the test URLs are not normally set on the device, but do not fail if the
// test URLs are set to what this test uses (URLs on localhost), in case the test was
// interrupted manually and rerun.
- assertEmptyOrLocalhostUrl(TEST_CAPTIVE_PORTAL_HTTPS_URL_SETTING)
- assertEmptyOrLocalhostUrl(TEST_CAPTIVE_PORTAL_HTTP_URL_SETTING)
+ assertEmptyOrLocalhostUrl(TEST_CAPTIVE_PORTAL_HTTPS_URL)
+ assertEmptyOrLocalhostUrl(TEST_CAPTIVE_PORTAL_HTTP_URL)
}
- clearTestUrls()
+ clearValidationTestUrlsDeviceConfig()
server.start()
}
@After
fun tearDown() {
- clearTestUrls()
+ clearValidationTestUrlsDeviceConfig()
if (pm.hasSystemFeature(FEATURE_WIFI)) {
reconnectWifi()
}
@@ -118,12 +119,6 @@
"$urlKey must not be set in production scenarios (current value: $url)")
}
- private fun clearTestUrls() {
- setHttpsUrl(null)
- setHttpUrl(null)
- setUrlExpiration(null)
- }
-
@Test
fun testCaptivePortalIsNotDefaultNetwork() {
assumeTrue(pm.hasSystemFeature(FEATURE_TELEPHONY))
@@ -132,19 +127,15 @@
utils.connectToCell()
// Have network validation use a local server that serves a HTTPS error / HTTP redirect
- server.addResponse(TEST_PORTAL_URL_PATH, Status.OK,
+ server.addResponse(Request(TEST_PORTAL_URL_PATH), Status.OK,
content = "Test captive portal content")
- server.addResponse(TEST_HTTPS_URL_PATH, Status.INTERNAL_ERROR)
- server.addResponse(TEST_HTTP_URL_PATH, Status.REDIRECT,
- locationHeader = server.makeUrl(TEST_PORTAL_URL_PATH))
- setHttpsUrl(server.makeUrl(TEST_HTTPS_URL_PATH))
- setHttpUrl(server.makeUrl(TEST_HTTP_URL_PATH))
+ server.addResponse(Request(TEST_HTTPS_URL_PATH), Status.INTERNAL_ERROR)
+ server.addResponse(Request(TEST_HTTP_URL_PATH), Status.REDIRECT,
+ locationHeader = makeUrl(TEST_PORTAL_URL_PATH))
+ setHttpsUrlDeviceConfig(makeUrl(TEST_HTTPS_URL_PATH))
+ setHttpUrlDeviceConfig(makeUrl(TEST_HTTP_URL_PATH))
// URL expiration needs to be in the next 10 minutes
- setUrlExpiration(System.currentTimeMillis() + TimeUnit.MINUTES.toMillis(9))
-
- // Expect the portal content to be fetched at some point after detecting the portal.
- // Some implementations may fetch the URL before startCaptivePortalApp is called.
- val portalContentRequestCv = server.addExpectRequestCv(TEST_PORTAL_URL_PATH)
+ setUrlExpirationDeviceConfig(System.currentTimeMillis() + TimeUnit.MINUTES.toMillis(9))
// Wait for a captive portal to be detected on the network
val wifiNetworkFuture = CompletableFuture<Network>()
@@ -173,9 +164,14 @@
val startPortalAppPermission =
if (isDevSdkInRange(0, Build.VERSION_CODES.Q)) CONNECTIVITY_INTERNAL
else NETWORK_SETTINGS
- doAsShell(startPortalAppPermission) { cm.startCaptivePortalApp(network) }
- assertTrue(portalContentRequestCv.block(TEST_TIMEOUT_MS), "The captive portal login " +
- "page was still not fetched ${TEST_TIMEOUT_MS}ms after startCaptivePortalApp.")
+ runAsShell(startPortalAppPermission) { cm.startCaptivePortalApp(network) }
+
+ // Expect the portal content to be fetched at some point after detecting the portal.
+ // Some implementations may fetch the URL before startCaptivePortalApp is called.
+ assertNotNull(server.requestsRecord.poll(TEST_TIMEOUT_MS, pos = 0) {
+ it.path == TEST_PORTAL_URL_PATH
+ }, "The captive portal login page was still not fetched ${TEST_TIMEOUT_MS}ms " +
+ "after startCaptivePortalApp.")
assertNotEquals(network, cm.activeNetwork, wifiDefaultMessage)
} finally {
@@ -186,73 +182,13 @@
}
}
- private fun setHttpsUrl(url: String?) = setConfig(TEST_CAPTIVE_PORTAL_HTTPS_URL_SETTING, url)
- private fun setHttpUrl(url: String?) = setConfig(TEST_CAPTIVE_PORTAL_HTTP_URL_SETTING, url)
- private fun setUrlExpiration(timestamp: Long?) = setConfig(TEST_URL_EXPIRATION_TIME,
- timestamp?.toString())
-
- private fun setConfig(configKey: String, value: String?) {
- doAsShell(WRITE_DEVICE_CONFIG) {
- DeviceConfig.setProperty(
- NAMESPACE_CONNECTIVITY, configKey, value, false /* makeDefault */)
- }
- }
-
- private fun doAsShell(vararg permissions: String, action: () -> Unit) {
- // Wrap the below call to allow for more kotlin-like syntax
- SystemUtil.runWithShellPermissionIdentity(action, permissions)
- }
+ /**
+ * Create a URL string that, when fetched, will hit the test server with the given URL [path].
+ */
+ private fun makeUrl(path: String) = "http://localhost:${server.listeningPort}" + path
private fun reconnectWifi() {
utils.ensureWifiDisconnected(null /* wifiNetworkToCheck */)
utils.ensureWifiConnected()
}
-
- /**
- * A minimal HTTP server running on localhost (loopback), on a random available port.
- */
- private class HttpServer : NanoHTTPD("localhost", 0 /* auto-select the port */) {
- // Map of URL path -> HTTP response code
- private val responses = HashMap<String, Response>()
-
- // Map of path -> CV to open as soon as a request to the path is received
- private val waitForRequestCv = HashMap<String, ConditionVariable>()
-
- /**
- * Create a URL string that, when fetched, will hit this server with the given URL [path].
- */
- fun makeUrl(path: String): String {
- return Uri.Builder()
- .scheme("http")
- .encodedAuthority("localhost:$listeningPort")
- .query(path)
- .build()
- .toString()
- }
-
- fun addResponse(
- path: String,
- statusCode: IStatus,
- locationHeader: String? = null,
- content: String = ""
- ) {
- val response = newFixedLengthResponse(statusCode, "text/plain", content)
- locationHeader?.let { response.addHeader("Location", it) }
- responses[path] = response
- }
-
- /**
- * Create a [ConditionVariable] that will open when a request to [path] is received.
- */
- fun addExpectRequestCv(path: String): ConditionVariable {
- return ConditionVariable().apply { waitForRequestCv[path] = this }
- }
-
- override fun serve(session: IHTTPSession): Response {
- waitForRequestCv[session.queryParameterString]?.open()
- return responses[session.queryParameterString]
- // Default response is a 404
- ?: super.serve(session)
- }
- }
}
\ No newline at end of file
diff --git a/tests/cts/net/src/android/net/cts/ConnectivityDiagnosticsManagerTest.java b/tests/cts/net/src/android/net/cts/ConnectivityDiagnosticsManagerTest.java
index 8f42f79..54509cd 100644
--- a/tests/cts/net/src/android/net/cts/ConnectivityDiagnosticsManagerTest.java
+++ b/tests/cts/net/src/android/net/cts/ConnectivityDiagnosticsManagerTest.java
@@ -30,6 +30,7 @@
import static android.net.ConnectivityDiagnosticsManager.DataStallReport.KEY_TCP_METRICS_COLLECTION_PERIOD_MILLIS;
import static android.net.ConnectivityDiagnosticsManager.DataStallReport.KEY_TCP_PACKET_FAIL_RATE;
import static android.net.ConnectivityDiagnosticsManager.persistableBundleEquals;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET;
import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VPN;
import static android.net.NetworkCapabilities.NET_CAPABILITY_TRUSTED;
import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
@@ -77,7 +78,7 @@
import com.android.internal.telephony.uicc.IccUtils;
import com.android.internal.util.ArrayUtils;
-import com.android.testutils.ArrayTrackRecord;
+import com.android.net.module.util.ArrayTrackRecord;
import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo;
import com.android.testutils.DevSdkIgnoreRunner;
import com.android.testutils.SkipPresubmit;
@@ -121,7 +122,10 @@
private static final String SHA_256 = "SHA-256";
private static final NetworkRequest CELLULAR_NETWORK_REQUEST =
- new NetworkRequest.Builder().addTransportType(TRANSPORT_CELLULAR).build();
+ new NetworkRequest.Builder()
+ .addTransportType(TRANSPORT_CELLULAR)
+ .addCapability(NET_CAPABILITY_INTERNET)
+ .build();
private static final IBinder BINDER = new Binder();
diff --git a/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java b/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java
index 3880664..0790acb 100644
--- a/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java
+++ b/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java
@@ -55,6 +55,7 @@
import android.app.Instrumentation;
import android.app.PendingIntent;
import android.app.UiAutomation;
+import android.content.BroadcastReceiver;
import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
@@ -122,6 +123,7 @@
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
+import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.Executor;
import java.util.concurrent.LinkedBlockingQueue;
@@ -152,6 +154,9 @@
// device could have only one interface: data, wifi.
private static final int MIN_NUM_NETWORK_TYPES = 1;
+ // Airplane Mode BroadcastReceiver Timeout
+ private static final int AIRPLANE_MODE_CHANGE_TIMEOUT_MS = 5000;
+
// 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;
@@ -199,6 +204,8 @@
} catch (Exception e) {}
}
mUiAutomation = mInstrumentation.getUiAutomation();
+
+ assertNotNull("CTS requires a working Internet connection", mCm.getActiveNetwork());
}
@After
@@ -347,8 +354,8 @@
wifiAddressString, wifiNetwork, cellNetwork),
wifiAddressString.equals(cellAddressString));
- // Sanity check that the IP addresses that the requests appeared to come from
- // are actually on the respective networks.
+ // Verify that the IP addresses that the requests appeared to come from are actually on the
+ // respective networks.
assertOnNetwork(wifiAddressString, wifiNetwork);
assertOnNetwork(cellAddressString, cellNetwork);
@@ -704,7 +711,7 @@
private void assertMultipathPreferenceIsEventually(Network network, int oldValue,
int expectedValue) {
- // Sanity check : if oldValue == expectedValue, there is no way to guarantee the test
+ // Quick check : if oldValue == expectedValue, there is no way to guarantee the test
// is not flaky.
assertNotSame(oldValue, expectedValue);
@@ -1008,7 +1015,7 @@
// 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.
+ // Verify that the callback result is expected.
runWithShellPermissionIdentity(() -> {
assertEquals(0, createConcurrentSocketKeepalives(network, srcAddr, 0, 1));
});
@@ -1371,4 +1378,84 @@
}
}
}
+
+ /**
+ * Verifies that apps are allowed to call setAirplaneMode if they declare
+ * NETWORK_AIRPLANE_MODE permission in their manifests.
+ * See b/145164696.
+ */
+ @AppModeFull(reason = "NETWORK_AIRPLANE_MODE permission can't be granted to instant apps")
+ @Test
+ public void testSetAirplaneMode() throws Exception{
+ // store the current state of airplane mode
+ final boolean isAirplaneModeEnabled = isAirplaneModeEnabled();
+
+ // disable airplane mode to reach a known state
+ runShellCommand("cmd connectivity airplane-mode disable");
+
+ try {
+ // Verify we cannot set Airplane Mode without correct permission:
+ try {
+ setAndVerifyAirplaneMode(true);
+ fail("SecurityException should have been thrown when setAirplaneMode was called"
+ + "without holding permission NETWORK_AIRPLANE_MODE.");
+ } catch (SecurityException expected) {}
+
+ // disable airplane mode again to reach a known state
+ runShellCommand("cmd connectivity airplane-mode disable");
+
+ // adopt shell permission which holds NETWORK_AIRPLANE_MODE
+ mUiAutomation.adoptShellPermissionIdentity();
+
+ // Verify we can enable Airplane Mode with correct permission:
+ try {
+ setAndVerifyAirplaneMode(true);
+ } catch (SecurityException e) {
+ fail("SecurityException should not have been thrown when setAirplaneMode(true) was"
+ + "called whilst holding the NETWORK_AIRPLANE_MODE permission.");
+ }
+
+ // Verify we can disable Airplane Mode with correct permission:
+ try {
+ setAndVerifyAirplaneMode(false);
+ } catch (SecurityException e) {
+ fail("SecurityException should not have been thrown when setAirplaneMode(false) was"
+ + "called whilst holding the NETWORK_AIRPLANE_MODE permission.");
+ }
+
+ } finally {
+ // Restore the previous state of airplane mode and permissions:
+ runShellCommand("cmd connectivity airplane-mode "
+ + (isAirplaneModeEnabled ? "enable" : "disable"));
+ mUiAutomation.dropShellPermissionIdentity();
+ }
+ }
+
+ private void setAndVerifyAirplaneMode(Boolean expectedResult)
+ throws Exception {
+ final CompletableFuture<Boolean> actualResult = new CompletableFuture();
+ BroadcastReceiver receiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ // The defaultValue of getExtraBoolean should be the opposite of what is
+ // expected, thus ensuring a test failure if the extra is absent.
+ actualResult.complete(intent.getBooleanExtra("state", !expectedResult));
+ }
+ };
+ try {
+ mContext.registerReceiver(receiver,
+ new IntentFilter(Intent.ACTION_AIRPLANE_MODE_CHANGED));
+ mCm.setAirplaneMode(expectedResult);
+ final String msg = "Setting Airplane Mode failed,";
+ assertEquals(msg, expectedResult, actualResult.get(AIRPLANE_MODE_CHANGE_TIMEOUT_MS,
+ TimeUnit.MILLISECONDS));
+ } finally {
+ mContext.unregisterReceiver(receiver);
+ }
+ }
+
+ private static boolean isAirplaneModeEnabled() {
+ return runShellCommand("cmd connectivity airplane-mode")
+ .trim().equals("enabled");
+ }
}
diff --git a/tests/cts/net/src/android/net/cts/IpConfigurationTest.java b/tests/cts/net/src/android/net/cts/IpConfigurationTest.java
index c6bc077..56ab2a7 100644
--- a/tests/cts/net/src/android/net/cts/IpConfigurationTest.java
+++ b/tests/cts/net/src/android/net/cts/IpConfigurationTest.java
@@ -16,7 +16,7 @@
package android.net.cts;
-import static com.android.testutils.ParcelUtilsKt.assertParcelSane;
+import static com.android.testutils.ParcelUtils.assertParcelSane;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
diff --git a/tests/cts/net/src/android/net/cts/MacAddressTest.java b/tests/cts/net/src/android/net/cts/MacAddressTest.java
index 4d25e62..3fd3bba 100644
--- a/tests/cts/net/src/android/net/cts/MacAddressTest.java
+++ b/tests/cts/net/src/android/net/cts/MacAddressTest.java
@@ -20,7 +20,7 @@
import static android.net.MacAddress.TYPE_MULTICAST;
import static android.net.MacAddress.TYPE_UNICAST;
-import static com.android.testutils.ParcelUtilsKt.assertParcelSane;
+import static com.android.testutils.ParcelUtils.assertParcelSane;
import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertFalse;
diff --git a/tests/cts/net/src/android/net/cts/NetworkAgentTest.kt b/tests/cts/net/src/android/net/cts/NetworkAgentTest.kt
index 2824db7..d2ca3f8 100644
--- a/tests/cts/net/src/android/net/cts/NetworkAgentTest.kt
+++ b/tests/cts/net/src/android/net/cts/NetworkAgentTest.kt
@@ -39,13 +39,6 @@
import android.net.SocketKeepalive
import android.net.StringNetworkSpecifier
import android.net.Uri
-import android.os.Build
-import android.os.Bundle
-import android.os.Handler
-import android.os.HandlerThread
-import android.os.Looper
-import android.os.Message
-import android.os.Messenger
import android.net.cts.NetworkAgentTest.TestableNetworkAgent.CallbackEntry.OnAddKeepalivePacketFilter
import android.net.cts.NetworkAgentTest.TestableNetworkAgent.CallbackEntry.OnAutomaticReconnectDisabled
import android.net.cts.NetworkAgentTest.TestableNetworkAgent.CallbackEntry.OnBandwidthUpdateRequested
@@ -56,15 +49,21 @@
import android.net.cts.NetworkAgentTest.TestableNetworkAgent.CallbackEntry.OnStartSocketKeepalive
import android.net.cts.NetworkAgentTest.TestableNetworkAgent.CallbackEntry.OnStopSocketKeepalive
import android.net.cts.NetworkAgentTest.TestableNetworkAgent.CallbackEntry.OnValidationStatus
+import android.os.Build
+import android.os.Bundle
+import android.os.Handler
+import android.os.HandlerThread
+import android.os.Looper
+import android.os.Message
+import android.os.Messenger
import androidx.test.InstrumentationRegistry
import androidx.test.runner.AndroidJUnit4
import com.android.internal.util.AsyncChannel
-import com.android.testutils.ArrayTrackRecord
+import com.android.net.module.util.ArrayTrackRecord
import com.android.testutils.DevSdkIgnoreRule
import com.android.testutils.RecorderCallback.CallbackEntry.Available
import com.android.testutils.RecorderCallback.CallbackEntry.Lost
import com.android.testutils.TestableNetworkCallback
-import java.util.UUID
import org.junit.After
import org.junit.Assert.assertArrayEquals
import org.junit.Assert.fail
@@ -74,9 +73,10 @@
import org.junit.runner.RunWith
import java.net.InetAddress
import java.time.Duration
+import java.util.UUID
import kotlin.test.assertEquals
-import kotlin.test.assertFalse
import kotlin.test.assertFailsWith
+import kotlin.test.assertFalse
import kotlin.test.assertNotNull
import kotlin.test.assertNull
import kotlin.test.assertTrue
@@ -495,8 +495,8 @@
.addTransportType(NetworkCapabilities.TRANSPORT_TEST)
.setNetworkSpecifier(StringNetworkSpecifier(name2))
.build()
- val callback1 = TestableNetworkCallback()
- val callback2 = TestableNetworkCallback()
+ val callback1 = TestableNetworkCallback(timeoutMs = DEFAULT_TIMEOUT_MS)
+ val callback2 = TestableNetworkCallback(timeoutMs = DEFAULT_TIMEOUT_MS)
requestNetwork(request1, callback1)
requestNetwork(request2, callback2)
@@ -505,7 +505,7 @@
.clearCapabilities()
.addTransportType(NetworkCapabilities.TRANSPORT_TEST)
.build()
- val callback = TestableNetworkCallback()
+ val callback = TestableNetworkCallback(timeoutMs = DEFAULT_TIMEOUT_MS)
requestNetwork(request, callback)
// Connect the first Network
@@ -602,7 +602,7 @@
.clearCapabilities()
.addTransportType(NetworkCapabilities.TRANSPORT_TEST)
.build()
- val callback1 = TestableNetworkCallback(DEFAULT_TIMEOUT_MS).also {
+ val callback1 = TestableNetworkCallback(timeoutMs = DEFAULT_TIMEOUT_MS).also {
registerNetworkCallback(request1, it)
}
requestNetwork(request1, callback1)
@@ -612,7 +612,7 @@
.clearCapabilities()
.addTransportType(NetworkCapabilities.TRANSPORT_TEST)
.build()
- val callback = TestableNetworkCallback()
+ val callback = TestableNetworkCallback(timeoutMs = DEFAULT_TIMEOUT_MS)
requestNetwork(request, callback)
// Connect the network
diff --git a/tests/cts/net/src/android/net/cts/NetworkStackDependenciesTest.kt b/tests/cts/net/src/android/net/cts/NetworkStackDependenciesTest.kt
new file mode 100644
index 0000000..1a7f955
--- /dev/null
+++ b/tests/cts/net/src/android/net/cts/NetworkStackDependenciesTest.kt
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2020 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 android.content.pm.PackageManager
+import android.net.cts.util.CtsNetUtils
+import android.net.wifi.WifiManager
+import android.os.Build
+import androidx.test.filters.SdkSuppress
+import androidx.test.platform.app.InstrumentationRegistry
+import org.junit.Assume.assumeTrue
+import org.junit.Test
+import kotlin.test.assertNotNull
+import kotlin.test.assertTrue
+
+/**
+ * Basic tests for APIs used by the network stack module.
+ */
+class NetworkStackDependenciesTest {
+ @Test
+ @SdkSuppress(maxSdkVersion = Build.VERSION_CODES.Q)
+ fun testGetFrequency() {
+ // WifiInfo#getFrequency was missing a CTS test in Q: this test is run as part of MTS on Q
+ // devices to ensure it behaves correctly.
+ val context = InstrumentationRegistry.getInstrumentation().getContext()
+ assumeTrue("This test only applies to devices that support wifi",
+ context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_WIFI))
+ val wifiManager = context.getSystemService(WifiManager::class.java)
+ assertNotNull(wifiManager, "Device supports wifi but there is no WifiManager")
+
+ CtsNetUtils(context).ensureWifiConnected()
+ val wifiInfo = wifiManager.getConnectionInfo()
+ // The NetworkStack can handle any value of getFrequency; unknown frequencies will not be
+ // classified in metrics, but this is expected behavior. It is only important that the
+ // method does not crash. Still verify that the frequency is positive
+ val frequency = wifiInfo.getFrequency()
+ assertTrue(frequency > 0, "Frequency must be > 0")
+ }
+}
\ No newline at end of file
diff --git a/tests/cts/net/src/android/net/cts/CaptivePortalApiTest.kt b/tests/cts/net/src/android/net/cts/NetworkValidationTest.kt
similarity index 82%
rename from tests/cts/net/src/android/net/cts/CaptivePortalApiTest.kt
rename to tests/cts/net/src/android/net/cts/NetworkValidationTest.kt
index ef2b0ce..ec656de 100644
--- a/tests/cts/net/src/android/net/cts/CaptivePortalApiTest.kt
+++ b/tests/cts/net/src/android/net/cts/NetworkValidationTest.kt
@@ -19,16 +19,19 @@
import android.Manifest.permission.MANAGE_TEST_NETWORKS
import android.Manifest.permission.NETWORK_SETTINGS
import android.content.Context
+import android.content.pm.PackageManager
import android.net.ConnectivityManager
import android.net.EthernetManager
import android.net.InetAddresses
import android.net.NetworkCapabilities.NET_CAPABILITY_CAPTIVE_PORTAL
import android.net.NetworkCapabilities.NET_CAPABILITY_TRUSTED
import android.net.NetworkCapabilities.TRANSPORT_ETHERNET
+import android.net.NetworkCapabilities.TRANSPORT_TEST
import android.net.NetworkRequest
import android.net.TestNetworkInterface
import android.net.TestNetworkManager
import android.net.Uri
+import android.net.cts.NetworkValidationTestUtil.runAsShell
import android.net.dhcp.DhcpDiscoverPacket
import android.net.dhcp.DhcpPacket
import android.net.dhcp.DhcpPacket.DHCP_MESSAGE_TYPE
@@ -40,27 +43,26 @@
import android.platform.test.annotations.AppModeFull
import androidx.test.platform.app.InstrumentationRegistry
import androidx.test.runner.AndroidJUnit4
-import com.android.compatibility.common.util.SystemUtil.runWithShellPermissionIdentity
-import com.android.compatibility.common.util.ThrowingRunnable
import com.android.net.module.util.Inet4AddressUtils.getBroadcastAddress
import com.android.net.module.util.Inet4AddressUtils.getPrefixMaskAsInet4Address
import com.android.server.util.NetworkStackConstants.IPV4_ADDR_ANY
+import com.android.testutils.ArpResponder
import com.android.testutils.DevSdkIgnoreRule
import com.android.testutils.DhcpClientPacketFilter
import com.android.testutils.DhcpOptionFilter
import com.android.testutils.RecorderCallback.CallbackEntry
import com.android.testutils.TapPacketReader
+import com.android.testutils.TestHttpServer
import com.android.testutils.TestableNetworkCallback
-import fi.iki.elonen.NanoHTTPD
+import fi.iki.elonen.NanoHTTPD.Response.Status
import org.junit.After
import org.junit.Assume.assumeFalse
+import org.junit.Assume.assumeTrue
import org.junit.Before
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
import java.net.Inet4Address
-import java.util.concurrent.ArrayBlockingQueue
-import java.util.concurrent.TimeUnit
import kotlin.test.assertEquals
import kotlin.test.assertNotNull
import kotlin.test.assertTrue
@@ -79,7 +81,7 @@
@AppModeFull(reason = "Instant apps cannot create test networks")
@RunWith(AndroidJUnit4::class)
-class CaptivePortalApiTest {
+class NetworkValidationTest {
@JvmField
@Rule
val ignoreRule = DevSdkIgnoreRule(ignoreClassUpTo = Build.VERSION_CODES.Q)
@@ -89,14 +91,15 @@
private val eth by lazy { context.assertHasService(EthernetManager::class.java) }
private val cm by lazy { context.assertHasService(ConnectivityManager::class.java) }
- private val handlerThread = HandlerThread(CaptivePortalApiTest::class.java.simpleName)
+ private val handlerThread = HandlerThread(NetworkValidationTest::class.java.simpleName)
private val serverIpAddr = InetAddresses.parseNumericAddress("192.0.2.222") as Inet4Address
private val clientIpAddr = InetAddresses.parseNumericAddress("192.0.2.111") as Inet4Address
- private val httpServer = HttpServer()
+ private val httpServer = TestHttpServer()
private val ethRequest = NetworkRequest.Builder()
// ETHERNET|TEST transport networks do not have NET_CAPABILITY_TRUSTED
.removeCapability(NET_CAPABILITY_TRUSTED)
- .addTransportType(TRANSPORT_ETHERNET).build()
+ .addTransportType(TRANSPORT_ETHERNET)
+ .addTransportType(TRANSPORT_TEST).build()
private val ethRequestCb = TestableNetworkCallback()
private lateinit var iface: TestNetworkInterface
@@ -107,9 +110,10 @@
@Before
fun setUp() {
- // This test requires using a tap interface as the default ethernet interface: skip if there
- // is already an ethernet interface connected.
- testSkipped = eth.isAvailable()
+ // This test requires using a tap interface as an ethernet interface.
+ val pm = context.getPackageManager()
+ testSkipped = !pm.hasSystemFeature(PackageManager.FEATURE_ETHERNET) &&
+ context.getSystemService(EthernetManager::class.java) == null
assumeFalse(testSkipped)
// Register a request so the network does not get torn down
@@ -151,7 +155,15 @@
}
@Test
- fun testApiCallbacks() {
+ fun testCapportApiCallbacks() {
+ httpServer.addResponse(capportUrl, Status.OK, content = """
+ |{
+ | "captive": true,
+ | "user-portal-url": "$TEST_LOGIN_URL",
+ | "venue-info-url": "$TEST_VENUE_INFO_URL"
+ |}
+ """.trimMargin())
+
// Handle the DHCP handshake that includes the capport API URL
val discover = reader.assertDhcpPacketReceived(
DhcpDiscoverPacket::class.java, TEST_TIMEOUT_MS, DHCP_MESSAGE_TYPE_DISCOVER)
@@ -163,11 +175,9 @@
assertEquals(clientIpAddr, request.mRequestedIp)
reader.sendResponse(makeAckPacket(request.clientMac, request.transactionId))
- // Expect a request to the capport API
- val capportReq = httpServer.recordedRequests.poll(TEST_TIMEOUT_MS, TimeUnit.MILLISECONDS)
- assertNotNull(capportReq, "The device did not fetch captive portal API data within timeout")
- assertEquals(capportUrl.path, capportReq.uri)
- assertEquals(capportUrl.query, capportReq.queryParameterString)
+ // The first request received by the server should be for the portal API
+ assertTrue(httpServer.requestsRecord.poll(TEST_TIMEOUT_MS, 0)?.matches(capportUrl) ?: false,
+ "The device did not fetch captive portal API data within timeout")
// Expect network callbacks with capport info
val testCb = TestableNetworkCallback(TEST_TIMEOUT_MS)
@@ -216,30 +226,6 @@
listOf(serverIpAddr) /* gateways */, listOf(serverIpAddr) /* dnsServers */,
serverIpAddr, TEST_DOMAIN_NAME, null /* hostname */, true /* metered */,
TEST_MTU, false /* rapidCommit */, capportUrl.toString())
-
- private fun parseDhcpPacket(bytes: ByteArray) = DhcpPacket.decodeFullPacket(
- bytes, MAX_PACKET_LENGTH, DhcpPacket.ENCAP_L2)
-}
-
-/**
- * A minimal HTTP server running on localhost (loopback), on a random available port.
- *
- * The server records each request in [recordedRequests] and will not serve any further request
- * until the last one is removed from the queue for verification.
- */
-private class HttpServer : NanoHTTPD("localhost", 0 /* auto-select the port */) {
- val recordedRequests = ArrayBlockingQueue<IHTTPSession>(1 /* capacity */)
-
- override fun serve(session: IHTTPSession): Response {
- recordedRequests.offer(session)
- return newFixedLengthResponse("""
- |{
- | "captive": true,
- | "user-portal-url": "$TEST_LOGIN_URL",
- | "venue-info-url": "$TEST_VENUE_INFO_URL"
- |}
- """.trimMargin())
- }
}
private fun <T : DhcpPacket> TapPacketReader.assertDhcpPacketReceived(
@@ -259,12 +245,3 @@
private fun <T> Context.assertHasService(manager: Class<T>): T {
return getSystemService(manager) ?: fail("Service $manager not found")
}
-
-/**
- * Wrapper around runWithShellPermissionIdentity with kotlin-like syntax.
- */
-private fun <T> runAsShell(vararg permissions: String, task: () -> T): T {
- var ret: T? = null
- runWithShellPermissionIdentity(ThrowingRunnable { ret = task() }, *permissions)
- return ret ?: fail("ThrowingRunnable was not run")
-}
diff --git a/tests/cts/net/src/android/net/cts/NetworkValidationTestUtil.kt b/tests/cts/net/src/android/net/cts/NetworkValidationTestUtil.kt
new file mode 100644
index 0000000..5ef1854
--- /dev/null
+++ b/tests/cts/net/src/android/net/cts/NetworkValidationTestUtil.kt
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2020 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 android.Manifest
+import android.net.util.NetworkStackUtils
+import android.provider.DeviceConfig
+import com.android.compatibility.common.util.SystemUtil.runWithShellPermissionIdentity
+import com.android.compatibility.common.util.ThrowingRunnable
+import kotlin.test.fail
+
+/**
+ * Collection of utility methods for configuring network validation.
+ */
+internal object NetworkValidationTestUtil {
+
+ /**
+ * Clear the test network validation URLs.
+ */
+ fun clearValidationTestUrlsDeviceConfig() {
+ setHttpsUrlDeviceConfig(null)
+ setHttpUrlDeviceConfig(null)
+ setUrlExpirationDeviceConfig(null)
+ }
+
+ /**
+ * Set the test validation HTTPS URL.
+ *
+ * @see NetworkStackUtils.TEST_CAPTIVE_PORTAL_HTTPS_URL
+ */
+ fun setHttpsUrlDeviceConfig(url: String?) =
+ setConfig(NetworkStackUtils.TEST_CAPTIVE_PORTAL_HTTPS_URL, url)
+
+ /**
+ * Set the test validation HTTP URL.
+ *
+ * @see NetworkStackUtils.TEST_CAPTIVE_PORTAL_HTTP_URL
+ */
+ fun setHttpUrlDeviceConfig(url: String?) =
+ setConfig(NetworkStackUtils.TEST_CAPTIVE_PORTAL_HTTP_URL, url)
+
+ /**
+ * Set the test validation URL expiration.
+ *
+ * @see NetworkStackUtils.TEST_URL_EXPIRATION_TIME
+ */
+ fun setUrlExpirationDeviceConfig(timestamp: Long?) =
+ setConfig(NetworkStackUtils.TEST_URL_EXPIRATION_TIME, timestamp?.toString())
+
+ private fun setConfig(configKey: String, value: String?) {
+ runAsShell(Manifest.permission.WRITE_DEVICE_CONFIG) {
+ DeviceConfig.setProperty(
+ DeviceConfig.NAMESPACE_CONNECTIVITY, configKey, value, false /* makeDefault */)
+ }
+ }
+
+ /**
+ * Wrapper around runWithShellPermissionIdentity with kotlin-like syntax.
+ */
+ fun <T> runAsShell(vararg permissions: String, task: () -> T): T {
+ var ret: T? = null
+ runWithShellPermissionIdentity(ThrowingRunnable { ret = task() }, *permissions)
+ return ret ?: fail("ThrowingRunnable did not return")
+ }
+}
\ No newline at end of file
diff --git a/tests/cts/net/util/java/android/net/cts/util/CtsNetUtils.java b/tests/cts/net/util/java/android/net/cts/util/CtsNetUtils.java
index 85d2113..f1bc130 100644
--- a/tests/cts/net/util/java/android/net/cts/util/CtsNetUtils.java
+++ b/tests/cts/net/util/java/android/net/cts/util/CtsNetUtils.java
@@ -21,6 +21,9 @@
import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET;
import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
import static android.net.NetworkCapabilities.TRANSPORT_TEST;
+import static android.net.wifi.WifiManager.SCAN_RESULTS_AVAILABLE_ACTION;
+
+import static com.android.compatibility.common.util.ShellIdentityUtils.invokeWithShellPermissions;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
@@ -44,6 +47,7 @@
import android.net.NetworkInfo.State;
import android.net.NetworkRequest;
import android.net.TestNetworkManager;
+import android.net.wifi.ScanResult;
import android.net.wifi.WifiConfiguration;
import android.net.wifi.WifiInfo;
import android.net.wifi.WifiManager;
@@ -58,13 +62,21 @@
import com.android.compatibility.common.util.SystemUtil;
+import junit.framework.AssertionFailedError;
+
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.InetSocketAddress;
import java.net.Socket;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Optional;
+import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
public final class CtsNetUtils {
private static final String TAG = CtsNetUtils.class.getSimpleName();
@@ -72,7 +84,8 @@
private static final int SOCKET_TIMEOUT_MS = 2000;
private static final int PRIVATE_DNS_PROBE_MS = 1_000;
- public static final int PRIVATE_DNS_SETTING_TIMEOUT_MS = 6_000;
+ private static final int PRIVATE_DNS_SETTING_TIMEOUT_MS = 6_000;
+ private static final int CONNECTIVITY_CHANGE_TIMEOUT_SECS = 30;
public static final int HTTP_PORT = 80;
public static final String TEST_HOST = "connectivitycheck.gstatic.com";
public static final String HTTP_REQUEST =
@@ -170,8 +183,8 @@
/**
* Enable WiFi and wait for it to become connected to a network.
*
- * A network is considered connected when a {@link NetworkCallback#onAvailable(Network)}
- * callback is received.
+ * A network is considered connected when a {@link NetworkRequest} with TRANSPORT_WIFI
+ * receives a {@link NetworkCallback#onAvailable(Network)} callback.
*/
public Network ensureWifiConnected() {
return connectToWifi(false /* expectLegacyBroadcast */);
@@ -202,8 +215,18 @@
try {
clearWifiBlacklist();
SystemUtil.runShellCommand("svc wifi enable");
- SystemUtil.runWithShellPermissionIdentity(() -> mWifiManager.reconnect(),
- NETWORK_SETTINGS);
+ final WifiConfiguration config = maybeAddVirtualWifiConfiguration();
+ if (config == null) {
+ // TODO: this may not clear the BSSID blacklist, as opposed to
+ // mWifiManager.connect(config)
+ SystemUtil.runWithShellPermissionIdentity(() -> mWifiManager.reconnect(),
+ NETWORK_SETTINGS);
+ } else {
+ // When running CTS, devices are expected to have wifi networks pre-configured.
+ // This condition is only hit on virtual devices.
+ SystemUtil.runWithShellPermissionIdentity(
+ () -> mWifiManager.connect(config, null /* listener */), NETWORK_SETTINGS);
+ }
// Ensure we get an onAvailable callback and possibly a CONNECTIVITY_ACTION.
wifiNetwork = callback.waitForAvailable();
assertNotNull(err, wifiNetwork);
@@ -219,6 +242,68 @@
return wifiNetwork;
}
+ private WifiConfiguration maybeAddVirtualWifiConfiguration() {
+ final List<WifiConfiguration> configs = invokeWithShellPermissions(
+ mWifiManager::getConfiguredNetworks);
+ // If no network is configured, add a config for virtual access points if applicable
+ if (configs.size() == 0) {
+ final List<ScanResult> scanResults = getWifiScanResults();
+ final WifiConfiguration virtualConfig = maybeConfigureVirtualNetwork(scanResults);
+ assertNotNull("The device has no configured wifi network", virtualConfig);
+
+ return virtualConfig;
+ }
+ // No need to add a configuration: there is already one
+ return null;
+ }
+
+ private List<ScanResult> getWifiScanResults() {
+ final CompletableFuture<List<ScanResult>> scanResultsFuture = new CompletableFuture<>();
+ SystemUtil.runWithShellPermissionIdentity(() -> {
+ final BroadcastReceiver receiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ scanResultsFuture.complete(mWifiManager.getScanResults());
+ }
+ };
+ mContext.registerReceiver(receiver, new IntentFilter(SCAN_RESULTS_AVAILABLE_ACTION));
+ mWifiManager.startScan();
+ });
+
+ try {
+ return scanResultsFuture.get(CONNECTIVITY_CHANGE_TIMEOUT_SECS, TimeUnit.SECONDS);
+ } catch (ExecutionException | InterruptedException | TimeoutException e) {
+ throw new AssertionFailedError("Wifi scan results not received within timeout");
+ }
+ }
+
+ /**
+ * If a virtual wifi network is detected, add a configuration for that network.
+ * TODO(b/158150376): have the test infrastructure add virtual wifi networks when appropriate.
+ */
+ private WifiConfiguration maybeConfigureVirtualNetwork(List<ScanResult> scanResults) {
+ // Virtual wifi networks used on the emulator and cloud testing infrastructure
+ final List<String> virtualSsids = Arrays.asList("VirtWifi", "AndroidWifi");
+ Log.d(TAG, "Wifi scan results: " + scanResults);
+ final ScanResult virtualScanResult = scanResults.stream().filter(
+ s -> virtualSsids.contains(s.SSID)).findFirst().orElse(null);
+
+ // Only add the virtual configuration if the virtual AP is detected in scans
+ if (virtualScanResult == null) return null;
+
+ final WifiConfiguration virtualConfig = new WifiConfiguration();
+ // ASCII SSIDs need to be surrounded by double quotes
+ virtualConfig.SSID = "\"" + virtualScanResult.SSID + "\"";
+ virtualConfig.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE);
+
+ SystemUtil.runWithShellPermissionIdentity(() -> {
+ final int networkId = mWifiManager.addNetwork(virtualConfig);
+ assertTrue(networkId >= 0);
+ assertTrue(mWifiManager.enableNetwork(networkId, false /* attemptConnect */));
+ });
+ return virtualConfig;
+ }
+
/**
* Re-enable wifi networks that were blacklisted, typically because no internet connection was
* detected the last time they were connected. This is necessary to make sure wifi can reconnect
@@ -226,8 +311,8 @@
*/
private void clearWifiBlacklist() {
SystemUtil.runWithShellPermissionIdentity(() -> {
- for (WifiConfiguration config : mWifiManager.getConfiguredNetworks()) {
- mWifiManager.enableNetwork(config.networkId, false /* attemptConnect */);
+ for (WifiConfiguration cfg : mWifiManager.getConfiguredNetworks()) {
+ assertTrue(mWifiManager.enableNetwork(cfg.networkId, false /* attemptConnect */));
}
});
}
@@ -533,7 +618,7 @@
}
public boolean waitForState() throws InterruptedException {
- return mReceiveLatch.await(30, TimeUnit.SECONDS);
+ return mReceiveLatch.await(CONNECTIVITY_CHANGE_TIMEOUT_SECS, TimeUnit.SECONDS);
}
}
@@ -550,11 +635,13 @@
public Network lastLostNetwork;
public Network waitForAvailable() throws InterruptedException {
- return mAvailableLatch.await(30, TimeUnit.SECONDS) ? currentNetwork : null;
+ return mAvailableLatch.await(CONNECTIVITY_CHANGE_TIMEOUT_SECS, TimeUnit.SECONDS)
+ ? currentNetwork : null;
}
public Network waitForLost() throws InterruptedException {
- return mLostLatch.await(30, TimeUnit.SECONDS) ? lastLostNetwork : null;
+ return mLostLatch.await(CONNECTIVITY_CHANGE_TIMEOUT_SECS, TimeUnit.SECONDS)
+ ? lastLostNetwork : null;
}
public boolean waitForUnavailable() throws InterruptedException {
diff --git a/tests/cts/tethering/Android.bp b/tests/cts/tethering/Android.bp
index 85bb0e0..b1d4a60 100644
--- a/tests/cts/tethering/Android.bp
+++ b/tests/cts/tethering/Android.bp
@@ -17,7 +17,7 @@
defaults: ["cts_defaults"],
libs: [
- "android.test.base.stubs",
+ "android.test.base",
],
srcs: [
diff --git a/tests/cts/tethering/src/android/tethering/cts/TetheringManagerTest.java b/tests/cts/tethering/src/android/tethering/cts/TetheringManagerTest.java
index 5e2f627..65a8c7c 100644
--- a/tests/cts/tethering/src/android/tethering/cts/TetheringManagerTest.java
+++ b/tests/cts/tethering/src/android/tethering/cts/TetheringManagerTest.java
@@ -72,7 +72,7 @@
import androidx.test.InstrumentationRegistry;
import androidx.test.runner.AndroidJUnit4;
-import com.android.testutils.ArrayTrackRecord;
+import com.android.net.module.util.ArrayTrackRecord;
import org.junit.After;
import org.junit.Before;
@@ -697,6 +697,7 @@
@Test
public void testRequestLatestEntitlementResult() throws Exception {
+ assumeTrue(mTM.isTetheringSupported());
// Verify that requestLatestTetheringEntitlementResult() can get entitlement
// result(TETHER_ERROR_ENTITLEMENT_UNKNOWN due to invalid downstream type) via listener.
assertEntitlementResult(listener -> mTM.requestLatestTetheringEntitlementResult(
@@ -715,6 +716,9 @@
}, false),
TETHER_ERROR_ENTITLEMENT_UNKNOWN);
+ // Do not request TETHERING_WIFI entitlement result if TETHERING_WIFI is not available.
+ assumeTrue(mTM.getTetherableWifiRegexs().length > 0);
+
// Verify that null listener will cause IllegalArgumentException.
try {
mTM.requestLatestTetheringEntitlementResult(