From 4a15140077bd55ec9fec880afb42ce0601a70ad1 Mon Sep 17 00:00:00 2001 From: Treehugger Robot Date: Wed, 9 Jun 2021 11:09:35 +0000 Subject: [PATCH 01/11] Improve handling of invalid private DNS settings When private DNS mode is strict, there should always be a private DNS specifier with the hostname. Instead of restoring an invalid strict mode setting when set, have tests reset private DNS mode to opportunistic and fail. Bug: 190465704 Test: atest CtsNetTestCases Original-Change: https://android-review.googlesource.com/1730543 Merged-In: I45adc527267aa86d52e824f426699c5a7e874f63 Change-Id: I45adc527267aa86d52e824f426699c5a7e874f63 --- .../net/util/java/android/net/cts/util/CtsNetUtils.java | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) 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 b32218bc3f..4abbecce2c 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 @@ -529,12 +529,14 @@ public final class CtsNetUtils { } // restore private DNS setting if (PRIVATE_DNS_MODE_STRICT.equals(mOldPrivateDnsMode)) { - setPrivateDnsStrictMode(mOldPrivateDnsSpecifier); - - // In case of invalid setting, still restore it but fail the test + // In case of invalid setting, set to opportunistic to avoid a bad state and fail if (mOldPrivateDnsSpecifier == null) { + Settings.Global.putString(mCR, Settings.Global.PRIVATE_DNS_MODE, + PRIVATE_DNS_MODE_OPPORTUNISTIC); fail("Invalid private DNS setting: no hostname specified in strict mode"); } + setPrivateDnsStrictMode(mOldPrivateDnsSpecifier); + awaitPrivateDnsSetting("restorePrivateDnsSetting timeout", mCm.getActiveNetwork(), mOldPrivateDnsSpecifier, true); From ecad16cf28a187914733df4cc2d69874563e9cec Mon Sep 17 00:00:00 2001 From: Treehugger Robot Date: Wed, 9 Jun 2021 18:42:59 +0000 Subject: [PATCH 02/11] Skip CaptivePortalTest for wearables Watch devices do not support Captive Portal connection Bug: 189540750 Original-Change: https://android-review.googlesource.com/1727591 Merged-In: Iaf1a799d0cda1d7156fedcdab34184a52f351fbf Change-Id: Iaf1a799d0cda1d7156fedcdab34184a52f351fbf Test: run cts -m CtsNetTestCases -t android.net.cts.CaptivePortalTest#testCaptivePortalIsNotDefaultNetwork --- tests/cts/net/src/android/net/cts/CaptivePortalTest.kt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tests/cts/net/src/android/net/cts/CaptivePortalTest.kt b/tests/cts/net/src/android/net/cts/CaptivePortalTest.kt index a889c41f53..f993aedd1f 100644 --- a/tests/cts/net/src/android/net/cts/CaptivePortalTest.kt +++ b/tests/cts/net/src/android/net/cts/CaptivePortalTest.kt @@ -20,6 +20,7 @@ import android.Manifest.permission.CONNECTIVITY_INTERNAL import android.Manifest.permission.NETWORK_SETTINGS import android.Manifest.permission.READ_DEVICE_CONFIG import android.content.pm.PackageManager.FEATURE_TELEPHONY +import android.content.pm.PackageManager.FEATURE_WATCH import android.content.pm.PackageManager.FEATURE_WIFI import android.net.ConnectivityManager import android.net.ConnectivityManager.NetworkCallback @@ -57,6 +58,7 @@ import fi.iki.elonen.NanoHTTPD.Response.Status import junit.framework.AssertionFailedError import org.junit.After import org.junit.Assume.assumeTrue +import org.junit.Assume.assumeFalse import org.junit.Before import org.junit.runner.RunWith import java.util.concurrent.CompletableFuture @@ -128,6 +130,7 @@ class CaptivePortalTest { fun testCaptivePortalIsNotDefaultNetwork() { assumeTrue(pm.hasSystemFeature(FEATURE_TELEPHONY)) assumeTrue(pm.hasSystemFeature(FEATURE_WIFI)) + assumeFalse(pm.hasSystemFeature(FEATURE_WATCH)) utils.ensureWifiConnected() val cellNetwork = utils.connectToCell() From b9c9e07fe2dccc387d22bce25132f950f7e59bb3 Mon Sep 17 00:00:00 2001 From: Chiachang Wang Date: Wed, 16 Jun 2021 15:29:37 +0000 Subject: [PATCH 03/11] Add test for CM#setAcceptPartialConnectivity Bug: 186061922 Test: atest CtsNetTestCases:android.net.cts.ConnectivityManagerTest Test: atest CtsNetTestCasesLatestSdk Original-Change: https://android-review.googlesource.com/1730545 Merged-In: Iba312defb6f02896eac518d71d36f1ef3df3d00b Change-Id: Iba312defb6f02896eac518d71d36f1ef3df3d00b --- .../net/cts/ConnectivityManagerTest.java | 156 +++++++++++++++++- .../net/cts/NetworkValidationTestUtil.kt | 8 +- 2 files changed, 159 insertions(+), 5 deletions(-) diff --git a/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java b/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java index d649518528..fc1c743dd7 100644 --- a/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java +++ b/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java @@ -19,6 +19,7 @@ package android.net.cts; import static android.Manifest.permission.CONNECTIVITY_INTERNAL; import static android.Manifest.permission.CONNECTIVITY_USE_RESTRICTED_NETWORKS; import static android.Manifest.permission.NETWORK_SETTINGS; +import static android.Manifest.permission.READ_DEVICE_CONFIG; import static android.content.pm.PackageManager.FEATURE_BLUETOOTH; import static android.content.pm.PackageManager.FEATURE_ETHERNET; import static android.content.pm.PackageManager.FEATURE_TELEPHONY; @@ -48,6 +49,8 @@ import static android.net.NetworkCapabilities.NET_CAPABILITY_IMS; import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET; import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_METERED; import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED; +import static android.net.NetworkCapabilities.NET_CAPABILITY_PARTIAL_CONNECTIVITY; +import static android.net.NetworkCapabilities.NET_CAPABILITY_VALIDATED; import static android.net.NetworkCapabilities.TRANSPORT_TEST; import static android.net.NetworkCapabilities.TRANSPORT_WIFI; import static android.net.TetheringManager.TETHERING_WIFI; @@ -60,6 +63,8 @@ import static android.net.cts.util.CtsNetUtils.TestNetworkCallback; import static android.net.cts.util.CtsTetheringUtils.StartTetheringCallback; import static android.net.cts.util.CtsTetheringUtils.TestTetheringEventCallback; import static android.net.cts.util.CtsTetheringUtils.isWifiTetheringSupported; +import static android.net.util.NetworkStackUtils.TEST_CAPTIVE_PORTAL_HTTPS_URL; +import static android.net.util.NetworkStackUtils.TEST_CAPTIVE_PORTAL_HTTP_URL; import static android.os.MessageQueue.OnFileDescriptorEventListener.EVENT_INPUT; import static android.provider.Settings.Global.NETWORK_METERED_MULTIPATH_PREFERENCE; import static android.system.OsConstants.AF_INET; @@ -81,7 +86,6 @@ import static org.junit.Assert.assertNotEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNotSame; import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertThrows; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import static org.junit.Assume.assumeTrue; @@ -122,6 +126,7 @@ import android.net.TelephonyNetworkSpecifier; import android.net.TestNetworkInterface; import android.net.TestNetworkManager; import android.net.TetheringManager; +import android.net.Uri; import android.net.cts.util.CtsNetUtils; import android.net.util.KeepaliveUtils; import android.net.wifi.WifiManager; @@ -136,6 +141,7 @@ import android.os.SystemProperties; import android.os.UserHandle; import android.os.VintfRuntimeInfo; import android.platform.test.annotations.AppModeFull; +import android.provider.DeviceConfig; import android.provider.Settings; import android.telephony.SubscriptionManager; import android.telephony.TelephonyManager; @@ -160,6 +166,7 @@ import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo; import com.android.testutils.DevSdkIgnoreRuleKt; import com.android.testutils.RecorderCallback.CallbackEntry; import com.android.testutils.SkipPresubmit; +import com.android.testutils.TestHttpServer; import com.android.testutils.TestNetworkTracker; import com.android.testutils.TestableNetworkCallback; @@ -202,6 +209,10 @@ import java.util.function.Supplier; import java.util.regex.Matcher; import java.util.regex.Pattern; +import fi.iki.elonen.NanoHTTPD.Method; +import fi.iki.elonen.NanoHTTPD.Response.IStatus; +import fi.iki.elonen.NanoHTTPD.Response.Status; + @RunWith(AndroidJUnit4.class) public class ConnectivityManagerTest { @Rule @@ -245,6 +256,12 @@ public class ConnectivityManagerTest { private static final int AIRPLANE_MODE_OFF = 0; private static final int AIRPLANE_MODE_ON = 1; + private static final String TEST_HTTPS_URL_PATH = "/https_path"; + private static final String TEST_HTTP_URL_PATH = "/http_path"; + private static final String LOCALHOST_HOSTNAME = "localhost"; + // Re-connecting to the AP, obtaining an IP address, revalidating can take a long time + private static final long WIFI_CONNECT_TIMEOUT_MS = 60_000L; + private Context mContext; private Instrumentation mInstrumentation; private ConnectivityManager mCm; @@ -259,6 +276,8 @@ public class ConnectivityManagerTest { // Used for cleanup purposes. private final List> mVpnRequiredUidRanges = new ArrayList<>(); + private final TestHttpServer mHttpServer = new TestHttpServer(LOCALHOST_HOSTNAME); + @Before public void setUp() throws Exception { mInstrumentation = InstrumentationRegistry.getInstrumentation(); @@ -2327,4 +2346,139 @@ public class ConnectivityManagerTest { } oemPrefListener.expectOnComplete(); } + + @Test + public void testSetAcceptPartialConnectivity_NoPermission_GetException() { + assumeTrue(TestUtils.shouldTestSApis()); + assertThrows(SecurityException.class, () -> mCm.setAcceptPartialConnectivity( + mCm.getActiveNetwork(), false /* accept */ , false /* always */)); + } + + @AppModeFull(reason = "WRITE_DEVICE_CONFIG permission can't be granted to instant apps") + @Test + public void testAcceptPartialConnectivity_validatedNetwork() throws Exception { + assumeTrue(TestUtils.shouldTestSApis()); + assumeTrue("testAcceptPartialConnectivity_validatedNetwork cannot execute" + + " unless device supports WiFi", + mPackageManager.hasSystemFeature(FEATURE_WIFI)); + + try { + // Wait for partial connectivity to be detected on the network + final Network network = preparePartialConnectivity(); + + runAsShell(NETWORK_SETTINGS, () -> { + // The always bit is verified in NetworkAgentTest + mCm.setAcceptPartialConnectivity(network, true /* accept */, false /* always */); + }); + + // Accept partial connectivity network should result in a validated network + expectNetworkHasCapability(network, NET_CAPABILITY_VALIDATED, WIFI_CONNECT_TIMEOUT_MS); + } finally { + resetValidationConfig(); + // Reconnect wifi to reset the wifi status + mCtsNetUtils.ensureWifiDisconnected(null /* wifiNetworkToCheck */); + mCtsNetUtils.ensureWifiConnected(); + } + } + + @AppModeFull(reason = "WRITE_DEVICE_CONFIG permission can't be granted to instant apps") + @Test + public void testRejectPartialConnectivity_TearDownNetwork() throws Exception { + assumeTrue(TestUtils.shouldTestSApis()); + assumeTrue("testAcceptPartialConnectivity_validatedNetwork cannot execute" + + " unless device supports WiFi", + mPackageManager.hasSystemFeature(FEATURE_WIFI)); + + final TestNetworkCallback cb = new TestNetworkCallback(); + try { + // Wait for partial connectivity to be detected on the network + final Network network = preparePartialConnectivity(); + + mCm.requestNetwork(makeWifiNetworkRequest(), cb); + runAsShell(NETWORK_SETTINGS, () -> { + // The always bit is verified in NetworkAgentTest + mCm.setAcceptPartialConnectivity(network, false /* accept */, false /* always */); + }); + // Reject partial connectivity network should cause the network being torn down + assertEquals(network, cb.waitForLost()); + } finally { + mCm.unregisterNetworkCallback(cb); + resetValidationConfig(); + // Wifi will not automatically reconnect to the network. ensureWifiDisconnected cannot + // apply here. Thus, turn off wifi first and restart to restore. + runShellCommand("svc wifi disable"); + mCtsNetUtils.ensureWifiConnected(); + } + } + + private Network expectNetworkHasCapability(Network network, int expectedNetCap, long timeout) + throws Exception { + final CompletableFuture future = new CompletableFuture(); + final NetworkCallback cb = new NetworkCallback() { + @Override + public void onCapabilitiesChanged(Network n, NetworkCapabilities nc) { + if (n.equals(network) && nc.hasCapability(expectedNetCap)) { + future.complete(network); + } + } + }; + + try { + mCm.registerNetworkCallback(new NetworkRequest.Builder().build(), cb); + return future.get(timeout, TimeUnit.MILLISECONDS); + } finally { + mCm.unregisterNetworkCallback(cb); + } + } + + private void resetValidationConfig() { + NetworkValidationTestUtil.clearValidationTestUrlsDeviceConfig(); + mHttpServer.stop(); + } + + private Network preparePartialConnectivity() throws Exception { + 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); + assertEmptyOrLocalhostUrl(TEST_CAPTIVE_PORTAL_HTTP_URL); + }); + + NetworkValidationTestUtil.clearValidationTestUrlsDeviceConfig(); + + mHttpServer.start(); + // Configure response code for partial connectivity + configTestServer(Status.INTERNAL_ERROR /* httpsStatusCode */, + Status.NO_CONTENT /* httpStatusCode */); + // Disconnect wifi first then start wifi network with configuration. + mCtsNetUtils.ensureWifiDisconnected(null /* wifiNetworkToCheck */); + final Network network = mCtsNetUtils.ensureWifiConnected(); + + return expectNetworkHasCapability(network, NET_CAPABILITY_PARTIAL_CONNECTIVITY, + WIFI_CONNECT_TIMEOUT_MS); + } + + private String makeUrl(String path) { + return "http://localhost:" + mHttpServer.getListeningPort() + path; + } + + private void assertEmptyOrLocalhostUrl(String urlKey) { + final String url = DeviceConfig.getProperty(DeviceConfig.NAMESPACE_CONNECTIVITY, urlKey); + assertTrue(urlKey + " must not be set in production scenarios, current value= " + url, + TextUtils.isEmpty(url) || LOCALHOST_HOSTNAME.equals(Uri.parse(url).getHost())); + } + + private void configTestServer(IStatus httpsStatusCode, IStatus httpStatusCode) { + mHttpServer.addResponse(new TestHttpServer.Request( + TEST_HTTPS_URL_PATH, Method.GET, "" /* queryParameters */), + httpsStatusCode, null /* locationHeader */, "" /* content */); + mHttpServer.addResponse(new TestHttpServer.Request( + TEST_HTTP_URL_PATH, Method.GET, "" /* queryParameters */), + httpStatusCode, null /* locationHeader */, "" /* content */); + NetworkValidationTestUtil.setHttpsUrlDeviceConfig(makeUrl(TEST_HTTPS_URL_PATH)); + NetworkValidationTestUtil.setHttpUrlDeviceConfig(makeUrl(TEST_HTTP_URL_PATH)); + NetworkValidationTestUtil.setUrlExpirationDeviceConfig( + System.currentTimeMillis() + WIFI_CONNECT_TIMEOUT_MS); + } } diff --git a/tests/cts/net/src/android/net/cts/NetworkValidationTestUtil.kt b/tests/cts/net/src/android/net/cts/NetworkValidationTestUtil.kt index f6fc75b5f4..dde14ac585 100644 --- a/tests/cts/net/src/android/net/cts/NetworkValidationTestUtil.kt +++ b/tests/cts/net/src/android/net/cts/NetworkValidationTestUtil.kt @@ -29,7 +29,7 @@ internal object NetworkValidationTestUtil { /** * Clear the test network validation URLs. */ - fun clearValidationTestUrlsDeviceConfig() { + @JvmStatic fun clearValidationTestUrlsDeviceConfig() { setHttpsUrlDeviceConfig(null) setHttpUrlDeviceConfig(null) setUrlExpirationDeviceConfig(null) @@ -40,7 +40,7 @@ internal object NetworkValidationTestUtil { * * @see NetworkStackUtils.TEST_CAPTIVE_PORTAL_HTTPS_URL */ - fun setHttpsUrlDeviceConfig(url: String?) = + @JvmStatic fun setHttpsUrlDeviceConfig(url: String?) = setConfig(NetworkStackUtils.TEST_CAPTIVE_PORTAL_HTTPS_URL, url) /** @@ -48,7 +48,7 @@ internal object NetworkValidationTestUtil { * * @see NetworkStackUtils.TEST_CAPTIVE_PORTAL_HTTP_URL */ - fun setHttpUrlDeviceConfig(url: String?) = + @JvmStatic fun setHttpUrlDeviceConfig(url: String?) = setConfig(NetworkStackUtils.TEST_CAPTIVE_PORTAL_HTTP_URL, url) /** @@ -56,7 +56,7 @@ internal object NetworkValidationTestUtil { * * @see NetworkStackUtils.TEST_URL_EXPIRATION_TIME */ - fun setUrlExpirationDeviceConfig(timestamp: Long?) = + @JvmStatic fun setUrlExpirationDeviceConfig(timestamp: Long?) = setConfig(NetworkStackUtils.TEST_URL_EXPIRATION_TIME, timestamp?.toString()) private fun setConfig(configKey: String, value: String?) { From 1981466747b7e3b45343bf52b8dc96c0578621ea Mon Sep 17 00:00:00 2001 From: Chiachang Wang Date: Wed, 16 Jun 2021 15:29:47 +0000 Subject: [PATCH 04/11] Add test for CM#setAcceptUnvalidated The always bit is verified in NetworkAgentTest. There is no easy configuration to set an explicitly selected network to accept an unvalidated network. Verify the accepted case also in NetworkAgentTest. Bug: 186061922 Test: atest CtsNetTestCases:android.net.cts.ConnectivityManagerTest Test: atest CtsNetTestCasesLatestSdk Original-Change: https://android-review.googlesource.com/1731234 Merged-In: I803eb975fb0b6c52d55b2310293bcad407d21f42 Change-Id: I803eb975fb0b6c52d55b2310293bcad407d21f42 --- .../net/cts/ConnectivityManagerTest.java | 62 ++++++++++++++++++- 1 file changed, 61 insertions(+), 1 deletion(-) diff --git a/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java b/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java index fc1c743dd7..2cca1e6b58 100644 --- a/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java +++ b/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java @@ -686,12 +686,14 @@ public class ConnectivityManagerTest { private NetworkRequest makeWifiNetworkRequest() { return new NetworkRequest.Builder() .addTransportType(NetworkCapabilities.TRANSPORT_WIFI) + .addCapability(NET_CAPABILITY_INTERNET) .build(); } private NetworkRequest makeCellNetworkRequest() { return new NetworkRequest.Builder() .addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR) + .addCapability(NET_CAPABILITY_INTERNET) .build(); } @@ -2411,6 +2413,47 @@ public class ConnectivityManagerTest { } } + @Test + public void testSetAcceptUnvalidated_NoPermission_GetException() { + assumeTrue(TestUtils.shouldTestSApis()); + assertThrows(SecurityException.class, () -> mCm.setAcceptUnvalidated( + mCm.getActiveNetwork(), false /* accept */ , false /* always */)); + } + + @AppModeFull(reason = "WRITE_DEVICE_CONFIG permission can't be granted to instant apps") + @Test + public void testRejectUnvalidated_TearDownNetwork() throws Exception { + assumeTrue(TestUtils.shouldTestSApis()); + final boolean canRunTest = mPackageManager.hasSystemFeature(FEATURE_WIFI) + && mPackageManager.hasSystemFeature(FEATURE_TELEPHONY); + assumeTrue("testAcceptPartialConnectivity_validatedNetwork cannot execute" + + " unless device supports WiFi and telephony", canRunTest); + + final TestableNetworkCallback wifiCb = new TestableNetworkCallback(); + try { + // Ensure at least one default network candidate connected. + mCtsNetUtils.connectToCell(); + + final Network wifiNetwork = prepareUnvalidatedNetwork(); + // Default network should not be wifi ,but checking that wifi is not the default doesn't + // guarantee that it won't become the default in the future. + assertNotEquals(wifiNetwork, mCm.getActiveNetwork()); + + mCm.registerNetworkCallback(makeWifiNetworkRequest(), wifiCb); + runAsShell(NETWORK_SETTINGS, () -> { + mCm.setAcceptUnvalidated(wifiNetwork, false /* accept */, false /* always */); + }); + waitForLost(wifiCb); + } finally { + mCm.unregisterNetworkCallback(wifiCb); + resetValidationConfig(); + /// Wifi will not automatically reconnect to the network. ensureWifiDisconnected cannot + // apply here. Thus, turn off wifi first and restart to restore. + runShellCommand("svc wifi disable"); + mCtsNetUtils.ensureWifiConnected(); + } + } + private Network expectNetworkHasCapability(Network network, int expectedNetCap, long timeout) throws Exception { final CompletableFuture future = new CompletableFuture(); @@ -2436,7 +2479,7 @@ public class ConnectivityManagerTest { mHttpServer.stop(); } - private Network preparePartialConnectivity() throws Exception { + private void prepareHttpServer() throws Exception { 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 @@ -2448,6 +2491,10 @@ public class ConnectivityManagerTest { NetworkValidationTestUtil.clearValidationTestUrlsDeviceConfig(); mHttpServer.start(); + } + + private Network preparePartialConnectivity() throws Exception { + prepareHttpServer(); // Configure response code for partial connectivity configTestServer(Status.INTERNAL_ERROR /* httpsStatusCode */, Status.NO_CONTENT /* httpStatusCode */); @@ -2459,6 +2506,19 @@ public class ConnectivityManagerTest { WIFI_CONNECT_TIMEOUT_MS); } + private Network prepareUnvalidatedNetwork() throws Exception { + prepareHttpServer(); + // Configure response code for unvalidated network + configTestServer(Status.INTERNAL_ERROR /* httpsStatusCode */, + Status.INTERNAL_ERROR /* httpStatusCode */); + + // Disconnect wifi first then start wifi network with configuration. + mCtsNetUtils.ensureWifiDisconnected(null /* wifiNetworkToCheck */); + final Network wifiNetwork = mCtsNetUtils.ensureWifiConnected(); + return expectNetworkHasCapability(wifiNetwork, NET_CAPABILITY_INTERNET, + WIFI_CONNECT_TIMEOUT_MS); + } + private String makeUrl(String path) { return "http://localhost:" + mHttpServer.getListeningPort() + path; } From 1eb05790a268f8e971af51a5f8572cb3f2e4e34b Mon Sep 17 00:00:00 2001 From: Aaron Huang Date: Mon, 21 Jun 2021 09:59:33 +0000 Subject: [PATCH 05/11] CTS test for PacProxyManager Bug: 181745786 Test: build CtsNetTestCases pass CtsNetTestCases:PacProxyManagerTest CtsNetTestCases:CaptivePortalTest Original-Change: https://android-review.googlesource.com/1705131 Merged-In: I88cf3ecac12f4e8726d95a9b051e83eb719b0702 Change-Id: I88cf3ecac12f4e8726d95a9b051e83eb719b0702 --- .../src/android/net/cts/CaptivePortalTest.kt | 4 +- .../android/net/cts/PacProxyManagerTest.java | 192 ++++++++++++++++++ 2 files changed, 194 insertions(+), 2 deletions(-) create mode 100644 tests/cts/net/src/android/net/cts/PacProxyManagerTest.java diff --git a/tests/cts/net/src/android/net/cts/CaptivePortalTest.kt b/tests/cts/net/src/android/net/cts/CaptivePortalTest.kt index f993aedd1f..9f079c42ed 100644 --- a/tests/cts/net/src/android/net/cts/CaptivePortalTest.kt +++ b/tests/cts/net/src/android/net/cts/CaptivePortalTest.kt @@ -151,8 +151,8 @@ class CaptivePortalTest { server.addResponse(Request(TEST_PORTAL_URL_PATH), Status.OK, content = "Test captive portal content") 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)) + val headers = mapOf("Location" to makeUrl(TEST_PORTAL_URL_PATH)) + server.addResponse(Request(TEST_HTTP_URL_PATH), Status.REDIRECT, headers) setHttpsUrlDeviceConfig(makeUrl(TEST_HTTPS_URL_PATH)) setHttpUrlDeviceConfig(makeUrl(TEST_HTTP_URL_PATH)) // URL expiration needs to be in the next 10 minutes diff --git a/tests/cts/net/src/android/net/cts/PacProxyManagerTest.java b/tests/cts/net/src/android/net/cts/PacProxyManagerTest.java new file mode 100644 index 0000000000..7d5e9ff02e --- /dev/null +++ b/tests/cts/net/src/android/net/cts/PacProxyManagerTest.java @@ -0,0 +1,192 @@ +/* + * Copyright (C) 2021 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.Manifest.permission.NETWORK_SETTINGS; + +import static com.android.testutils.TestPermissionUtil.runAsShell; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +import android.app.Instrumentation; +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.net.ConnectivityManager; +import android.net.Network; +import android.net.PacProxyManager; +import android.net.Proxy; +import android.net.ProxyInfo; +import android.net.Uri; +import android.os.Build; +import android.util.Log; +import android.util.Range; + +import androidx.test.InstrumentationRegistry; + +import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo; +import com.android.testutils.DevSdkIgnoreRunner; +import com.android.testutils.TestHttpServer; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; + +import java.net.ServerSocket; +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.Executor; +import java.util.concurrent.TimeUnit; + +import fi.iki.elonen.NanoHTTPD.Response.Status; + +@IgnoreUpTo(Build.VERSION_CODES.R) +@RunWith(DevSdkIgnoreRunner.class) +public final class PacProxyManagerTest { + private static final String TAG = PacProxyManagerTest.class.getSimpleName(); + private static final int PROXY_CHANGED_BROADCAST_TIMEOUT_MS = 5000; + private static final int CALLBACK_TIMEOUT_MS = 3 * 1000; + + private Context mContext; + private TestHttpServer mServer; + private ConnectivityManager mCm; + private PacProxyManager mPacProxyManager; + private ServerSocket mServerSocket; + private Instrumentation mInstrumentation; + + private static final String PAC_FILE = "function FindProxyForURL(url, host)" + + "{" + + " return \"PROXY 192.168.0.1:9091\";" + + "}"; + + @Before + public void setUp() throws Exception { + mInstrumentation = InstrumentationRegistry.getInstrumentation(); + mContext = mInstrumentation.getContext(); + + mCm = mContext.getSystemService(ConnectivityManager.class); + mPacProxyManager = (PacProxyManager) mContext.getSystemService(PacProxyManager.class); + mServer = new TestHttpServer(); + mServer.start(); + } + + @After + public void tearDown() throws Exception { + if (mServer != null) { + mServer.stop(); + mServer = null; + } + } + + private class TestPacProxyInstalledListener implements + PacProxyManager.PacProxyInstalledListener { + private final CountDownLatch mLatch = new CountDownLatch(1); + + public void onPacProxyInstalled(Network network, ProxyInfo proxy) { + Log.e(TAG, "onPacProxyInstalled is called."); + mLatch.countDown(); + } + + public boolean waitForCallback() throws Exception { + final boolean result = mLatch.await(CALLBACK_TIMEOUT_MS, TimeUnit.MILLISECONDS); + return result; + } + } + + private class ProxyBroadcastReceiver extends BroadcastReceiver { + private final CountDownLatch mLatch = new CountDownLatch(1); + private final ProxyInfo mProxy; + + ProxyBroadcastReceiver(ProxyInfo proxy) { + mProxy = proxy; + } + + @Override + public void onReceive(Context context, Intent intent) { + final ProxyInfo proxy = (ProxyInfo) intent.getExtra(Proxy.EXTRA_PROXY_INFO, + ProxyInfo.buildPacProxy(Uri.EMPTY)); + // ProxyTracker sends sticky broadcast which will receive the last broadcast while + // register the intent receiver. That is, if system never receives the intent then + // it won't receive an intent when register the receiver. How many intents will be + // received in the test is unpredictable so here counts down the latch when the PAC + // file in the intent is the same as the one at registration. + if (mProxy.getPacFileUrl().equals(proxy.getPacFileUrl())) { + // Host/Port represent a local proxy server that redirects to the PAC-configured + // server. Host should be "localhost" and the port should be a value which is + // between 0 and 65535. + assertEquals(proxy.getHost(), "localhost"); + assertInRange(proxy.getPort(), 0 /* lower */, 65535 /* upper */); + mLatch.countDown(); + } + } + + public boolean waitForProxyChanged() throws Exception { + final boolean result = mLatch.await(PROXY_CHANGED_BROADCAST_TIMEOUT_MS, + TimeUnit.MILLISECONDS); + return result; + } + } + + @Test + public void testSetCurrentProxyScriptUrl() throws Exception { + // Register a PacProxyInstalledListener + final TestPacProxyInstalledListener listener = new TestPacProxyInstalledListener(); + final Executor executor = (Runnable r) -> r.run(); + + runAsShell(NETWORK_SETTINGS, () -> { + mPacProxyManager.addPacProxyInstalledListener(executor, listener); + }); + + final Map headers = new HashMap(); + headers.put("Content-Type", "application/x-ns-proxy-autoconfig"); + final Uri pacProxyUrl = Uri.parse("http://localhost:" + + mServer.getListeningPort() + "/proxy.pac"); + mServer.addResponse(pacProxyUrl, Status.OK, headers, PAC_FILE); + + final ProxyInfo proxy = ProxyInfo.buildPacProxy(pacProxyUrl); + final ProxyBroadcastReceiver receiver = new ProxyBroadcastReceiver(proxy); + mContext.registerReceiver(receiver, new IntentFilter(Proxy.PROXY_CHANGE_ACTION)); + + // Call setCurrentProxyScriptUrl with the URL of the pac file. + runAsShell(NETWORK_SETTINGS, () -> { + mPacProxyManager.setCurrentProxyScriptUrl(proxy); + }); + + // Make sure the listener was called and testing the intent is received. + try { + assertTrue("Didn't receive PROXY_CHANGE_ACTION broadcast.", + receiver.waitForProxyChanged()); + assertTrue("Did not receive onPacProxyInstalled callback.", + listener.waitForCallback()); + } finally { + runAsShell(NETWORK_SETTINGS, () -> { + mPacProxyManager.removePacProxyInstalledListener(listener); + }); + mContext.unregisterReceiver(receiver); + } + } + + private void assertInRange(int value, int lower, int upper) { + final Range range = new Range(lower, upper); + assertTrue(value + "is not within range [" + lower + ", " + upper + "]", + range.contains(value)); + } +} From 34c8be9ac701832f0a746854a88b20a48616de1d Mon Sep 17 00:00:00 2001 From: Treehugger Robot Date: Mon, 21 Jun 2021 13:54:39 +0000 Subject: [PATCH 06/11] Add test for setHttpProxyConfiguration The test verifies that system properties are set as expected by the method. Bug: 174436414 Test: atest ProxyTest Original-Change: https://android-review.googlesource.com/1564956 Merged-In: Id15909c5e52f1042d7210cf7e416874bb01baee7 Change-Id: Id15909c5e52f1042d7210cf7e416874bb01baee7 --- .../net/src/android/net/cts/ProxyTest.java | 39 ------- .../cts/net/src/android/net/cts/ProxyTest.kt | 103 ++++++++++++++++++ 2 files changed, 103 insertions(+), 39 deletions(-) delete mode 100644 tests/cts/net/src/android/net/cts/ProxyTest.java create mode 100644 tests/cts/net/src/android/net/cts/ProxyTest.kt diff --git a/tests/cts/net/src/android/net/cts/ProxyTest.java b/tests/cts/net/src/android/net/cts/ProxyTest.java deleted file mode 100644 index 467d12f9dc..0000000000 --- a/tests/cts/net/src/android/net/cts/ProxyTest.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright (C) 2009 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.net.Proxy; -import android.test.AndroidTestCase; - -public class ProxyTest extends AndroidTestCase { - - public void testConstructor() { - new Proxy(); - } - - public void testAccessProperties() { - final int minValidPort = 0; - final int maxValidPort = 65535; - int defaultPort = Proxy.getDefaultPort(); - if(null == Proxy.getDefaultHost()) { - assertEquals(-1, defaultPort); - } else { - assertTrue(defaultPort >= minValidPort && defaultPort <= maxValidPort); - } - } -} diff --git a/tests/cts/net/src/android/net/cts/ProxyTest.kt b/tests/cts/net/src/android/net/cts/ProxyTest.kt new file mode 100644 index 0000000000..a661b26f33 --- /dev/null +++ b/tests/cts/net/src/android/net/cts/ProxyTest.kt @@ -0,0 +1,103 @@ +/* + * Copyright (C) 2021 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.net.ConnectivityManager +import android.net.Proxy +import android.net.ProxyInfo +import android.net.Uri +import android.os.Build +import android.text.TextUtils +import androidx.test.ext.junit.runners.AndroidJUnit4 +import androidx.test.filters.SmallTest +import androidx.test.platform.app.InstrumentationRegistry +import com.android.testutils.DevSdkIgnoreRule +import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo +import org.junit.Assert +import org.junit.Assert.assertEquals +import org.junit.Rule +import org.junit.Test +import org.junit.runner.RunWith + +@SmallTest +@RunWith(AndroidJUnit4::class) +class ProxyTest { + @get:Rule + val ignoreRule = DevSdkIgnoreRule() + + @Test + fun testConstructor() { + Proxy() + } + + @Test + fun testAccessProperties() { + val minValidPort = 0 + val maxValidPort = 65535 + val defaultPort = Proxy.getDefaultPort() + if (null == Proxy.getDefaultHost()) { + assertEquals(-1, defaultPort.toLong()) + } else { + Assert.assertTrue(defaultPort in minValidPort..maxValidPort) + } + } + + private fun verifyProxySystemProperties(info: ProxyInfo) { + assertEquals(info.host, System.getProperty("http.proxyHost")) + assertEquals(info.host, System.getProperty("https.proxyHost")) + + assertEquals(info.port.toString(), System.getProperty("http.proxyPort")) + assertEquals(info.port.toString(), System.getProperty("https.proxyPort")) + + val strExcludes = if (info.exclusionList.isEmpty()) null + else TextUtils.join("|", info.exclusionList) + assertEquals(strExcludes, System.getProperty("https.nonProxyHosts")) + assertEquals(strExcludes, System.getProperty("http.nonProxyHosts")) + } + + private fun getDefaultProxy(): ProxyInfo? { + return InstrumentationRegistry.getInstrumentation().context + .getSystemService(ConnectivityManager::class.java) + .getDefaultProxy() + } + + @Test @IgnoreUpTo(Build.VERSION_CODES.R) // setHttpProxyConfiguration was added in S + fun testSetHttpProxyConfiguration_DirectProxy() { + val info = ProxyInfo.buildDirectProxy( + "testproxy.android.com", + 12345 /* port */, + listOf("testexclude1.android.com", "testexclude2.android.com")) + val original = getDefaultProxy() + try { + Proxy.setHttpProxyConfiguration(info) + verifyProxySystemProperties(info) + } finally { + Proxy.setHttpProxyConfiguration(original) + } + } + + @Test @IgnoreUpTo(Build.VERSION_CODES.R) // setHttpProxyConfiguration was added in S + fun testSetHttpProxyConfiguration_PacProxy() { + val pacInfo = ProxyInfo.buildPacProxy(Uri.parse("http://testpac.android.com/pac.pac")) + val original = getDefaultProxy() + try { + Proxy.setHttpProxyConfiguration(pacInfo) + verifyProxySystemProperties(pacInfo) + } finally { + Proxy.setHttpProxyConfiguration(original) + } + } +} \ No newline at end of file From e4a2abad44e09e0d7430d42bc9b07fec39174222 Mon Sep 17 00:00:00 2001 From: Paul Hu Date: Tue, 22 Jun 2021 03:26:32 +0000 Subject: [PATCH 07/11] Add test for CSM#[get|set]MobileDataPreferredUids Bug: 171872461 Test: atest ConnectivityManagerTest Original-Change: https://android-review.googlesource.com/1736504 Merged-In: I43dfb049c271602526fa3e89ebb91219c7785a21 Change-Id: I43dfb049c271602526fa3e89ebb91219c7785a21 --- .../net/cts/ConnectivityManagerTest.java | 72 +++++++++++++++++++ 1 file changed, 72 insertions(+) diff --git a/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java b/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java index 2cca1e6b58..88755c8a31 100644 --- a/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java +++ b/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java @@ -199,6 +199,7 @@ import java.util.ArrayList; import java.util.Collection; import java.util.List; import java.util.Objects; +import java.util.Set; import java.util.concurrent.CompletableFuture; import java.util.concurrent.CountDownLatch; import java.util.concurrent.Executor; @@ -2541,4 +2542,75 @@ public class ConnectivityManagerTest { NetworkValidationTestUtil.setUrlExpirationDeviceConfig( System.currentTimeMillis() + WIFI_CONNECT_TIMEOUT_MS); } + + @AppModeFull(reason = "Cannot get WifiManager in instant app mode") + @Test + public void testMobileDataPreferredUids() throws Exception { + assumeTrue(TestUtils.shouldTestSApis()); + final boolean canRunTest = mPackageManager.hasSystemFeature(FEATURE_WIFI) + && mPackageManager.hasSystemFeature(FEATURE_TELEPHONY); + assumeTrue("testMobileDataPreferredUidsWithCallback cannot execute" + + " unless device supports both WiFi and telephony", canRunTest); + + final int uid = mPackageManager.getPackageUid(mContext.getPackageName(), 0 /* flag */); + final Set mobileDataPreferredUids = + ConnectivitySettingsManager.getMobileDataPreferredUids(mContext); + // CtsNetTestCases uid should not list in MOBILE_DATA_PREFERRED_UIDS setting because it just + // installs to device. In case the uid is existed in setting mistakenly, try to remove the + // uid and set correct uids to setting. + mobileDataPreferredUids.remove(uid); + ConnectivitySettingsManager.setMobileDataPreferredUids(mContext, mobileDataPreferredUids); + + // For testing mobile data preferred uids feature, it needs both wifi and cell network. + final Network wifiNetwork = mCtsNetUtils.ensureWifiConnected(); + final Network cellNetwork = mCtsNetUtils.connectToCell(); + final TestableNetworkCallback defaultTrackingCb = new TestableNetworkCallback(); + final TestableNetworkCallback systemDefaultCb = new TestableNetworkCallback(); + final Handler h = new Handler(Looper.getMainLooper()); + runWithShellPermissionIdentity(() -> mCm.registerSystemDefaultNetworkCallback( + systemDefaultCb, h), NETWORK_SETTINGS); + mCm.registerDefaultNetworkCallback(defaultTrackingCb); + + try { + // CtsNetTestCases uid is not listed in MOBILE_DATA_PREFERRED_UIDS setting, so the + // per-app default network should be same as system default network. + waitForAvailable(systemDefaultCb, wifiNetwork); + defaultTrackingCb.eventuallyExpect(CallbackEntry.AVAILABLE, NETWORK_CALLBACK_TIMEOUT_MS, + entry -> wifiNetwork.equals(entry.getNetwork())); + // Active network for CtsNetTestCases uid should be wifi now. + assertEquals(wifiNetwork, mCm.getActiveNetwork()); + + // Add CtsNetTestCases uid to MOBILE_DATA_PREFERRED_UIDS setting, then available per-app + // default network callback should be received with cell network. + final Set newMobileDataPreferredUids = new ArraySet<>(mobileDataPreferredUids); + newMobileDataPreferredUids.add(uid); + ConnectivitySettingsManager.setMobileDataPreferredUids( + mContext, newMobileDataPreferredUids); + defaultTrackingCb.eventuallyExpect(CallbackEntry.AVAILABLE, NETWORK_CALLBACK_TIMEOUT_MS, + entry -> cellNetwork.equals(entry.getNetwork())); + // System default network doesn't change. + systemDefaultCb.assertNoCallback(); + // Active network for CtsNetTestCases uid should change to cell, too. + assertEquals(cellNetwork, mCm.getActiveNetwork()); + + // Remove CtsNetTestCases uid from MOBILE_DATA_PREFERRED_UIDS setting, then available + // per-app default network callback should be received again with system default network + newMobileDataPreferredUids.remove(uid); + ConnectivitySettingsManager.setMobileDataPreferredUids( + mContext, newMobileDataPreferredUids); + defaultTrackingCb.eventuallyExpect(CallbackEntry.AVAILABLE, NETWORK_CALLBACK_TIMEOUT_MS, + entry -> wifiNetwork.equals(entry.getNetwork())); + // System default network still doesn't change. + systemDefaultCb.assertNoCallback(); + // Active network for CtsNetTestCases uid should change back to wifi. + assertEquals(wifiNetwork, mCm.getActiveNetwork()); + } finally { + mCm.unregisterNetworkCallback(systemDefaultCb); + mCm.unregisterNetworkCallback(defaultTrackingCb); + + // Restore setting. + ConnectivitySettingsManager.setMobileDataPreferredUids( + mContext, mobileDataPreferredUids); + } + } } From 77cb456671195769250f82e129be93bde82f67d3 Mon Sep 17 00:00:00 2001 From: Lucas Lin Date: Tue, 22 Jun 2021 03:16:30 +0000 Subject: [PATCH 08/11] Add CTS for isUidNetworkingBlocked & isUidRestrictedOnMeteredNetworks BYPASS_INCLUSIVE_LANGUAGE_REASON=To make the change more clear, fix the inclusive problem in a follow-up commit. Bug: 176289731 Test: atest CtsHostsideNetworkTests:HostsideNetworkPolicyManagerTests Original-Change: https://android-review.googlesource.com/1737395 Merged-In: Ie6bda8570979b10a28dbeb20f6db7a9c44735964 Change-Id: Ie6bda8570979b10a28dbeb20f6db7a9c44735964 --- ...ractRestrictBackgroundNetworkTestCase.java | 11 + .../hostside/NetworkPolicyManagerTest.java | 241 ++++++++++++++++++ .../net/hostside/NetworkPolicyTestUtils.java | 39 +++ .../cts/net/hostside/RestrictedModeTest.java | 19 +- .../HostsideNetworkPolicyManagerTests.java | 66 +++++ 5 files changed, 361 insertions(+), 15 deletions(-) create mode 100644 tests/cts/hostside/app/src/com/android/cts/net/hostside/NetworkPolicyManagerTest.java create mode 100644 tests/cts/hostside/src/com/android/cts/net/HostsideNetworkPolicyManagerTests.java 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 5b95eea332..5352a604b3 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 @@ -975,4 +975,15 @@ public abstract class AbstractRestrictBackgroundNetworkTestCase { */ String getExpected(); } + + protected void setRestrictedNetworkingMode(boolean enabled) throws Exception { + executeSilentShellCommand( + "settings put global restricted_networking_mode " + (enabled ? 1 : 0)); + assertRestrictedNetworkingModeState(enabled); + } + + protected void assertRestrictedNetworkingModeState(boolean enabled) throws Exception { + assertDelayedShellCommand("cmd netpolicy get restricted-mode", + "Restricted mode status: " + (enabled ? "enabled" : "disabled")); + } } diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/NetworkPolicyManagerTest.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/NetworkPolicyManagerTest.java new file mode 100644 index 0000000000..ddc5fd4357 --- /dev/null +++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/NetworkPolicyManagerTest.java @@ -0,0 +1,241 @@ +/* + * Copyright (C) 2021 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 com.android.cts.net.hostside; + +import static android.os.Process.SYSTEM_UID; + +import static com.android.cts.net.hostside.NetworkPolicyTestUtils.assertNetworkingBlockedStatusForUid; +import static com.android.cts.net.hostside.NetworkPolicyTestUtils.canChangeActiveNetworkMeteredness; +import static com.android.cts.net.hostside.NetworkPolicyTestUtils.isUidNetworkingBlocked; +import static com.android.cts.net.hostside.NetworkPolicyTestUtils.isUidRestrictedOnMeteredNetworks; +import static com.android.cts.net.hostside.NetworkPolicyTestUtils.setRestrictBackground; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; +import static org.junit.Assume.assumeTrue; + +import org.junit.After; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; + +public class NetworkPolicyManagerTest extends AbstractRestrictBackgroundNetworkTestCase { + private static final boolean METERED = true; + private static final boolean NON_METERED = false; + + @Rule + public final MeterednessConfigurationRule mMeterednessConfiguration = + new MeterednessConfigurationRule(); + + @Before + public void setUp() throws Exception { + super.setUp(); + + assumeTrue(canChangeActiveNetworkMeteredness()); + + registerBroadcastReceiver(); + + removeRestrictBackgroundWhitelist(mUid); + removeRestrictBackgroundBlacklist(mUid); + assertRestrictBackgroundChangedReceived(0); + + // Initial state + setBatterySaverMode(false); + setRestrictBackground(false); + setRestrictedNetworkingMode(false); + } + + @After + public void tearDown() throws Exception { + super.tearDown(); + + setBatterySaverMode(false); + setRestrictBackground(false); + setRestrictedNetworkingMode(false); + unregisterNetworkCallback(); + } + + @Test + public void testIsUidNetworkingBlocked_withUidNotBlocked() throws Exception { + // Refer to NetworkPolicyManagerService#isUidNetworkingBlockedInternal(), this test is to + // test the cases of non-metered network and uid not matched by any rule. + // If mUid is not blocked by data saver mode or power saver mode, no matter the network is + // metered or non-metered, mUid shouldn't be blocked. + assertFalse(isUidNetworkingBlocked(mUid, METERED)); // Match NTWK_ALLOWED_DEFAULT + assertFalse(isUidNetworkingBlocked(mUid, NON_METERED)); // Match NTWK_ALLOWED_NON_METERED + } + + @Test + public void testIsUidNetworkingBlocked_withSystemUid() throws Exception { + // Refer to NetworkPolicyManagerService#isUidNetworkingBlockedInternal(), this test is to + // test the case of uid is system uid. + // SYSTEM_UID will never be blocked. + assertFalse(isUidNetworkingBlocked(SYSTEM_UID, METERED)); // Match NTWK_ALLOWED_SYSTEM + assertFalse(isUidNetworkingBlocked(SYSTEM_UID, NON_METERED)); // Match NTWK_ALLOWED_SYSTEM + try { + setRestrictBackground(true); + setBatterySaverMode(true); + setRestrictedNetworkingMode(true); + assertNetworkingBlockedStatusForUid(SYSTEM_UID, METERED, + false /* expectedResult */); // Match NTWK_ALLOWED_SYSTEM + assertFalse( + isUidNetworkingBlocked(SYSTEM_UID, NON_METERED)); // Match NTWK_ALLOWED_SYSTEM + } finally { + setRestrictBackground(false); + setBatterySaverMode(false); + setRestrictedNetworkingMode(false); + assertNetworkingBlockedStatusForUid(mUid, METERED, + false /* expectedResult */); // Match NTWK_ALLOWED_DEFAULT + } + } + + @Test + public void testIsUidNetworkingBlocked_withDataSaverMode() throws Exception { + // Refer to NetworkPolicyManagerService#isUidNetworkingBlockedInternal(), this test is to + // test the cases of non-metered network, uid is matched by restrict background blacklist, + // uid is matched by restrict background whitelist, app is in the foreground with restrict + // background enabled and the app is in the background with restrict background enabled. + try { + // Enable restrict background and mUid will be blocked because it's not in the + // foreground. + setRestrictBackground(true); + assertNetworkingBlockedStatusForUid(mUid, METERED, + true /* expectedResult */); // Match NTWK_BLOCKED_BG_RESTRICT + + // Although restrict background is enabled and mUid is in the background, but mUid will + // not be blocked if network is non-metered. + assertFalse( + isUidNetworkingBlocked(mUid, NON_METERED)); // Match NTWK_ALLOWED_NON_METERED + + // Add mUid into the restrict background blacklist. + addRestrictBackgroundBlacklist(mUid); + assertNetworkingBlockedStatusForUid(mUid, METERED, + true /* expectedResult */); // Match NTWK_BLOCKED_DENYLIST + + // Although mUid is in the restrict background blacklist, but mUid won't be blocked if + // the network is non-metered. + assertFalse( + isUidNetworkingBlocked(mUid, NON_METERED)); // Match NTWK_ALLOWED_NON_METERED + removeRestrictBackgroundBlacklist(mUid); + + // Add mUid into the restrict background whitelist. + addRestrictBackgroundWhitelist(mUid); + assertNetworkingBlockedStatusForUid(mUid, METERED, + false /* expectedResult */); // Match NTWK_ALLOWED_ALLOWLIST + assertFalse( + isUidNetworkingBlocked(mUid, NON_METERED)); // Match NTWK_ALLOWED_NON_METERED + removeRestrictBackgroundWhitelist(mUid); + + // Make TEST_APP2_PKG go to foreground and mUid will be allowed temporarily. + launchComponentAndAssertNetworkAccess(TYPE_COMPONENT_ACTIVTIY); + assertForegroundState(); + assertNetworkingBlockedStatusForUid(mUid, METERED, + false /* expectedResult */); // Match NTWK_ALLOWED_TMP_ALLOWLIST + + // Back to background. + finishActivity(); + assertNetworkingBlockedStatusForUid(mUid, METERED, + true /* expectedResult */); // Match NTWK_BLOCKED_BG_RESTRICT + } finally { + setRestrictBackground(false); + assertNetworkingBlockedStatusForUid(mUid, METERED, + false /* expectedResult */); // Match NTWK_ALLOWED_DEFAULT + } + } + + @Test + public void testIsUidNetworkingBlocked_withRestrictedNetworkingMode() throws Exception { + // Refer to NetworkPolicyManagerService#isUidNetworkingBlockedInternal(), this test is to + // test the cases of restricted networking mode enabled. + try { + // All apps should be blocked if restricted networking mode is enabled except for those + // apps who have CONNECTIVITY_USE_RESTRICTED_NETWORKS permission. + // This test won't test if an app who has CONNECTIVITY_USE_RESTRICTED_NETWORKS will not + // be blocked because CONNECTIVITY_USE_RESTRICTED_NETWORKS is a signature/privileged + // permission that CTS cannot acquire. Also it's not good for this test to use those + // privileged apps which have CONNECTIVITY_USE_RESTRICTED_NETWORKS to test because there + // is no guarantee that those apps won't remove this permission someday, and if it + // happens, then this test will fail. + setRestrictedNetworkingMode(true); + assertNetworkingBlockedStatusForUid(mUid, METERED, + true /* expectedResult */); // Match NTWK_BLOCKED_RESTRICTED_MODE + assertTrue(isUidNetworkingBlocked(mUid, + NON_METERED)); // Match NTWK_BLOCKED_RESTRICTED_MODE + } finally { + setRestrictedNetworkingMode(false); + assertNetworkingBlockedStatusForUid(mUid, METERED, + false /* expectedResult */); // Match NTWK_ALLOWED_DEFAULT + } + } + + @Test + public void testIsUidNetworkingBlocked_withPowerSaverMode() throws Exception { + // Refer to NetworkPolicyManagerService#isUidNetworkingBlockedInternal(), this test is to + // test the cases of power saver mode enabled, uid in the power saver mode whitelist and + // uid in the power saver mode whitelist with non-metered network. + try { + // mUid should be blocked if power saver mode is enabled. + setBatterySaverMode(true); + assertNetworkingBlockedStatusForUid(mUid, METERED, + true /* expectedResult */); // Match NTWK_BLOCKED_POWER + assertTrue(isUidNetworkingBlocked(mUid, NON_METERED)); // Match NTWK_BLOCKED_POWER + + // Add TEST_APP2_PKG into power saver mode whitelist, its uid rule is RULE_ALLOW_ALL and + // it shouldn't be blocked. + addPowerSaveModeWhitelist(TEST_APP2_PKG); + assertNetworkingBlockedStatusForUid(mUid, METERED, + false /* expectedResult */); // Match NTWK_ALLOWED_DEFAULT + assertFalse( + isUidNetworkingBlocked(mUid, NON_METERED)); // Match NTWK_ALLOWED_NON_METERED + removePowerSaveModeWhitelist(TEST_APP2_PKG); + } finally { + setBatterySaverMode(false); + assertNetworkingBlockedStatusForUid(mUid, METERED, + false /* expectedResult */); // Match NTWK_ALLOWED_DEFAULT + } + } + + @Test + public void testIsUidRestrictedOnMeteredNetworks() throws Exception { + try { + // isUidRestrictedOnMeteredNetworks() will only return true when restrict background is + // enabled and mUid is not in the restrict background whitelist and TEST_APP2_PKG is not + // in the foreground. For other cases, it will return false. + setRestrictBackground(true); + assertTrue(isUidRestrictedOnMeteredNetworks(mUid)); + + // Make TEST_APP2_PKG go to foreground and isUidRestrictedOnMeteredNetworks() will + // return false. + launchComponentAndAssertNetworkAccess(TYPE_COMPONENT_ACTIVTIY); + assertForegroundState(); + assertFalse(isUidRestrictedOnMeteredNetworks(mUid)); + // Back to background. + finishActivity(); + + // Add mUid into restrict background whitelist and isUidRestrictedOnMeteredNetworks() + // will return false. + addRestrictBackgroundWhitelist(mUid); + assertFalse(isUidRestrictedOnMeteredNetworks(mUid)); + removeRestrictBackgroundWhitelist(mUid); + } finally { + // Restrict background is disabled and isUidRestrictedOnMeteredNetworks() will return + // false. + setRestrictBackground(false); + assertFalse(isUidRestrictedOnMeteredNetworks(mUid)); + } + } +} diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/NetworkPolicyTestUtils.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/NetworkPolicyTestUtils.java index 7da1a212ad..4f9ce7cf0d 100644 --- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/NetworkPolicyTestUtils.java +++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/NetworkPolicyTestUtils.java @@ -43,6 +43,7 @@ import android.net.ConnectivityManager; import android.net.ConnectivityManager.NetworkCallback; import android.net.Network; import android.net.NetworkCapabilities; +import android.net.NetworkPolicyManager; import android.net.wifi.WifiConfiguration; import android.net.wifi.WifiManager; import android.net.wifi.WifiManager.ActionListener; @@ -58,6 +59,7 @@ import androidx.test.platform.app.InstrumentationRegistry; import com.android.compatibility.common.util.AppStandbyUtils; import com.android.compatibility.common.util.BatteryUtils; +import com.android.compatibility.common.util.PollingCheck; import com.android.compatibility.common.util.ShellIdentityUtils; import com.android.compatibility.common.util.ThrowingRunnable; @@ -81,6 +83,7 @@ public class NetworkPolicyTestUtils { private static ConnectivityManager mCm; private static WifiManager mWm; private static CarrierConfigManager mCarrierConfigManager; + private static NetworkPolicyManager sNpm; private static Boolean mBatterySaverSupported; private static Boolean mDataSaverSupported; @@ -408,6 +411,13 @@ public class NetworkPolicyTestUtils { return mCarrierConfigManager; } + public static NetworkPolicyManager getNetworkPolicyManager() { + if (sNpm == null) { + sNpm = getContext().getSystemService(NetworkPolicyManager.class); + } + return sNpm; + } + public static Context getContext() { return getInstrumentation().getContext(); } @@ -415,4 +425,33 @@ public class NetworkPolicyTestUtils { public static Instrumentation getInstrumentation() { return InstrumentationRegistry.getInstrumentation(); } + + // When power saver mode or restrict background enabled or adding any white/black list into + // those modes, NetworkPolicy may need to take some time to update the rules of uids. So having + // this function and using PollingCheck to try to make sure the uid has updated and reduce the + // flaky rate. + public static void assertNetworkingBlockedStatusForUid(int uid, boolean metered, + boolean expectedResult) throws Exception { + PollingCheck.waitFor(() -> (expectedResult == isUidNetworkingBlocked(uid, metered))); + } + + public static boolean isUidNetworkingBlocked(int uid, boolean meteredNetwork) { + final UiAutomation uiAutomation = getInstrumentation().getUiAutomation(); + try { + uiAutomation.adoptShellPermissionIdentity(); + return getNetworkPolicyManager().isUidNetworkingBlocked(uid, meteredNetwork); + } finally { + uiAutomation.dropShellPermissionIdentity(); + } + } + + public static boolean isUidRestrictedOnMeteredNetworks(int uid) { + final UiAutomation uiAutomation = getInstrumentation().getUiAutomation(); + try { + uiAutomation.adoptShellPermissionIdentity(); + return getNetworkPolicyManager().isUidRestrictedOnMeteredNetworks(uid); + } finally { + uiAutomation.dropShellPermissionIdentity(); + } + } } diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/RestrictedModeTest.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/RestrictedModeTest.java index 29d3c6e1ba..5f0f6d6bea 100644 --- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/RestrictedModeTest.java +++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/RestrictedModeTest.java @@ -28,28 +28,17 @@ public final class RestrictedModeTest extends AbstractRestrictBackgroundNetworkT @After public void tearDown() throws Exception { - setRestrictedMode(false); + setRestrictedNetworkingMode(false); super.tearDown(); } - private void setRestrictedMode(boolean enabled) throws Exception { - executeSilentShellCommand( - "settings put global restricted_networking_mode " + (enabled ? 1 : 0)); - assertRestrictedModeState(enabled); - } - - private void assertRestrictedModeState(boolean enabled) throws Exception { - assertDelayedShellCommand("cmd netpolicy get restricted-mode", - "Restricted mode status: " + (enabled ? "enabled" : "disabled")); - } - @Test public void testNetworkAccess() throws Exception { - setRestrictedMode(false); + setRestrictedNetworkingMode(false); // go to foreground state and enable restricted mode launchComponentAndAssertNetworkAccess(TYPE_COMPONENT_ACTIVTIY); - setRestrictedMode(true); + setRestrictedNetworkingMode(true); assertForegroundNetworkAccess(false); // go to background state @@ -57,7 +46,7 @@ public final class RestrictedModeTest extends AbstractRestrictBackgroundNetworkT assertBackgroundNetworkAccess(false); // disable restricted mode and assert network access in foreground and background states - setRestrictedMode(false); + setRestrictedNetworkingMode(false); launchComponentAndAssertNetworkAccess(TYPE_COMPONENT_ACTIVTIY); assertForegroundNetworkAccess(true); diff --git a/tests/cts/hostside/src/com/android/cts/net/HostsideNetworkPolicyManagerTests.java b/tests/cts/hostside/src/com/android/cts/net/HostsideNetworkPolicyManagerTests.java new file mode 100644 index 0000000000..fdb8876a36 --- /dev/null +++ b/tests/cts/hostside/src/com/android/cts/net/HostsideNetworkPolicyManagerTests.java @@ -0,0 +1,66 @@ +/* + * Copyright (C) 2021 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 com.android.cts.net; + +public class HostsideNetworkPolicyManagerTests extends HostsideNetworkTestCase { + @Override + protected void setUp() throws Exception { + super.setUp(); + uninstallPackage(TEST_APP2_PKG, false); + installPackage(TEST_APP2_APK); + } + + @Override + protected void tearDown() throws Exception { + super.tearDown(); + uninstallPackage(TEST_APP2_PKG, true); + } + + public void testIsUidNetworkingBlocked_withUidNotBlocked() throws Exception { + runDeviceTests(TEST_PKG, + TEST_PKG + ".NetworkPolicyManagerTest", + "testIsUidNetworkingBlocked_withUidNotBlocked"); + } + + public void testIsUidNetworkingBlocked_withSystemUid() throws Exception { + runDeviceTests(TEST_PKG, + TEST_PKG + ".NetworkPolicyManagerTest", "testIsUidNetworkingBlocked_withSystemUid"); + } + + public void testIsUidNetworkingBlocked_withDataSaverMode() throws Exception { + runDeviceTests(TEST_PKG, + TEST_PKG + ".NetworkPolicyManagerTest", + "testIsUidNetworkingBlocked_withDataSaverMode"); + } + + public void testIsUidNetworkingBlocked_withRestrictedNetworkingMode() throws Exception { + runDeviceTests(TEST_PKG, + TEST_PKG + ".NetworkPolicyManagerTest", + "testIsUidNetworkingBlocked_withRestrictedNetworkingMode"); + } + + public void testIsUidNetworkingBlocked_withPowerSaverMode() throws Exception { + runDeviceTests(TEST_PKG, + TEST_PKG + ".NetworkPolicyManagerTest", + "testIsUidNetworkingBlocked_withPowerSaverMode"); + } + + public void testIsUidRestrictedOnMeteredNetworks() throws Exception { + runDeviceTests(TEST_PKG, + TEST_PKG + ".NetworkPolicyManagerTest", "testIsUidRestrictedOnMeteredNetworks"); + } +} From 611bc021e6702f4067af3cf270317b97d93e9123 Mon Sep 17 00:00:00 2001 From: Lucas Lin Date: Mon, 21 Jun 2021 20:22:10 +0000 Subject: [PATCH 09/11] Call ConnectivitySettingsUtils to set/get private DNS related settings ConnectivitySettingsManager and CtsNetUtils are doing the same thing to set/get private DNS related settings. To prevent making the duplication code in two places, move the body to frameworks/libs/net and call it. Bug: 185311744 Test: atest CtsNetTestCases CtsNetTestCasesLatestSdk Original-Change: https://android-review.googlesource.com/1719017 Merged-In: I3272c825b86ec30c3d0bf4097088c653e668461b Change-Id: I3272c825b86ec30c3d0bf4097088c653e668461b --- .../net/ConnectivitySettingsManager.java | 65 +++----------- tests/cts/net/util/Android.bp | 1 + .../android/net/cts/util/CtsNetUtils.java | 87 ++++++++++--------- 3 files changed, 60 insertions(+), 93 deletions(-) diff --git a/framework/src/android/net/ConnectivitySettingsManager.java b/framework/src/android/net/ConnectivitySettingsManager.java index 03c3600414..4644e4f483 100644 --- a/framework/src/android/net/ConnectivitySettingsManager.java +++ b/framework/src/android/net/ConnectivitySettingsManager.java @@ -20,12 +20,13 @@ import static android.net.ConnectivityManager.MULTIPATH_PREFERENCE_HANDOVER; import static android.net.ConnectivityManager.MULTIPATH_PREFERENCE_PERFORMANCE; import static android.net.ConnectivityManager.MULTIPATH_PREFERENCE_RELIABILITY; +import static com.android.net.module.util.ConnectivitySettingsUtils.getPrivateDnsModeAsString; + import android.annotation.IntDef; import android.annotation.IntRange; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.SystemApi; -import android.content.ContentResolver; import android.content.Context; import android.net.ConnectivityManager.MultipathPreference; import android.os.Process; @@ -35,6 +36,7 @@ import android.text.TextUtils; import android.util.ArraySet; import android.util.Range; +import com.android.net.module.util.ConnectivitySettingsUtils; import com.android.net.module.util.ProxyUtils; import java.lang.annotation.Retention; @@ -345,20 +347,22 @@ public class ConnectivitySettingsManager { /** * One of the private DNS modes that indicates the private DNS mode is off. */ - public static final int PRIVATE_DNS_MODE_OFF = 1; + public static final int PRIVATE_DNS_MODE_OFF = ConnectivitySettingsUtils.PRIVATE_DNS_MODE_OFF; /** * One of the private DNS modes that indicates the private DNS mode is automatic, which * will try to use the current DNS as private DNS. */ - public static final int PRIVATE_DNS_MODE_OPPORTUNISTIC = 2; + public static final int PRIVATE_DNS_MODE_OPPORTUNISTIC = + ConnectivitySettingsUtils.PRIVATE_DNS_MODE_OPPORTUNISTIC; /** * One of the private DNS modes that indicates the private DNS mode is strict and the * {@link #PRIVATE_DNS_SPECIFIER} is required, which will try to use the value of * {@link #PRIVATE_DNS_SPECIFIER} as private DNS. */ - public static final int PRIVATE_DNS_MODE_PROVIDER_HOSTNAME = 3; + public static final int PRIVATE_DNS_MODE_PROVIDER_HOSTNAME = + ConnectivitySettingsUtils.PRIVATE_DNS_MODE_PROVIDER_HOSTNAME; /** @hide */ @Retention(RetentionPolicy.SOURCE) @@ -369,10 +373,6 @@ public class ConnectivitySettingsManager { }) public @interface PrivateDnsMode {} - private static final String PRIVATE_DNS_MODE_OFF_STRING = "off"; - private static final String PRIVATE_DNS_MODE_OPPORTUNISTIC_STRING = "opportunistic"; - private static final String PRIVATE_DNS_MODE_PROVIDER_HOSTNAME_STRING = "hostname"; - /** * A list of uids that is allowed to use restricted networks. * @@ -730,32 +730,6 @@ public class ConnectivitySettingsManager { context.getContentResolver(), GLOBAL_HTTP_PROXY_PAC, "" /* value */); } - private static String getPrivateDnsModeAsString(@PrivateDnsMode int mode) { - switch (mode) { - case PRIVATE_DNS_MODE_OFF: - return PRIVATE_DNS_MODE_OFF_STRING; - case PRIVATE_DNS_MODE_OPPORTUNISTIC: - return PRIVATE_DNS_MODE_OPPORTUNISTIC_STRING; - case PRIVATE_DNS_MODE_PROVIDER_HOSTNAME: - return PRIVATE_DNS_MODE_PROVIDER_HOSTNAME_STRING; - default: - throw new IllegalArgumentException("Invalid private dns mode: " + mode); - } - } - - private static int getPrivateDnsModeAsInt(String mode) { - switch (mode) { - case "off": - return PRIVATE_DNS_MODE_OFF; - case "hostname": - return PRIVATE_DNS_MODE_PROVIDER_HOSTNAME; - case "opportunistic": - return PRIVATE_DNS_MODE_OPPORTUNISTIC; - default: - throw new IllegalArgumentException("Invalid private dns mode: " + mode); - } - } - /** * Get private DNS mode from settings. * @@ -764,13 +738,7 @@ public class ConnectivitySettingsManager { */ @PrivateDnsMode public static int getPrivateDnsMode(@NonNull Context context) { - final ContentResolver cr = context.getContentResolver(); - String mode = Settings.Global.getString(cr, PRIVATE_DNS_MODE); - if (TextUtils.isEmpty(mode)) mode = Settings.Global.getString(cr, PRIVATE_DNS_DEFAULT_MODE); - // If both PRIVATE_DNS_MODE and PRIVATE_DNS_DEFAULT_MODE are not set, choose - // PRIVATE_DNS_MODE_OPPORTUNISTIC as default mode. - if (TextUtils.isEmpty(mode)) return PRIVATE_DNS_MODE_OPPORTUNISTIC; - return getPrivateDnsModeAsInt(mode); + return ConnectivitySettingsUtils.getPrivateDnsMode(context); } /** @@ -780,13 +748,7 @@ public class ConnectivitySettingsManager { * @param mode The private dns mode. This should be one of the PRIVATE_DNS_MODE_* constants. */ public static void setPrivateDnsMode(@NonNull Context context, @PrivateDnsMode int mode) { - if (!(mode == PRIVATE_DNS_MODE_OFF - || mode == PRIVATE_DNS_MODE_OPPORTUNISTIC - || mode == PRIVATE_DNS_MODE_PROVIDER_HOSTNAME)) { - throw new IllegalArgumentException("Invalid private dns mode: " + mode); - } - Settings.Global.putString(context.getContentResolver(), PRIVATE_DNS_MODE, - getPrivateDnsModeAsString(mode)); + ConnectivitySettingsUtils.setPrivateDnsMode(context, mode); } /** @@ -797,7 +759,7 @@ public class ConnectivitySettingsManager { */ @Nullable public static String getPrivateDnsHostname(@NonNull Context context) { - return Settings.Global.getString(context.getContentResolver(), PRIVATE_DNS_SPECIFIER); + return ConnectivitySettingsUtils.getPrivateDnsHostname(context); } /** @@ -806,9 +768,8 @@ public class ConnectivitySettingsManager { * @param context The {@link Context} to set the setting. * @param specifier The specific private dns provider name. */ - public static void setPrivateDnsHostname(@NonNull Context context, - @Nullable String specifier) { - Settings.Global.putString(context.getContentResolver(), PRIVATE_DNS_SPECIFIER, specifier); + public static void setPrivateDnsHostname(@NonNull Context context, @Nullable String specifier) { + ConnectivitySettingsUtils.setPrivateDnsHostname(context, specifier); } /** diff --git a/tests/cts/net/util/Android.bp b/tests/cts/net/util/Android.bp index b5f1208a4d..fffd30f7e1 100644 --- a/tests/cts/net/util/Android.bp +++ b/tests/cts/net/util/Android.bp @@ -27,5 +27,6 @@ java_library { "junit", "net-tests-utils", "modules-utils-build", + "net-utils-framework-common", ], } 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 4abbecce2c..bce9880db8 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 @@ -56,12 +56,13 @@ import android.net.wifi.WifiManager; import android.os.Binder; import android.os.Build; import android.os.IBinder; -import android.provider.Settings; import android.system.Os; import android.system.OsConstants; +import android.text.TextUtils; import android.util.Log; import com.android.compatibility.common.util.SystemUtil; +import com.android.net.module.util.ConnectivitySettingsUtils; import junit.framework.AssertionFailedError; @@ -80,7 +81,6 @@ import java.util.concurrent.TimeoutException; public final class CtsNetUtils { private static final String TAG = CtsNetUtils.class.getSimpleName(); - private static final int DURATION = 10000; private static final int SOCKET_TIMEOUT_MS = 2000; private static final int PRIVATE_DNS_PROBE_MS = 1_000; @@ -104,7 +104,7 @@ public final class CtsNetUtils { private final ContentResolver mCR; private final WifiManager mWifiManager; private TestNetworkCallback mCellNetworkCallback; - private String mOldPrivateDnsMode; + private int mOldPrivateDnsMode = 0; private String mOldPrivateDnsSpecifier; public CtsNetUtils(Context context) { @@ -508,64 +508,69 @@ public final class CtsNetUtils { } public void storePrivateDnsSetting() { - // Store private DNS setting - mOldPrivateDnsMode = Settings.Global.getString(mCR, Settings.Global.PRIVATE_DNS_MODE); - mOldPrivateDnsSpecifier = Settings.Global.getString(mCR, - Settings.Global.PRIVATE_DNS_SPECIFIER); - // It's possible that there is no private DNS default value in Settings. - // Give it a proper default mode which is opportunistic mode. - if (mOldPrivateDnsMode == null) { - mOldPrivateDnsSpecifier = ""; - mOldPrivateDnsMode = PRIVATE_DNS_MODE_OPPORTUNISTIC; - Settings.Global.putString(mCR, - Settings.Global.PRIVATE_DNS_SPECIFIER, mOldPrivateDnsSpecifier); - Settings.Global.putString(mCR, Settings.Global.PRIVATE_DNS_MODE, mOldPrivateDnsMode); - } + mOldPrivateDnsMode = ConnectivitySettingsUtils.getPrivateDnsMode(mContext); + mOldPrivateDnsSpecifier = ConnectivitySettingsUtils.getPrivateDnsHostname(mContext); } public void restorePrivateDnsSetting() throws InterruptedException { - if (mOldPrivateDnsMode == null) { + if (mOldPrivateDnsMode == 0) { fail("restorePrivateDnsSetting without storing settings first"); } - // restore private DNS setting - if (PRIVATE_DNS_MODE_STRICT.equals(mOldPrivateDnsMode)) { - // In case of invalid setting, set to opportunistic to avoid a bad state and fail - if (mOldPrivateDnsSpecifier == null) { - Settings.Global.putString(mCR, Settings.Global.PRIVATE_DNS_MODE, - PRIVATE_DNS_MODE_OPPORTUNISTIC); - fail("Invalid private DNS setting: no hostname specified in strict mode"); - } - setPrivateDnsStrictMode(mOldPrivateDnsSpecifier); - awaitPrivateDnsSetting("restorePrivateDnsSetting timeout", - mCm.getActiveNetwork(), - mOldPrivateDnsSpecifier, true); - } else { - Settings.Global.putString(mCR, Settings.Global.PRIVATE_DNS_MODE, mOldPrivateDnsMode); + if (mOldPrivateDnsMode != ConnectivitySettingsUtils.PRIVATE_DNS_MODE_PROVIDER_HOSTNAME) { + ConnectivitySettingsUtils.setPrivateDnsMode(mContext, mOldPrivateDnsMode); + return; } + // restore private DNS setting + // In case of invalid setting, set to opportunistic to avoid a bad state and fail + if (TextUtils.isEmpty(mOldPrivateDnsSpecifier)) { + ConnectivitySettingsUtils.setPrivateDnsMode(mContext, + ConnectivitySettingsUtils.PRIVATE_DNS_MODE_OPPORTUNISTIC); + fail("Invalid private DNS setting: no hostname specified in strict mode"); + } + setPrivateDnsStrictMode(mOldPrivateDnsSpecifier); + + // There might be a race before private DNS setting is applied and the next test is + // running. So waiting private DNS to be validated can reduce the flaky rate of test. + awaitPrivateDnsSetting("restorePrivateDnsSetting timeout", + mCm.getActiveNetwork(), + mOldPrivateDnsSpecifier, true /* requiresValidatedServer */); } public void setPrivateDnsStrictMode(String server) { // To reduce flake rate, set PRIVATE_DNS_SPECIFIER before PRIVATE_DNS_MODE. This ensures // that if the previous private DNS mode was not strict, the system only sees one // EVENT_PRIVATE_DNS_SETTINGS_CHANGED event instead of two. - Settings.Global.putString(mCR, Settings.Global.PRIVATE_DNS_SPECIFIER, server); - final String mode = Settings.Global.getString(mCR, Settings.Global.PRIVATE_DNS_MODE); + ConnectivitySettingsUtils.setPrivateDnsHostname(mContext, server); + final int mode = ConnectivitySettingsUtils.getPrivateDnsMode(mContext); // If current private DNS mode is strict, we only need to set PRIVATE_DNS_SPECIFIER. - if (!PRIVATE_DNS_MODE_STRICT.equals(mode)) { - Settings.Global.putString(mCR, Settings.Global.PRIVATE_DNS_MODE, - PRIVATE_DNS_MODE_STRICT); + if (mode != ConnectivitySettingsUtils.PRIVATE_DNS_MODE_PROVIDER_HOSTNAME) { + ConnectivitySettingsUtils.setPrivateDnsMode(mContext, + ConnectivitySettingsUtils.PRIVATE_DNS_MODE_PROVIDER_HOSTNAME); } } + /** + * Waiting for the new private DNS setting to be validated. + * This method is helpful when the new private DNS setting is configured and ensure the new + * setting is applied and workable. It can also reduce the flaky rate when the next test is + * running. + * + * @param msg A message that will be printed when the validation of private DNS is timeout. + * @param network A network which will apply the new private DNS setting. + * @param server The hostname of private DNS. + * @param requiresValidatedServer A boolean to decide if it's needed to wait private DNS to be + * validated or not. + * @throws InterruptedException If the thread is interrupted. + */ public void awaitPrivateDnsSetting(@NonNull String msg, @NonNull Network network, - @NonNull String server, boolean requiresValidatedServers) throws InterruptedException { - CountDownLatch latch = new CountDownLatch(1); - NetworkRequest request = new NetworkRequest.Builder().clearCapabilities().build(); + @NonNull String server, boolean requiresValidatedServer) throws InterruptedException { + final CountDownLatch latch = new CountDownLatch(1); + final NetworkRequest request = new NetworkRequest.Builder().clearCapabilities().build(); NetworkCallback callback = new NetworkCallback() { @Override public void onLinkPropertiesChanged(Network n, LinkProperties lp) { - if (requiresValidatedServers && lp.getValidatedPrivateDnsServers().isEmpty()) { + if (requiresValidatedServer && lp.getValidatedPrivateDnsServers().isEmpty()) { return; } if (network.equals(n) && server.equals(lp.getPrivateDnsServerName())) { @@ -585,7 +590,7 @@ public final class CtsNetUtils { // private DNS probe. There is no way to know when the probe has completed: because the // network is likely already validated, there is no callback that we can listen to, so // just sleep. - if (requiresValidatedServers) { + if (requiresValidatedServer) { Thread.sleep(PRIVATE_DNS_PROBE_MS); } } From 03a1a97bf967106341bb971e9ddd034a8a253813 Mon Sep 17 00:00:00 2001 From: Lucas Lin Date: Mon, 21 Jun 2021 23:22:19 +0000 Subject: [PATCH 10/11] Add CTS for systemReady() & getIpSecNetIdRange() Bug: 182963354 Test: 1. atest CtsNetTestCases:ConnectivityManagerTest 2. atest CtsNetTestCasesLatestSdk:ConnectivityManagerTest Original-Change: https://android-review.googlesource.com/1676425 Merged-In: I0b286f32389501402e552010546c62f3e56833d6 Change-Id: I0b286f32389501402e552010546c62f3e56833d6 --- .../net/cts/ConnectivityManagerTest.java | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java b/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java index 88755c8a31..eb9c3054cb 100644 --- a/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java +++ b/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java @@ -2156,6 +2156,24 @@ public class ConnectivityManagerTest { null /* listener */)); } + @Test + public void testSystemReady() { + assumeTrue(TestUtils.shouldTestSApis()); + assertThrows(SecurityException.class, () -> mCm.systemReady()); + } + + @Test + public void testGetIpSecNetIdRange() { + assumeTrue(TestUtils.shouldTestSApis()); + // The lower refers to ConnectivityManager.TUN_INTF_NETID_START. + final long lower = 64512; + // The upper refers to ConnectivityManager.TUN_INTF_NETID_START + // + ConnectivityManager.TUN_INTF_NETID_RANGE - 1 + final long upper = 65535; + assertEquals(lower, (long) ConnectivityManager.getIpSecNetIdRange().getLower()); + assertEquals(upper, (long) ConnectivityManager.getIpSecNetIdRange().getUpper()); + } + private void verifySettings(int expectedAirplaneMode, int expectedPrivateDnsMode, int expectedAvoidBadWifi) throws Exception { assertEquals(expectedAirplaneMode, Settings.Global.getInt( From da2a7c3daa9d95f57a548e26c3cc84003be42c31 Mon Sep 17 00:00:00 2001 From: Lucas Lin Date: Mon, 21 Jun 2021 23:50:27 +0000 Subject: [PATCH 11/11] Use assertEquals instead of assertTrue to compare the vpn type Bug: 184261389 Test: atest CtsHostsideNetworkTests:HostsideVpnTests#testDefault Original-Change: https://android-review.googlesource.com/1739093 Merged-In: I55371fabe0d2fa32a71520af11f18f1eeea31460 Change-Id: I55371fabe0d2fa32a71520af11f18f1eeea31460 --- .../hostside/app/src/com/android/cts/net/hostside/VpnTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 84852636fc..62aa493c6f 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 @@ -760,7 +760,7 @@ public class VpnTest extends InstrumentationTestCase { assertEquals(vpnNetwork, mCM.getActiveNetwork()); assertNotEqual(defaultNetwork, vpnNetwork); maybeExpectVpnTransportInfo(vpnNetwork); - assertTrue(mCM.getNetworkInfo(vpnNetwork).getType() == TYPE_VPN); + assertEquals(TYPE_VPN, mCM.getNetworkInfo(vpnNetwork).getType()); if (SdkLevel.isAtLeastS()) { // Check that system default network callback has not seen any network changes, even