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:
committed by
Android (Google) Code Review
commit
77fb999ed0
@@ -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);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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"));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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");
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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?) {
|
||||
|
||||
192
tests/cts/net/src/android/net/cts/PacProxyManagerTest.java
Normal file
192
tests/cts/net/src/android/net/cts/PacProxyManagerTest.java
Normal 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));
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
103
tests/cts/net/src/android/net/cts/ProxyTest.kt
Normal file
103
tests/cts/net/src/android/net/cts/ProxyTest.kt
Normal 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)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -27,5 +27,6 @@ java_library {
|
||||
"junit",
|
||||
"net-tests-utils",
|
||||
"modules-utils-build",
|
||||
"net-utils-framework-common",
|
||||
],
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user