Add option to skip and avoid captive portals.

am: 5139717c74

Change-Id: Id38d5c03d06822f9b20abd65db9dd04c90110b63
This commit is contained in:
Calvin On
2016-10-20 20:18:10 +00:00
committed by android-build-merger
2 changed files with 75 additions and 6 deletions

View File

@@ -2261,11 +2261,19 @@ public class ConnectivityService extends IConnectivityManager.Stub
synchronized (mNetworkForNetId) { synchronized (mNetworkForNetId) {
nai = mNetworkForNetId.get(netId); 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)) { if (nai != null && (visible != nai.lastCaptivePortalDetected)) {
final int oldScore = nai.getCurrentScore(); final int oldScore = nai.getCurrentScore();
nai.lastCaptivePortalDetected = visible; nai.lastCaptivePortalDetected = visible;
nai.everCaptivePortalDetected |= 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); updateCapabilities(oldScore, nai, nai.networkCapabilities);
} }
if (!visible) { if (!visible) {
@@ -2286,6 +2294,12 @@ public class ConnectivityService extends IConnectivityManager.Stub
return true; 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) { private boolean maybeHandleNetworkAgentInfoMessage(Message msg) {
switch (msg.what) { switch (msg.what) {
default: default:

View File

@@ -236,6 +236,7 @@ public class ConnectivityServiceTest extends AndroidTestCase {
private final IdleableHandlerThread mHandlerThread; private final IdleableHandlerThread mHandlerThread;
private final ConditionVariable mDisconnected = new ConditionVariable(); private final ConditionVariable mDisconnected = new ConditionVariable();
private final ConditionVariable mNetworkStatusReceived = new ConditionVariable(); private final ConditionVariable mNetworkStatusReceived = new ConditionVariable();
private final ConditionVariable mPreventReconnectReceived = new ConditionVariable();
private int mScore; private int mScore;
private NetworkAgent mNetworkAgent; private NetworkAgent mNetworkAgent;
private int mStartKeepaliveError = PacketKeepalive.ERROR_HARDWARE_UNSUPPORTED; private int mStartKeepaliveError = PacketKeepalive.ERROR_HARDWARE_UNSUPPORTED;
@@ -291,6 +292,11 @@ public class ConnectivityServiceTest extends AndroidTestCase {
mRedirectUrl = redirectUrl; mRedirectUrl = redirectUrl;
mNetworkStatusReceived.open(); mNetworkStatusReceived.open();
} }
@Override
protected void preventAutomaticReconnect() {
mPreventReconnectReceived.open();
}
}; };
// Waits for the NetworkAgent to be registered, which includes the creation of the // Waits for the NetworkAgent to be registered, which includes the creation of the
// NetworkMonitor. // NetworkMonitor.
@@ -375,11 +381,6 @@ public class ConnectivityServiceTest extends AndroidTestCase {
mWrappedNetworkMonitor.gen204ProbeResult = 200; mWrappedNetworkMonitor.gen204ProbeResult = 200;
mWrappedNetworkMonitor.gen204ProbeRedirectUrl = redirectUrl; mWrappedNetworkMonitor.gen204ProbeRedirectUrl = redirectUrl;
connect(false); 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() { public void disconnect() {
@@ -391,6 +392,10 @@ public class ConnectivityServiceTest extends AndroidTestCase {
return new Network(mNetworkAgent.netId); return new Network(mNetworkAgent.netId);
} }
public ConditionVariable getPreventReconnectReceived() {
return mPreventReconnectReceived;
}
public ConditionVariable getDisconnectedCV() { public ConditionVariable getDisconnectedCV() {
return mDisconnected; return mDisconnected;
} }
@@ -597,6 +602,7 @@ public class ConnectivityServiceTest extends AndroidTestCase {
@Override @Override
protected CaptivePortalProbeResult isCaptivePortal() { protected CaptivePortalProbeResult isCaptivePortal() {
if (!mIsCaptivePortalCheckEnabled) { return new CaptivePortalProbeResult(204); }
return new CaptivePortalProbeResult(gen204ProbeResult, gen204ProbeRedirectUrl, null); return new CaptivePortalProbeResult(gen204ProbeResult, gen204ProbeRedirectUrl, null);
} }
} }
@@ -743,6 +749,9 @@ public class ConnectivityServiceTest extends AndroidTestCase {
mService.systemReady(); mService.systemReady();
mCm = new WrappedConnectivityManager(getContext(), mService); mCm = new WrappedConnectivityManager(getContext(), mService);
mCm.bindProcessToNetwork(null); 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 { public void tearDown() throws Exception {
@@ -1704,6 +1713,47 @@ public class ConnectivityServiceTest extends AndroidTestCase {
validatedCallback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent); 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 @SmallTest
public void testInvalidNetworkSpecifier() { public void testInvalidNetworkSpecifier() {
boolean execptionCalled = true; boolean execptionCalled = true;
@@ -1844,6 +1894,11 @@ public class ConnectivityServiceTest extends AndroidTestCase {
mCm.unregisterNetworkCallback(cellNetworkCallback); 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) { private void setMobileDataAlwaysOn(boolean enable) {
ContentResolver cr = mServiceContext.getContentResolver(); ContentResolver cr = mServiceContext.getContentResolver();
Settings.Global.putInt(cr, Settings.Global.MOBILE_DATA_ALWAYS_ON, enable ? 1 : 0); Settings.Global.putInt(cr, Settings.Global.MOBILE_DATA_ALWAYS_ON, enable ? 1 : 0);