Merge changes from topic "connectivity-cts-cherrypicks" into sc-dev
* changes:
Use assertEquals instead of assertTrue to compare the vpn type
Add CTS for systemReady() & getIpSecNetIdRange()
Call ConnectivitySettingsUtils to set/get private DNS related settings
Add CTS for isUidNetworkingBlocked & isUidRestrictedOnMeteredNetworks
Add test for CSM#[get|set]MobileDataPreferredUids
Add test for setHttpProxyConfiguration
CTS test for PacProxyManager
Add test for CM#setAcceptUnvalidated
Add test for CM#setAcceptPartialConnectivity
Skip CaptivePortalTest for wearables
Improve handling of invalid private DNS settings
diff --git a/framework/src/android/net/ConnectivitySettingsManager.java b/framework/src/android/net/ConnectivitySettingsManager.java
index 03c3600..4644e4f 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_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.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 @@
/**
* 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 @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 @@
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 @@
*/
@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 @@
* @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 @@
*/
@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 @@
* @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/hostside/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java
index 5b95eea..5352a60 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 @@
*/
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 0000000..ddc5fd4
--- /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 7da1a21..4f9ce7c 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.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 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 @@
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 @@
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 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 29d3c6e..5f0f6d6 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 @@
@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 @@
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/app/src/com/android/cts/net/hostside/VpnTest.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/VpnTest.java
index 8485263..62aa493 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 @@
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
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 0000000..fdb8876
--- /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");
+ }
+}
diff --git a/tests/cts/net/src/android/net/cts/CaptivePortalTest.kt b/tests/cts/net/src/android/net/cts/CaptivePortalTest.kt
index a889c41..9f079c4 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.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 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 @@
fun testCaptivePortalIsNotDefaultNetwork() {
assumeTrue(pm.hasSystemFeature(FEATURE_TELEPHONY))
assumeTrue(pm.hasSystemFeature(FEATURE_WIFI))
+ assumeFalse(pm.hasSystemFeature(FEATURE_WATCH))
utils.ensureWifiConnected()
val cellNetwork = utils.connectToCell()
@@ -148,8 +151,8 @@
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/ConnectivityManagerTest.java b/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java
index d649518..eb9c305 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 @@
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_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.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.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.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.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.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;
@@ -192,6 +199,7 @@
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;
@@ -202,6 +210,10 @@
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 +257,12 @@
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 +277,8 @@
// Used for cleanup purposes.
private final List<Range<Integer>> mVpnRequiredUidRanges = new ArrayList<>();
+ private final TestHttpServer mHttpServer = new TestHttpServer(LOCALHOST_HOSTNAME);
+
@Before
public void setUp() throws Exception {
mInstrumentation = InstrumentationRegistry.getInstrumentation();
@@ -667,12 +687,14 @@
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();
}
@@ -2134,6 +2156,24 @@
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(
@@ -2327,4 +2367,268 @@
}
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();
+ }
+ }
+
+ @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<Network> 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 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
+ // interrupted manually and rerun.
+ assertEmptyOrLocalhostUrl(TEST_CAPTIVE_PORTAL_HTTPS_URL);
+ assertEmptyOrLocalhostUrl(TEST_CAPTIVE_PORTAL_HTTP_URL);
+ });
+
+ 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 */);
+ // 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 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;
+ }
+
+ 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);
+ }
+
+ @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<Integer> 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<Integer> 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);
+ }
+ }
}
diff --git a/tests/cts/net/src/android/net/cts/NetworkValidationTestUtil.kt b/tests/cts/net/src/android/net/cts/NetworkValidationTestUtil.kt
index f6fc75b..dde14ac 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 @@
/**
* Clear the test network validation URLs.
*/
- fun clearValidationTestUrlsDeviceConfig() {
+ @JvmStatic fun clearValidationTestUrlsDeviceConfig() {
setHttpsUrlDeviceConfig(null)
setHttpUrlDeviceConfig(null)
setUrlExpirationDeviceConfig(null)
@@ -40,7 +40,7 @@
*
* @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 @@
*
* @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 @@
*
* @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?) {
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 0000000..7d5e9ff
--- /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<String, String> headers = new HashMap<String, String>();
+ 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));
+ }
+}
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 467d12f..0000000
--- 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 0000000..a661b26
--- /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
diff --git a/tests/cts/net/util/Android.bp b/tests/cts/net/util/Android.bp
index b5f1208..fffd30f 100644
--- a/tests/cts/net/util/Android.bp
+++ b/tests/cts/net/util/Android.bp
@@ -27,5 +27,6 @@
"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 b32218b..bce9880 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.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 @@
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 @@
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,62 +508,69 @@
}
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)) {
- setPrivateDnsStrictMode(mOldPrivateDnsSpecifier);
- // In case of invalid setting, still restore it but fail the test
- if (mOldPrivateDnsSpecifier == null) {
- fail("Invalid private DNS setting: no hostname specified in strict mode");
- }
- 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())) {
@@ -583,7 +590,7 @@
// 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);
}
}