DO NOT MERGE: Add option to skip and avoid captive portals.
Test: ConnectivityServiceTest updated with test cases.
Test: Manually tested against att-wifi in B42.
Bug: 30222699
(cherry picked from commit be96da11cc)
Change-Id: I90c0f97fe0e41de4059bceae7b56ab3a70145696
This commit is contained in:
committed by
Lorenzo Colitti
parent
dafc44ea11
commit
1f64f3fd14
@@ -8024,11 +8024,45 @@ public final class Settings {
|
||||
public static final String PAC_CHANGE_DELAY = "pac_change_delay";
|
||||
|
||||
/**
|
||||
* Setting to turn off captive portal detection. Feature is enabled by
|
||||
* default and the setting needs to be set to 0 to disable it.
|
||||
* Don't attempt to detect captive portals.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public static final int CAPTIVE_PORTAL_MODE_IGNORE = 0;
|
||||
|
||||
/**
|
||||
* When detecting a captive portal, display a notification that
|
||||
* prompts the user to sign in.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public static final int CAPTIVE_PORTAL_MODE_PROMPT = 1;
|
||||
|
||||
/**
|
||||
* When detecting a captive portal, immediately disconnect from the
|
||||
* network and do not reconnect to that network in the future.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public static final int CAPTIVE_PORTAL_MODE_AVOID = 2;
|
||||
|
||||
/**
|
||||
* What to do when connecting a network that presents a captive portal.
|
||||
* Must be one of the CAPTIVE_PORTAL_MODE_* constants above.
|
||||
*
|
||||
* The default for this setting is CAPTIVE_PORTAL_MODE_PROMPT.
|
||||
* @hide
|
||||
*/
|
||||
public static final String CAPTIVE_PORTAL_MODE = "captive_portal_mode";
|
||||
|
||||
/**
|
||||
* Setting to turn off captive portal detection. Feature is enabled by
|
||||
* default and the setting needs to be set to 0 to disable it.
|
||||
*
|
||||
* @deprecated use CAPTIVE_PORTAL_MODE_IGNORE to disable captive portal detection
|
||||
* @hide
|
||||
*/
|
||||
@Deprecated
|
||||
public static final String
|
||||
CAPTIVE_PORTAL_DETECTION_ENABLED = "captive_portal_detection_enabled";
|
||||
|
||||
|
||||
@@ -2266,11 +2266,19 @@ public class ConnectivityService extends IConnectivityManager.Stub
|
||||
synchronized (mNetworkForNetId) {
|
||||
nai = mNetworkForNetId.get(netId);
|
||||
}
|
||||
// If captive portal status has changed, update capabilities.
|
||||
// If captive portal status has changed, update capabilities or disconnect.
|
||||
if (nai != null && (visible != nai.lastCaptivePortalDetected)) {
|
||||
final int oldScore = nai.getCurrentScore();
|
||||
nai.lastCaptivePortalDetected = visible;
|
||||
nai.everCaptivePortalDetected |= visible;
|
||||
if (nai.lastCaptivePortalDetected &&
|
||||
Settings.Global.CAPTIVE_PORTAL_MODE_AVOID == getCaptivePortalMode()) {
|
||||
if (DBG) log("Avoiding captive portal network: " + nai.name());
|
||||
nai.asyncChannel.sendMessage(
|
||||
NetworkAgent.CMD_PREVENT_AUTOMATIC_RECONNECT);
|
||||
teardownUnneededNetwork(nai);
|
||||
break;
|
||||
}
|
||||
updateCapabilities(oldScore, nai, nai.networkCapabilities);
|
||||
}
|
||||
if (!visible) {
|
||||
@@ -2291,6 +2299,12 @@ public class ConnectivityService extends IConnectivityManager.Stub
|
||||
return true;
|
||||
}
|
||||
|
||||
private int getCaptivePortalMode() {
|
||||
return Settings.Global.getInt(mContext.getContentResolver(),
|
||||
Settings.Global.CAPTIVE_PORTAL_MODE,
|
||||
Settings.Global.CAPTIVE_PORTAL_MODE_PROMPT);
|
||||
}
|
||||
|
||||
private boolean maybeHandleNetworkAgentInfoMessage(Message msg) {
|
||||
switch (msg.what) {
|
||||
default:
|
||||
|
||||
@@ -211,7 +211,9 @@ public class NetworkMonitor extends StateMachine {
|
||||
private final NetworkRequest mDefaultRequest;
|
||||
private final IpConnectivityLog mMetricsLog;
|
||||
|
||||
private boolean mIsCaptivePortalCheckEnabled;
|
||||
@VisibleForTesting
|
||||
protected boolean mIsCaptivePortalCheckEnabled;
|
||||
|
||||
private boolean mUseHttps;
|
||||
|
||||
// Set if the user explicitly selected "Do not use this network" in captive portal sign-in app.
|
||||
@@ -265,7 +267,8 @@ public class NetworkMonitor extends StateMachine {
|
||||
setInitialState(mDefaultState);
|
||||
|
||||
mIsCaptivePortalCheckEnabled = Settings.Global.getInt(mContext.getContentResolver(),
|
||||
Settings.Global.CAPTIVE_PORTAL_DETECTION_ENABLED, 1) == 1;
|
||||
Settings.Global.CAPTIVE_PORTAL_MODE, Settings.Global.CAPTIVE_PORTAL_MODE_PROMPT)
|
||||
!= Settings.Global.CAPTIVE_PORTAL_MODE_IGNORE;
|
||||
mUseHttps = Settings.Global.getInt(mContext.getContentResolver(),
|
||||
Settings.Global.CAPTIVE_PORTAL_USE_HTTPS, 1) == 1;
|
||||
|
||||
@@ -632,7 +635,10 @@ public class NetworkMonitor extends StateMachine {
|
||||
|
||||
@VisibleForTesting
|
||||
protected CaptivePortalProbeResult isCaptivePortal() {
|
||||
if (!mIsCaptivePortalCheckEnabled) return new CaptivePortalProbeResult(204);
|
||||
if (!mIsCaptivePortalCheckEnabled) {
|
||||
validationLog("Validation disabled.");
|
||||
return new CaptivePortalProbeResult(204);
|
||||
}
|
||||
|
||||
URL pacUrl = null, httpsUrl = null, httpUrl = null, fallbackUrl = null;
|
||||
|
||||
|
||||
@@ -236,6 +236,7 @@ public class ConnectivityServiceTest extends AndroidTestCase {
|
||||
private final IdleableHandlerThread mHandlerThread;
|
||||
private final ConditionVariable mDisconnected = new ConditionVariable();
|
||||
private final ConditionVariable mNetworkStatusReceived = new ConditionVariable();
|
||||
private final ConditionVariable mPreventReconnectReceived = new ConditionVariable();
|
||||
private int mScore;
|
||||
private NetworkAgent mNetworkAgent;
|
||||
private int mStartKeepaliveError = PacketKeepalive.ERROR_HARDWARE_UNSUPPORTED;
|
||||
@@ -291,6 +292,11 @@ public class ConnectivityServiceTest extends AndroidTestCase {
|
||||
mRedirectUrl = redirectUrl;
|
||||
mNetworkStatusReceived.open();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void preventAutomaticReconnect() {
|
||||
mPreventReconnectReceived.open();
|
||||
}
|
||||
};
|
||||
// Waits for the NetworkAgent to be registered, which includes the creation of the
|
||||
// NetworkMonitor.
|
||||
@@ -375,11 +381,6 @@ public class ConnectivityServiceTest extends AndroidTestCase {
|
||||
mWrappedNetworkMonitor.gen204ProbeResult = 200;
|
||||
mWrappedNetworkMonitor.gen204ProbeRedirectUrl = redirectUrl;
|
||||
connect(false);
|
||||
waitFor(new Criteria() { public boolean get() {
|
||||
NetworkCapabilities caps = mCm.getNetworkCapabilities(getNetwork());
|
||||
return caps != null && caps.hasCapability(NET_CAPABILITY_CAPTIVE_PORTAL);} });
|
||||
mWrappedNetworkMonitor.gen204ProbeResult = 500;
|
||||
mWrappedNetworkMonitor.gen204ProbeRedirectUrl = null;
|
||||
}
|
||||
|
||||
public void disconnect() {
|
||||
@@ -391,6 +392,10 @@ public class ConnectivityServiceTest extends AndroidTestCase {
|
||||
return new Network(mNetworkAgent.netId);
|
||||
}
|
||||
|
||||
public ConditionVariable getPreventReconnectReceived() {
|
||||
return mPreventReconnectReceived;
|
||||
}
|
||||
|
||||
public ConditionVariable getDisconnectedCV() {
|
||||
return mDisconnected;
|
||||
}
|
||||
@@ -597,6 +602,7 @@ public class ConnectivityServiceTest extends AndroidTestCase {
|
||||
|
||||
@Override
|
||||
protected CaptivePortalProbeResult isCaptivePortal() {
|
||||
if (!mIsCaptivePortalCheckEnabled) { return new CaptivePortalProbeResult(204); }
|
||||
return new CaptivePortalProbeResult(gen204ProbeResult, gen204ProbeRedirectUrl, null);
|
||||
}
|
||||
}
|
||||
@@ -743,6 +749,9 @@ public class ConnectivityServiceTest extends AndroidTestCase {
|
||||
mService.systemReady();
|
||||
mCm = new WrappedConnectivityManager(getContext(), mService);
|
||||
mCm.bindProcessToNetwork(null);
|
||||
|
||||
// Ensure that the default setting for Captive Portals is used for most tests
|
||||
setCaptivePortalMode(Settings.Global.CAPTIVE_PORTAL_MODE_PROMPT);
|
||||
}
|
||||
|
||||
public void tearDown() throws Exception {
|
||||
@@ -1710,6 +1719,47 @@ public class ConnectivityServiceTest extends AndroidTestCase {
|
||||
validatedCallback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
|
||||
}
|
||||
|
||||
@LargeTest
|
||||
public void testAvoidOrIgnoreCaptivePortals() {
|
||||
final TestNetworkCallback captivePortalCallback = new TestNetworkCallback();
|
||||
final NetworkRequest captivePortalRequest = new NetworkRequest.Builder()
|
||||
.addCapability(NET_CAPABILITY_CAPTIVE_PORTAL).build();
|
||||
mCm.registerNetworkCallback(captivePortalRequest, captivePortalCallback);
|
||||
|
||||
final TestNetworkCallback validatedCallback = new TestNetworkCallback();
|
||||
final NetworkRequest validatedRequest = new NetworkRequest.Builder()
|
||||
.addCapability(NET_CAPABILITY_VALIDATED).build();
|
||||
mCm.registerNetworkCallback(validatedRequest, validatedCallback);
|
||||
|
||||
setCaptivePortalMode(Settings.Global.CAPTIVE_PORTAL_MODE_AVOID);
|
||||
// Bring up a network with a captive portal.
|
||||
// Expect it to fail to connect and not result in any callbacks.
|
||||
mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
|
||||
String firstRedirectUrl = "http://example.com/firstPath";
|
||||
|
||||
ConditionVariable disconnectCv = mWiFiNetworkAgent.getDisconnectedCV();
|
||||
ConditionVariable avoidCv = mWiFiNetworkAgent.getPreventReconnectReceived();
|
||||
mWiFiNetworkAgent.connectWithCaptivePortal(firstRedirectUrl);
|
||||
waitFor(disconnectCv);
|
||||
waitFor(avoidCv);
|
||||
|
||||
assertNoCallbacks(captivePortalCallback, validatedCallback);
|
||||
|
||||
// Now test ignore mode.
|
||||
setCaptivePortalMode(Settings.Global.CAPTIVE_PORTAL_MODE_IGNORE);
|
||||
|
||||
// Bring up a network with a captive portal.
|
||||
// Since we're ignoring captive portals, the network will validate.
|
||||
mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
|
||||
String secondRedirectUrl = "http://example.com/secondPath";
|
||||
mWiFiNetworkAgent.connectWithCaptivePortal(secondRedirectUrl);
|
||||
|
||||
// Expect NET_CAPABILITY_VALIDATED onAvailable callback.
|
||||
validatedCallback.expectCallback(CallbackState.AVAILABLE, mWiFiNetworkAgent);
|
||||
// But there should be no CaptivePortal callback.
|
||||
captivePortalCallback.assertNoCallback();
|
||||
}
|
||||
|
||||
@SmallTest
|
||||
public void testInvalidNetworkSpecifier() {
|
||||
boolean execptionCalled = true;
|
||||
@@ -1850,6 +1900,11 @@ public class ConnectivityServiceTest extends AndroidTestCase {
|
||||
mCm.unregisterNetworkCallback(cellNetworkCallback);
|
||||
}
|
||||
|
||||
private void setCaptivePortalMode(int mode) {
|
||||
ContentResolver cr = mServiceContext.getContentResolver();
|
||||
Settings.Global.putInt(cr, Settings.Global.CAPTIVE_PORTAL_MODE, mode);
|
||||
}
|
||||
|
||||
private void setMobileDataAlwaysOn(boolean enable) {
|
||||
ContentResolver cr = mServiceContext.getContentResolver();
|
||||
Settings.Global.putInt(cr, Settings.Global.MOBILE_DATA_ALWAYS_ON, enable ? 1 : 0);
|
||||
|
||||
Reference in New Issue
Block a user