shill: Add portal metrics

Add support for Network.*.PortalAttempts,
Network.*.PortalAttemptsToOnline and Network.*.PortalResult.

BUG=chromium-os:27670
TEST=Unit tests

Change-Id: I0589c0f811a46f249ebb97540fc9d8a6ed7293ad
Reviewed-on: https://gerrit.chromium.org/gerrit/18036
Commit-Ready: Thieu Le <thieule@chromium.org>
Reviewed-by: Thieu Le <thieule@chromium.org>
Tested-by: Thieu Le <thieule@chromium.org>
diff --git a/metrics.cc b/metrics.cc
index 2ba58d9..48f5293 100644
--- a/metrics.cc
+++ b/metrics.cc
@@ -55,6 +55,22 @@
 const int Metrics::kTimerHistogramMillisecondsMin = 1;
 const int Metrics::kTimerHistogramNumBuckets = 50;
 
+const char Metrics::kMetricPortalAttempts[] =
+    "Network.Shill.%s.PortalAttempts";
+const int Metrics::kMetricPortalAttemptsMax =
+    PortalDetector::kMaxRequestAttempts;
+const int Metrics::kMetricPortalAttemptsMin = 1;
+const int Metrics::kMetricPortalAttemptsNumBuckets =
+    Metrics::kMetricPortalAttemptsMax;
+
+const char Metrics::kMetricPortalAttemptsToOnline[] =
+    "Network.Shill.%s.PortalAttemptsToOnline";
+const int Metrics::kMetricPortalAttemptsToOnlineMax = 100;
+const int Metrics::kMetricPortalAttemptsToOnlineMin = 1;
+const int Metrics::kMetricPortalAttemptsToOnlineNumBuckets = 10;
+
+const char Metrics::kMetricPortalResult[] = "Network.Shill.%s.PortalResult";
+
 // static
 const uint16 Metrics::kWiFiBandwidth5MHz = 5;
 const uint16 Metrics::kWiFiBandwidth20MHz = 20;
@@ -156,6 +172,69 @@
   }
 }
 
+// static
+Metrics::PortalResult Metrics::PortalDetectionResultToEnum(
+      const PortalDetector::Result &result) {
+  DCHECK(result.final);
+  PortalResult retval = kPortalResultUnknown;
+  // The only time we should end a successful portal detection is when we're
+  // in the Content phase.  If we end with kStatusSuccess in any other phase,
+  // then this indicates that something bad has happened.
+  switch (result.phase) {
+    case PortalDetector::kPhaseDNS:
+      if (result.status == PortalDetector::kStatusFailure)
+        retval = kPortalResultDNSFailure;
+      else if (result.status == PortalDetector::kStatusTimeout)
+        retval = kPortalResultDNSTimeout;
+      else
+        LOG(DFATAL) << __func__ << ": Final result status " << result.status
+                    << " is not allowed in the DNS phase";
+      break;
+
+    case PortalDetector::kPhaseConnection:
+      if (result.status == PortalDetector::kStatusFailure)
+        retval = kPortalResultConnectionFailure;
+      else if (result.status == PortalDetector::kStatusTimeout)
+        retval = kPortalResultConnectionTimeout;
+      else
+        LOG(DFATAL) << __func__ << ": Final result status " << result.status
+                    << " is not allowed in the Connection phase";
+      break;
+
+    case PortalDetector::kPhaseHTTP:
+      if (result.status == PortalDetector::kStatusFailure)
+        retval = kPortalResultHTTPFailure;
+      else if (result.status == PortalDetector::kStatusTimeout)
+        retval = kPortalResultHTTPTimeout;
+      else
+        LOG(DFATAL) << __func__ << ": Final result status " << result.status
+                    << " is not allowed in the HTTP phase";
+      break;
+
+    case PortalDetector::kPhaseContent:
+      if (result.status == PortalDetector::kStatusSuccess)
+        retval = kPortalResultSuccess;
+      else if (result.status == PortalDetector::kStatusFailure)
+        retval = kPortalResultContentFailure;
+      else if (result.status == PortalDetector::kStatusTimeout)
+        retval = kPortalResultContentTimeout;
+      else
+        LOG(DFATAL) << __func__ << ": Final result status " << result.status
+                    << " is not allowed in the Content phase";
+      break;
+
+    case PortalDetector::kPhaseUnknown:
+      retval = kPortalResultUnknown;
+      break;
+
+    default:
+      LOG(DFATAL) << __func__ << ": Invalid phase " << result.phase;
+      break;
+  }
+
+  return retval;
+}
+
 void Metrics::RegisterService(const Service *service) {
   shared_ptr<ServiceMetrics> service_metrics(new ServiceMetrics);
   services_metrics_[service] = service_metrics;