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
This commit is contained in:
Lorenzo Colitti
2021-06-22 22:53:26 +00:00
committed by Android (Google) Code Review
15 changed files with 1031 additions and 153 deletions

View File

@@ -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);
}
/**

View File

@@ -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"));
}
}

View File

@@ -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));
}
}
}

View File

@@ -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();
}
}
}

View File

@@ -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);

View File

@@ -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

View File

@@ -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");
}
}

View File

@@ -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()
@@ -148,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

View File

@@ -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;
@@ -192,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;
@@ -202,6 +210,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 +257,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 +277,8 @@ public class ConnectivityManagerTest {
// 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 @@ 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();
}
@@ -2134,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(
@@ -2327,4 +2367,268 @@ 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();
}
}
@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);
}
}
}

View File

@@ -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?) {

View File

@@ -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));
}
}

View File

@@ -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);
}
}
}

View File

@@ -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)
}
}
}

View File

@@ -27,5 +27,6 @@ java_library {
"junit",
"net-tests-utils",
"modules-utils-build",
"net-utils-framework-common",
],
}

View File

@@ -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,62 +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)) {
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 @@ 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);
}
}