From 9c9e48fbd1fbe9979c54ec93924bdbe869cf22e7 Mon Sep 17 00:00:00 2001 From: Paul Jensen Date: Wed, 6 Apr 2016 09:51:26 -0400 Subject: [PATCH] If Internet probe is redirected, pass redirect destination to NetworkAgent. Transport may use the redirect to make additional determination about network state. Bug: 25203607 Change-Id: I07d8918f13fdcbe0b6fd757536bfc1850a2a244f --- core/java/android/net/NetworkAgent.java | 16 +++++++-- .../android/server/ConnectivityService.java | 16 ++++++--- .../server/ConnectivityServiceTest.java | 33 ++++++++++++++++--- 3 files changed, 52 insertions(+), 13 deletions(-) diff --git a/core/java/android/net/NetworkAgent.java b/core/java/android/net/NetworkAgent.java index 20c2168265..2dacf8f460 100644 --- a/core/java/android/net/NetworkAgent.java +++ b/core/java/android/net/NetworkAgent.java @@ -120,12 +120,17 @@ public abstract class NetworkAgent extends Handler { * either a bad network configuration (no internet link) or captive portal. * * arg1 = either {@code VALID_NETWORK} or {@code INVALID_NETWORK} + * obj = Bundle containing map from {@code REDIRECT_URL_KEY} to {@code String} + * representing URL that Internet probe was redirect to, if it was redirected, + * or mapping to {@code null} otherwise. */ public static final int CMD_REPORT_NETWORK_STATUS = BASE + 7; public static final int VALID_NETWORK = 1; public static final int INVALID_NETWORK = 2; + public static String REDIRECT_URL_KEY = "redirect URL"; + /** * Sent by the NetworkAgent to ConnectivityService to indicate this network was * explicitly selected. This should be sent before the NetworkInfo is marked @@ -283,11 +288,12 @@ public abstract class NetworkAgent extends Handler { break; } case CMD_REPORT_NETWORK_STATUS: { + String redirectUrl = ((Bundle)msg.obj).getString(REDIRECT_URL_KEY); if (VDBG) { log("CMD_REPORT_NETWORK_STATUS(" + - (msg.arg1 == VALID_NETWORK ? "VALID)" : "INVALID)")); + (msg.arg1 == VALID_NETWORK ? "VALID, " : "INVALID, ") + redirectUrl); } - networkStatus(msg.arg1); + networkStatus(msg.arg1, redirectUrl); break; } case CMD_SAVE_ACCEPT_UNVALIDATED: { @@ -443,8 +449,12 @@ public abstract class NetworkAgent extends Handler { * * This may be called multiple times as the network status changes and may * generate false negatives if we lose ip connectivity before the link is torn down. + * + * @param status one of {@code VALID_NETWORK} or {@code INVALID_NETWORK}. + * @param redirectUrl If the Internet probe was redirected, this is the destination it was + * redirected to, otherwise {@code null}. */ - protected void networkStatus(int status) { + protected void networkStatus(int status, String redirectUrl) { } /** diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java index 428e192bb0..2ccc3fe80e 100644 --- a/services/core/java/com/android/server/ConnectivityService.java +++ b/services/core/java/com/android/server/ConnectivityService.java @@ -2025,11 +2025,15 @@ public class ConnectivityService extends IConnectivityManager.Stub default: return false; case NetworkMonitor.EVENT_NETWORK_TESTED: { - NetworkAgentInfo nai = (NetworkAgentInfo)msg.obj; - if (isLiveNetworkAgent(nai, msg.what)) { + final NetworkAgentInfo nai; + synchronized (mNetworkForNetId) { + nai = mNetworkForNetId.get(msg.arg2); + } + if (nai != null) { final boolean valid = (msg.arg1 == NetworkMonitor.NETWORK_TEST_RESULT_VALID); - if (DBG) log(nai.name() + " validation " + (valid ? " passed" : "failed")); + if (DBG) log(nai.name() + " validation " + (valid ? "passed" : "failed") + + (msg.obj == null ? "" : " with redirect to " + (String)msg.obj)); if (valid != nai.lastValidated) { final int oldScore = nai.getCurrentScore(); nai.lastValidated = valid; @@ -2040,10 +2044,12 @@ public class ConnectivityService extends IConnectivityManager.Stub } updateInetCondition(nai); // Let the NetworkAgent know the state of its network + Bundle redirectUrlBundle = new Bundle(); + redirectUrlBundle.putString(NetworkAgent.REDIRECT_URL_KEY, (String)msg.obj); nai.asyncChannel.sendMessage( - android.net.NetworkAgent.CMD_REPORT_NETWORK_STATUS, + NetworkAgent.CMD_REPORT_NETWORK_STATUS, (valid ? NetworkAgent.VALID_NETWORK : NetworkAgent.INVALID_NETWORK), - 0, null); + 0, redirectUrlBundle); } break; } diff --git a/services/tests/servicestests/src/com/android/server/ConnectivityServiceTest.java b/services/tests/servicestests/src/com/android/server/ConnectivityServiceTest.java index 2f20a4bf22..26eed24c4f 100644 --- a/services/tests/servicestests/src/com/android/server/ConnectivityServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/ConnectivityServiceTest.java @@ -70,6 +70,7 @@ import android.util.LogPrinter; import com.android.internal.util.WakeupMessage; import com.android.server.connectivity.NetworkAgentInfo; import com.android.server.connectivity.NetworkMonitor; +import com.android.server.connectivity.NetworkMonitor.CaptivePortalProbeResult; import com.android.server.net.NetworkPinner; import java.net.InetAddress; @@ -223,11 +224,15 @@ public class ConnectivityServiceTest extends AndroidTestCase { private final NetworkCapabilities mNetworkCapabilities; private final IdleableHandlerThread mHandlerThread; private final ConditionVariable mDisconnected = new ConditionVariable(); + private final ConditionVariable mNetworkStatusReceived = new ConditionVariable(); private int mScore; private NetworkAgent mNetworkAgent; private int mStartKeepaliveError = PacketKeepalive.ERROR_HARDWARE_UNSUPPORTED; private int mStopKeepaliveError = PacketKeepalive.NO_KEEPALIVE; private Integer mExpectedKeepaliveSlot = null; + // Contains the redirectUrl from networkStatus(). Before reading, wait for + // mNetworkStatusReceived. + private String mRedirectUrl; MockNetworkAgent(int transport) { final int type = transportToLegacyType(transport); @@ -266,6 +271,12 @@ public class ConnectivityServiceTest extends AndroidTestCase { public void stopPacketKeepalive(Message msg) { onPacketKeepaliveEvent(msg.arg1, mStopKeepaliveError); } + + @Override + public void networkStatus(int status, String redirectUrl) { + mRedirectUrl = redirectUrl; + mNetworkStatusReceived.open(); + } }; // Waits for the NetworkAgent to be registered, which includes the creation of the // NetworkMonitor. @@ -340,13 +351,15 @@ public class ConnectivityServiceTest extends AndroidTestCase { if (callback != null) mCm.unregisterNetworkCallback(callback); } - public void connectWithCaptivePortal() { + public void connectWithCaptivePortal(String redirectUrl) { 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() { @@ -381,6 +394,11 @@ public class ConnectivityServiceTest extends AndroidTestCase { public void setExpectedKeepaliveSlot(Integer slot) { mExpectedKeepaliveSlot = slot; } + + public String waitForRedirectUrl() { + assertTrue(mNetworkStatusReceived.block(TIMEOUT_MS)); + return mRedirectUrl; + } } /** @@ -543,6 +561,7 @@ public class ConnectivityServiceTest extends AndroidTestCase { private class WrappedNetworkMonitor extends NetworkMonitor { // HTTP response code fed back to NetworkMonitor for Internet connectivity probe. public int gen204ProbeResult = 500; + public String gen204ProbeRedirectUrl = null; public WrappedNetworkMonitor(Context context, Handler handler, NetworkAgentInfo networkAgentInfo, NetworkRequest defaultRequest) { @@ -550,8 +569,8 @@ public class ConnectivityServiceTest extends AndroidTestCase { } @Override - protected int isCaptivePortal() { - return gen204ProbeResult; + protected CaptivePortalProbeResult isCaptivePortal() { + return new CaptivePortalProbeResult(gen204ProbeResult, gen204ProbeRedirectUrl); } @Override @@ -1344,8 +1363,10 @@ public class ConnectivityServiceTest extends AndroidTestCase { // Bring up a network with a captive portal. // Expect onAvailable callback of listen for NET_CAPABILITY_CAPTIVE_PORTAL. mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI); - mWiFiNetworkAgent.connectWithCaptivePortal(); + String firstRedirectUrl = "http://example.com/firstPath"; + mWiFiNetworkAgent.connectWithCaptivePortal(firstRedirectUrl); captivePortalCallback.expectCallback(CallbackState.AVAILABLE); + assertEquals(mWiFiNetworkAgent.waitForRedirectUrl(), firstRedirectUrl); // Take down network. // Expect onLost callback. @@ -1355,8 +1376,10 @@ public class ConnectivityServiceTest extends AndroidTestCase { // Bring up a network with a captive portal. // Expect onAvailable callback of listen for NET_CAPABILITY_CAPTIVE_PORTAL. mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI); - mWiFiNetworkAgent.connectWithCaptivePortal(); + String secondRedirectUrl = "http://example.com/secondPath"; + mWiFiNetworkAgent.connectWithCaptivePortal(secondRedirectUrl); captivePortalCallback.expectCallback(CallbackState.AVAILABLE); + assertEquals(mWiFiNetworkAgent.waitForRedirectUrl(), secondRedirectUrl); // Make captive portal disappear then revalidate. // Expect onLost callback because network no longer provides NET_CAPABILITY_CAPTIVE_PORTAL.