Home | History | Annotate | Download | only in shill
      1 //
      2 // Copyright (C) 2012 The Android Open Source Project
      3 //
      4 // Licensed under the Apache License, Version 2.0 (the "License");
      5 // you may not use this file except in compliance with the License.
      6 // You may obtain a copy of the License at
      7 //
      8 //      http://www.apache.org/licenses/LICENSE-2.0
      9 //
     10 // Unless required by applicable law or agreed to in writing, software
     11 // distributed under the License is distributed on an "AS IS" BASIS,
     12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13 // See the License for the specific language governing permissions and
     14 // limitations under the License.
     15 //
     16 
     17 #include "shill/metrics.h"
     18 
     19 #include <base/strings/string_util.h>
     20 #include <base/strings/stringprintf.h>
     21 #if defined(__ANDROID__)
     22 #include <dbus/service_constants.h>
     23 #else
     24 #include <chromeos/dbus/service_constants.h>
     25 #endif  // __ANDROID__
     26 #if !defined(__ANDROID__)
     27 #include <metrics/bootstat.h>
     28 #endif  // __ANDROID__
     29 
     30 #include "shill/connection_diagnostics.h"
     31 #include "shill/link_monitor.h"
     32 #include "shill/logging.h"
     33 
     34 using std::string;
     35 using std::shared_ptr;
     36 
     37 namespace shill {
     38 
     39 namespace Logging {
     40 static auto kModuleLogScope = ScopeLogger::kMetrics;
     41 static string ObjectID(const Metrics* m) { return "(metrics)"; }
     42 }
     43 
     44 static const char kMetricPrefix[] = "Network.Shill";
     45 
     46 // static
     47 // Our disconnect enumeration values are 0 (System Disconnect) and
     48 // 1 (User Disconnect), see histograms.xml, but Chrome needs a minimum
     49 // enum value of 1 and the minimum number of buckets needs to be 3 (see
     50 // histogram.h).  Instead of remapping System Disconnect to 1 and
     51 // User Disconnect to 2, we can just leave the enumerated values as-is
     52 // because Chrome implicitly creates a [0-1) bucket for us.  Using Min=1,
     53 // Max=2 and NumBuckets=3 gives us the following three buckets:
     54 // [0-1), [1-2), [2-INT_MAX).  We end up with an extra bucket [2-INT_MAX)
     55 // that we can safely ignore.
     56 const char Metrics::kMetricDisconnectSuffix[] = "Disconnect";
     57 const int Metrics::kMetricDisconnectMax = 2;
     58 const int Metrics::kMetricDisconnectMin = 1;
     59 const int Metrics::kMetricDisconnectNumBuckets = 3;
     60 
     61 const char Metrics::kMetricSignalAtDisconnectSuffix[] = "SignalAtDisconnect";
     62 const int Metrics::kMetricSignalAtDisconnectMin = 0;
     63 const int Metrics::kMetricSignalAtDisconnectMax = 200;
     64 const int Metrics::kMetricSignalAtDisconnectNumBuckets = 40;
     65 
     66 const char Metrics::kMetricNetworkApModeSuffix[] = "ApMode";
     67 const char Metrics::kMetricNetworkChannelSuffix[] = "Channel";
     68 const int Metrics::kMetricNetworkChannelMax = Metrics::kWiFiChannelMax;
     69 const char Metrics::kMetricNetworkEapInnerProtocolSuffix[] = "EapInnerProtocol";
     70 const int Metrics::kMetricNetworkEapInnerProtocolMax =
     71     Metrics::kEapInnerProtocolMax;
     72 const char Metrics::kMetricNetworkEapOuterProtocolSuffix[] = "EapOuterProtocol";
     73 const int Metrics::kMetricNetworkEapOuterProtocolMax =
     74     Metrics::kEapOuterProtocolMax;
     75 const char Metrics::kMetricNetworkPhyModeSuffix[] = "PhyMode";
     76 const int Metrics::kMetricNetworkPhyModeMax = Metrics::kWiFiNetworkPhyModeMax;
     77 const char Metrics::kMetricNetworkSecuritySuffix[] = "Security";
     78 const int Metrics::kMetricNetworkSecurityMax = Metrics::kWiFiSecurityMax;
     79 const char Metrics::kMetricNetworkServiceErrors[] =
     80     "Network.Shill.ServiceErrors";
     81 const char Metrics::kMetricNetworkSignalStrengthSuffix[] = "SignalStrength";
     82 const int Metrics::kMetricNetworkSignalStrengthMax = 200;
     83 const int Metrics::kMetricNetworkSignalStrengthMin = 0;
     84 const int Metrics::kMetricNetworkSignalStrengthNumBuckets = 40;
     85 
     86 constexpr char
     87     Metrics::kMetricRememberedSystemWiFiNetworkCountBySecurityModeFormat[];
     88 constexpr char
     89     Metrics::kMetricRememberedUserWiFiNetworkCountBySecurityModeFormat[];
     90 
     91 const char Metrics::kMetricRememberedWiFiNetworkCount[] =
     92     "Network.Shill.WiFi.RememberedNetworkCount";
     93 const int Metrics::kMetricRememberedWiFiNetworkCountMax = 1024;
     94 const int Metrics::kMetricRememberedWiFiNetworkCountMin = 0;
     95 const int Metrics::kMetricRememberedWiFiNetworkCountNumBuckets = 32;
     96 
     97 const char Metrics::kMetricTimeOnlineSecondsSuffix[] = "TimeOnline";
     98 const int Metrics::kMetricTimeOnlineSecondsMax = 8 * 60 * 60;  // 8 hours
     99 const int Metrics::kMetricTimeOnlineSecondsMin = 1;
    100 
    101 const char Metrics::kMetricTimeToConnectMillisecondsSuffix[] = "TimeToConnect";
    102 const int Metrics::kMetricTimeToConnectMillisecondsMax =
    103     60 * 1000;  // 60 seconds
    104 const int Metrics::kMetricTimeToConnectMillisecondsMin = 1;
    105 const int Metrics::kMetricTimeToConnectMillisecondsNumBuckets = 60;
    106 
    107 const char Metrics::kMetricTimeToScanAndConnectMillisecondsSuffix[] =
    108     "TimeToScanAndConnect";
    109 
    110 const char Metrics::kMetricTimeToDropSeconds[] = "Network.Shill.TimeToDrop";;
    111 const int Metrics::kMetricTimeToDropSecondsMax = 8 * 60 * 60;  // 8 hours
    112 const int Metrics::kMetricTimeToDropSecondsMin = 1;
    113 
    114 const char Metrics::kMetricTimeToDisableMillisecondsSuffix[] = "TimeToDisable";
    115 const int Metrics::kMetricTimeToDisableMillisecondsMax =
    116     60 * 1000;  // 60 seconds
    117 const int Metrics::kMetricTimeToDisableMillisecondsMin = 1;
    118 const int Metrics::kMetricTimeToDisableMillisecondsNumBuckets = 60;
    119 
    120 const char Metrics::kMetricTimeToEnableMillisecondsSuffix[] = "TimeToEnable";
    121 const int Metrics::kMetricTimeToEnableMillisecondsMax =
    122     60 * 1000;  // 60 seconds
    123 const int Metrics::kMetricTimeToEnableMillisecondsMin = 1;
    124 const int Metrics::kMetricTimeToEnableMillisecondsNumBuckets = 60;
    125 
    126 const char Metrics::kMetricTimeToInitializeMillisecondsSuffix[] =
    127     "TimeToInitialize";
    128 const int Metrics::kMetricTimeToInitializeMillisecondsMax =
    129     30 * 1000;  // 30 seconds
    130 const int Metrics::kMetricTimeToInitializeMillisecondsMin = 1;
    131 const int Metrics::kMetricTimeToInitializeMillisecondsNumBuckets = 30;
    132 
    133 const char Metrics::kMetricTimeResumeToReadyMillisecondsSuffix[] =
    134     "TimeResumeToReady";
    135 const char Metrics::kMetricTimeToConfigMillisecondsSuffix[] = "TimeToConfig";
    136 const char Metrics::kMetricTimeToJoinMillisecondsSuffix[] = "TimeToJoin";
    137 const char Metrics::kMetricTimeToOnlineMillisecondsSuffix[] = "TimeToOnline";
    138 const char Metrics::kMetricTimeToPortalMillisecondsSuffix[] = "TimeToPortal";
    139 
    140 const char Metrics::kMetricTimeToScanMillisecondsSuffix[] = "TimeToScan";
    141 const int Metrics::kMetricTimeToScanMillisecondsMax = 180 * 1000;  // 3 minutes
    142 const int Metrics::kMetricTimeToScanMillisecondsMin = 1;
    143 const int Metrics::kMetricTimeToScanMillisecondsNumBuckets = 90;
    144 
    145 const int Metrics::kTimerHistogramMillisecondsMax = 45 * 1000;
    146 const int Metrics::kTimerHistogramMillisecondsMin = 1;
    147 const int Metrics::kTimerHistogramNumBuckets = 50;
    148 
    149 const char Metrics::kMetricPortalAttemptsSuffix[] = "PortalAttempts";
    150 const int Metrics::kMetricPortalAttemptsMax =
    151     PortalDetector::kMaxRequestAttempts;
    152 const int Metrics::kMetricPortalAttemptsMin = 1;
    153 const int Metrics::kMetricPortalAttemptsNumBuckets =
    154     Metrics::kMetricPortalAttemptsMax;
    155 
    156 const char Metrics::kMetricPortalAttemptsToOnlineSuffix[] =
    157     "PortalAttemptsToOnline";
    158 const int Metrics::kMetricPortalAttemptsToOnlineMax = 100;
    159 const int Metrics::kMetricPortalAttemptsToOnlineMin = 1;
    160 const int Metrics::kMetricPortalAttemptsToOnlineNumBuckets = 10;
    161 
    162 const char Metrics::kMetricPortalResultSuffix[] = "PortalResult";
    163 
    164 const char Metrics::kMetricFrequenciesConnectedEver[] =
    165     "Network.Shill.WiFi.FrequenciesConnectedEver";
    166 const int Metrics::kMetricFrequenciesConnectedMax = 50;
    167 const int Metrics::kMetricFrequenciesConnectedMin = 1;
    168 const int Metrics::kMetricFrequenciesConnectedNumBuckets = 50;
    169 
    170 const char Metrics::kMetricScanResult[] =
    171     "Network.Shill.WiFi.ScanResult";
    172 const char Metrics::kMetricWiFiScanTimeInEbusyMilliseconds[] =
    173     "Network.Shill.WiFi.ScanTimeInEbusy";
    174 
    175 const char Metrics::kMetricTerminationActionTimeTaken[] =
    176     "Network.Shill.TerminationActionTimeTaken";
    177 const char Metrics::kMetricTerminationActionResult[] =
    178     "Network.Shill.TerminationActionResult";
    179 const int Metrics::kMetricTerminationActionTimeTakenMillisecondsMax = 20000;
    180 const int Metrics::kMetricTerminationActionTimeTakenMillisecondsMin = 1;
    181 
    182 const char Metrics::kMetricSuspendActionTimeTaken[] =
    183     "Network.Shill.SuspendActionTimeTaken";
    184 const char Metrics::kMetricSuspendActionResult[] =
    185     "Network.Shill.SuspendActionResult";
    186 const int Metrics::kMetricSuspendActionTimeTakenMillisecondsMax = 20000;
    187 const int Metrics::kMetricSuspendActionTimeTakenMillisecondsMin = 1;
    188 
    189 const char Metrics::kMetricDarkResumeActionTimeTaken[] =
    190     "Network.Shill.DarkResumeActionTimeTaken";
    191 const char Metrics::kMetricDarkResumeActionResult[] =
    192     "Network.Shill.DarkResumeActionResult";
    193 const int Metrics::kMetricDarkResumeActionTimeTakenMillisecondsMax = 20000;
    194 const int Metrics::kMetricDarkResumeActionTimeTakenMillisecondsMin = 1;
    195 const char Metrics::kMetricDarkResumeUnmatchedScanResultReceived[] =
    196     "Network.Shill.WiFi.DarkResumeUnmatchedScanResultsReceived";
    197 
    198 const char Metrics::kMetricWakeOnWiFiFeaturesEnabledState[] =
    199     "Network.Shill.WiFi.WakeOnWiFiFeaturesEnabledState";
    200 const char Metrics::kMetricVerifyWakeOnWiFiSettingsResult[] =
    201     "Network.Shill.WiFi.VerifyWakeOnWiFiSettingsResult";
    202 const char Metrics::kMetricWiFiConnectionStatusAfterWake[] =
    203     "Network.Shill.WiFi.WiFiConnectionStatusAfterWake";
    204 const char Metrics::kMetricWakeOnWiFiThrottled[] =
    205     "Network.Shill.WiFi.WakeOnWiFiThrottled";
    206 const char Metrics::kMetricWakeReasonReceivedBeforeOnDarkResume[] =
    207     "Network.Shill.WiFi.WakeReasonReceivedBeforeOnDarkResume";
    208 const char Metrics::kMetricDarkResumeWakeReason[] =
    209     "Network.Shill.WiFi.DarkResumeWakeReason";
    210 const char Metrics::kMetricDarkResumeScanType[] =
    211     "Network.Shill.WiFi.DarkResumeScanType";
    212 const char Metrics::kMetricDarkResumeScanRetryResult[] =
    213     "Network.Shill.WiFi.DarkResumeScanRetryResult";
    214 const char Metrics::kMetricDarkResumeScanNumRetries[] =
    215     "Network.Shill.WiFi.DarkResumeScanNumRetries";
    216 const int Metrics::kMetricDarkResumeScanNumRetriesMax = 20;
    217 const int Metrics::kMetricDarkResumeScanNumRetriesMin = 0;
    218 
    219 // static
    220 const char Metrics::kMetricServiceFixupEntriesSuffix[] = "ServiceFixupEntries";
    221 
    222 // static
    223 const uint16_t Metrics::kWiFiBandwidth5MHz = 5;
    224 const uint16_t Metrics::kWiFiBandwidth20MHz = 20;
    225 const uint16_t Metrics::kWiFiFrequency2412 = 2412;
    226 const uint16_t Metrics::kWiFiFrequency2472 = 2472;
    227 const uint16_t Metrics::kWiFiFrequency2484 = 2484;
    228 const uint16_t Metrics::kWiFiFrequency5170 = 5170;
    229 const uint16_t Metrics::kWiFiFrequency5180 = 5180;
    230 const uint16_t Metrics::kWiFiFrequency5230 = 5230;
    231 const uint16_t Metrics::kWiFiFrequency5240 = 5240;
    232 const uint16_t Metrics::kWiFiFrequency5320 = 5320;
    233 const uint16_t Metrics::kWiFiFrequency5500 = 5500;
    234 const uint16_t Metrics::kWiFiFrequency5700 = 5700;
    235 const uint16_t Metrics::kWiFiFrequency5745 = 5745;
    236 const uint16_t Metrics::kWiFiFrequency5825 = 5825;
    237 
    238 // static
    239 const char Metrics::kMetricPowerManagerKey[] = "metrics";
    240 
    241 // static
    242 const char Metrics::kMetricLinkMonitorFailureSuffix[] = "LinkMonitorFailure";
    243 const char Metrics::kMetricLinkMonitorResponseTimeSampleSuffix[] =
    244     "LinkMonitorResponseTimeSample";
    245 const int Metrics::kMetricLinkMonitorResponseTimeSampleMin = 0;
    246 const int Metrics::kMetricLinkMonitorResponseTimeSampleMax =
    247     LinkMonitor::kDefaultTestPeriodMilliseconds;
    248 const int Metrics::kMetricLinkMonitorResponseTimeSampleNumBuckets = 50;
    249 const char Metrics::kMetricLinkMonitorSecondsToFailureSuffix[] =
    250     "LinkMonitorSecondsToFailure";
    251 const int Metrics::kMetricLinkMonitorSecondsToFailureMin = 0;
    252 const int Metrics::kMetricLinkMonitorSecondsToFailureMax = 7200;
    253 const int Metrics::kMetricLinkMonitorSecondsToFailureNumBuckets = 50;
    254 const char Metrics::kMetricLinkMonitorBroadcastErrorsAtFailureSuffix[] =
    255     "LinkMonitorBroadcastErrorsAtFailure";
    256 const char Metrics::kMetricLinkMonitorUnicastErrorsAtFailureSuffix[] =
    257     "LinkMonitorUnicastErrorsAtFailure";
    258 const int Metrics::kMetricLinkMonitorErrorCountMin = 0;
    259 const int Metrics::kMetricLinkMonitorErrorCountMax =
    260     LinkMonitor::kFailureThreshold;
    261 const int Metrics::kMetricLinkMonitorErrorCountNumBuckets =
    262     LinkMonitor::kFailureThreshold + 1;
    263 
    264 // static
    265 const char Metrics::kMetricLinkClientDisconnectReason[] =
    266     "Network.Shill.WiFi.ClientDisconnectReason";
    267 const char Metrics::kMetricLinkApDisconnectReason[] =
    268     "Network.Shill.WiFi.ApDisconnectReason";
    269 const char Metrics::kMetricLinkClientDisconnectType[] =
    270     "Network.Shill.WiFi.ClientDisconnectType";
    271 const char Metrics::kMetricLinkApDisconnectType[] =
    272     "Network.Shill.WiFi.ApDisconnectType";
    273 
    274 // static
    275 const char Metrics::kMetricCellular3GPPRegistrationDelayedDrop[] =
    276     "Network.Shill.Cellular.3GPPRegistrationDelayedDrop";
    277 const char Metrics::kMetricCellularAutoConnectTries[] =
    278     "Network.Shill.Cellular.AutoConnectTries";
    279 const int Metrics::kMetricCellularAutoConnectTriesMax = 20;
    280 const int Metrics::kMetricCellularAutoConnectTriesMin = 1;
    281 const int Metrics::kMetricCellularAutoConnectTriesNumBuckets = 20;
    282 const char Metrics::kMetricCellularAutoConnectTotalTime[] =
    283     "Network.Shill.Cellular.AutoConnectTotalTime";
    284 const int Metrics::kMetricCellularAutoConnectTotalTimeMax =
    285     60 * 1000;  // 60 seconds
    286 const int Metrics::kMetricCellularAutoConnectTotalTimeMin = 0;
    287 const int Metrics::kMetricCellularAutoConnectTotalTimeNumBuckets = 60;
    288 const char Metrics::kMetricCellularDrop[] =
    289     "Network.Shill.Cellular.Drop";
    290 
    291 // static
    292 const char Metrics::kMetricCellularFailure[] =
    293     "Network.Shill.Cellular.Failure";
    294 const int Metrics::kMetricCellularConnectionFailure = 0;
    295 const int Metrics::kMetricCellularDisconnectionFailure = 1;
    296 const int Metrics::kMetricCellularMaxFailure =
    297     kMetricCellularDisconnectionFailure + 1;
    298 
    299 const char Metrics::kMetricCellularOutOfCreditsReason[] =
    300     "Network.Shill.Cellular.OutOfCreditsReason";
    301 const char Metrics::kMetricCellularSignalStrengthBeforeDrop[] =
    302     "Network.Shill.Cellular.SignalStrengthBeforeDrop";
    303 const int Metrics::kMetricCellularSignalStrengthBeforeDropMax = 100;
    304 const int Metrics::kMetricCellularSignalStrengthBeforeDropMin = 0;
    305 const int Metrics::kMetricCellularSignalStrengthBeforeDropNumBuckets = 10;
    306 
    307 // static
    308 const char Metrics::kMetricCorruptedProfile[] =
    309     "Network.Shill.CorruptedProfile";
    310 
    311 // static
    312 const char Metrics::kMetricVpnDriver[] =
    313     "Network.Shill.Vpn.Driver";
    314 const int Metrics::kMetricVpnDriverMax = Metrics::kVpnDriverMax;
    315 const char Metrics::kMetricVpnRemoteAuthenticationType[] =
    316     "Network.Shill.Vpn.RemoteAuthenticationType";
    317 const int Metrics::kMetricVpnRemoteAuthenticationTypeMax =
    318     Metrics::kVpnRemoteAuthenticationTypeMax;
    319 const char Metrics::kMetricVpnUserAuthenticationType[] =
    320     "Network.Shill.Vpn.UserAuthenticationType";
    321 const int Metrics::kMetricVpnUserAuthenticationTypeMax =
    322     Metrics::kVpnUserAuthenticationTypeMax;
    323 
    324 const char Metrics::kMetricExpiredLeaseLengthSecondsSuffix[] =
    325     "ExpiredLeaseLengthSeconds";
    326 const int Metrics::kMetricExpiredLeaseLengthSecondsMax =
    327     7 * 24 * 60 * 60;  // 7 days
    328 const int Metrics::kMetricExpiredLeaseLengthSecondsMin = 1;
    329 const int Metrics::kMetricExpiredLeaseLengthSecondsNumBuckets =
    330     Metrics::kMetricExpiredLeaseLengthSecondsMax;
    331 
    332 // static
    333 const char Metrics::kMetricWifiAutoConnectableServices[] =
    334     "Network.Shill.WiFi.AutoConnectableServices";
    335 const int Metrics::kMetricWifiAutoConnectableServicesMax = 50;
    336 const int Metrics::kMetricWifiAutoConnectableServicesMin = 1;
    337 const int Metrics::kMetricWifiAutoConnectableServicesNumBuckets = 10;
    338 
    339 // static
    340 const char Metrics::kMetricWifiAvailableBSSes[] =
    341     "Network.Shill.WiFi.AvailableBSSesAtConnect";
    342 const int Metrics::kMetricWifiAvailableBSSesMax = 50;
    343 const int Metrics::kMetricWifiAvailableBSSesMin = 1;
    344 const int Metrics::kMetricWifiAvailableBSSesNumBuckets = 10;
    345 
    346 // static
    347 const char Metrics::kMetricWifiStoppedTxQueueReason[] =
    348     "Network.Shill.WiFi.StoppedTxQueueReason";
    349 // Values are defined in mac80211_monitor.h.
    350 
    351 // static
    352 const char Metrics::kMetricWifiStoppedTxQueueLength[] =
    353     "Network.Shill.WiFi.StoppedTxQueueLength";
    354 const int Metrics::kMetricWifiStoppedTxQueueLengthMax = 10000;
    355 const int Metrics::kMetricWifiStoppedTxQueueLengthMin = 1;
    356 const int Metrics::kMetricWifiStoppedTxQueueLengthNumBuckets = 50;
    357 
    358 // Number of services associated with currently connected network.
    359 const char Metrics::kMetricServicesOnSameNetwork[] =
    360     "Network.Shill.ServicesOnSameNetwork";
    361 const int Metrics::kMetricServicesOnSameNetworkMax = 20;
    362 const int Metrics::kMetricServicesOnSameNetworkMin = 1;
    363 const int Metrics::kMetricServicesOnSameNetworkNumBuckets = 10;
    364 
    365 // static
    366 const char Metrics::kMetricUserInitiatedEvents[] =
    367     "Network.Shill.UserInitiatedEvents";
    368 
    369 // static
    370 const char Metrics::kMetricWifiTxBitrate[] =
    371     "Network.Shill.WiFi.TransmitBitrateMbps";
    372 const int Metrics::kMetricWifiTxBitrateMax = 7000;
    373 const int Metrics::kMetricWifiTxBitrateMin = 1;
    374 const int Metrics::kMetricWifiTxBitrateNumBuckets = 100;
    375 
    376 // static
    377 const char Metrics::kMetricWifiUserInitiatedConnectionResult[] =
    378     "Network.Shill.WiFi.UserInitiatedConnectionResult";
    379 
    380 // static
    381 const char Metrics::kMetricWifiUserInitiatedConnectionFailureReason[] =
    382     "Network.Shill.WiFi.UserInitiatedConnectionFailureReason";
    383 
    384 // static
    385 const char Metrics::kMetricFallbackDNSTestResultSuffix[] =
    386     "FallbackDNSTestResult";
    387 
    388 // static
    389 const char Metrics::kMetricNetworkProblemDetectedSuffix[] =
    390     "NetworkProblemDetected";
    391 
    392 // static
    393 const char Metrics::kMetricDeviceConnectionStatus[] =
    394     "Network.Shill.DeviceConnectionStatus";
    395 
    396 // static
    397 const char Metrics::kMetricDhcpClientStatus[] =
    398     "Network.Shill.DHCPClientStatus";
    399 
    400 // static
    401 const char Metrics::kMetricDhcpClientMTUValue[] =
    402     "Network.Shill.DHCPClientMTUValue";
    403 const char Metrics::kMetricPPPMTUValue[] = "Network.Shill.PPPMTUValue";
    404 
    405 // static
    406 const char Metrics::kMetricNetworkConnectionIPTypeSuffix[] =
    407     "NetworkConnectionIPType";
    408 
    409 // static
    410 const char Metrics::kMetricIPv6ConnectivityStatusSuffix[] =
    411     "IPv6ConnectivityStatus";
    412 
    413 // static
    414 const char Metrics::kMetricDevicePresenceStatusSuffix[] =
    415     "DevicePresenceStatus";
    416 
    417 // static
    418 const char Metrics::kMetricDeviceRemovedEvent[] =
    419     "Network.Shill.DeviceRemovedEvent";
    420 
    421 // static
    422 const char Metrics::kMetricConnectionDiagnosticsIssue[] =
    423     "Network.Shill.ConnectionDiagnosticsIssue";
    424 
    425     // static
    426     const char Metrics::kMetricUnreliableLinkSignalStrengthSuffix[] =
    427         "UnreliableLinkSignalStrength";
    428 const int Metrics::kMetricSerivceSignalStrengthMin = 0;
    429 const int Metrics::kMetricServiceSignalStrengthMax = 100;
    430 const int Metrics::kMetricServiceSignalStrengthNumBuckets = 40;
    431 
    432 Metrics::Metrics(EventDispatcher* dispatcher)
    433     : dispatcher_(dispatcher),
    434       library_(&metrics_library_),
    435       last_default_technology_(Technology::kUnknown),
    436       was_online_(false),
    437       time_online_timer_(new chromeos_metrics::Timer),
    438       time_to_drop_timer_(new chromeos_metrics::Timer),
    439       time_resume_to_ready_timer_(new chromeos_metrics::Timer),
    440       time_termination_actions_timer(new chromeos_metrics::Timer),
    441       time_suspend_actions_timer(new chromeos_metrics::Timer),
    442       time_dark_resume_actions_timer(new chromeos_metrics::Timer),
    443       collect_bootstats_(true),
    444       num_scan_results_expected_in_dark_resume_(0),
    445       wake_on_wifi_throttled_(false),
    446       wake_reason_received_(false),
    447       dark_resume_scan_retries_(0) {
    448   metrics_library_.Init();
    449   chromeos_metrics::TimerReporter::set_metrics_lib(library_);
    450 }
    451 
    452 Metrics::~Metrics() {}
    453 
    454 // static
    455 Metrics::WiFiChannel Metrics::WiFiFrequencyToChannel(uint16_t frequency) {
    456   WiFiChannel channel = kWiFiChannelUndef;
    457   if (kWiFiFrequency2412 <= frequency && frequency <= kWiFiFrequency2472) {
    458     if (((frequency - kWiFiFrequency2412) % kWiFiBandwidth5MHz) == 0)
    459       channel = static_cast<WiFiChannel>(
    460                     kWiFiChannel2412 +
    461                     (frequency - kWiFiFrequency2412) / kWiFiBandwidth5MHz);
    462   } else if (frequency == kWiFiFrequency2484) {
    463     channel = kWiFiChannel2484;
    464   } else if (kWiFiFrequency5170 <= frequency &&
    465              frequency <= kWiFiFrequency5230) {
    466     if ((frequency % kWiFiBandwidth20MHz) == 0)
    467       channel = static_cast<WiFiChannel>(
    468                     kWiFiChannel5180 +
    469                     (frequency - kWiFiFrequency5180) / kWiFiBandwidth20MHz);
    470     if ((frequency % kWiFiBandwidth20MHz) == 10)
    471       channel = static_cast<WiFiChannel>(
    472                     kWiFiChannel5170 +
    473                     (frequency - kWiFiFrequency5170) / kWiFiBandwidth20MHz);
    474   } else if (kWiFiFrequency5240 <= frequency &&
    475              frequency <= kWiFiFrequency5320) {
    476     if (((frequency - kWiFiFrequency5180) % kWiFiBandwidth20MHz) == 0)
    477       channel = static_cast<WiFiChannel>(
    478                     kWiFiChannel5180 +
    479                     (frequency - kWiFiFrequency5180) / kWiFiBandwidth20MHz);
    480   } else if (kWiFiFrequency5500 <= frequency &&
    481              frequency <= kWiFiFrequency5700) {
    482     if (((frequency - kWiFiFrequency5500) % kWiFiBandwidth20MHz) == 0)
    483       channel = static_cast<WiFiChannel>(
    484                     kWiFiChannel5500 +
    485                     (frequency - kWiFiFrequency5500) / kWiFiBandwidth20MHz);
    486   } else if (kWiFiFrequency5745 <= frequency &&
    487              frequency <= kWiFiFrequency5825) {
    488     if (((frequency - kWiFiFrequency5745) % kWiFiBandwidth20MHz) == 0)
    489       channel = static_cast<WiFiChannel>(
    490                     kWiFiChannel5745 +
    491                     (frequency - kWiFiFrequency5745) / kWiFiBandwidth20MHz);
    492   }
    493   CHECK(kWiFiChannelUndef <= channel && channel < kWiFiChannelMax);
    494 
    495   if (channel == kWiFiChannelUndef)
    496     LOG(WARNING) << "no mapping for frequency " << frequency;
    497   else
    498     SLOG(nullptr, 3) << "mapped frequency " << frequency
    499                   << " to enum bucket " << channel;
    500 
    501   return channel;
    502 }
    503 
    504 // static
    505 Metrics::WiFiSecurity Metrics::WiFiSecurityStringToEnum(
    506     const string& security) {
    507   if (security == kSecurityNone) {
    508     return kWiFiSecurityNone;
    509   } else if (security == kSecurityWep) {
    510     return kWiFiSecurityWep;
    511   } else if (security == kSecurityWpa) {
    512     return kWiFiSecurityWpa;
    513   } else if (security == kSecurityRsn) {
    514     return kWiFiSecurityRsn;
    515   } else if (security == kSecurity8021x) {
    516     return kWiFiSecurity8021x;
    517   } else if (security == kSecurityPsk) {
    518     return kWiFiSecurityPsk;
    519   } else {
    520     return kWiFiSecurityUnknown;
    521   }
    522 }
    523 
    524 // static
    525 Metrics::WiFiApMode Metrics::WiFiApModeStringToEnum(const string& ap_mode) {
    526   if (ap_mode == kModeManaged) {
    527     return kWiFiApModeManaged;
    528   } else if (ap_mode == kModeAdhoc) {
    529     return kWiFiApModeAdHoc;
    530   } else {
    531     return kWiFiApModeUnknown;
    532   }
    533 }
    534 
    535 // static
    536 Metrics::EapOuterProtocol Metrics::EapOuterProtocolStringToEnum(
    537     const string& outer) {
    538   if (outer == kEapMethodPEAP) {
    539     return kEapOuterProtocolPeap;
    540   } else if (outer == kEapMethodTLS) {
    541     return kEapOuterProtocolTls;
    542   } else if (outer == kEapMethodTTLS) {
    543     return kEapOuterProtocolTtls;
    544   } else if (outer == kEapMethodLEAP) {
    545     return kEapOuterProtocolLeap;
    546   } else {
    547     return kEapOuterProtocolUnknown;
    548   }
    549 }
    550 
    551 // static
    552 Metrics::EapInnerProtocol Metrics::EapInnerProtocolStringToEnum(
    553     const string& inner) {
    554   if (inner.empty()) {
    555     return kEapInnerProtocolNone;
    556   } else if (inner == kEapPhase2AuthPEAPMD5) {
    557     return kEapInnerProtocolPeapMd5;
    558   } else if (inner == kEapPhase2AuthPEAPMSCHAPV2) {
    559     return kEapInnerProtocolPeapMschapv2;
    560   } else if (inner == kEapPhase2AuthTTLSEAPMD5) {
    561     return kEapInnerProtocolTtlsEapMd5;
    562   } else if (inner == kEapPhase2AuthTTLSEAPMSCHAPV2) {
    563     return kEapInnerProtocolTtlsEapMschapv2;
    564   } else if (inner == kEapPhase2AuthTTLSMSCHAPV2) {
    565     return kEapInnerProtocolTtlsMschapv2;
    566   } else if (inner == kEapPhase2AuthTTLSMSCHAP) {
    567     return kEapInnerProtocolTtlsMschap;
    568   } else if (inner == kEapPhase2AuthTTLSPAP) {
    569     return kEapInnerProtocolTtlsPap;
    570   } else if (inner == kEapPhase2AuthTTLSCHAP) {
    571     return kEapInnerProtocolTtlsChap;
    572   } else {
    573     return kEapInnerProtocolUnknown;
    574   }
    575 }
    576 
    577 // static
    578 Metrics::PortalResult Metrics::PortalDetectionResultToEnum(
    579       const PortalDetector::Result& portal_result) {
    580   DCHECK(portal_result.final);
    581   PortalResult retval = kPortalResultUnknown;
    582   ConnectivityTrial::Result result = portal_result.trial_result;
    583   // The only time we should end a successful portal detection is when we're
    584   // in the Content phase.  If we end with kStatusSuccess in any other phase,
    585   // then this indicates that something bad has happened.
    586   switch (result.phase) {
    587     case ConnectivityTrial::kPhaseDNS:
    588       if (result.status == ConnectivityTrial::kStatusFailure)
    589         retval = kPortalResultDNSFailure;
    590       else if (result.status == ConnectivityTrial::kStatusTimeout)
    591         retval = kPortalResultDNSTimeout;
    592       else
    593         LOG(DFATAL) << __func__ << ": Final result status " << result.status
    594                     << " is not allowed in the DNS phase";
    595       break;
    596 
    597     case ConnectivityTrial::kPhaseConnection:
    598       if (result.status == ConnectivityTrial::kStatusFailure)
    599         retval = kPortalResultConnectionFailure;
    600       else if (result.status == ConnectivityTrial::kStatusTimeout)
    601         retval = kPortalResultConnectionTimeout;
    602       else
    603         LOG(DFATAL) << __func__ << ": Final result status " << result.status
    604                     << " is not allowed in the Connection phase";
    605       break;
    606 
    607     case ConnectivityTrial::kPhaseHTTP:
    608       if (result.status == ConnectivityTrial::kStatusFailure)
    609         retval = kPortalResultHTTPFailure;
    610       else if (result.status == ConnectivityTrial::kStatusTimeout)
    611         retval = kPortalResultHTTPTimeout;
    612       else
    613         LOG(DFATAL) << __func__ << ": Final result status " << result.status
    614                     << " is not allowed in the HTTP phase";
    615       break;
    616 
    617     case ConnectivityTrial::kPhaseContent:
    618       if (result.status == ConnectivityTrial::kStatusSuccess)
    619         retval = kPortalResultSuccess;
    620       else if (result.status == ConnectivityTrial::kStatusFailure)
    621         retval = kPortalResultContentFailure;
    622       else if (result.status == ConnectivityTrial::kStatusTimeout)
    623         retval = kPortalResultContentTimeout;
    624       else
    625         LOG(DFATAL) << __func__ << ": Final result status " << result.status
    626                     << " is not allowed in the Content phase";
    627       break;
    628 
    629     case ConnectivityTrial::kPhaseUnknown:
    630       retval = kPortalResultUnknown;
    631       break;
    632 
    633     default:
    634       LOG(DFATAL) << __func__ << ": Invalid phase " << result.phase;
    635       break;
    636   }
    637 
    638   return retval;
    639 }
    640 
    641 void Metrics::Start() {
    642   SLOG(this, 2) << __func__;
    643 }
    644 
    645 void Metrics::Stop() {
    646   SLOG(this, 2) << __func__;
    647 }
    648 
    649 void Metrics::RegisterService(const Service& service) {
    650   SLOG(this, 2) << __func__;
    651   LOG_IF(WARNING, ContainsKey(services_metrics_, &service))
    652       << "Repeatedly registering " << service.unique_name();
    653   shared_ptr<ServiceMetrics> service_metrics(new ServiceMetrics());
    654   services_metrics_[&service] = service_metrics;
    655   InitializeCommonServiceMetrics(service);
    656 }
    657 
    658 void Metrics::DeregisterService(const Service& service) {
    659   services_metrics_.erase(&service);
    660 }
    661 
    662 void Metrics::AddServiceStateTransitionTimer(
    663     const Service& service,
    664     const string& histogram_name,
    665     Service::ConnectState start_state,
    666     Service::ConnectState stop_state) {
    667   SLOG(this, 2) << __func__ << ": adding " << histogram_name << " for "
    668                 << Service::ConnectStateToString(start_state) << " -> "
    669                 << Service::ConnectStateToString(stop_state);
    670   ServiceMetricsLookupMap::iterator it = services_metrics_.find(&service);
    671   if (it == services_metrics_.end()) {
    672     SLOG(this, 1) << "service not found";
    673     DCHECK(false);
    674     return;
    675   }
    676   ServiceMetrics* service_metrics = it->second.get();
    677   CHECK(start_state < stop_state);
    678   chromeos_metrics::TimerReporter* timer =
    679       new chromeos_metrics::TimerReporter(histogram_name,
    680                                           kTimerHistogramMillisecondsMin,
    681                                           kTimerHistogramMillisecondsMax,
    682                                           kTimerHistogramNumBuckets);
    683   service_metrics->timers.push_back(timer);  // passes ownership.
    684   service_metrics->start_on_state[start_state].push_back(timer);
    685   service_metrics->stop_on_state[stop_state].push_back(timer);
    686 }
    687 
    688 void Metrics::NotifyDefaultServiceChanged(const Service* service) {
    689   base::TimeDelta elapsed_seconds;
    690 
    691   Technology::Identifier technology = (service) ? service->technology() :
    692                                                   Technology::kUnknown;
    693   if (technology != last_default_technology_) {
    694     if (last_default_technology_ != Technology::kUnknown) {
    695       string histogram = GetFullMetricName(kMetricTimeOnlineSecondsSuffix,
    696                                            last_default_technology_);
    697       time_online_timer_->GetElapsedTime(&elapsed_seconds);
    698       SendToUMA(histogram,
    699                 elapsed_seconds.InSeconds(),
    700                 kMetricTimeOnlineSecondsMin,
    701                 kMetricTimeOnlineSecondsMax,
    702                 kTimerHistogramNumBuckets);
    703     }
    704     last_default_technology_ = technology;
    705     time_online_timer_->Start();
    706   }
    707 
    708   // Ignore changes that are not online/offline transitions; e.g.
    709   // switching between wired and wireless.  TimeToDrop measures
    710   // time online regardless of how we are connected.
    711   if ((service == nullptr && !was_online_) ||
    712       (service != nullptr && was_online_))
    713     return;
    714 
    715   if (service == nullptr) {
    716     time_to_drop_timer_->GetElapsedTime(&elapsed_seconds);
    717     SendToUMA(kMetricTimeToDropSeconds,
    718               elapsed_seconds.InSeconds(),
    719               kMetricTimeToDropSecondsMin,
    720               kMetricTimeToDropSecondsMax,
    721               kTimerHistogramNumBuckets);
    722   } else {
    723     time_to_drop_timer_->Start();
    724   }
    725 
    726   was_online_ = (service != nullptr);
    727 }
    728 
    729 void Metrics::NotifyServiceStateChanged(const Service& service,
    730                                         Service::ConnectState new_state) {
    731   ServiceMetricsLookupMap::iterator it = services_metrics_.find(&service);
    732   if (it == services_metrics_.end()) {
    733     SLOG(this, 1) << "service not found";
    734     DCHECK(false);
    735     return;
    736   }
    737   ServiceMetrics* service_metrics = it->second.get();
    738   UpdateServiceStateTransitionMetrics(service_metrics, new_state);
    739 
    740   if (new_state == Service::kStateFailure)
    741     SendServiceFailure(service);
    742 
    743 #if !defined(__ANDROID__)
    744   if (collect_bootstats_) {
    745     bootstat_log(base::StringPrintf("network-%s-%s",
    746                                     Technology::NameFromIdentifier(
    747                                         service.technology()).c_str(),
    748                                     service.GetStateString().c_str()).c_str());
    749   }
    750 #endif  // __ANDROID__
    751 
    752   if (new_state != Service::kStateConnected)
    753     return;
    754 
    755   base::TimeDelta time_resume_to_ready;
    756   time_resume_to_ready_timer_->GetElapsedTime(&time_resume_to_ready);
    757   time_resume_to_ready_timer_->Reset();
    758   service.SendPostReadyStateMetrics(time_resume_to_ready.InMilliseconds());
    759 }
    760 
    761 string Metrics::GetFullMetricName(const char* metric_suffix,
    762                                   Technology::Identifier technology_id) {
    763   string technology = Technology::NameFromIdentifier(technology_id);
    764   technology[0] = base::ToUpperASCII(technology[0]);
    765   return base::StringPrintf("%s.%s.%s", kMetricPrefix, technology.c_str(),
    766                             metric_suffix);
    767 }
    768 
    769 void Metrics::NotifyServiceDisconnect(const Service& service) {
    770   Technology::Identifier technology = service.technology();
    771   string histogram = GetFullMetricName(kMetricDisconnectSuffix, technology);
    772   SendToUMA(histogram,
    773             service.explicitly_disconnected(),
    774             kMetricDisconnectMin,
    775             kMetricDisconnectMax,
    776             kMetricDisconnectNumBuckets);
    777 }
    778 
    779 void Metrics::NotifySignalAtDisconnect(const Service& service,
    780                                        int16_t signal_strength) {
    781   // Negate signal_strength (goes from dBm to -dBm) because the metrics don't
    782   // seem to handle negative values well.  Now everything's positive.
    783   Technology::Identifier technology = service.technology();
    784   string histogram = GetFullMetricName(kMetricSignalAtDisconnectSuffix,
    785                                        technology);
    786   SendToUMA(histogram,
    787             -signal_strength,
    788             kMetricSignalAtDisconnectMin,
    789             kMetricSignalAtDisconnectMax,
    790             kMetricSignalAtDisconnectNumBuckets);
    791 }
    792 
    793 void Metrics::NotifySuspendDone() {
    794   time_resume_to_ready_timer_->Start();
    795 }
    796 
    797 void Metrics::NotifyWakeOnWiFiFeaturesEnabledState(
    798     WakeOnWiFiFeaturesEnabledState state) {
    799   SendEnumToUMA(kMetricWakeOnWiFiFeaturesEnabledState, state,
    800                 kWakeOnWiFiFeaturesEnabledStateMax);
    801 }
    802 
    803 void Metrics::NotifyVerifyWakeOnWiFiSettingsResult(
    804     VerifyWakeOnWiFiSettingsResult result) {
    805   SendEnumToUMA(kMetricVerifyWakeOnWiFiSettingsResult, result,
    806                 kVerifyWakeOnWiFiSettingsResultMax);
    807 }
    808 
    809 void Metrics::NotifyConnectedToServiceAfterWake(
    810     WiFiConnectionStatusAfterWake status) {
    811   SendEnumToUMA(kMetricWiFiConnectionStatusAfterWake, status,
    812                 kWiFiConnetionStatusAfterWakeMax);
    813 }
    814 
    815 void Metrics::NotifyTerminationActionsStarted() {
    816   if (time_termination_actions_timer->HasStarted())
    817     return;
    818   time_termination_actions_timer->Start();
    819 }
    820 
    821 void Metrics::NotifyTerminationActionsCompleted(bool success) {
    822   if (!time_termination_actions_timer->HasStarted())
    823     return;
    824 
    825   TerminationActionResult result = success ? kTerminationActionResultSuccess
    826                                            : kTerminationActionResultFailure;
    827 
    828   base::TimeDelta elapsed_time;
    829   time_termination_actions_timer->GetElapsedTime(&elapsed_time);
    830   time_termination_actions_timer->Reset();
    831   string time_metric, result_metric;
    832   time_metric = kMetricTerminationActionTimeTaken;
    833   result_metric = kMetricTerminationActionResult;
    834 
    835   SendToUMA(time_metric,
    836             elapsed_time.InMilliseconds(),
    837             kMetricTerminationActionTimeTakenMillisecondsMin,
    838             kMetricTerminationActionTimeTakenMillisecondsMax,
    839             kTimerHistogramNumBuckets);
    840 
    841   SendEnumToUMA(result_metric,
    842                 result,
    843                 kTerminationActionResultMax);
    844 }
    845 
    846 void Metrics::NotifySuspendActionsStarted() {
    847   if (time_suspend_actions_timer->HasStarted())
    848     return;
    849   time_suspend_actions_timer->Start();
    850   wake_on_wifi_throttled_ = false;
    851 }
    852 
    853 void Metrics::NotifySuspendActionsCompleted(bool success) {
    854   if (!time_suspend_actions_timer->HasStarted())
    855     return;
    856 
    857   // Reset for next dark resume.
    858   wake_reason_received_ = false;
    859 
    860   SuspendActionResult result =
    861       success ? kSuspendActionResultSuccess : kSuspendActionResultFailure;
    862 
    863   base::TimeDelta elapsed_time;
    864   time_suspend_actions_timer->GetElapsedTime(&elapsed_time);
    865   time_suspend_actions_timer->Reset();
    866   string time_metric, result_metric;
    867   time_metric = kMetricSuspendActionTimeTaken;
    868   result_metric = kMetricSuspendActionResult;
    869 
    870   SendToUMA(time_metric,
    871             elapsed_time.InMilliseconds(),
    872             kMetricSuspendActionTimeTakenMillisecondsMin,
    873             kMetricSuspendActionTimeTakenMillisecondsMax,
    874             kTimerHistogramNumBuckets);
    875 
    876   SendEnumToUMA(result_metric,
    877                 result,
    878                 kSuspendActionResultMax);
    879 }
    880 
    881 void Metrics::NotifyDarkResumeActionsStarted() {
    882   if (time_dark_resume_actions_timer->HasStarted())
    883     return;
    884   time_dark_resume_actions_timer->Start();
    885   num_scan_results_expected_in_dark_resume_ = 0;
    886   dark_resume_scan_retries_ = 0;
    887 }
    888 
    889 void Metrics::NotifyDarkResumeActionsCompleted(bool success) {
    890   if (!time_dark_resume_actions_timer->HasStarted())
    891     return;
    892 
    893   // Reset for next dark resume.
    894   wake_reason_received_ = false;
    895 
    896   DarkResumeActionResult result =
    897       success ? kDarkResumeActionResultSuccess : kDarkResumeActionResultFailure;
    898 
    899   base::TimeDelta elapsed_time;
    900   time_dark_resume_actions_timer->GetElapsedTime(&elapsed_time);
    901   time_dark_resume_actions_timer->Reset();
    902 
    903   SendToUMA(kMetricDarkResumeActionTimeTaken,
    904             elapsed_time.InMilliseconds(),
    905             kMetricDarkResumeActionTimeTakenMillisecondsMin,
    906             kMetricDarkResumeActionTimeTakenMillisecondsMax,
    907             kTimerHistogramNumBuckets);
    908 
    909   SendEnumToUMA(kMetricDarkResumeActionResult,
    910                 result,
    911                 kDarkResumeActionResultMax);
    912 
    913   DarkResumeUnmatchedScanResultReceived unmatched_scan_results_received =
    914       (num_scan_results_expected_in_dark_resume_ < 0)
    915           ? kDarkResumeUnmatchedScanResultsReceivedTrue
    916           : kDarkResumeUnmatchedScanResultsReceivedFalse;
    917   SendEnumToUMA(kMetricDarkResumeUnmatchedScanResultReceived,
    918                 unmatched_scan_results_received,
    919                 kDarkResumeUnmatchedScanResultsReceivedMax);
    920 
    921   SendToUMA(kMetricDarkResumeScanNumRetries, dark_resume_scan_retries_,
    922             kMetricDarkResumeScanNumRetriesMin,
    923             kMetricDarkResumeScanNumRetriesMax, kTimerHistogramNumBuckets);
    924 }
    925 
    926 void Metrics::NotifyDarkResumeInitiateScan() {
    927   ++num_scan_results_expected_in_dark_resume_;
    928 }
    929 
    930 void Metrics::NotifyDarkResumeScanResultsReceived() {
    931   --num_scan_results_expected_in_dark_resume_;
    932 }
    933 
    934 void Metrics::NotifyLinkMonitorFailure(
    935     Technology::Identifier technology,
    936     LinkMonitorFailure failure,
    937     int seconds_to_failure,
    938     int broadcast_error_count,
    939     int unicast_error_count) {
    940   string histogram = GetFullMetricName(kMetricLinkMonitorFailureSuffix,
    941                                        technology);
    942   SendEnumToUMA(histogram, failure, kLinkMonitorFailureMax);
    943 
    944   if (failure == kLinkMonitorFailureThresholdReached) {
    945     if (seconds_to_failure > kMetricLinkMonitorSecondsToFailureMax) {
    946       seconds_to_failure = kMetricLinkMonitorSecondsToFailureMax;
    947     }
    948     histogram = GetFullMetricName(kMetricLinkMonitorSecondsToFailureSuffix,
    949                                   technology);
    950     SendToUMA(histogram,
    951               seconds_to_failure,
    952               kMetricLinkMonitorSecondsToFailureMin,
    953               kMetricLinkMonitorSecondsToFailureMax,
    954               kMetricLinkMonitorSecondsToFailureNumBuckets);
    955     histogram = GetFullMetricName(
    956         kMetricLinkMonitorBroadcastErrorsAtFailureSuffix, technology);
    957     SendToUMA(histogram,
    958               broadcast_error_count,
    959               kMetricLinkMonitorErrorCountMin,
    960               kMetricLinkMonitorErrorCountMax,
    961               kMetricLinkMonitorErrorCountNumBuckets);
    962     histogram = GetFullMetricName(
    963         kMetricLinkMonitorUnicastErrorsAtFailureSuffix, technology);
    964     SendToUMA(histogram,
    965               unicast_error_count,
    966               kMetricLinkMonitorErrorCountMin,
    967               kMetricLinkMonitorErrorCountMax,
    968               kMetricLinkMonitorErrorCountNumBuckets);
    969   }
    970 }
    971 
    972 void Metrics::NotifyLinkMonitorResponseTimeSampleAdded(
    973     Technology::Identifier technology,
    974     int response_time_milliseconds) {
    975   string histogram = GetFullMetricName(
    976       kMetricLinkMonitorResponseTimeSampleSuffix,  technology);
    977   SendToUMA(histogram,
    978             response_time_milliseconds,
    979             kMetricLinkMonitorResponseTimeSampleMin,
    980             kMetricLinkMonitorResponseTimeSampleMax,
    981             kMetricLinkMonitorResponseTimeSampleNumBuckets);
    982 }
    983 
    984 #if !defined(DISABLE_WIFI)
    985 // TODO(zqiu): Change argument type from IEEE_80211::WiFiReasonCode to
    986 // Metrics::WiFiStatusType, to remove dependency for IEEE_80211.
    987 void Metrics::Notify80211Disconnect(WiFiDisconnectByWhom by_whom,
    988                                     IEEE_80211::WiFiReasonCode reason) {
    989   string metric_disconnect_reason;
    990   string metric_disconnect_type;
    991   WiFiStatusType type;
    992 
    993   if (by_whom == kDisconnectedByAp) {
    994     metric_disconnect_reason = kMetricLinkApDisconnectReason;
    995     metric_disconnect_type = kMetricLinkApDisconnectType;
    996     type = kStatusCodeTypeByAp;
    997   } else {
    998     metric_disconnect_reason = kMetricLinkClientDisconnectReason;
    999     metric_disconnect_type = kMetricLinkClientDisconnectType;
   1000     switch (reason) {
   1001       case IEEE_80211::kReasonCodeSenderHasLeft:
   1002       case IEEE_80211::kReasonCodeDisassociatedHasLeft:
   1003         type = kStatusCodeTypeByUser;
   1004         break;
   1005 
   1006       case IEEE_80211::kReasonCodeInactivity:
   1007         type = kStatusCodeTypeConsideredDead;
   1008         break;
   1009 
   1010       default:
   1011         type = kStatusCodeTypeByClient;
   1012         break;
   1013     }
   1014   }
   1015   SendEnumToUMA(metric_disconnect_reason, reason,
   1016                 IEEE_80211::kStatusCodeMax);
   1017   SendEnumToUMA(metric_disconnect_type, type, kStatusCodeTypeMax);
   1018 }
   1019 #endif  // DISABLE_WIFI
   1020 
   1021 void Metrics::RegisterDevice(int interface_index,
   1022                              Technology::Identifier technology) {
   1023   SLOG(this, 2) << __func__ << ": " << interface_index;
   1024   shared_ptr<DeviceMetrics> device_metrics(new DeviceMetrics);
   1025   devices_metrics_[interface_index] = device_metrics;
   1026   device_metrics->technology = technology;
   1027   string histogram = GetFullMetricName(
   1028       kMetricTimeToInitializeMillisecondsSuffix, technology);
   1029   device_metrics->initialization_timer.reset(
   1030       new chromeos_metrics::TimerReporter(
   1031           histogram,
   1032           kMetricTimeToInitializeMillisecondsMin,
   1033           kMetricTimeToInitializeMillisecondsMax,
   1034           kMetricTimeToInitializeMillisecondsNumBuckets));
   1035   device_metrics->initialization_timer->Start();
   1036   histogram = GetFullMetricName(kMetricTimeToEnableMillisecondsSuffix,
   1037                                 technology);
   1038   device_metrics->enable_timer.reset(
   1039       new chromeos_metrics::TimerReporter(
   1040           histogram,
   1041           kMetricTimeToEnableMillisecondsMin,
   1042           kMetricTimeToEnableMillisecondsMax,
   1043           kMetricTimeToEnableMillisecondsNumBuckets));
   1044   histogram = GetFullMetricName(kMetricTimeToDisableMillisecondsSuffix,
   1045                                 technology);
   1046   device_metrics->disable_timer.reset(
   1047       new chromeos_metrics::TimerReporter(
   1048           histogram,
   1049           kMetricTimeToDisableMillisecondsMin,
   1050           kMetricTimeToDisableMillisecondsMax,
   1051           kMetricTimeToDisableMillisecondsNumBuckets));
   1052   histogram = GetFullMetricName(kMetricTimeToScanMillisecondsSuffix,
   1053                                 technology);
   1054   device_metrics->scan_timer.reset(
   1055       new chromeos_metrics::TimerReporter(
   1056           histogram,
   1057           kMetricTimeToScanMillisecondsMin,
   1058           kMetricTimeToScanMillisecondsMax,
   1059           kMetricTimeToScanMillisecondsNumBuckets));
   1060   histogram = GetFullMetricName(kMetricTimeToConnectMillisecondsSuffix,
   1061                                 technology);
   1062   device_metrics->connect_timer.reset(
   1063       new chromeos_metrics::TimerReporter(
   1064           histogram,
   1065           kMetricTimeToConnectMillisecondsMin,
   1066           kMetricTimeToConnectMillisecondsMax,
   1067           kMetricTimeToConnectMillisecondsNumBuckets));
   1068   histogram = GetFullMetricName(kMetricTimeToScanAndConnectMillisecondsSuffix,
   1069                                 technology);
   1070   device_metrics->scan_connect_timer.reset(
   1071       new chromeos_metrics::TimerReporter(
   1072           histogram,
   1073           kMetricTimeToScanMillisecondsMin,
   1074           kMetricTimeToScanMillisecondsMax +
   1075               kMetricTimeToConnectMillisecondsMax,
   1076           kMetricTimeToScanMillisecondsNumBuckets +
   1077               kMetricTimeToConnectMillisecondsNumBuckets));
   1078   device_metrics->auto_connect_timer.reset(
   1079       new chromeos_metrics::TimerReporter(
   1080           kMetricCellularAutoConnectTotalTime,
   1081           kMetricCellularAutoConnectTotalTimeMin,
   1082           kMetricCellularAutoConnectTotalTimeMax,
   1083           kMetricCellularAutoConnectTotalTimeNumBuckets));
   1084 }
   1085 
   1086 bool Metrics::IsDeviceRegistered(int interface_index,
   1087                                  Technology::Identifier technology) {
   1088   SLOG(this, 2) << __func__ << ": interface index: " << interface_index
   1089                             << ", technology: " << technology;
   1090   DeviceMetrics* device_metrics = GetDeviceMetrics(interface_index);
   1091   if (device_metrics == nullptr)
   1092     return false;
   1093   // Make sure the device technologies match.
   1094   return (technology == device_metrics->technology);
   1095 }
   1096 
   1097 void Metrics::DeregisterDevice(int interface_index) {
   1098   SLOG(this, 2) << __func__ << ": interface index: " << interface_index;
   1099 
   1100   DeviceMetrics* device_metrics = GetDeviceMetrics(interface_index);
   1101   if (device_metrics != nullptr) {
   1102     NotifyDeviceRemovedEvent(device_metrics->technology);
   1103   }
   1104 
   1105   devices_metrics_.erase(interface_index);
   1106 }
   1107 
   1108 void Metrics::NotifyDeviceInitialized(int interface_index) {
   1109   DeviceMetrics* device_metrics = GetDeviceMetrics(interface_index);
   1110   if (device_metrics == nullptr)
   1111     return;
   1112   if (!device_metrics->initialization_timer->Stop())
   1113     return;
   1114   device_metrics->initialization_timer->ReportMilliseconds();
   1115 }
   1116 
   1117 void Metrics::NotifyDeviceEnableStarted(int interface_index) {
   1118   DeviceMetrics* device_metrics = GetDeviceMetrics(interface_index);
   1119   if (device_metrics == nullptr)
   1120     return;
   1121   device_metrics->enable_timer->Start();
   1122 }
   1123 
   1124 void Metrics::NotifyDeviceEnableFinished(int interface_index) {
   1125   DeviceMetrics* device_metrics = GetDeviceMetrics(interface_index);
   1126   if (device_metrics == nullptr)
   1127     return;
   1128   if (!device_metrics->enable_timer->Stop())
   1129       return;
   1130   device_metrics->enable_timer->ReportMilliseconds();
   1131 }
   1132 
   1133 void Metrics::NotifyDeviceDisableStarted(int interface_index) {
   1134   DeviceMetrics* device_metrics = GetDeviceMetrics(interface_index);
   1135   if (device_metrics == nullptr)
   1136     return;
   1137   device_metrics->disable_timer->Start();
   1138 }
   1139 
   1140 void Metrics::NotifyDeviceDisableFinished(int interface_index) {
   1141   DeviceMetrics* device_metrics = GetDeviceMetrics(interface_index);
   1142   if (device_metrics == nullptr)
   1143     return;
   1144   if (!device_metrics->disable_timer->Stop())
   1145     return;
   1146   device_metrics->disable_timer->ReportMilliseconds();
   1147 }
   1148 
   1149 void Metrics::NotifyDeviceScanStarted(int interface_index) {
   1150   DeviceMetrics* device_metrics = GetDeviceMetrics(interface_index);
   1151   if (device_metrics == nullptr)
   1152     return;
   1153   device_metrics->scan_timer->Start();
   1154   device_metrics->scan_connect_timer->Start();
   1155 }
   1156 
   1157 void Metrics::NotifyDeviceScanFinished(int interface_index) {
   1158   DeviceMetrics* device_metrics = GetDeviceMetrics(interface_index);
   1159   if (device_metrics == nullptr)
   1160     return;
   1161   if (!device_metrics->scan_timer->Stop())
   1162     return;
   1163   // Don't send TimeToScan metrics if the elapsed time exceeds the max metrics
   1164   // value.  Huge scan times usually mean something's gone awry; for cellular,
   1165   // for instance, this usually means that the modem is in an area without
   1166   // service and we're not interested in this scenario.
   1167   base::TimeDelta elapsed_time;
   1168   device_metrics->scan_timer->GetElapsedTime(&elapsed_time);
   1169   if (elapsed_time.InMilliseconds() <= kMetricTimeToScanMillisecondsMax)
   1170     device_metrics->scan_timer->ReportMilliseconds();
   1171 }
   1172 
   1173 void Metrics::ResetScanTimer(int interface_index) {
   1174   DeviceMetrics* device_metrics = GetDeviceMetrics(interface_index);
   1175   if (device_metrics == nullptr)
   1176     return;
   1177   device_metrics->scan_timer->Reset();
   1178 }
   1179 
   1180 void Metrics::NotifyDeviceConnectStarted(int interface_index,
   1181                                          bool is_auto_connecting) {
   1182   DeviceMetrics* device_metrics = GetDeviceMetrics(interface_index);
   1183   if (device_metrics == nullptr)
   1184     return;
   1185   device_metrics->connect_timer->Start();
   1186 
   1187   if (is_auto_connecting) {
   1188     device_metrics->auto_connect_tries++;
   1189     if (device_metrics->auto_connect_tries == 1)
   1190       device_metrics->auto_connect_timer->Start();
   1191   } else {
   1192     AutoConnectMetricsReset(device_metrics);
   1193   }
   1194 }
   1195 
   1196 void Metrics::NotifyDeviceConnectFinished(int interface_index) {
   1197   DeviceMetrics* device_metrics = GetDeviceMetrics(interface_index);
   1198   if (device_metrics == nullptr)
   1199     return;
   1200   if (!device_metrics->connect_timer->Stop())
   1201     return;
   1202   device_metrics->connect_timer->ReportMilliseconds();
   1203 
   1204   if (device_metrics->auto_connect_tries > 0) {
   1205     if (!device_metrics->auto_connect_timer->Stop())
   1206       return;
   1207     base::TimeDelta elapsed_time;
   1208     device_metrics->auto_connect_timer->GetElapsedTime(&elapsed_time);
   1209     if (elapsed_time.InMilliseconds() > kMetricCellularAutoConnectTotalTimeMax)
   1210       return;
   1211     device_metrics->auto_connect_timer->ReportMilliseconds();
   1212     SendToUMA(kMetricCellularAutoConnectTries,
   1213               device_metrics->auto_connect_tries,
   1214               kMetricCellularAutoConnectTriesMin,
   1215               kMetricCellularAutoConnectTriesMax,
   1216               kMetricCellularAutoConnectTriesNumBuckets);
   1217     AutoConnectMetricsReset(device_metrics);
   1218   }
   1219 
   1220   if (!device_metrics->scan_connect_timer->Stop())
   1221     return;
   1222   device_metrics->scan_connect_timer->ReportMilliseconds();
   1223 }
   1224 
   1225 void Metrics::ResetConnectTimer(int interface_index) {
   1226   DeviceMetrics* device_metrics = GetDeviceMetrics(interface_index);
   1227   if (device_metrics == nullptr)
   1228     return;
   1229   device_metrics->connect_timer->Reset();
   1230   device_metrics->scan_connect_timer->Reset();
   1231 }
   1232 
   1233 void Metrics::Notify3GPPRegistrationDelayedDropPosted() {
   1234   SendEnumToUMA(kMetricCellular3GPPRegistrationDelayedDrop,
   1235                 kCellular3GPPRegistrationDelayedDropPosted,
   1236                 kCellular3GPPRegistrationDelayedDropMax);
   1237 }
   1238 
   1239 void Metrics::Notify3GPPRegistrationDelayedDropCanceled() {
   1240   SendEnumToUMA(kMetricCellular3GPPRegistrationDelayedDrop,
   1241                 kCellular3GPPRegistrationDelayedDropCanceled,
   1242                 kCellular3GPPRegistrationDelayedDropMax);
   1243 }
   1244 
   1245 void Metrics::NotifyCellularDeviceDrop(const string& network_technology,
   1246                                        uint16_t signal_strength) {
   1247   SLOG(this, 2) << __func__ << ": " << network_technology
   1248                             << ", " << signal_strength;
   1249   CellularDropTechnology drop_technology = kCellularDropTechnologyUnknown;
   1250   if (network_technology == kNetworkTechnology1Xrtt) {
   1251     drop_technology = kCellularDropTechnology1Xrtt;
   1252   } else if (network_technology == kNetworkTechnologyEdge) {
   1253     drop_technology = kCellularDropTechnologyEdge;
   1254   } else if (network_technology == kNetworkTechnologyEvdo) {
   1255     drop_technology = kCellularDropTechnologyEvdo;
   1256   } else if (network_technology == kNetworkTechnologyGprs) {
   1257     drop_technology = kCellularDropTechnologyGprs;
   1258   } else if (network_technology == kNetworkTechnologyGsm) {
   1259     drop_technology = kCellularDropTechnologyGsm;
   1260   } else if (network_technology == kNetworkTechnologyHspa) {
   1261     drop_technology = kCellularDropTechnologyHspa;
   1262   } else if (network_technology == kNetworkTechnologyHspaPlus) {
   1263     drop_technology = kCellularDropTechnologyHspaPlus;
   1264   } else if (network_technology == kNetworkTechnologyLte) {
   1265     drop_technology = kCellularDropTechnologyLte;
   1266   } else if (network_technology == kNetworkTechnologyUmts) {
   1267     drop_technology = kCellularDropTechnologyUmts;
   1268   }
   1269   SendEnumToUMA(kMetricCellularDrop,
   1270                 drop_technology,
   1271                 kCellularDropTechnologyMax);
   1272   SendToUMA(kMetricCellularSignalStrengthBeforeDrop,
   1273             signal_strength,
   1274             kMetricCellularSignalStrengthBeforeDropMin,
   1275             kMetricCellularSignalStrengthBeforeDropMax,
   1276             kMetricCellularSignalStrengthBeforeDropNumBuckets);
   1277 }
   1278 
   1279 void Metrics::NotifyCellularDeviceConnectionFailure() {
   1280   library_->SendEnumToUMA(
   1281       kMetricCellularFailure, kMetricCellularConnectionFailure,
   1282       kMetricCellularMaxFailure);
   1283 }
   1284 
   1285 void Metrics::NotifyCellularDeviceDisconnectionFailure() {
   1286   library_->SendEnumToUMA(
   1287       kMetricCellularFailure, kMetricCellularDisconnectionFailure,
   1288       kMetricCellularMaxFailure);
   1289 }
   1290 
   1291 void Metrics::NotifyCellularOutOfCredits(
   1292     Metrics::CellularOutOfCreditsReason reason) {
   1293   SendEnumToUMA(kMetricCellularOutOfCreditsReason,
   1294                 reason,
   1295                 kCellularOutOfCreditsReasonMax);
   1296 }
   1297 
   1298 void Metrics::NotifyCorruptedProfile() {
   1299   SendEnumToUMA(kMetricCorruptedProfile,
   1300                 kCorruptedProfile,
   1301                 kCorruptedProfileMax);
   1302 }
   1303 
   1304 void Metrics::NotifyWifiAutoConnectableServices(int num_services) {
   1305   SendToUMA(kMetricWifiAutoConnectableServices,
   1306             num_services,
   1307             kMetricWifiAutoConnectableServicesMin,
   1308             kMetricWifiAutoConnectableServicesMax,
   1309             kMetricWifiAutoConnectableServicesNumBuckets);
   1310 }
   1311 
   1312 void Metrics::NotifyWifiAvailableBSSes(int num_bss) {
   1313   SendToUMA(kMetricWifiAvailableBSSes,
   1314             num_bss,
   1315             kMetricWifiAvailableBSSesMin,
   1316             kMetricWifiAvailableBSSesMax,
   1317             kMetricWifiAvailableBSSesNumBuckets);
   1318 }
   1319 
   1320 void Metrics::NotifyServicesOnSameNetwork(int num_services) {
   1321   SendToUMA(kMetricServicesOnSameNetwork,
   1322             num_services,
   1323             kMetricServicesOnSameNetworkMin,
   1324             kMetricServicesOnSameNetworkMax,
   1325             kMetricServicesOnSameNetworkNumBuckets);
   1326 }
   1327 
   1328 void Metrics::NotifyUserInitiatedEvent(int event) {
   1329   SendEnumToUMA(kMetricUserInitiatedEvents,
   1330                 event,
   1331                 kUserInitiatedEventMax);
   1332 }
   1333 
   1334 void Metrics::NotifyWifiTxBitrate(int bitrate) {
   1335   SendToUMA(kMetricWifiTxBitrate,
   1336             bitrate,
   1337             kMetricWifiTxBitrateMin,
   1338             kMetricWifiTxBitrateMax,
   1339             kMetricWifiTxBitrateNumBuckets);
   1340 }
   1341 
   1342 void Metrics::NotifyUserInitiatedConnectionResult(const string& name,
   1343                                                   int result) {
   1344   SendEnumToUMA(name,
   1345                 result,
   1346                 kUserInitiatedConnectionResultMax);
   1347 }
   1348 
   1349 void Metrics::NotifyUserInitiatedConnectionFailureReason(
   1350     const string& name, const Service::ConnectFailure failure) {
   1351   UserInitiatedConnectionFailureReason reason;
   1352   switch (failure) {
   1353     case Service::kFailureBadPassphrase:
   1354       reason = kUserInitiatedConnectionFailureReasonBadPassphrase;
   1355       break;
   1356     case Service::kFailureBadWEPKey:
   1357       reason = kUserInitiatedConnectionFailureReasonBadWEPKey;
   1358       break;
   1359     case Service::kFailureConnect:
   1360       reason = kUserInitiatedConnectionFailureReasonConnect;
   1361       break;
   1362     case Service::kFailureDHCP:
   1363       reason = kUserInitiatedConnectionFailureReasonDHCP;
   1364       break;
   1365     case Service::kFailureDNSLookup:
   1366       reason = kUserInitiatedConnectionFailureReasonDNSLookup;
   1367       break;
   1368     case Service::kFailureEAPAuthentication:
   1369       reason = kUserInitiatedConnectionFailureReasonEAPAuthentication;
   1370       break;
   1371     case Service::kFailureEAPLocalTLS:
   1372       reason = kUserInitiatedConnectionFailureReasonEAPLocalTLS;
   1373       break;
   1374     case Service::kFailureEAPRemoteTLS:
   1375       reason = kUserInitiatedConnectionFailureReasonEAPRemoteTLS;
   1376       break;
   1377     case Service::kFailureOutOfRange:
   1378       reason = kUserInitiatedConnectionFailureReasonOutOfRange;
   1379       break;
   1380     case Service::kFailurePinMissing:
   1381       reason = kUserInitiatedConnectionFailureReasonPinMissing;
   1382       break;
   1383     default:
   1384       reason = kUserInitiatedConnectionFailureReasonUnknown;
   1385       break;
   1386   }
   1387   SendEnumToUMA(name,
   1388                 reason,
   1389                 kUserInitiatedConnectionFailureReasonMax);
   1390 }
   1391 
   1392 void Metrics::NotifyFallbackDNSTestResult(Technology::Identifier technology_id,
   1393                                           int result) {
   1394   string histogram = GetFullMetricName(kMetricFallbackDNSTestResultSuffix,
   1395                                        technology_id);
   1396   SendEnumToUMA(histogram,
   1397                 result,
   1398                 kFallbackDNSTestResultMax);
   1399 }
   1400 
   1401 void Metrics::NotifyNetworkProblemDetected(Technology::Identifier technology_id,
   1402                                            int reason) {
   1403   string histogram = GetFullMetricName(kMetricNetworkProblemDetectedSuffix,
   1404                                        technology_id);
   1405   SendEnumToUMA(histogram,
   1406                 reason,
   1407                 kNetworkProblemMax);
   1408 }
   1409 
   1410 void Metrics::NotifyDeviceConnectionStatus(ConnectionStatus status) {
   1411   SendEnumToUMA(kMetricDeviceConnectionStatus, status, kConnectionStatusMax);
   1412 }
   1413 
   1414 void Metrics::NotifyDhcpClientStatus(DhcpClientStatus status) {
   1415   SendEnumToUMA(kMetricDhcpClientStatus, status, kDhcpClientStatusMax);
   1416 }
   1417 
   1418 void Metrics::NotifyNetworkConnectionIPType(
   1419     Technology::Identifier technology_id, NetworkConnectionIPType type) {
   1420   string histogram = GetFullMetricName(kMetricNetworkConnectionIPTypeSuffix,
   1421                                        technology_id);
   1422   SendEnumToUMA(histogram, type, kNetworkConnectionIPTypeMax);
   1423 }
   1424 
   1425 void Metrics::NotifyIPv6ConnectivityStatus(Technology::Identifier technology_id,
   1426                                            bool status) {
   1427   string histogram = GetFullMetricName(kMetricIPv6ConnectivityStatusSuffix,
   1428                                        technology_id);
   1429   IPv6ConnectivityStatus ipv6_status = status ? kIPv6ConnectivityStatusYes
   1430                                               : kIPv6ConnectivityStatusNo;
   1431   SendEnumToUMA(histogram, ipv6_status, kIPv6ConnectivityStatusMax);
   1432 }
   1433 
   1434 void Metrics::NotifyDevicePresenceStatus(Technology::Identifier technology_id,
   1435                                          bool status) {
   1436   string histogram = GetFullMetricName(kMetricDevicePresenceStatusSuffix,
   1437                                        technology_id);
   1438   DevicePresenceStatus presence = status ? kDevicePresenceStatusYes
   1439                                          : kDevicePresenceStatusNo;
   1440   SendEnumToUMA(histogram, presence, kDevicePresenceStatusMax);
   1441 }
   1442 
   1443 void Metrics::NotifyDeviceRemovedEvent(Technology::Identifier technology_id) {
   1444   DeviceTechnologyType type;
   1445   switch (technology_id) {
   1446     case Technology::kEthernet:
   1447       type = kDeviceTechnologyTypeEthernet;
   1448       break;
   1449     case Technology::kWifi:
   1450       type = kDeviceTechnologyTypeWifi;
   1451       break;
   1452     case Technology::kWiMax:
   1453       type = kDeviceTechnologyTypeWimax;
   1454       break;
   1455     case Technology::kCellular:
   1456       type = kDeviceTechnologyTypeCellular;
   1457       break;
   1458     default:
   1459       type = kDeviceTechnologyTypeUnknown;
   1460       break;
   1461   }
   1462   SendEnumToUMA(kMetricDeviceRemovedEvent, type, kDeviceTechnologyTypeMax);
   1463 }
   1464 
   1465 void Metrics::NotifyUnreliableLinkSignalStrength(
   1466     Technology::Identifier technology_id, int signal_strength) {
   1467   string histogram = GetFullMetricName(
   1468       kMetricUnreliableLinkSignalStrengthSuffix, technology_id);
   1469   SendToUMA(histogram,
   1470             signal_strength,
   1471             kMetricSerivceSignalStrengthMin,
   1472             kMetricServiceSignalStrengthMax,
   1473             kMetricServiceSignalStrengthNumBuckets);
   1474 }
   1475 
   1476 bool Metrics::SendEnumToUMA(const string& name, int sample, int max) {
   1477   SLOG(this, 5)
   1478       << "Sending enum " << name << " with value " << sample << ".";
   1479   return library_->SendEnumToUMA(name, sample, max);
   1480 }
   1481 
   1482 bool Metrics::SendToUMA(const string& name, int sample, int min, int max,
   1483                         int num_buckets) {
   1484   SLOG(this, 5)
   1485       << "Sending metric " << name << " with value " << sample << ".";
   1486   return library_->SendToUMA(name, sample, min, max, num_buckets);
   1487 }
   1488 
   1489 bool Metrics::SendSparseToUMA(const string& name, int sample) {
   1490   SLOG(this, 5)
   1491       << "Sending sparse metric " << name << " with value " << sample << ".";
   1492   return library_->SendSparseToUMA(name, sample);
   1493 }
   1494 
   1495 void Metrics::NotifyWakeOnWiFiThrottled() {
   1496     wake_on_wifi_throttled_ = true;
   1497 }
   1498 
   1499 void Metrics::NotifySuspendWithWakeOnWiFiEnabledDone() {
   1500   WakeOnWiFiThrottled throttled_result = wake_on_wifi_throttled_
   1501                                              ? kWakeOnWiFiThrottledTrue
   1502                                              : kWakeOnWiFiThrottledFalse;
   1503   SendEnumToUMA(kMetricWakeOnWiFiThrottled, throttled_result,
   1504                 kWakeOnWiFiThrottledMax);
   1505 }
   1506 
   1507 void Metrics::NotifyWakeupReasonReceived() { wake_reason_received_ = true; }
   1508 
   1509 #if !defined(DISABLE_WIFI)
   1510 // TODO(zqiu): Change argument type from WakeOnWiFi::WakeOnWiFiTrigger to
   1511 // Metrics::DarkResumeWakeReason, to remove the dependency for WakeOnWiFi.
   1512 // to remove the dependency for WakeOnWiFi.
   1513 void Metrics::NotifyWakeOnWiFiOnDarkResume(
   1514     WakeOnWiFi::WakeOnWiFiTrigger reason) {
   1515   WakeReasonReceivedBeforeOnDarkResume result =
   1516       wake_reason_received_ ? kWakeReasonReceivedBeforeOnDarkResumeTrue
   1517                             : kWakeReasonReceivedBeforeOnDarkResumeFalse;
   1518 
   1519   SendEnumToUMA(kMetricWakeReasonReceivedBeforeOnDarkResume, result,
   1520                 kWakeReasonReceivedBeforeOnDarkResumeMax);
   1521 
   1522   DarkResumeWakeReason wake_reason;
   1523   switch (reason) {
   1524     case WakeOnWiFi::kWakeTriggerPattern:
   1525       wake_reason = kDarkResumeWakeReasonPattern;
   1526       break;
   1527     case WakeOnWiFi::kWakeTriggerDisconnect:
   1528       wake_reason = kDarkResumeWakeReasonDisconnect;
   1529       break;
   1530     case WakeOnWiFi::kWakeTriggerSSID:
   1531       wake_reason = kDarkResumeWakeReasonSSID;
   1532       break;
   1533     case WakeOnWiFi::kWakeTriggerUnsupported:
   1534     default:
   1535       wake_reason = kDarkResumeWakeReasonUnsupported;
   1536       break;
   1537   }
   1538   SendEnumToUMA(kMetricDarkResumeWakeReason, wake_reason,
   1539                 kDarkResumeWakeReasonMax);
   1540 }
   1541 #endif  // DISABLE_WIFI
   1542 
   1543 void Metrics::NotifyScanStartedInDarkResume(bool is_active_scan) {
   1544   DarkResumeScanType scan_type =
   1545       is_active_scan ? kDarkResumeScanTypeActive : kDarkResumeScanTypePassive;
   1546   SendEnumToUMA(kMetricDarkResumeScanType, scan_type, kDarkResumeScanTypeMax);
   1547 }
   1548 
   1549 void Metrics::NotifyDarkResumeScanRetry() {
   1550   ++dark_resume_scan_retries_;
   1551 }
   1552 
   1553 void Metrics::NotifyBeforeSuspendActions(bool is_connected,
   1554                                          bool in_dark_resume) {
   1555   if (in_dark_resume && dark_resume_scan_retries_) {
   1556     DarkResumeScanRetryResult connect_result =
   1557         is_connected ? kDarkResumeScanRetryResultConnected
   1558                      : kDarkResumeScanRetryResultNotConnected;
   1559     SendEnumToUMA(kMetricDarkResumeScanRetryResult, connect_result,
   1560                   kDarkResumeScanRetryResultMax);
   1561   }
   1562 }
   1563 
   1564 void Metrics::NotifyConnectionDiagnosticsIssue(const string& issue) {
   1565   ConnectionDiagnosticsIssue issue_enum;
   1566   if (issue == ConnectionDiagnostics::kIssueIPCollision) {
   1567     issue_enum = kConnectionDiagnosticsIssueIPCollision;
   1568   } else if (issue == ConnectionDiagnostics::kIssueRouting) {
   1569     issue_enum = kConnectionDiagnosticsIssueRouting;
   1570   } else if (issue == ConnectionDiagnostics::kIssueHTTPBrokenPortal) {
   1571     issue_enum = kConnectionDiagnosticsIssueHTTPBrokenPortal;
   1572   } else if (issue == ConnectionDiagnostics::kIssueDNSServerMisconfig) {
   1573     issue_enum = kConnectionDiagnosticsIssueDNSServerMisconfig;
   1574   } else if (issue == ConnectionDiagnostics::kIssueDNSServerNoResponse) {
   1575     issue_enum = kConnectionDiagnosticsIssueDNSServerNoResponse;
   1576   } else if (issue == ConnectionDiagnostics::kIssueNoDNSServersConfigured) {
   1577     issue_enum = kConnectionDiagnosticsIssueNoDNSServersConfigured;
   1578   } else if (issue == ConnectionDiagnostics::kIssueDNSServersInvalid) {
   1579     issue_enum = kConnectionDiagnosticsIssueDNSServersInvalid;
   1580   } else if (issue == ConnectionDiagnostics::kIssueNone) {
   1581     issue_enum = kConnectionDiagnosticsIssueNone;
   1582   } else if (issue == ConnectionDiagnostics::kIssueCaptivePortal) {
   1583     issue_enum = kConnectionDiagnosticsIssueCaptivePortal;
   1584   } else if (issue == ConnectionDiagnostics::kIssueGatewayUpstream) {
   1585     issue_enum = kConnectionDiagnosticsIssueGatewayUpstream;
   1586   } else if (issue == ConnectionDiagnostics::kIssueGatewayNotResponding) {
   1587     issue_enum = kConnectionDiagnosticsIssueGatewayNotResponding;
   1588   } else if (issue == ConnectionDiagnostics::kIssueServerNotResponding) {
   1589     issue_enum = kConnectionDiagnosticsIssueServerNotResponding;
   1590   } else if (issue == ConnectionDiagnostics::kIssueGatewayArpFailed) {
   1591     issue_enum = kConnectionDiagnosticsIssueGatewayArpFailed;
   1592   } else if (issue == ConnectionDiagnostics::kIssueServerArpFailed) {
   1593     issue_enum = kConnectionDiagnosticsIssueServerArpFailed;
   1594   } else if (issue == ConnectionDiagnostics::kIssueInternalError) {
   1595     issue_enum = kConnectionDiagnosticsIssueInternalError;
   1596   } else if (issue == ConnectionDiagnostics::kIssueGatewayNoNeighborEntry) {
   1597     issue_enum = kConnectionDiagnosticsIssueGatewayNoNeighborEntry;
   1598   } else if (issue == ConnectionDiagnostics::kIssueServerNoNeighborEntry) {
   1599     issue_enum = kConnectionDiagnosticsIssueServerNoNeighborEntry;
   1600   } else if (issue ==
   1601              ConnectionDiagnostics::kIssueGatewayNeighborEntryNotConnected) {
   1602     issue_enum = kConnectionDiagnosticsIssueGatewayNeighborEntryNotConnected;
   1603   } else if (issue ==
   1604              ConnectionDiagnostics::kIssueServerNeighborEntryNotConnected) {
   1605     issue_enum = kConnectionDiagnosticsIssueServerNeighborEntryNotConnected;
   1606   } else {
   1607     LOG(ERROR) << __func__ << ": Invalid issue: " << issue;
   1608     return;
   1609   }
   1610 
   1611   SendEnumToUMA(kMetricConnectionDiagnosticsIssue, issue_enum,
   1612                 kConnectionDiagnosticsIssueMax);
   1613 }
   1614 
   1615 void Metrics::InitializeCommonServiceMetrics(const Service& service) {
   1616   Technology::Identifier technology = service.technology();
   1617   string histogram = GetFullMetricName(kMetricTimeToConfigMillisecondsSuffix,
   1618                                        technology);
   1619   AddServiceStateTransitionTimer(
   1620       service,
   1621       histogram,
   1622       Service::kStateConfiguring,
   1623       Service::kStateConnected);
   1624   histogram = GetFullMetricName(kMetricTimeToPortalMillisecondsSuffix,
   1625                                 technology);
   1626   AddServiceStateTransitionTimer(
   1627       service,
   1628       histogram,
   1629       Service::kStateConnected,
   1630       Service::kStatePortal);
   1631   histogram = GetFullMetricName(kMetricTimeToOnlineMillisecondsSuffix,
   1632                                 technology);
   1633   AddServiceStateTransitionTimer(
   1634       service,
   1635       histogram,
   1636       Service::kStateConnected,
   1637       Service::kStateOnline);
   1638 }
   1639 
   1640 void Metrics::UpdateServiceStateTransitionMetrics(
   1641     ServiceMetrics* service_metrics,
   1642     Service::ConnectState new_state) {
   1643   const char* state_string = Service::ConnectStateToString(new_state);
   1644   SLOG(this, 5) << __func__ << ": new_state=" << state_string;
   1645   TimerReportersList& start_timers = service_metrics->start_on_state[new_state];
   1646   for (auto& start_timer : start_timers) {
   1647     SLOG(this, 5) << "Starting timer for " << start_timer->histogram_name()
   1648                   << " due to new state " << state_string << ".";
   1649     start_timer->Start();
   1650   }
   1651 
   1652   TimerReportersList& stop_timers = service_metrics->stop_on_state[new_state];
   1653   for (auto& stop_timer : stop_timers) {
   1654     SLOG(this, 5) << "Stopping timer for " << stop_timer->histogram_name()
   1655                   << " due to new state " << state_string << ".";
   1656     if (stop_timer->Stop())
   1657       stop_timer->ReportMilliseconds();
   1658   }
   1659 }
   1660 
   1661 void Metrics::SendServiceFailure(const Service& service) {
   1662   NetworkServiceError error = kNetworkServiceErrorUnknown;
   1663   // Explicitly map all possible failures. So when new failures are added,
   1664   // they will need to be mapped as well. Otherwise, the compiler will
   1665   // complain.
   1666   switch (service.failure()) {
   1667     case Service::kFailureUnknown:
   1668     case Service::kFailureMax:
   1669       error = kNetworkServiceErrorUnknown;
   1670       break;
   1671     case Service::kFailureAAA:
   1672       error = kNetworkServiceErrorAAA;
   1673       break;
   1674     case Service::kFailureActivation:
   1675       error = kNetworkServiceErrorActivation;
   1676       break;
   1677     case Service::kFailureBadPassphrase:
   1678       error = kNetworkServiceErrorBadPassphrase;
   1679       break;
   1680     case Service::kFailureBadWEPKey:
   1681       error = kNetworkServiceErrorBadWEPKey;
   1682       break;
   1683     case Service::kFailureConnect:
   1684       error = kNetworkServiceErrorConnect;
   1685       break;
   1686     case Service::kFailureDHCP:
   1687       error = kNetworkServiceErrorDHCP;
   1688       break;
   1689     case Service::kFailureDNSLookup:
   1690       error = kNetworkServiceErrorDNSLookup;
   1691       break;
   1692     case Service::kFailureEAPAuthentication:
   1693       error = kNetworkServiceErrorEAPAuthentication;
   1694       break;
   1695     case Service::kFailureEAPLocalTLS:
   1696       error = kNetworkServiceErrorEAPLocalTLS;
   1697       break;
   1698     case Service::kFailureEAPRemoteTLS:
   1699       error = kNetworkServiceErrorEAPRemoteTLS;
   1700       break;
   1701     case Service::kFailureHTTPGet:
   1702       error = kNetworkServiceErrorHTTPGet;
   1703       break;
   1704     case Service::kFailureIPSecCertAuth:
   1705       error = kNetworkServiceErrorIPSecCertAuth;
   1706       break;
   1707     case Service::kFailureIPSecPSKAuth:
   1708       error = kNetworkServiceErrorIPSecPSKAuth;
   1709       break;
   1710     case Service::kFailureInternal:
   1711       error = kNetworkServiceErrorInternal;
   1712       break;
   1713     case Service::kFailureNeedEVDO:
   1714       error = kNetworkServiceErrorNeedEVDO;
   1715       break;
   1716     case Service::kFailureNeedHomeNetwork:
   1717       error = kNetworkServiceErrorNeedHomeNetwork;
   1718       break;
   1719     case Service::kFailureOTASP:
   1720       error = kNetworkServiceErrorOTASP;
   1721       break;
   1722     case Service::kFailureOutOfRange:
   1723       error = kNetworkServiceErrorOutOfRange;
   1724       break;
   1725     case Service::kFailurePPPAuth:
   1726       error = kNetworkServiceErrorPPPAuth;
   1727       break;
   1728     case Service::kFailurePinMissing:
   1729       error = kNetworkServiceErrorPinMissing;
   1730       break;
   1731   }
   1732 
   1733   library_->SendEnumToUMA(kMetricNetworkServiceErrors,
   1734                           error,
   1735                           kNetworkServiceErrorMax);
   1736 }
   1737 
   1738 Metrics::DeviceMetrics* Metrics::GetDeviceMetrics(int interface_index) const {
   1739   DeviceMetricsLookupMap::const_iterator it =
   1740       devices_metrics_.find(interface_index);
   1741   if (it == devices_metrics_.end()) {
   1742     SLOG(this, 2) << __func__ << ": device " << interface_index
   1743                   << " not found";
   1744     return nullptr;
   1745   }
   1746   return it->second.get();
   1747 }
   1748 
   1749 void Metrics::AutoConnectMetricsReset(DeviceMetrics* device_metrics) {
   1750   device_metrics->auto_connect_tries = 0;
   1751   device_metrics->auto_connect_timer->Reset();
   1752 }
   1753 
   1754 void Metrics::set_library(MetricsLibraryInterface* library) {
   1755   chromeos_metrics::TimerReporter::set_metrics_lib(library);
   1756   library_ = library;
   1757 }
   1758 
   1759 }  // namespace shill
   1760