//
// Copyright (C) 2012 The Android Open Source Project
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
#include "shill/metrics.h"
#include <base/strings/string_util.h>
#include <base/strings/stringprintf.h>
#if defined(__ANDROID__)
#include <dbus/service_constants.h>
#else
#include <chromeos/dbus/service_constants.h>
#endif // __ANDROID__
#if !defined(__ANDROID__)
#include <metrics/bootstat.h>
#endif // __ANDROID__
#include "shill/connection_diagnostics.h"
#include "shill/link_monitor.h"
#include "shill/logging.h"
using std::string;
using std::shared_ptr;
namespace shill {
namespace Logging {
static auto kModuleLogScope = ScopeLogger::kMetrics;
static string ObjectID(const Metrics* m) { return "(metrics)"; }
}
static const char kMetricPrefix[] = "Network.Shill";
// static
// Our disconnect enumeration values are 0 (System Disconnect) and
// 1 (User Disconnect), see histograms.xml, but Chrome needs a minimum
// enum value of 1 and the minimum number of buckets needs to be 3 (see
// histogram.h). Instead of remapping System Disconnect to 1 and
// User Disconnect to 2, we can just leave the enumerated values as-is
// because Chrome implicitly creates a [0-1) bucket for us. Using Min=1,
// Max=2 and NumBuckets=3 gives us the following three buckets:
// [0-1), [1-2), [2-INT_MAX). We end up with an extra bucket [2-INT_MAX)
// that we can safely ignore.
const char Metrics::kMetricDisconnectSuffix[] = "Disconnect";
const int Metrics::kMetricDisconnectMax = 2;
const int Metrics::kMetricDisconnectMin = 1;
const int Metrics::kMetricDisconnectNumBuckets = 3;
const char Metrics::kMetricSignalAtDisconnectSuffix[] = "SignalAtDisconnect";
const int Metrics::kMetricSignalAtDisconnectMin = 0;
const int Metrics::kMetricSignalAtDisconnectMax = 200;
const int Metrics::kMetricSignalAtDisconnectNumBuckets = 40;
const char Metrics::kMetricNetworkApModeSuffix[] = "ApMode";
const char Metrics::kMetricNetworkChannelSuffix[] = "Channel";
const int Metrics::kMetricNetworkChannelMax = Metrics::kWiFiChannelMax;
const char Metrics::kMetricNetworkEapInnerProtocolSuffix[] = "EapInnerProtocol";
const int Metrics::kMetricNetworkEapInnerProtocolMax =
Metrics::kEapInnerProtocolMax;
const char Metrics::kMetricNetworkEapOuterProtocolSuffix[] = "EapOuterProtocol";
const int Metrics::kMetricNetworkEapOuterProtocolMax =
Metrics::kEapOuterProtocolMax;
const char Metrics::kMetricNetworkPhyModeSuffix[] = "PhyMode";
const int Metrics::kMetricNetworkPhyModeMax = Metrics::kWiFiNetworkPhyModeMax;
const char Metrics::kMetricNetworkSecuritySuffix[] = "Security";
const int Metrics::kMetricNetworkSecurityMax = Metrics::kWiFiSecurityMax;
const char Metrics::kMetricNetworkServiceErrors[] =
"Network.Shill.ServiceErrors";
const char Metrics::kMetricNetworkSignalStrengthSuffix[] = "SignalStrength";
const int Metrics::kMetricNetworkSignalStrengthMax = 200;
const int Metrics::kMetricNetworkSignalStrengthMin = 0;
const int Metrics::kMetricNetworkSignalStrengthNumBuckets = 40;
constexpr char
Metrics::kMetricRememberedSystemWiFiNetworkCountBySecurityModeFormat[];
constexpr char
Metrics::kMetricRememberedUserWiFiNetworkCountBySecurityModeFormat[];
const char Metrics::kMetricRememberedWiFiNetworkCount[] =
"Network.Shill.WiFi.RememberedNetworkCount";
const int Metrics::kMetricRememberedWiFiNetworkCountMax = 1024;
const int Metrics::kMetricRememberedWiFiNetworkCountMin = 0;
const int Metrics::kMetricRememberedWiFiNetworkCountNumBuckets = 32;
const char Metrics::kMetricTimeOnlineSecondsSuffix[] = "TimeOnline";
const int Metrics::kMetricTimeOnlineSecondsMax = 8 * 60 * 60; // 8 hours
const int Metrics::kMetricTimeOnlineSecondsMin = 1;
const char Metrics::kMetricTimeToConnectMillisecondsSuffix[] = "TimeToConnect";
const int Metrics::kMetricTimeToConnectMillisecondsMax =
60 * 1000; // 60 seconds
const int Metrics::kMetricTimeToConnectMillisecondsMin = 1;
const int Metrics::kMetricTimeToConnectMillisecondsNumBuckets = 60;
const char Metrics::kMetricTimeToScanAndConnectMillisecondsSuffix[] =
"TimeToScanAndConnect";
const char Metrics::kMetricTimeToDropSeconds[] = "Network.Shill.TimeToDrop";;
const int Metrics::kMetricTimeToDropSecondsMax = 8 * 60 * 60; // 8 hours
const int Metrics::kMetricTimeToDropSecondsMin = 1;
const char Metrics::kMetricTimeToDisableMillisecondsSuffix[] = "TimeToDisable";
const int Metrics::kMetricTimeToDisableMillisecondsMax =
60 * 1000; // 60 seconds
const int Metrics::kMetricTimeToDisableMillisecondsMin = 1;
const int Metrics::kMetricTimeToDisableMillisecondsNumBuckets = 60;
const char Metrics::kMetricTimeToEnableMillisecondsSuffix[] = "TimeToEnable";
const int Metrics::kMetricTimeToEnableMillisecondsMax =
60 * 1000; // 60 seconds
const int Metrics::kMetricTimeToEnableMillisecondsMin = 1;
const int Metrics::kMetricTimeToEnableMillisecondsNumBuckets = 60;
const char Metrics::kMetricTimeToInitializeMillisecondsSuffix[] =
"TimeToInitialize";
const int Metrics::kMetricTimeToInitializeMillisecondsMax =
30 * 1000; // 30 seconds
const int Metrics::kMetricTimeToInitializeMillisecondsMin = 1;
const int Metrics::kMetricTimeToInitializeMillisecondsNumBuckets = 30;
const char Metrics::kMetricTimeResumeToReadyMillisecondsSuffix[] =
"TimeResumeToReady";
const char Metrics::kMetricTimeToConfigMillisecondsSuffix[] = "TimeToConfig";
const char Metrics::kMetricTimeToJoinMillisecondsSuffix[] = "TimeToJoin";
const char Metrics::kMetricTimeToOnlineMillisecondsSuffix[] = "TimeToOnline";
const char Metrics::kMetricTimeToPortalMillisecondsSuffix[] = "TimeToPortal";
const char Metrics::kMetricTimeToScanMillisecondsSuffix[] = "TimeToScan";
const int Metrics::kMetricTimeToScanMillisecondsMax = 180 * 1000; // 3 minutes
const int Metrics::kMetricTimeToScanMillisecondsMin = 1;
const int Metrics::kMetricTimeToScanMillisecondsNumBuckets = 90;
const int Metrics::kTimerHistogramMillisecondsMax = 45 * 1000;
const int Metrics::kTimerHistogramMillisecondsMin = 1;
const int Metrics::kTimerHistogramNumBuckets = 50;
const char Metrics::kMetricPortalAttemptsSuffix[] = "PortalAttempts";
const int Metrics::kMetricPortalAttemptsMax =
PortalDetector::kMaxRequestAttempts;
const int Metrics::kMetricPortalAttemptsMin = 1;
const int Metrics::kMetricPortalAttemptsNumBuckets =
Metrics::kMetricPortalAttemptsMax;
const char Metrics::kMetricPortalAttemptsToOnlineSuffix[] =
"PortalAttemptsToOnline";
const int Metrics::kMetricPortalAttemptsToOnlineMax = 100;
const int Metrics::kMetricPortalAttemptsToOnlineMin = 1;
const int Metrics::kMetricPortalAttemptsToOnlineNumBuckets = 10;
const char Metrics::kMetricPortalResultSuffix[] = "PortalResult";
const char Metrics::kMetricFrequenciesConnectedEver[] =
"Network.Shill.WiFi.FrequenciesConnectedEver";
const int Metrics::kMetricFrequenciesConnectedMax = 50;
const int Metrics::kMetricFrequenciesConnectedMin = 1;
const int Metrics::kMetricFrequenciesConnectedNumBuckets = 50;
const char Metrics::kMetricScanResult[] =
"Network.Shill.WiFi.ScanResult";
const char Metrics::kMetricWiFiScanTimeInEbusyMilliseconds[] =
"Network.Shill.WiFi.ScanTimeInEbusy";
const char Metrics::kMetricTerminationActionTimeTaken[] =
"Network.Shill.TerminationActionTimeTaken";
const char Metrics::kMetricTerminationActionResult[] =
"Network.Shill.TerminationActionResult";
const int Metrics::kMetricTerminationActionTimeTakenMillisecondsMax = 20000;
const int Metrics::kMetricTerminationActionTimeTakenMillisecondsMin = 1;
const char Metrics::kMetricSuspendActionTimeTaken[] =
"Network.Shill.SuspendActionTimeTaken";
const char Metrics::kMetricSuspendActionResult[] =
"Network.Shill.SuspendActionResult";
const int Metrics::kMetricSuspendActionTimeTakenMillisecondsMax = 20000;
const int Metrics::kMetricSuspendActionTimeTakenMillisecondsMin = 1;
const char Metrics::kMetricDarkResumeActionTimeTaken[] =
"Network.Shill.DarkResumeActionTimeTaken";
const char Metrics::kMetricDarkResumeActionResult[] =
"Network.Shill.DarkResumeActionResult";
const int Metrics::kMetricDarkResumeActionTimeTakenMillisecondsMax = 20000;
const int Metrics::kMetricDarkResumeActionTimeTakenMillisecondsMin = 1;
const char Metrics::kMetricDarkResumeUnmatchedScanResultReceived[] =
"Network.Shill.WiFi.DarkResumeUnmatchedScanResultsReceived";
const char Metrics::kMetricWakeOnWiFiFeaturesEnabledState[] =
"Network.Shill.WiFi.WakeOnWiFiFeaturesEnabledState";
const char Metrics::kMetricVerifyWakeOnWiFiSettingsResult[] =
"Network.Shill.WiFi.VerifyWakeOnWiFiSettingsResult";
const char Metrics::kMetricWiFiConnectionStatusAfterWake[] =
"Network.Shill.WiFi.WiFiConnectionStatusAfterWake";
const char Metrics::kMetricWakeOnWiFiThrottled[] =
"Network.Shill.WiFi.WakeOnWiFiThrottled";
const char Metrics::kMetricWakeReasonReceivedBeforeOnDarkResume[] =
"Network.Shill.WiFi.WakeReasonReceivedBeforeOnDarkResume";
const char Metrics::kMetricDarkResumeWakeReason[] =
"Network.Shill.WiFi.DarkResumeWakeReason";
const char Metrics::kMetricDarkResumeScanType[] =
"Network.Shill.WiFi.DarkResumeScanType";
const char Metrics::kMetricDarkResumeScanRetryResult[] =
"Network.Shill.WiFi.DarkResumeScanRetryResult";
const char Metrics::kMetricDarkResumeScanNumRetries[] =
"Network.Shill.WiFi.DarkResumeScanNumRetries";
const int Metrics::kMetricDarkResumeScanNumRetriesMax = 20;
const int Metrics::kMetricDarkResumeScanNumRetriesMin = 0;
// static
const char Metrics::kMetricServiceFixupEntriesSuffix[] = "ServiceFixupEntries";
// static
const uint16_t Metrics::kWiFiBandwidth5MHz = 5;
const uint16_t Metrics::kWiFiBandwidth20MHz = 20;
const uint16_t Metrics::kWiFiFrequency2412 = 2412;
const uint16_t Metrics::kWiFiFrequency2472 = 2472;
const uint16_t Metrics::kWiFiFrequency2484 = 2484;
const uint16_t Metrics::kWiFiFrequency5170 = 5170;
const uint16_t Metrics::kWiFiFrequency5180 = 5180;
const uint16_t Metrics::kWiFiFrequency5230 = 5230;
const uint16_t Metrics::kWiFiFrequency5240 = 5240;
const uint16_t Metrics::kWiFiFrequency5320 = 5320;
const uint16_t Metrics::kWiFiFrequency5500 = 5500;
const uint16_t Metrics::kWiFiFrequency5700 = 5700;
const uint16_t Metrics::kWiFiFrequency5745 = 5745;
const uint16_t Metrics::kWiFiFrequency5825 = 5825;
// static
const char Metrics::kMetricPowerManagerKey[] = "metrics";
// static
const char Metrics::kMetricLinkMonitorFailureSuffix[] = "LinkMonitorFailure";
const char Metrics::kMetricLinkMonitorResponseTimeSampleSuffix[] =
"LinkMonitorResponseTimeSample";
const int Metrics::kMetricLinkMonitorResponseTimeSampleMin = 0;
const int Metrics::kMetricLinkMonitorResponseTimeSampleMax =
LinkMonitor::kDefaultTestPeriodMilliseconds;
const int Metrics::kMetricLinkMonitorResponseTimeSampleNumBuckets = 50;
const char Metrics::kMetricLinkMonitorSecondsToFailureSuffix[] =
"LinkMonitorSecondsToFailure";
const int Metrics::kMetricLinkMonitorSecondsToFailureMin = 0;
const int Metrics::kMetricLinkMonitorSecondsToFailureMax = 7200;
const int Metrics::kMetricLinkMonitorSecondsToFailureNumBuckets = 50;
const char Metrics::kMetricLinkMonitorBroadcastErrorsAtFailureSuffix[] =
"LinkMonitorBroadcastErrorsAtFailure";
const char Metrics::kMetricLinkMonitorUnicastErrorsAtFailureSuffix[] =
"LinkMonitorUnicastErrorsAtFailure";
const int Metrics::kMetricLinkMonitorErrorCountMin = 0;
const int Metrics::kMetricLinkMonitorErrorCountMax =
LinkMonitor::kFailureThreshold;
const int Metrics::kMetricLinkMonitorErrorCountNumBuckets =
LinkMonitor::kFailureThreshold + 1;
// static
const char Metrics::kMetricLinkClientDisconnectReason[] =
"Network.Shill.WiFi.ClientDisconnectReason";
const char Metrics::kMetricLinkApDisconnectReason[] =
"Network.Shill.WiFi.ApDisconnectReason";
const char Metrics::kMetricLinkClientDisconnectType[] =
"Network.Shill.WiFi.ClientDisconnectType";
const char Metrics::kMetricLinkApDisconnectType[] =
"Network.Shill.WiFi.ApDisconnectType";
// static
const char Metrics::kMetricCellular3GPPRegistrationDelayedDrop[] =
"Network.Shill.Cellular.3GPPRegistrationDelayedDrop";
const char Metrics::kMetricCellularAutoConnectTries[] =
"Network.Shill.Cellular.AutoConnectTries";
const int Metrics::kMetricCellularAutoConnectTriesMax = 20;
const int Metrics::kMetricCellularAutoConnectTriesMin = 1;
const int Metrics::kMetricCellularAutoConnectTriesNumBuckets = 20;
const char Metrics::kMetricCellularAutoConnectTotalTime[] =
"Network.Shill.Cellular.AutoConnectTotalTime";
const int Metrics::kMetricCellularAutoConnectTotalTimeMax =
60 * 1000; // 60 seconds
const int Metrics::kMetricCellularAutoConnectTotalTimeMin = 0;
const int Metrics::kMetricCellularAutoConnectTotalTimeNumBuckets = 60;
const char Metrics::kMetricCellularDrop[] =
"Network.Shill.Cellular.Drop";
// static
const char Metrics::kMetricCellularFailure[] =
"Network.Shill.Cellular.Failure";
const int Metrics::kMetricCellularConnectionFailure = 0;
const int Metrics::kMetricCellularDisconnectionFailure = 1;
const int Metrics::kMetricCellularMaxFailure =
kMetricCellularDisconnectionFailure + 1;
const char Metrics::kMetricCellularOutOfCreditsReason[] =
"Network.Shill.Cellular.OutOfCreditsReason";
const char Metrics::kMetricCellularSignalStrengthBeforeDrop[] =
"Network.Shill.Cellular.SignalStrengthBeforeDrop";
const int Metrics::kMetricCellularSignalStrengthBeforeDropMax = 100;
const int Metrics::kMetricCellularSignalStrengthBeforeDropMin = 0;
const int Metrics::kMetricCellularSignalStrengthBeforeDropNumBuckets = 10;
// static
const char Metrics::kMetricCorruptedProfile[] =
"Network.Shill.CorruptedProfile";
// static
const char Metrics::kMetricVpnDriver[] =
"Network.Shill.Vpn.Driver";
const int Metrics::kMetricVpnDriverMax = Metrics::kVpnDriverMax;
const char Metrics::kMetricVpnRemoteAuthenticationType[] =
"Network.Shill.Vpn.RemoteAuthenticationType";
const int Metrics::kMetricVpnRemoteAuthenticationTypeMax =
Metrics::kVpnRemoteAuthenticationTypeMax;
const char Metrics::kMetricVpnUserAuthenticationType[] =
"Network.Shill.Vpn.UserAuthenticationType";
const int Metrics::kMetricVpnUserAuthenticationTypeMax =
Metrics::kVpnUserAuthenticationTypeMax;
const char Metrics::kMetricExpiredLeaseLengthSecondsSuffix[] =
"ExpiredLeaseLengthSeconds";
const int Metrics::kMetricExpiredLeaseLengthSecondsMax =
7 * 24 * 60 * 60; // 7 days
const int Metrics::kMetricExpiredLeaseLengthSecondsMin = 1;
const int Metrics::kMetricExpiredLeaseLengthSecondsNumBuckets =
Metrics::kMetricExpiredLeaseLengthSecondsMax;
// static
const char Metrics::kMetricWifiAutoConnectableServices[] =
"Network.Shill.WiFi.AutoConnectableServices";
const int Metrics::kMetricWifiAutoConnectableServicesMax = 50;
const int Metrics::kMetricWifiAutoConnectableServicesMin = 1;
const int Metrics::kMetricWifiAutoConnectableServicesNumBuckets = 10;
// static
const char Metrics::kMetricWifiAvailableBSSes[] =
"Network.Shill.WiFi.AvailableBSSesAtConnect";
const int Metrics::kMetricWifiAvailableBSSesMax = 50;
const int Metrics::kMetricWifiAvailableBSSesMin = 1;
const int Metrics::kMetricWifiAvailableBSSesNumBuckets = 10;
// static
const char Metrics::kMetricWifiStoppedTxQueueReason[] =
"Network.Shill.WiFi.StoppedTxQueueReason";
// Values are defined in mac80211_monitor.h.
// static
const char Metrics::kMetricWifiStoppedTxQueueLength[] =
"Network.Shill.WiFi.StoppedTxQueueLength";
const int Metrics::kMetricWifiStoppedTxQueueLengthMax = 10000;
const int Metrics::kMetricWifiStoppedTxQueueLengthMin = 1;
const int Metrics::kMetricWifiStoppedTxQueueLengthNumBuckets = 50;
// Number of services associated with currently connected network.
const char Metrics::kMetricServicesOnSameNetwork[] =
"Network.Shill.ServicesOnSameNetwork";
const int Metrics::kMetricServicesOnSameNetworkMax = 20;
const int Metrics::kMetricServicesOnSameNetworkMin = 1;
const int Metrics::kMetricServicesOnSameNetworkNumBuckets = 10;
// static
const char Metrics::kMetricUserInitiatedEvents[] =
"Network.Shill.UserInitiatedEvents";
// static
const char Metrics::kMetricWifiTxBitrate[] =
"Network.Shill.WiFi.TransmitBitrateMbps";
const int Metrics::kMetricWifiTxBitrateMax = 7000;
const int Metrics::kMetricWifiTxBitrateMin = 1;
const int Metrics::kMetricWifiTxBitrateNumBuckets = 100;
// static
const char Metrics::kMetricWifiUserInitiatedConnectionResult[] =
"Network.Shill.WiFi.UserInitiatedConnectionResult";
// static
const char Metrics::kMetricWifiUserInitiatedConnectionFailureReason[] =
"Network.Shill.WiFi.UserInitiatedConnectionFailureReason";
// static
const char Metrics::kMetricFallbackDNSTestResultSuffix[] =
"FallbackDNSTestResult";
// static
const char Metrics::kMetricNetworkProblemDetectedSuffix[] =
"NetworkProblemDetected";
// static
const char Metrics::kMetricDeviceConnectionStatus[] =
"Network.Shill.DeviceConnectionStatus";
// static
const char Metrics::kMetricDhcpClientStatus[] =
"Network.Shill.DHCPClientStatus";
// static
const char Metrics::kMetricDhcpClientMTUValue[] =
"Network.Shill.DHCPClientMTUValue";
const char Metrics::kMetricPPPMTUValue[] = "Network.Shill.PPPMTUValue";
// static
const char Metrics::kMetricNetworkConnectionIPTypeSuffix[] =
"NetworkConnectionIPType";
// static
const char Metrics::kMetricIPv6ConnectivityStatusSuffix[] =
"IPv6ConnectivityStatus";
// static
const char Metrics::kMetricDevicePresenceStatusSuffix[] =
"DevicePresenceStatus";
// static
const char Metrics::kMetricDeviceRemovedEvent[] =
"Network.Shill.DeviceRemovedEvent";
// static
const char Metrics::kMetricConnectionDiagnosticsIssue[] =
"Network.Shill.ConnectionDiagnosticsIssue";
// static
const char Metrics::kMetricUnreliableLinkSignalStrengthSuffix[] =
"UnreliableLinkSignalStrength";
const int Metrics::kMetricSerivceSignalStrengthMin = 0;
const int Metrics::kMetricServiceSignalStrengthMax = 100;
const int Metrics::kMetricServiceSignalStrengthNumBuckets = 40;
Metrics::Metrics(EventDispatcher* dispatcher)
: dispatcher_(dispatcher),
library_(&metrics_library_),
last_default_technology_(Technology::kUnknown),
was_online_(false),
time_online_timer_(new chromeos_metrics::Timer),
time_to_drop_timer_(new chromeos_metrics::Timer),
time_resume_to_ready_timer_(new chromeos_metrics::Timer),
time_termination_actions_timer(new chromeos_metrics::Timer),
time_suspend_actions_timer(new chromeos_metrics::Timer),
time_dark_resume_actions_timer(new chromeos_metrics::Timer),
collect_bootstats_(true),
num_scan_results_expected_in_dark_resume_(0),
wake_on_wifi_throttled_(false),
wake_reason_received_(false),
dark_resume_scan_retries_(0) {
metrics_library_.Init();
chromeos_metrics::TimerReporter::set_metrics_lib(library_);
}
Metrics::~Metrics() {}
// static
Metrics::WiFiChannel Metrics::WiFiFrequencyToChannel(uint16_t frequency) {
WiFiChannel channel = kWiFiChannelUndef;
if (kWiFiFrequency2412 <= frequency && frequency <= kWiFiFrequency2472) {
if (((frequency - kWiFiFrequency2412) % kWiFiBandwidth5MHz) == 0)
channel = static_cast<WiFiChannel>(
kWiFiChannel2412 +
(frequency - kWiFiFrequency2412) / kWiFiBandwidth5MHz);
} else if (frequency == kWiFiFrequency2484) {
channel = kWiFiChannel2484;
} else if (kWiFiFrequency5170 <= frequency &&
frequency <= kWiFiFrequency5230) {
if ((frequency % kWiFiBandwidth20MHz) == 0)
channel = static_cast<WiFiChannel>(
kWiFiChannel5180 +
(frequency - kWiFiFrequency5180) / kWiFiBandwidth20MHz);
if ((frequency % kWiFiBandwidth20MHz) == 10)
channel = static_cast<WiFiChannel>(
kWiFiChannel5170 +
(frequency - kWiFiFrequency5170) / kWiFiBandwidth20MHz);
} else if (kWiFiFrequency5240 <= frequency &&
frequency <= kWiFiFrequency5320) {
if (((frequency - kWiFiFrequency5180) % kWiFiBandwidth20MHz) == 0)
channel = static_cast<WiFiChannel>(
kWiFiChannel5180 +
(frequency - kWiFiFrequency5180) / kWiFiBandwidth20MHz);
} else if (kWiFiFrequency5500 <= frequency &&
frequency <= kWiFiFrequency5700) {
if (((frequency - kWiFiFrequency5500) % kWiFiBandwidth20MHz) == 0)
channel = static_cast<WiFiChannel>(
kWiFiChannel5500 +
(frequency - kWiFiFrequency5500) / kWiFiBandwidth20MHz);
} else if (kWiFiFrequency5745 <= frequency &&
frequency <= kWiFiFrequency5825) {
if (((frequency - kWiFiFrequency5745) % kWiFiBandwidth20MHz) == 0)
channel = static_cast<WiFiChannel>(
kWiFiChannel5745 +
(frequency - kWiFiFrequency5745) / kWiFiBandwidth20MHz);
}
CHECK(kWiFiChannelUndef <= channel && channel < kWiFiChannelMax);
if (channel == kWiFiChannelUndef)
LOG(WARNING) << "no mapping for frequency " << frequency;
else
SLOG(nullptr, 3) << "mapped frequency " << frequency
<< " to enum bucket " << channel;
return channel;
}
// static
Metrics::WiFiSecurity Metrics::WiFiSecurityStringToEnum(
const string& security) {
if (security == kSecurityNone) {
return kWiFiSecurityNone;
} else if (security == kSecurityWep) {
return kWiFiSecurityWep;
} else if (security == kSecurityWpa) {
return kWiFiSecurityWpa;
} else if (security == kSecurityRsn) {
return kWiFiSecurityRsn;
} else if (security == kSecurity8021x) {
return kWiFiSecurity8021x;
} else if (security == kSecurityPsk) {
return kWiFiSecurityPsk;
} else {
return kWiFiSecurityUnknown;
}
}
// static
Metrics::WiFiApMode Metrics::WiFiApModeStringToEnum(const string& ap_mode) {
if (ap_mode == kModeManaged) {
return kWiFiApModeManaged;
} else if (ap_mode == kModeAdhoc) {
return kWiFiApModeAdHoc;
} else {
return kWiFiApModeUnknown;
}
}
// static
Metrics::EapOuterProtocol Metrics::EapOuterProtocolStringToEnum(
const string& outer) {
if (outer == kEapMethodPEAP) {
return kEapOuterProtocolPeap;
} else if (outer == kEapMethodTLS) {
return kEapOuterProtocolTls;
} else if (outer == kEapMethodTTLS) {
return kEapOuterProtocolTtls;
} else if (outer == kEapMethodLEAP) {
return kEapOuterProtocolLeap;
} else {
return kEapOuterProtocolUnknown;
}
}
// static
Metrics::EapInnerProtocol Metrics::EapInnerProtocolStringToEnum(
const string& inner) {
if (inner.empty()) {
return kEapInnerProtocolNone;
} else if (inner == kEapPhase2AuthPEAPMD5) {
return kEapInnerProtocolPeapMd5;
} else if (inner == kEapPhase2AuthPEAPMSCHAPV2) {
return kEapInnerProtocolPeapMschapv2;
} else if (inner == kEapPhase2AuthTTLSEAPMD5) {
return kEapInnerProtocolTtlsEapMd5;
} else if (inner == kEapPhase2AuthTTLSEAPMSCHAPV2) {
return kEapInnerProtocolTtlsEapMschapv2;
} else if (inner == kEapPhase2AuthTTLSMSCHAPV2) {
return kEapInnerProtocolTtlsMschapv2;
} else if (inner == kEapPhase2AuthTTLSMSCHAP) {
return kEapInnerProtocolTtlsMschap;
} else if (inner == kEapPhase2AuthTTLSPAP) {
return kEapInnerProtocolTtlsPap;
} else if (inner == kEapPhase2AuthTTLSCHAP) {
return kEapInnerProtocolTtlsChap;
} else {
return kEapInnerProtocolUnknown;
}
}
// static
Metrics::PortalResult Metrics::PortalDetectionResultToEnum(
const PortalDetector::Result& portal_result) {
DCHECK(portal_result.final);
PortalResult retval = kPortalResultUnknown;
ConnectivityTrial::Result result = portal_result.trial_result;
// 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 ConnectivityTrial::kPhaseDNS:
if (result.status == ConnectivityTrial::kStatusFailure)
retval = kPortalResultDNSFailure;
else if (result.status == ConnectivityTrial::kStatusTimeout)
retval = kPortalResultDNSTimeout;
else
LOG(DFATAL) << __func__ << ": Final result status " << result.status
<< " is not allowed in the DNS phase";
break;
case ConnectivityTrial::kPhaseConnection:
if (result.status == ConnectivityTrial::kStatusFailure)
retval = kPortalResultConnectionFailure;
else if (result.status == ConnectivityTrial::kStatusTimeout)
retval = kPortalResultConnectionTimeout;
else
LOG(DFATAL) << __func__ << ": Final result status " << result.status
<< " is not allowed in the Connection phase";
break;
case ConnectivityTrial::kPhaseHTTP:
if (result.status == ConnectivityTrial::kStatusFailure)
retval = kPortalResultHTTPFailure;
else if (result.status == ConnectivityTrial::kStatusTimeout)
retval = kPortalResultHTTPTimeout;
else
LOG(DFATAL) << __func__ << ": Final result status " << result.status
<< " is not allowed in the HTTP phase";
break;
case ConnectivityTrial::kPhaseContent:
if (result.status == ConnectivityTrial::kStatusSuccess)
retval = kPortalResultSuccess;
else if (result.status == ConnectivityTrial::kStatusFailure)
retval = kPortalResultContentFailure;
else if (result.status == ConnectivityTrial::kStatusTimeout)
retval = kPortalResultContentTimeout;
else
LOG(DFATAL) << __func__ << ": Final result status " << result.status
<< " is not allowed in the Content phase";
break;
case ConnectivityTrial::kPhaseUnknown:
retval = kPortalResultUnknown;
break;
default:
LOG(DFATAL) << __func__ << ": Invalid phase " << result.phase;
break;
}
return retval;
}
void Metrics::Start() {
SLOG(this, 2) << __func__;
}
void Metrics::Stop() {
SLOG(this, 2) << __func__;
}
void Metrics::RegisterService(const Service& service) {
SLOG(this, 2) << __func__;
LOG_IF(WARNING, ContainsKey(services_metrics_, &service))
<< "Repeatedly registering " << service.unique_name();
shared_ptr<ServiceMetrics> service_metrics(new ServiceMetrics());
services_metrics_[&service] = service_metrics;
InitializeCommonServiceMetrics(service);
}
void Metrics::DeregisterService(const Service& service) {
services_metrics_.erase(&service);
}
void Metrics::AddServiceStateTransitionTimer(
const Service& service,
const string& histogram_name,
Service::ConnectState start_state,
Service::ConnectState stop_state) {
SLOG(this, 2) << __func__ << ": adding " << histogram_name << " for "
<< Service::ConnectStateToString(start_state) << " -> "
<< Service::ConnectStateToString(stop_state);
ServiceMetricsLookupMap::iterator it = services_metrics_.find(&service);
if (it == services_metrics_.end()) {
SLOG(this, 1) << "service not found";
DCHECK(false);
return;
}
ServiceMetrics* service_metrics = it->second.get();
CHECK(start_state < stop_state);
chromeos_metrics::TimerReporter* timer =
new chromeos_metrics::TimerReporter(histogram_name,
kTimerHistogramMillisecondsMin,
kTimerHistogramMillisecondsMax,
kTimerHistogramNumBuckets);
service_metrics->timers.push_back(timer); // passes ownership.
service_metrics->start_on_state[start_state].push_back(timer);
service_metrics->stop_on_state[stop_state].push_back(timer);
}
void Metrics::NotifyDefaultServiceChanged(const Service* service) {
base::TimeDelta elapsed_seconds;
Technology::Identifier technology = (service) ? service->technology() :
Technology::kUnknown;
if (technology != last_default_technology_) {
if (last_default_technology_ != Technology::kUnknown) {
string histogram = GetFullMetricName(kMetricTimeOnlineSecondsSuffix,
last_default_technology_);
time_online_timer_->GetElapsedTime(&elapsed_seconds);
SendToUMA(histogram,
elapsed_seconds.InSeconds(),
kMetricTimeOnlineSecondsMin,
kMetricTimeOnlineSecondsMax,
kTimerHistogramNumBuckets);
}
last_default_technology_ = technology;
time_online_timer_->Start();
}
// Ignore changes that are not online/offline transitions; e.g.
// switching between wired and wireless. TimeToDrop measures
// time online regardless of how we are connected.
if ((service == nullptr && !was_online_) ||
(service != nullptr && was_online_))
return;
if (service == nullptr) {
time_to_drop_timer_->GetElapsedTime(&elapsed_seconds);
SendToUMA(kMetricTimeToDropSeconds,
elapsed_seconds.InSeconds(),
kMetricTimeToDropSecondsMin,
kMetricTimeToDropSecondsMax,
kTimerHistogramNumBuckets);
} else {
time_to_drop_timer_->Start();
}
was_online_ = (service != nullptr);
}
void Metrics::NotifyServiceStateChanged(const Service& service,
Service::ConnectState new_state) {
ServiceMetricsLookupMap::iterator it = services_metrics_.find(&service);
if (it == services_metrics_.end()) {
SLOG(this, 1) << "service not found";
DCHECK(false);
return;
}
ServiceMetrics* service_metrics = it->second.get();
UpdateServiceStateTransitionMetrics(service_metrics, new_state);
if (new_state == Service::kStateFailure)
SendServiceFailure(service);
#if !defined(__ANDROID__)
if (collect_bootstats_) {
bootstat_log(base::StringPrintf("network-%s-%s",
Technology::NameFromIdentifier(
service.technology()).c_str(),
service.GetStateString().c_str()).c_str());
}
#endif // __ANDROID__
if (new_state != Service::kStateConnected)
return;
base::TimeDelta time_resume_to_ready;
time_resume_to_ready_timer_->GetElapsedTime(&time_resume_to_ready);
time_resume_to_ready_timer_->Reset();
service.SendPostReadyStateMetrics(time_resume_to_ready.InMilliseconds());
}
string Metrics::GetFullMetricName(const char* metric_suffix,
Technology::Identifier technology_id) {
string technology = Technology::NameFromIdentifier(technology_id);
technology[0] = base::ToUpperASCII(technology[0]);
return base::StringPrintf("%s.%s.%s", kMetricPrefix, technology.c_str(),
metric_suffix);
}
void Metrics::NotifyServiceDisconnect(const Service& service) {
Technology::Identifier technology = service.technology();
string histogram = GetFullMetricName(kMetricDisconnectSuffix, technology);
SendToUMA(histogram,
service.explicitly_disconnected(),
kMetricDisconnectMin,
kMetricDisconnectMax,
kMetricDisconnectNumBuckets);
}
void Metrics::NotifySignalAtDisconnect(const Service& service,
int16_t signal_strength) {
// Negate signal_strength (goes from dBm to -dBm) because the metrics don't
// seem to handle negative values well. Now everything's positive.
Technology::Identifier technology = service.technology();
string histogram = GetFullMetricName(kMetricSignalAtDisconnectSuffix,
technology);
SendToUMA(histogram,
-signal_strength,
kMetricSignalAtDisconnectMin,
kMetricSignalAtDisconnectMax,
kMetricSignalAtDisconnectNumBuckets);
}
void Metrics::NotifySuspendDone() {
time_resume_to_ready_timer_->Start();
}
void Metrics::NotifyWakeOnWiFiFeaturesEnabledState(
WakeOnWiFiFeaturesEnabledState state) {
SendEnumToUMA(kMetricWakeOnWiFiFeaturesEnabledState, state,
kWakeOnWiFiFeaturesEnabledStateMax);
}
void Metrics::NotifyVerifyWakeOnWiFiSettingsResult(
VerifyWakeOnWiFiSettingsResult result) {
SendEnumToUMA(kMetricVerifyWakeOnWiFiSettingsResult, result,
kVerifyWakeOnWiFiSettingsResultMax);
}
void Metrics::NotifyConnectedToServiceAfterWake(
WiFiConnectionStatusAfterWake status) {
SendEnumToUMA(kMetricWiFiConnectionStatusAfterWake, status,
kWiFiConnetionStatusAfterWakeMax);
}
void Metrics::NotifyTerminationActionsStarted() {
if (time_termination_actions_timer->HasStarted())
return;
time_termination_actions_timer->Start();
}
void Metrics::NotifyTerminationActionsCompleted(bool success) {
if (!time_termination_actions_timer->HasStarted())
return;
TerminationActionResult result = success ? kTerminationActionResultSuccess
: kTerminationActionResultFailure;
base::TimeDelta elapsed_time;
time_termination_actions_timer->GetElapsedTime(&elapsed_time);
time_termination_actions_timer->Reset();
string time_metric, result_metric;
time_metric = kMetricTerminationActionTimeTaken;
result_metric = kMetricTerminationActionResult;
SendToUMA(time_metric,
elapsed_time.InMilliseconds(),
kMetricTerminationActionTimeTakenMillisecondsMin,
kMetricTerminationActionTimeTakenMillisecondsMax,
kTimerHistogramNumBuckets);
SendEnumToUMA(result_metric,
result,
kTerminationActionResultMax);
}
void Metrics::NotifySuspendActionsStarted() {
if (time_suspend_actions_timer->HasStarted())
return;
time_suspend_actions_timer->Start();
wake_on_wifi_throttled_ = false;
}
void Metrics::NotifySuspendActionsCompleted(bool success) {
if (!time_suspend_actions_timer->HasStarted())
return;
// Reset for next dark resume.
wake_reason_received_ = false;
SuspendActionResult result =
success ? kSuspendActionResultSuccess : kSuspendActionResultFailure;
base::TimeDelta elapsed_time;
time_suspend_actions_timer->GetElapsedTime(&elapsed_time);
time_suspend_actions_timer->Reset();
string time_metric, result_metric;
time_metric = kMetricSuspendActionTimeTaken;
result_metric = kMetricSuspendActionResult;
SendToUMA(time_metric,
elapsed_time.InMilliseconds(),
kMetricSuspendActionTimeTakenMillisecondsMin,
kMetricSuspendActionTimeTakenMillisecondsMax,
kTimerHistogramNumBuckets);
SendEnumToUMA(result_metric,
result,
kSuspendActionResultMax);
}
void Metrics::NotifyDarkResumeActionsStarted() {
if (time_dark_resume_actions_timer->HasStarted())
return;
time_dark_resume_actions_timer->Start();
num_scan_results_expected_in_dark_resume_ = 0;
dark_resume_scan_retries_ = 0;
}
void Metrics::NotifyDarkResumeActionsCompleted(bool success) {
if (!time_dark_resume_actions_timer->HasStarted())
return;
// Reset for next dark resume.
wake_reason_received_ = false;
DarkResumeActionResult result =
success ? kDarkResumeActionResultSuccess : kDarkResumeActionResultFailure;
base::TimeDelta elapsed_time;
time_dark_resume_actions_timer->GetElapsedTime(&elapsed_time);
time_dark_resume_actions_timer->Reset();
SendToUMA(kMetricDarkResumeActionTimeTaken,
elapsed_time.InMilliseconds(),
kMetricDarkResumeActionTimeTakenMillisecondsMin,
kMetricDarkResumeActionTimeTakenMillisecondsMax,
kTimerHistogramNumBuckets);
SendEnumToUMA(kMetricDarkResumeActionResult,
result,
kDarkResumeActionResultMax);
DarkResumeUnmatchedScanResultReceived unmatched_scan_results_received =
(num_scan_results_expected_in_dark_resume_ < 0)
? kDarkResumeUnmatchedScanResultsReceivedTrue
: kDarkResumeUnmatchedScanResultsReceivedFalse;
SendEnumToUMA(kMetricDarkResumeUnmatchedScanResultReceived,
unmatched_scan_results_received,
kDarkResumeUnmatchedScanResultsReceivedMax);
SendToUMA(kMetricDarkResumeScanNumRetries, dark_resume_scan_retries_,
kMetricDarkResumeScanNumRetriesMin,
kMetricDarkResumeScanNumRetriesMax, kTimerHistogramNumBuckets);
}
void Metrics::NotifyDarkResumeInitiateScan() {
++num_scan_results_expected_in_dark_resume_;
}
void Metrics::NotifyDarkResumeScanResultsReceived() {
--num_scan_results_expected_in_dark_resume_;
}
void Metrics::NotifyLinkMonitorFailure(
Technology::Identifier technology,
LinkMonitorFailure failure,
int seconds_to_failure,
int broadcast_error_count,
int unicast_error_count) {
string histogram = GetFullMetricName(kMetricLinkMonitorFailureSuffix,
technology);
SendEnumToUMA(histogram, failure, kLinkMonitorFailureMax);
if (failure == kLinkMonitorFailureThresholdReached) {
if (seconds_to_failure > kMetricLinkMonitorSecondsToFailureMax) {
seconds_to_failure = kMetricLinkMonitorSecondsToFailureMax;
}
histogram = GetFullMetricName(kMetricLinkMonitorSecondsToFailureSuffix,
technology);
SendToUMA(histogram,
seconds_to_failure,
kMetricLinkMonitorSecondsToFailureMin,
kMetricLinkMonitorSecondsToFailureMax,
kMetricLinkMonitorSecondsToFailureNumBuckets);
histogram = GetFullMetricName(
kMetricLinkMonitorBroadcastErrorsAtFailureSuffix, technology);
SendToUMA(histogram,
broadcast_error_count,
kMetricLinkMonitorErrorCountMin,
kMetricLinkMonitorErrorCountMax,
kMetricLinkMonitorErrorCountNumBuckets);
histogram = GetFullMetricName(
kMetricLinkMonitorUnicastErrorsAtFailureSuffix, technology);
SendToUMA(histogram,
unicast_error_count,
kMetricLinkMonitorErrorCountMin,
kMetricLinkMonitorErrorCountMax,
kMetricLinkMonitorErrorCountNumBuckets);
}
}
void Metrics::NotifyLinkMonitorResponseTimeSampleAdded(
Technology::Identifier technology,
int response_time_milliseconds) {
string histogram = GetFullMetricName(
kMetricLinkMonitorResponseTimeSampleSuffix, technology);
SendToUMA(histogram,
response_time_milliseconds,
kMetricLinkMonitorResponseTimeSampleMin,
kMetricLinkMonitorResponseTimeSampleMax,
kMetricLinkMonitorResponseTimeSampleNumBuckets);
}
#if !defined(DISABLE_WIFI)
// TODO(zqiu): Change argument type from IEEE_80211::WiFiReasonCode to
// Metrics::WiFiStatusType, to remove dependency for IEEE_80211.
void Metrics::Notify80211Disconnect(WiFiDisconnectByWhom by_whom,
IEEE_80211::WiFiReasonCode reason) {
string metric_disconnect_reason;
string metric_disconnect_type;
WiFiStatusType type;
if (by_whom == kDisconnectedByAp) {
metric_disconnect_reason = kMetricLinkApDisconnectReason;
metric_disconnect_type = kMetricLinkApDisconnectType;
type = kStatusCodeTypeByAp;
} else {
metric_disconnect_reason = kMetricLinkClientDisconnectReason;
metric_disconnect_type = kMetricLinkClientDisconnectType;
switch (reason) {
case IEEE_80211::kReasonCodeSenderHasLeft:
case IEEE_80211::kReasonCodeDisassociatedHasLeft:
type = kStatusCodeTypeByUser;
break;
case IEEE_80211::kReasonCodeInactivity:
type = kStatusCodeTypeConsideredDead;
break;
default:
type = kStatusCodeTypeByClient;
break;
}
}
SendEnumToUMA(metric_disconnect_reason, reason,
IEEE_80211::kStatusCodeMax);
SendEnumToUMA(metric_disconnect_type, type, kStatusCodeTypeMax);
}
#endif // DISABLE_WIFI
void Metrics::RegisterDevice(int interface_index,
Technology::Identifier technology) {
SLOG(this, 2) << __func__ << ": " << interface_index;
shared_ptr<DeviceMetrics> device_metrics(new DeviceMetrics);
devices_metrics_[interface_index] = device_metrics;
device_metrics->technology = technology;
string histogram = GetFullMetricName(
kMetricTimeToInitializeMillisecondsSuffix, technology);
device_metrics->initialization_timer.reset(
new chromeos_metrics::TimerReporter(
histogram,
kMetricTimeToInitializeMillisecondsMin,
kMetricTimeToInitializeMillisecondsMax,
kMetricTimeToInitializeMillisecondsNumBuckets));
device_metrics->initialization_timer->Start();
histogram = GetFullMetricName(kMetricTimeToEnableMillisecondsSuffix,
technology);
device_metrics->enable_timer.reset(
new chromeos_metrics::TimerReporter(
histogram,
kMetricTimeToEnableMillisecondsMin,
kMetricTimeToEnableMillisecondsMax,
kMetricTimeToEnableMillisecondsNumBuckets));
histogram = GetFullMetricName(kMetricTimeToDisableMillisecondsSuffix,
technology);
device_metrics->disable_timer.reset(
new chromeos_metrics::TimerReporter(
histogram,
kMetricTimeToDisableMillisecondsMin,
kMetricTimeToDisableMillisecondsMax,
kMetricTimeToDisableMillisecondsNumBuckets));
histogram = GetFullMetricName(kMetricTimeToScanMillisecondsSuffix,
technology);
device_metrics->scan_timer.reset(
new chromeos_metrics::TimerReporter(
histogram,
kMetricTimeToScanMillisecondsMin,
kMetricTimeToScanMillisecondsMax,
kMetricTimeToScanMillisecondsNumBuckets));
histogram = GetFullMetricName(kMetricTimeToConnectMillisecondsSuffix,
technology);
device_metrics->connect_timer.reset(
new chromeos_metrics::TimerReporter(
histogram,
kMetricTimeToConnectMillisecondsMin,
kMetricTimeToConnectMillisecondsMax,
kMetricTimeToConnectMillisecondsNumBuckets));
histogram = GetFullMetricName(kMetricTimeToScanAndConnectMillisecondsSuffix,
technology);
device_metrics->scan_connect_timer.reset(
new chromeos_metrics::TimerReporter(
histogram,
kMetricTimeToScanMillisecondsMin,
kMetricTimeToScanMillisecondsMax +
kMetricTimeToConnectMillisecondsMax,
kMetricTimeToScanMillisecondsNumBuckets +
kMetricTimeToConnectMillisecondsNumBuckets));
device_metrics->auto_connect_timer.reset(
new chromeos_metrics::TimerReporter(
kMetricCellularAutoConnectTotalTime,
kMetricCellularAutoConnectTotalTimeMin,
kMetricCellularAutoConnectTotalTimeMax,
kMetricCellularAutoConnectTotalTimeNumBuckets));
}
bool Metrics::IsDeviceRegistered(int interface_index,
Technology::Identifier technology) {
SLOG(this, 2) << __func__ << ": interface index: " << interface_index
<< ", technology: " << technology;
DeviceMetrics* device_metrics = GetDeviceMetrics(interface_index);
if (device_metrics == nullptr)
return false;
// Make sure the device technologies match.
return (technology == device_metrics->technology);
}
void Metrics::DeregisterDevice(int interface_index) {
SLOG(this, 2) << __func__ << ": interface index: " << interface_index;
DeviceMetrics* device_metrics = GetDeviceMetrics(interface_index);
if (device_metrics != nullptr) {
NotifyDeviceRemovedEvent(device_metrics->technology);
}
devices_metrics_.erase(interface_index);
}
void Metrics::NotifyDeviceInitialized(int interface_index) {
DeviceMetrics* device_metrics = GetDeviceMetrics(interface_index);
if (device_metrics == nullptr)
return;
if (!device_metrics->initialization_timer->Stop())
return;
device_metrics->initialization_timer->ReportMilliseconds();
}
void Metrics::NotifyDeviceEnableStarted(int interface_index) {
DeviceMetrics* device_metrics = GetDeviceMetrics(interface_index);
if (device_metrics == nullptr)
return;
device_metrics->enable_timer->Start();
}
void Metrics::NotifyDeviceEnableFinished(int interface_index) {
DeviceMetrics* device_metrics = GetDeviceMetrics(interface_index);
if (device_metrics == nullptr)
return;
if (!device_metrics->enable_timer->Stop())
return;
device_metrics->enable_timer->ReportMilliseconds();
}
void Metrics::NotifyDeviceDisableStarted(int interface_index) {
DeviceMetrics* device_metrics = GetDeviceMetrics(interface_index);
if (device_metrics == nullptr)
return;
device_metrics->disable_timer->Start();
}
void Metrics::NotifyDeviceDisableFinished(int interface_index) {
DeviceMetrics* device_metrics = GetDeviceMetrics(interface_index);
if (device_metrics == nullptr)
return;
if (!device_metrics->disable_timer->Stop())
return;
device_metrics->disable_timer->ReportMilliseconds();
}
void Metrics::NotifyDeviceScanStarted(int interface_index) {
DeviceMetrics* device_metrics = GetDeviceMetrics(interface_index);
if (device_metrics == nullptr)
return;
device_metrics->scan_timer->Start();
device_metrics->scan_connect_timer->Start();
}
void Metrics::NotifyDeviceScanFinished(int interface_index) {
DeviceMetrics* device_metrics = GetDeviceMetrics(interface_index);
if (device_metrics == nullptr)
return;
if (!device_metrics->scan_timer->Stop())
return;
// Don't send TimeToScan metrics if the elapsed time exceeds the max metrics
// value. Huge scan times usually mean something's gone awry; for cellular,
// for instance, this usually means that the modem is in an area without
// service and we're not interested in this scenario.
base::TimeDelta elapsed_time;
device_metrics->scan_timer->GetElapsedTime(&elapsed_time);
if (elapsed_time.InMilliseconds() <= kMetricTimeToScanMillisecondsMax)
device_metrics->scan_timer->ReportMilliseconds();
}
void Metrics::ResetScanTimer(int interface_index) {
DeviceMetrics* device_metrics = GetDeviceMetrics(interface_index);
if (device_metrics == nullptr)
return;
device_metrics->scan_timer->Reset();
}
void Metrics::NotifyDeviceConnectStarted(int interface_index,
bool is_auto_connecting) {
DeviceMetrics* device_metrics = GetDeviceMetrics(interface_index);
if (device_metrics == nullptr)
return;
device_metrics->connect_timer->Start();
if (is_auto_connecting) {
device_metrics->auto_connect_tries++;
if (device_metrics->auto_connect_tries == 1)
device_metrics->auto_connect_timer->Start();
} else {
AutoConnectMetricsReset(device_metrics);
}
}
void Metrics::NotifyDeviceConnectFinished(int interface_index) {
DeviceMetrics* device_metrics = GetDeviceMetrics(interface_index);
if (device_metrics == nullptr)
return;
if (!device_metrics->connect_timer->Stop())
return;
device_metrics->connect_timer->ReportMilliseconds();
if (device_metrics->auto_connect_tries > 0) {
if (!device_metrics->auto_connect_timer->Stop())
return;
base::TimeDelta elapsed_time;
device_metrics->auto_connect_timer->GetElapsedTime(&elapsed_time);
if (elapsed_time.InMilliseconds() > kMetricCellularAutoConnectTotalTimeMax)
return;
device_metrics->auto_connect_timer->ReportMilliseconds();
SendToUMA(kMetricCellularAutoConnectTries,
device_metrics->auto_connect_tries,
kMetricCellularAutoConnectTriesMin,
kMetricCellularAutoConnectTriesMax,
kMetricCellularAutoConnectTriesNumBuckets);
AutoConnectMetricsReset(device_metrics);
}
if (!device_metrics->scan_connect_timer->Stop())
return;
device_metrics->scan_connect_timer->ReportMilliseconds();
}
void Metrics::ResetConnectTimer(int interface_index) {
DeviceMetrics* device_metrics = GetDeviceMetrics(interface_index);
if (device_metrics == nullptr)
return;
device_metrics->connect_timer->Reset();
device_metrics->scan_connect_timer->Reset();
}
void Metrics::Notify3GPPRegistrationDelayedDropPosted() {
SendEnumToUMA(kMetricCellular3GPPRegistrationDelayedDrop,
kCellular3GPPRegistrationDelayedDropPosted,
kCellular3GPPRegistrationDelayedDropMax);
}
void Metrics::Notify3GPPRegistrationDelayedDropCanceled() {
SendEnumToUMA(kMetricCellular3GPPRegistrationDelayedDrop,
kCellular3GPPRegistrationDelayedDropCanceled,
kCellular3GPPRegistrationDelayedDropMax);
}
void Metrics::NotifyCellularDeviceDrop(const string& network_technology,
uint16_t signal_strength) {
SLOG(this, 2) << __func__ << ": " << network_technology
<< ", " << signal_strength;
CellularDropTechnology drop_technology = kCellularDropTechnologyUnknown;
if (network_technology == kNetworkTechnology1Xrtt) {
drop_technology = kCellularDropTechnology1Xrtt;
} else if (network_technology == kNetworkTechnologyEdge) {
drop_technology = kCellularDropTechnologyEdge;
} else if (network_technology == kNetworkTechnologyEvdo) {
drop_technology = kCellularDropTechnologyEvdo;
} else if (network_technology == kNetworkTechnologyGprs) {
drop_technology = kCellularDropTechnologyGprs;
} else if (network_technology == kNetworkTechnologyGsm) {
drop_technology = kCellularDropTechnologyGsm;
} else if (network_technology == kNetworkTechnologyHspa) {
drop_technology = kCellularDropTechnologyHspa;
} else if (network_technology == kNetworkTechnologyHspaPlus) {
drop_technology = kCellularDropTechnologyHspaPlus;
} else if (network_technology == kNetworkTechnologyLte) {
drop_technology = kCellularDropTechnologyLte;
} else if (network_technology == kNetworkTechnologyUmts) {
drop_technology = kCellularDropTechnologyUmts;
}
SendEnumToUMA(kMetricCellularDrop,
drop_technology,
kCellularDropTechnologyMax);
SendToUMA(kMetricCellularSignalStrengthBeforeDrop,
signal_strength,
kMetricCellularSignalStrengthBeforeDropMin,
kMetricCellularSignalStrengthBeforeDropMax,
kMetricCellularSignalStrengthBeforeDropNumBuckets);
}
void Metrics::NotifyCellularDeviceConnectionFailure() {
library_->SendEnumToUMA(
kMetricCellularFailure, kMetricCellularConnectionFailure,
kMetricCellularMaxFailure);
}
void Metrics::NotifyCellularDeviceDisconnectionFailure() {
library_->SendEnumToUMA(
kMetricCellularFailure, kMetricCellularDisconnectionFailure,
kMetricCellularMaxFailure);
}
void Metrics::NotifyCellularOutOfCredits(
Metrics::CellularOutOfCreditsReason reason) {
SendEnumToUMA(kMetricCellularOutOfCreditsReason,
reason,
kCellularOutOfCreditsReasonMax);
}
void Metrics::NotifyCorruptedProfile() {
SendEnumToUMA(kMetricCorruptedProfile,
kCorruptedProfile,
kCorruptedProfileMax);
}
void Metrics::NotifyWifiAutoConnectableServices(int num_services) {
SendToUMA(kMetricWifiAutoConnectableServices,
num_services,
kMetricWifiAutoConnectableServicesMin,
kMetricWifiAutoConnectableServicesMax,
kMetricWifiAutoConnectableServicesNumBuckets);
}
void Metrics::NotifyWifiAvailableBSSes(int num_bss) {
SendToUMA(kMetricWifiAvailableBSSes,
num_bss,
kMetricWifiAvailableBSSesMin,
kMetricWifiAvailableBSSesMax,
kMetricWifiAvailableBSSesNumBuckets);
}
void Metrics::NotifyServicesOnSameNetwork(int num_services) {
SendToUMA(kMetricServicesOnSameNetwork,
num_services,
kMetricServicesOnSameNetworkMin,
kMetricServicesOnSameNetworkMax,
kMetricServicesOnSameNetworkNumBuckets);
}
void Metrics::NotifyUserInitiatedEvent(int event) {
SendEnumToUMA(kMetricUserInitiatedEvents,
event,
kUserInitiatedEventMax);
}
void Metrics::NotifyWifiTxBitrate(int bitrate) {
SendToUMA(kMetricWifiTxBitrate,
bitrate,
kMetricWifiTxBitrateMin,
kMetricWifiTxBitrateMax,
kMetricWifiTxBitrateNumBuckets);
}
void Metrics::NotifyUserInitiatedConnectionResult(const string& name,
int result) {
SendEnumToUMA(name,
result,
kUserInitiatedConnectionResultMax);
}
void Metrics::NotifyUserInitiatedConnectionFailureReason(
const string& name, const Service::ConnectFailure failure) {
UserInitiatedConnectionFailureReason reason;
switch (failure) {
case Service::kFailureBadPassphrase:
reason = kUserInitiatedConnectionFailureReasonBadPassphrase;
break;
case Service::kFailureBadWEPKey:
reason = kUserInitiatedConnectionFailureReasonBadWEPKey;
break;
case Service::kFailureConnect:
reason = kUserInitiatedConnectionFailureReasonConnect;
break;
case Service::kFailureDHCP:
reason = kUserInitiatedConnectionFailureReasonDHCP;
break;
case Service::kFailureDNSLookup:
reason = kUserInitiatedConnectionFailureReasonDNSLookup;
break;
case Service::kFailureEAPAuthentication:
reason = kUserInitiatedConnectionFailureReasonEAPAuthentication;
break;
case Service::kFailureEAPLocalTLS:
reason = kUserInitiatedConnectionFailureReasonEAPLocalTLS;
break;
case Service::kFailureEAPRemoteTLS:
reason = kUserInitiatedConnectionFailureReasonEAPRemoteTLS;
break;
case Service::kFailureOutOfRange:
reason = kUserInitiatedConnectionFailureReasonOutOfRange;
break;
case Service::kFailurePinMissing:
reason = kUserInitiatedConnectionFailureReasonPinMissing;
break;
default:
reason = kUserInitiatedConnectionFailureReasonUnknown;
break;
}
SendEnumToUMA(name,
reason,
kUserInitiatedConnectionFailureReasonMax);
}
void Metrics::NotifyFallbackDNSTestResult(Technology::Identifier technology_id,
int result) {
string histogram = GetFullMetricName(kMetricFallbackDNSTestResultSuffix,
technology_id);
SendEnumToUMA(histogram,
result,
kFallbackDNSTestResultMax);
}
void Metrics::NotifyNetworkProblemDetected(Technology::Identifier technology_id,
int reason) {
string histogram = GetFullMetricName(kMetricNetworkProblemDetectedSuffix,
technology_id);
SendEnumToUMA(histogram,
reason,
kNetworkProblemMax);
}
void Metrics::NotifyDeviceConnectionStatus(ConnectionStatus status) {
SendEnumToUMA(kMetricDeviceConnectionStatus, status, kConnectionStatusMax);
}
void Metrics::NotifyDhcpClientStatus(DhcpClientStatus status) {
SendEnumToUMA(kMetricDhcpClientStatus, status, kDhcpClientStatusMax);
}
void Metrics::NotifyNetworkConnectionIPType(
Technology::Identifier technology_id, NetworkConnectionIPType type) {
string histogram = GetFullMetricName(kMetricNetworkConnectionIPTypeSuffix,
technology_id);
SendEnumToUMA(histogram, type, kNetworkConnectionIPTypeMax);
}
void Metrics::NotifyIPv6ConnectivityStatus(Technology::Identifier technology_id,
bool status) {
string histogram = GetFullMetricName(kMetricIPv6ConnectivityStatusSuffix,
technology_id);
IPv6ConnectivityStatus ipv6_status = status ? kIPv6ConnectivityStatusYes
: kIPv6ConnectivityStatusNo;
SendEnumToUMA(histogram, ipv6_status, kIPv6ConnectivityStatusMax);
}
void Metrics::NotifyDevicePresenceStatus(Technology::Identifier technology_id,
bool status) {
string histogram = GetFullMetricName(kMetricDevicePresenceStatusSuffix,
technology_id);
DevicePresenceStatus presence = status ? kDevicePresenceStatusYes
: kDevicePresenceStatusNo;
SendEnumToUMA(histogram, presence, kDevicePresenceStatusMax);
}
void Metrics::NotifyDeviceRemovedEvent(Technology::Identifier technology_id) {
DeviceTechnologyType type;
switch (technology_id) {
case Technology::kEthernet:
type = kDeviceTechnologyTypeEthernet;
break;
case Technology::kWifi:
type = kDeviceTechnologyTypeWifi;
break;
case Technology::kWiMax:
type = kDeviceTechnologyTypeWimax;
break;
case Technology::kCellular:
type = kDeviceTechnologyTypeCellular;
break;
default:
type = kDeviceTechnologyTypeUnknown;
break;
}
SendEnumToUMA(kMetricDeviceRemovedEvent, type, kDeviceTechnologyTypeMax);
}
void Metrics::NotifyUnreliableLinkSignalStrength(
Technology::Identifier technology_id, int signal_strength) {
string histogram = GetFullMetricName(
kMetricUnreliableLinkSignalStrengthSuffix, technology_id);
SendToUMA(histogram,
signal_strength,
kMetricSerivceSignalStrengthMin,
kMetricServiceSignalStrengthMax,
kMetricServiceSignalStrengthNumBuckets);
}
bool Metrics::SendEnumToUMA(const string& name, int sample, int max) {
SLOG(this, 5)
<< "Sending enum " << name << " with value " << sample << ".";
return library_->SendEnumToUMA(name, sample, max);
}
bool Metrics::SendToUMA(const string& name, int sample, int min, int max,
int num_buckets) {
SLOG(this, 5)
<< "Sending metric " << name << " with value " << sample << ".";
return library_->SendToUMA(name, sample, min, max, num_buckets);
}
bool Metrics::SendSparseToUMA(const string& name, int sample) {
SLOG(this, 5)
<< "Sending sparse metric " << name << " with value " << sample << ".";
return library_->SendSparseToUMA(name, sample);
}
void Metrics::NotifyWakeOnWiFiThrottled() {
wake_on_wifi_throttled_ = true;
}
void Metrics::NotifySuspendWithWakeOnWiFiEnabledDone() {
WakeOnWiFiThrottled throttled_result = wake_on_wifi_throttled_
? kWakeOnWiFiThrottledTrue
: kWakeOnWiFiThrottledFalse;
SendEnumToUMA(kMetricWakeOnWiFiThrottled, throttled_result,
kWakeOnWiFiThrottledMax);
}
void Metrics::NotifyWakeupReasonReceived() { wake_reason_received_ = true; }
#if !defined(DISABLE_WIFI)
// TODO(zqiu): Change argument type from WakeOnWiFi::WakeOnWiFiTrigger to
// Metrics::DarkResumeWakeReason, to remove the dependency for WakeOnWiFi.
// to remove the dependency for WakeOnWiFi.
void Metrics::NotifyWakeOnWiFiOnDarkResume(
WakeOnWiFi::WakeOnWiFiTrigger reason) {
WakeReasonReceivedBeforeOnDarkResume result =
wake_reason_received_ ? kWakeReasonReceivedBeforeOnDarkResumeTrue
: kWakeReasonReceivedBeforeOnDarkResumeFalse;
SendEnumToUMA(kMetricWakeReasonReceivedBeforeOnDarkResume, result,
kWakeReasonReceivedBeforeOnDarkResumeMax);
DarkResumeWakeReason wake_reason;
switch (reason) {
case WakeOnWiFi::kWakeTriggerPattern:
wake_reason = kDarkResumeWakeReasonPattern;
break;
case WakeOnWiFi::kWakeTriggerDisconnect:
wake_reason = kDarkResumeWakeReasonDisconnect;
break;
case WakeOnWiFi::kWakeTriggerSSID:
wake_reason = kDarkResumeWakeReasonSSID;
break;
case WakeOnWiFi::kWakeTriggerUnsupported:
default:
wake_reason = kDarkResumeWakeReasonUnsupported;
break;
}
SendEnumToUMA(kMetricDarkResumeWakeReason, wake_reason,
kDarkResumeWakeReasonMax);
}
#endif // DISABLE_WIFI
void Metrics::NotifyScanStartedInDarkResume(bool is_active_scan) {
DarkResumeScanType scan_type =
is_active_scan ? kDarkResumeScanTypeActive : kDarkResumeScanTypePassive;
SendEnumToUMA(kMetricDarkResumeScanType, scan_type, kDarkResumeScanTypeMax);
}
void Metrics::NotifyDarkResumeScanRetry() {
++dark_resume_scan_retries_;
}
void Metrics::NotifyBeforeSuspendActions(bool is_connected,
bool in_dark_resume) {
if (in_dark_resume && dark_resume_scan_retries_) {
DarkResumeScanRetryResult connect_result =
is_connected ? kDarkResumeScanRetryResultConnected
: kDarkResumeScanRetryResultNotConnected;
SendEnumToUMA(kMetricDarkResumeScanRetryResult, connect_result,
kDarkResumeScanRetryResultMax);
}
}
void Metrics::NotifyConnectionDiagnosticsIssue(const string& issue) {
ConnectionDiagnosticsIssue issue_enum;
if (issue == ConnectionDiagnostics::kIssueIPCollision) {
issue_enum = kConnectionDiagnosticsIssueIPCollision;
} else if (issue == ConnectionDiagnostics::kIssueRouting) {
issue_enum = kConnectionDiagnosticsIssueRouting;
} else if (issue == ConnectionDiagnostics::kIssueHTTPBrokenPortal) {
issue_enum = kConnectionDiagnosticsIssueHTTPBrokenPortal;
} else if (issue == ConnectionDiagnostics::kIssueDNSServerMisconfig) {
issue_enum = kConnectionDiagnosticsIssueDNSServerMisconfig;
} else if (issue == ConnectionDiagnostics::kIssueDNSServerNoResponse) {
issue_enum = kConnectionDiagnosticsIssueDNSServerNoResponse;
} else if (issue == ConnectionDiagnostics::kIssueNoDNSServersConfigured) {
issue_enum = kConnectionDiagnosticsIssueNoDNSServersConfigured;
} else if (issue == ConnectionDiagnostics::kIssueDNSServersInvalid) {
issue_enum = kConnectionDiagnosticsIssueDNSServersInvalid;
} else if (issue == ConnectionDiagnostics::kIssueNone) {
issue_enum = kConnectionDiagnosticsIssueNone;
} else if (issue == ConnectionDiagnostics::kIssueCaptivePortal) {
issue_enum = kConnectionDiagnosticsIssueCaptivePortal;
} else if (issue == ConnectionDiagnostics::kIssueGatewayUpstream) {
issue_enum = kConnectionDiagnosticsIssueGatewayUpstream;
} else if (issue == ConnectionDiagnostics::kIssueGatewayNotResponding) {
issue_enum = kConnectionDiagnosticsIssueGatewayNotResponding;
} else if (issue == ConnectionDiagnostics::kIssueServerNotResponding) {
issue_enum = kConnectionDiagnosticsIssueServerNotResponding;
} else if (issue == ConnectionDiagnostics::kIssueGatewayArpFailed) {
issue_enum = kConnectionDiagnosticsIssueGatewayArpFailed;
} else if (issue == ConnectionDiagnostics::kIssueServerArpFailed) {
issue_enum = kConnectionDiagnosticsIssueServerArpFailed;
} else if (issue == ConnectionDiagnostics::kIssueInternalError) {
issue_enum = kConnectionDiagnosticsIssueInternalError;
} else if (issue == ConnectionDiagnostics::kIssueGatewayNoNeighborEntry) {
issue_enum = kConnectionDiagnosticsIssueGatewayNoNeighborEntry;
} else if (issue == ConnectionDiagnostics::kIssueServerNoNeighborEntry) {
issue_enum = kConnectionDiagnosticsIssueServerNoNeighborEntry;
} else if (issue ==
ConnectionDiagnostics::kIssueGatewayNeighborEntryNotConnected) {
issue_enum = kConnectionDiagnosticsIssueGatewayNeighborEntryNotConnected;
} else if (issue ==
ConnectionDiagnostics::kIssueServerNeighborEntryNotConnected) {
issue_enum = kConnectionDiagnosticsIssueServerNeighborEntryNotConnected;
} else {
LOG(ERROR) << __func__ << ": Invalid issue: " << issue;
return;
}
SendEnumToUMA(kMetricConnectionDiagnosticsIssue, issue_enum,
kConnectionDiagnosticsIssueMax);
}
void Metrics::InitializeCommonServiceMetrics(const Service& service) {
Technology::Identifier technology = service.technology();
string histogram = GetFullMetricName(kMetricTimeToConfigMillisecondsSuffix,
technology);
AddServiceStateTransitionTimer(
service,
histogram,
Service::kStateConfiguring,
Service::kStateConnected);
histogram = GetFullMetricName(kMetricTimeToPortalMillisecondsSuffix,
technology);
AddServiceStateTransitionTimer(
service,
histogram,
Service::kStateConnected,
Service::kStatePortal);
histogram = GetFullMetricName(kMetricTimeToOnlineMillisecondsSuffix,
technology);
AddServiceStateTransitionTimer(
service,
histogram,
Service::kStateConnected,
Service::kStateOnline);
}
void Metrics::UpdateServiceStateTransitionMetrics(
ServiceMetrics* service_metrics,
Service::ConnectState new_state) {
const char* state_string = Service::ConnectStateToString(new_state);
SLOG(this, 5) << __func__ << ": new_state=" << state_string;
TimerReportersList& start_timers = service_metrics->start_on_state[new_state];
for (auto& start_timer : start_timers) {
SLOG(this, 5) << "Starting timer for " << start_timer->histogram_name()
<< " due to new state " << state_string << ".";
start_timer->Start();
}
TimerReportersList& stop_timers = service_metrics->stop_on_state[new_state];
for (auto& stop_timer : stop_timers) {
SLOG(this, 5) << "Stopping timer for " << stop_timer->histogram_name()
<< " due to new state " << state_string << ".";
if (stop_timer->Stop())
stop_timer->ReportMilliseconds();
}
}
void Metrics::SendServiceFailure(const Service& service) {
NetworkServiceError error = kNetworkServiceErrorUnknown;
// Explicitly map all possible failures. So when new failures are added,
// they will need to be mapped as well. Otherwise, the compiler will
// complain.
switch (service.failure()) {
case Service::kFailureUnknown:
case Service::kFailureMax:
error = kNetworkServiceErrorUnknown;
break;
case Service::kFailureAAA:
error = kNetworkServiceErrorAAA;
break;
case Service::kFailureActivation:
error = kNetworkServiceErrorActivation;
break;
case Service::kFailureBadPassphrase:
error = kNetworkServiceErrorBadPassphrase;
break;
case Service::kFailureBadWEPKey:
error = kNetworkServiceErrorBadWEPKey;
break;
case Service::kFailureConnect:
error = kNetworkServiceErrorConnect;
break;
case Service::kFailureDHCP:
error = kNetworkServiceErrorDHCP;
break;
case Service::kFailureDNSLookup:
error = kNetworkServiceErrorDNSLookup;
break;
case Service::kFailureEAPAuthentication:
error = kNetworkServiceErrorEAPAuthentication;
break;
case Service::kFailureEAPLocalTLS:
error = kNetworkServiceErrorEAPLocalTLS;
break;
case Service::kFailureEAPRemoteTLS:
error = kNetworkServiceErrorEAPRemoteTLS;
break;
case Service::kFailureHTTPGet:
error = kNetworkServiceErrorHTTPGet;
break;
case Service::kFailureIPSecCertAuth:
error = kNetworkServiceErrorIPSecCertAuth;
break;
case Service::kFailureIPSecPSKAuth:
error = kNetworkServiceErrorIPSecPSKAuth;
break;
case Service::kFailureInternal:
error = kNetworkServiceErrorInternal;
break;
case Service::kFailureNeedEVDO:
error = kNetworkServiceErrorNeedEVDO;
break;
case Service::kFailureNeedHomeNetwork:
error = kNetworkServiceErrorNeedHomeNetwork;
break;
case Service::kFailureOTASP:
error = kNetworkServiceErrorOTASP;
break;
case Service::kFailureOutOfRange:
error = kNetworkServiceErrorOutOfRange;
break;
case Service::kFailurePPPAuth:
error = kNetworkServiceErrorPPPAuth;
break;
case Service::kFailurePinMissing:
error = kNetworkServiceErrorPinMissing;
break;
}
library_->SendEnumToUMA(kMetricNetworkServiceErrors,
error,
kNetworkServiceErrorMax);
}
Metrics::DeviceMetrics* Metrics::GetDeviceMetrics(int interface_index) const {
DeviceMetricsLookupMap::const_iterator it =
devices_metrics_.find(interface_index);
if (it == devices_metrics_.end()) {
SLOG(this, 2) << __func__ << ": device " << interface_index
<< " not found";
return nullptr;
}
return it->second.get();
}
void Metrics::AutoConnectMetricsReset(DeviceMetrics* device_metrics) {
device_metrics->auto_connect_tries = 0;
device_metrics->auto_connect_timer->Reset();
}
void Metrics::set_library(MetricsLibraryInterface* library) {
chromeos_metrics::TimerReporter::set_metrics_lib(library);
library_ = library;
}
} // namespace shill