summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/java/android/net/metrics/NetworkEvent.java13
-rw-r--r--core/java/android/net/metrics/ValidationProbeEvent.java34
-rw-r--r--services/core/java/com/android/server/connectivity/NetworkMonitor.java157
-rw-r--r--services/core/java/com/android/server/connectivity/NetworkNotificationManager.java6
4 files changed, 146 insertions, 64 deletions
diff --git a/core/java/android/net/metrics/NetworkEvent.java b/core/java/android/net/metrics/NetworkEvent.java
index 3b3fa6976fc9..06674950a044 100644
--- a/core/java/android/net/metrics/NetworkEvent.java
+++ b/core/java/android/net/metrics/NetworkEvent.java
@@ -42,6 +42,15 @@ public final class NetworkEvent implements Parcelable {
public static final int NETWORK_DISCONNECTED = 7;
/** {@hide} */
+ public static final int NETWORK_FIRST_VALIDATION_SUCCESS = 8;
+ /** {@hide} */
+ public static final int NETWORK_REVALIDATION_SUCCESS = 9;
+ /** {@hide} */
+ public static final int NETWORK_FIRST_VALIDATION_PORTAL_FOUND = 10;
+ /** {@hide} */
+ public static final int NETWORK_REVALIDATION_PORTAL_FOUND = 11;
+
+ /** {@hide} */
@IntDef(value = {
NETWORK_CONNECTED,
NETWORK_VALIDATED,
@@ -50,6 +59,10 @@ public final class NetworkEvent implements Parcelable {
NETWORK_LINGER,
NETWORK_UNLINGER,
NETWORK_DISCONNECTED,
+ NETWORK_FIRST_VALIDATION_SUCCESS,
+ NETWORK_REVALIDATION_SUCCESS,
+ NETWORK_FIRST_VALIDATION_PORTAL_FOUND,
+ NETWORK_REVALIDATION_PORTAL_FOUND,
})
@Retention(RetentionPolicy.SOURCE)
public @interface EventType {}
diff --git a/core/java/android/net/metrics/ValidationProbeEvent.java b/core/java/android/net/metrics/ValidationProbeEvent.java
index 1a31b56f1ffb..a724ec12ed32 100644
--- a/core/java/android/net/metrics/ValidationProbeEvent.java
+++ b/core/java/android/net/metrics/ValidationProbeEvent.java
@@ -44,10 +44,8 @@ public final class ValidationProbeEvent implements Parcelable {
public static final int DNS_FAILURE = 0;
public static final int DNS_SUCCESS = 1;
- /** {@hide} */
- @IntDef(value = {PROBE_DNS, PROBE_HTTP, PROBE_HTTPS, PROBE_PAC})
- @Retention(RetentionPolicy.SOURCE)
- public @interface ProbeType {}
+ private static final int FIRST_VALIDATION = 1 << 8;
+ private static final int REVALIDATION = 2 << 8;
/** {@hide} */
@IntDef(value = {DNS_FAILURE, DNS_SUCCESS})
@@ -56,12 +54,17 @@ public final class ValidationProbeEvent implements Parcelable {
public final int netId;
public final long durationMs;
- public final @ProbeType int probeType;
+ // probeType byte format (MSB to LSB):
+ // byte 0: unused
+ // byte 1: unused
+ // byte 2: 0 = UNKNOWN, 1 = FIRST_VALIDATION, 2 = REVALIDATION
+ // byte 3: PROBE_* constant
+ public final int probeType;
public final @ReturnCode int returnCode;
/** {@hide} */
public ValidationProbeEvent(
- int netId, long durationMs, @ProbeType int probeType, @ReturnCode int returnCode) {
+ int netId, long durationMs, int probeType, @ReturnCode int returnCode) {
this.netId = netId;
this.durationMs = durationMs;
this.probeType = probeType;
@@ -100,8 +103,18 @@ public final class ValidationProbeEvent implements Parcelable {
};
/** @hide */
+ public static int makeProbeType(int probeType, boolean firstValidation) {
+ return (probeType & 0xff) | (firstValidation ? FIRST_VALIDATION : REVALIDATION);
+ }
+
+ /** @hide */
public static String getProbeName(int probeType) {
- return Decoder.constants.get(probeType, "PROBE_???");
+ return Decoder.constants.get(probeType & 0xff, "PROBE_???");
+ }
+
+ /** @hide */
+ public static String getValidationStage(int probeType) {
+ return Decoder.constants.get(probeType & 0xff00, "UNKNOWN");
}
public static void logEvent(int netId, long durationMs, int probeType, int returnCode) {
@@ -109,12 +122,13 @@ public final class ValidationProbeEvent implements Parcelable {
@Override
public String toString() {
- return String.format("ValidationProbeEvent(%d, %s:%d, %dms)",
- netId, getProbeName(probeType), returnCode, durationMs);
+ return String.format("ValidationProbeEvent(%d, %s:%d %s, %dms)", netId,
+ getProbeName(probeType), returnCode, getValidationStage(probeType), durationMs);
}
final static class Decoder {
static final SparseArray<String> constants = MessageUtils.findMessageNames(
- new Class[]{ValidationProbeEvent.class}, new String[]{"PROBE_"});
+ new Class[]{ValidationProbeEvent.class},
+ new String[]{"PROBE_", "FIRST_", "REVALIDATION"});
}
}
diff --git a/services/core/java/com/android/server/connectivity/NetworkMonitor.java b/services/core/java/com/android/server/connectivity/NetworkMonitor.java
index c73d1dd95437..5e9885914169 100644
--- a/services/core/java/com/android/server/connectivity/NetworkMonitor.java
+++ b/services/core/java/com/android/server/connectivity/NetworkMonitor.java
@@ -80,7 +80,8 @@ import java.util.concurrent.TimeUnit;
*/
public class NetworkMonitor extends StateMachine {
private static final String TAG = NetworkMonitor.class.getSimpleName();
- private static final boolean DBG = false;
+ private static final boolean DBG = true;
+ private static final boolean VDBG = false;
// Default configuration values for captive portal detection probes.
// TODO: append a random length parameter to the default HTTPS url.
@@ -96,6 +97,24 @@ public class NetworkMonitor extends StateMachine {
private static final int SOCKET_TIMEOUT_MS = 10000;
private static final int PROBE_TIMEOUT_MS = 3000;
+ static enum EvaluationResult {
+ VALIDATED(true),
+ CAPTIVE_PORTAL(false);
+ final boolean isValidated;
+ EvaluationResult(boolean isValidated) {
+ this.isValidated = isValidated;
+ }
+ }
+
+ static enum ValidationStage {
+ FIRST_VALIDATION(true),
+ REVALIDATION(false);
+ final boolean isFirstValidation;
+ ValidationStage(boolean isFirstValidation) {
+ this.isFirstValidation = isFirstValidation;
+ }
+ }
+
public static final String ACTION_NETWORK_CONDITIONS_MEASURED =
"android.net.conn.NETWORK_CONDITIONS_MEASURED";
public static final String EXTRA_CONNECTIVITY_TYPE = "extra_connectivity_type";
@@ -215,6 +234,8 @@ public class NetworkMonitor extends StateMachine {
protected boolean mIsCaptivePortalCheckEnabled;
private boolean mUseHttps;
+ // The total number of captive portal detection attempts for this NetworkMonitor instance.
+ private int mValidations = 0;
// Set if the user explicitly selected "Do not use this network" in captive portal sign-in app.
private boolean mUserDoesNotWant = false;
@@ -289,6 +310,10 @@ public class NetworkMonitor extends StateMachine {
return validationLogs.readOnlyLocalLog();
}
+ private ValidationStage validationStage() {
+ return 0 == mValidations ? ValidationStage.FIRST_VALIDATION : ValidationStage.REVALIDATION;
+ }
+
// DefaultState is the parent of all States. It exists only to handle CMD_* messages but
// does not entail any real state (hence no enter() or exit() routines).
private class DefaultState extends State {
@@ -365,9 +390,11 @@ public class NetworkMonitor extends StateMachine {
private class ValidatedState extends State {
@Override
public void enter() {
- maybeLogEvaluationResult(NetworkEvent.NETWORK_VALIDATED);
+ maybeLogEvaluationResult(
+ networkEventType(validationStage(), EvaluationResult.VALIDATED));
mConnectivityServiceHandler.sendMessage(obtainMessage(EVENT_NETWORK_TESTED,
NETWORK_TEST_RESULT_VALID, mNetworkAgentInfo.network.netId, null));
+ mValidations++;
}
@Override
@@ -583,7 +610,8 @@ public class NetworkMonitor extends StateMachine {
@Override
public void enter() {
- maybeLogEvaluationResult(NetworkEvent.NETWORK_CAPTIVE_PORTAL_FOUND);
+ maybeLogEvaluationResult(
+ networkEventType(validationStage(), EvaluationResult.CAPTIVE_PORTAL));
// Don't annoy user with sign-in notifications.
if (mDontDisplaySigninNotification) return;
// Create a CustomIntentReceiver that sends us a
@@ -603,6 +631,7 @@ public class NetworkMonitor extends StateMachine {
// Retest for captive portal occasionally.
sendMessageDelayed(CMD_CAPTIVE_PORTAL_RECHECK, 0 /* no UID */,
CAPTIVE_PORTAL_REEVALUATE_DELAY_MS);
+ mValidations++;
}
@Override
@@ -678,48 +707,13 @@ public class NetworkMonitor extends StateMachine {
long startTime = SystemClock.elapsedRealtime();
- // Pre-resolve the captive portal server host so we can log it.
- // Only do this if HttpURLConnection is about to, to avoid any potentially
- // unnecessary resolution.
- String hostToResolve = null;
+ final CaptivePortalProbeResult result;
if (pacUrl != null) {
- hostToResolve = pacUrl.getHost();
- } else if (proxyInfo != null) {
- hostToResolve = proxyInfo.getHost();
- } else {
- hostToResolve = httpUrl.getHost();
- }
-
- if (!TextUtils.isEmpty(hostToResolve)) {
- String probeName = ValidationProbeEvent.getProbeName(ValidationProbeEvent.PROBE_DNS);
- final Stopwatch dnsTimer = new Stopwatch().start();
- int dnsResult;
- long dnsLatency;
- try {
- InetAddress[] addresses = mNetworkAgentInfo.network.getAllByName(hostToResolve);
- dnsResult = ValidationProbeEvent.DNS_SUCCESS;
- dnsLatency = dnsTimer.stop();
- final StringBuffer connectInfo = new StringBuffer(", " + hostToResolve + "=");
- for (InetAddress address : addresses) {
- connectInfo.append(address.getHostAddress());
- if (address != addresses[addresses.length-1]) connectInfo.append(",");
- }
- validationLog(probeName + " OK " + dnsLatency + "ms" + connectInfo);
- } catch (UnknownHostException e) {
- dnsResult = ValidationProbeEvent.DNS_FAILURE;
- dnsLatency = dnsTimer.stop();
- validationLog(probeName + " FAIL " + dnsLatency + "ms, " + hostToResolve);
- }
- logValidationProbe(dnsLatency, ValidationProbeEvent.PROBE_DNS, dnsResult);
- }
-
- CaptivePortalProbeResult result;
- if (pacUrl != null) {
- result = sendHttpProbe(pacUrl, ValidationProbeEvent.PROBE_PAC);
+ result = sendDnsAndHttpProbes(null, pacUrl, ValidationProbeEvent.PROBE_PAC);
} else if (mUseHttps) {
- result = sendParallelHttpProbes(httpsUrl, httpUrl, fallbackUrl);
+ result = sendParallelHttpProbes(proxyInfo, httpsUrl, httpUrl, fallbackUrl);
} else {
- result = sendHttpProbe(httpUrl, ValidationProbeEvent.PROBE_HTTP);
+ result = sendDnsAndHttpProbes(proxyInfo, httpUrl, ValidationProbeEvent.PROBE_HTTP);
}
long endTime = SystemClock.elapsedRealtime();
@@ -732,8 +726,50 @@ public class NetworkMonitor extends StateMachine {
}
/**
- * Do a URL fetch on a known server to see if we get the data we expect.
- * Returns HTTP response code.
+ * Do a DNS resolution and URL fetch on a known web server to see if we get the data we expect.
+ * @return a CaptivePortalProbeResult inferred from the HTTP response.
+ */
+ private CaptivePortalProbeResult sendDnsAndHttpProbes(ProxyInfo proxy, URL url, int probeType) {
+ // Pre-resolve the captive portal server host so we can log it.
+ // Only do this if HttpURLConnection is about to, to avoid any potentially
+ // unnecessary resolution.
+ final String host = (proxy != null) ? proxy.getHost() : url.getHost();
+ sendDnsProbe(host);
+ return sendHttpProbe(url, probeType);
+ }
+
+ /** Do a DNS resolution of the given server. */
+ private void sendDnsProbe(String host) {
+ if (TextUtils.isEmpty(host)) {
+ return;
+ }
+
+ final String name = ValidationProbeEvent.getProbeName(ValidationProbeEvent.PROBE_DNS);
+ final Stopwatch watch = new Stopwatch().start();
+ int result;
+ String connectInfo;
+ try {
+ InetAddress[] addresses = mNetworkAgentInfo.network.getAllByName(host);
+ result = ValidationProbeEvent.DNS_SUCCESS;
+ StringBuffer buffer = new StringBuffer(host).append("=");
+ for (InetAddress address : addresses) {
+ buffer.append(address.getHostAddress());
+ if (address != addresses[addresses.length-1]) buffer.append(",");
+ }
+ connectInfo = buffer.toString();
+ } catch (UnknownHostException e) {
+ result = ValidationProbeEvent.DNS_FAILURE;
+ connectInfo = host;
+ }
+ final long latency = watch.stop();
+ String resultString = (ValidationProbeEvent.DNS_SUCCESS == result) ? "OK" : "FAIL";
+ validationLog(String.format("%s %s %dms, %s", name, resultString, latency, connectInfo));
+ logValidationProbe(latency, ValidationProbeEvent.PROBE_DNS, result);
+ }
+
+ /**
+ * Do a URL fetch on a known web server to see if we get the data we expect.
+ * @return a CaptivePortalProbeResult inferred from the HTTP response.
*/
@VisibleForTesting
protected CaptivePortalProbeResult sendHttpProbe(URL url, int probeType) {
@@ -800,7 +836,7 @@ public class NetworkMonitor extends StateMachine {
}
private CaptivePortalProbeResult sendParallelHttpProbes(
- URL httpsUrl, URL httpUrl, URL fallbackUrl) {
+ ProxyInfo proxy, URL httpsUrl, URL httpUrl, URL fallbackUrl) {
// Number of probes to wait for. If a probe completes with a conclusive answer
// it shortcuts the latch immediately by forcing the count to 0.
final CountDownLatch latch = new CountDownLatch(2);
@@ -820,9 +856,10 @@ public class NetworkMonitor extends StateMachine {
@Override
public void run() {
if (mIsHttps) {
- mResult = sendHttpProbe(httpsUrl, ValidationProbeEvent.PROBE_HTTPS);
+ mResult =
+ sendDnsAndHttpProbes(proxy, httpsUrl, ValidationProbeEvent.PROBE_HTTPS);
} else {
- mResult = sendHttpProbe(httpUrl, ValidationProbeEvent.PROBE_HTTP);
+ mResult = sendDnsAndHttpProbes(proxy, httpUrl, ValidationProbeEvent.PROBE_HTTP);
}
if ((mIsHttps && mResult.isSuccessful()) || (!mIsHttps && mResult.isPortal())) {
// Stop waiting immediately if https succeeds or if http finds a portal.
@@ -918,7 +955,7 @@ public class NetworkMonitor extends StateMachine {
latencyBroadcast.putExtra(EXTRA_SSID, currentWifiInfo.getSSID());
latencyBroadcast.putExtra(EXTRA_BSSID, currentWifiInfo.getBSSID());
} else {
- if (DBG) logw("network info is TYPE_WIFI but no ConnectionInfo found");
+ if (VDBG) logw("network info is TYPE_WIFI but no ConnectionInfo found");
return;
}
break;
@@ -931,8 +968,8 @@ public class NetworkMonitor extends StateMachine {
if (cellInfo.isRegistered()) {
numRegisteredCellInfo++;
if (numRegisteredCellInfo > 1) {
- log("more than one registered CellInfo. Can't " +
- "tell which is active. Bailing.");
+ if (VDBG) logw("more than one registered CellInfo." +
+ " Can't tell which is active. Bailing.");
return;
}
if (cellInfo instanceof CellInfoCdma) {
@@ -948,7 +985,7 @@ public class NetworkMonitor extends StateMachine {
CellIdentityWcdma cellId = ((CellInfoWcdma) cellInfo).getCellIdentity();
latencyBroadcast.putExtra(EXTRA_CELL_ID, cellId);
} else {
- if (DBG) logw("Registered cellinfo is unrecognized");
+ if (VDBG) logw("Registered cellinfo is unrecognized");
return;
}
}
@@ -973,6 +1010,22 @@ public class NetworkMonitor extends StateMachine {
mMetricsLog.log(new NetworkEvent(mNetId, evtype));
}
+ private int networkEventType(ValidationStage s, EvaluationResult r) {
+ if (s.isFirstValidation) {
+ if (r.isValidated) {
+ return NetworkEvent.NETWORK_FIRST_VALIDATION_SUCCESS;
+ } else {
+ return NetworkEvent.NETWORK_FIRST_VALIDATION_PORTAL_FOUND;
+ }
+ } else {
+ if (r.isValidated) {
+ return NetworkEvent.NETWORK_REVALIDATION_SUCCESS;
+ } else {
+ return NetworkEvent.NETWORK_REVALIDATION_PORTAL_FOUND;
+ }
+ }
+ }
+
private void maybeLogEvaluationResult(int evtype) {
if (mEvaluationTimer.isRunning()) {
mMetricsLog.log(new NetworkEvent(mNetId, evtype, mEvaluationTimer.stop()));
@@ -981,6 +1034,8 @@ public class NetworkMonitor extends StateMachine {
}
private void logValidationProbe(long durationMs, int probeType, int probeResult) {
+ probeType =
+ ValidationProbeEvent.makeProbeType(probeType, validationStage().isFirstValidation);
mMetricsLog.log(new ValidationProbeEvent(mNetId, durationMs, probeType, probeResult));
}
}
diff --git a/services/core/java/com/android/server/connectivity/NetworkNotificationManager.java b/services/core/java/com/android/server/connectivity/NetworkNotificationManager.java
index f7b01be48d88..c6bf4c5fcd6a 100644
--- a/services/core/java/com/android/server/connectivity/NetworkNotificationManager.java
+++ b/services/core/java/com/android/server/connectivity/NetworkNotificationManager.java
@@ -114,7 +114,7 @@ public class NetworkNotificationManager {
}
if (DBG) {
- Slog.d(TAG, "showNotification " + notifyType
+ Slog.d(TAG, "showNotification id=" + id + " " + notifyType
+ " transportType=" + getTransportName(transportType)
+ " extraInfo=" + extraInfo + " highPriority=" + highPriority);
}
@@ -187,7 +187,7 @@ public class NetworkNotificationManager {
try {
mNotificationManager.notifyAsUser(NOTIFICATION_ID, id, notification, UserHandle.ALL);
} catch (NullPointerException npe) {
- Slog.d(TAG, "setNotificationVisible: visible notificationManager npe=" + npe);
+ Slog.d(TAG, "setNotificationVisible: visible notificationManager error", npe);
}
}
@@ -198,7 +198,7 @@ public class NetworkNotificationManager {
try {
mNotificationManager.cancelAsUser(NOTIFICATION_ID, id, UserHandle.ALL);
} catch (NullPointerException npe) {
- Slog.d(TAG, "setNotificationVisible: cancel notificationManager npe=" + npe);
+ Slog.d(TAG, "setNotificationVisible: cancel notificationManager error", npe);
}
}