blob: 1f0f3bd0578bed32ea23d0c4fbeb858a30ca3ee0 [file] [log] [blame]
Thieu Lead1ec2c2012-01-05 23:39:48 +00001// Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
Thieu Le48e6d6d2011-12-06 00:40:27 +00002// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "shill/metrics.h"
6
7#include <base/lazy_instance.h>
8#include <base/logging.h>
9#include <base/string_util.h>
10#include <base/stringprintf.h>
Thieu Lead1ec2c2012-01-05 23:39:48 +000011#include <chromeos/dbus/service_constants.h>
Thieu Le48e6d6d2011-12-06 00:40:27 +000012
13#include "shill/wifi_service.h"
14
15using std::string;
16using std::tr1::shared_ptr;
17
18namespace shill {
19
20static base::LazyInstance<Metrics> g_metrics(base::LINKER_INITIALIZED);
21
22// static
23const char Metrics::kMetricNetworkChannel[] = "Network.Shill.%s.Channel";
24const int Metrics::kMetricNetworkChannelMax = Metrics::kWiFiChannelMax;
Thieu Lead1ec2c2012-01-05 23:39:48 +000025const char Metrics::kMetricNetworkPhyMode[] = "Network.Shill.%s.PhyMode";
26const int Metrics::kMetricNetworkPhyModeMax = Metrics::kWiFiNetworkPhyModeMax;
27const char Metrics::kMetricNetworkSecurity[] = "Network.Shill.%s.Security";
28const int Metrics::kMetricNetworkSecurityMax = Metrics::kWiFiSecurityMax;
Thieu Le48e6d6d2011-12-06 00:40:27 +000029const char Metrics::kMetricNetworkServiceErrors[] =
30 "Network.Shill.ServiceErrors";
31const int Metrics::kMetricNetworkServiceErrorsMax = Service::kFailureMax;
32const char Metrics::kMetricTimeToConfigMilliseconds[] =
33 "Network.Shill.%s.TimeToConfig";
34const char Metrics::kMetricTimeToJoinMilliseconds[] =
35 "Network.Shill.%s.TimeToJoin";
36const char Metrics::kMetricTimeToOnlineMilliseconds[] =
37 "Network.Shill.%s.TimeToOnline";
38const char Metrics::kMetricTimeToPortalMilliseconds[] =
39 "Network.Shill.%s.TimeToPortal";
40const int Metrics::kTimerHistogramMaxMilliseconds = 45 * 1000;
41const int Metrics::kTimerHistogramMinMilliseconds = 1;
42const int Metrics::kTimerHistogramNumBuckets = 50;
43
44// static
45const uint16 Metrics::kWiFiBandwidth5MHz = 5;
46const uint16 Metrics::kWiFiBandwidth20MHz = 20;
47const uint16 Metrics::kWiFiFrequency2412 = 2412;
48const uint16 Metrics::kWiFiFrequency2472 = 2472;
49const uint16 Metrics::kWiFiFrequency2484 = 2484;
50const uint16 Metrics::kWiFiFrequency5170 = 5170;
51const uint16 Metrics::kWiFiFrequency5180 = 5180;
52const uint16 Metrics::kWiFiFrequency5230 = 5230;
53const uint16 Metrics::kWiFiFrequency5240 = 5240;
54const uint16 Metrics::kWiFiFrequency5320 = 5320;
55const uint16 Metrics::kWiFiFrequency5500 = 5500;
56const uint16 Metrics::kWiFiFrequency5700 = 5700;
57const uint16 Metrics::kWiFiFrequency5745 = 5745;
58const uint16 Metrics::kWiFiFrequency5825 = 5825;
59
60Metrics::Metrics() : library_(&metrics_library_) {
61 metrics_library_.Init();
62 chromeos_metrics::TimerReporter::set_metrics_lib(library_);
63}
64
65Metrics::~Metrics() {}
66
67// static
Thieu Le48e6d6d2011-12-06 00:40:27 +000068Metrics::WiFiChannel Metrics::WiFiFrequencyToChannel(uint16 frequency) {
69 WiFiChannel channel = kWiFiChannelUndef;
70 if (kWiFiFrequency2412 <= frequency && frequency <= kWiFiFrequency2472) {
71 if (((frequency - kWiFiFrequency2412) % kWiFiBandwidth5MHz) == 0)
72 channel = static_cast<WiFiChannel>(
73 kWiFiChannel2412 +
74 (frequency - kWiFiFrequency2412) / kWiFiBandwidth5MHz);
75 } else if (frequency == kWiFiFrequency2484) {
76 channel = kWiFiChannel2484;
77 } else if (kWiFiFrequency5170 <= frequency &&
78 frequency <= kWiFiFrequency5230) {
79 if ((frequency % kWiFiBandwidth20MHz) == 0)
80 channel = static_cast<WiFiChannel>(
81 kWiFiChannel5180 +
82 (frequency - kWiFiFrequency5180) / kWiFiBandwidth20MHz);
83 if ((frequency % kWiFiBandwidth20MHz) == 10)
84 channel = static_cast<WiFiChannel>(
85 kWiFiChannel5170 +
86 (frequency - kWiFiFrequency5170) / kWiFiBandwidth20MHz);
87 } else if (kWiFiFrequency5240 <= frequency &&
88 frequency <= kWiFiFrequency5320) {
89 if (((frequency - kWiFiFrequency5180) % kWiFiBandwidth20MHz) == 0)
90 channel = static_cast<WiFiChannel>(
91 kWiFiChannel5180 +
92 (frequency - kWiFiFrequency5180) / kWiFiBandwidth20MHz);
93 } else if (kWiFiFrequency5500 <= frequency &&
94 frequency <= kWiFiFrequency5700) {
95 if (((frequency - kWiFiFrequency5500) % kWiFiBandwidth20MHz) == 0)
96 channel = static_cast<WiFiChannel>(
97 kWiFiChannel5500 +
98 (frequency - kWiFiFrequency5500) / kWiFiBandwidth20MHz);
99 } else if (kWiFiFrequency5745 <= frequency &&
100 frequency <= kWiFiFrequency5825) {
101 if (((frequency - kWiFiFrequency5745) % kWiFiBandwidth20MHz) == 0)
102 channel = static_cast<WiFiChannel>(
103 kWiFiChannel5745 +
104 (frequency - kWiFiFrequency5745) / kWiFiBandwidth20MHz);
105 }
106 CHECK(kWiFiChannelUndef <= channel && channel < kWiFiChannelMax);
107
108 if (channel == kWiFiChannelUndef)
109 LOG(WARNING) << "no mapping for frequency " << frequency;
110 else
111 VLOG(3) << "map " << frequency << " to " << channel;
112
113 return channel;
114}
115
Thieu Lead1ec2c2012-01-05 23:39:48 +0000116// static
117Metrics::WiFiSecurity Metrics::WiFiSecurityStringToEnum(
118 const std::string &security) {
119 if (security == flimflam::kSecurityNone) {
120 return kWiFiSecurityNone;
121 } else if (security == flimflam::kSecurityWep) {
122 return kWiFiSecurityWep;
123 } else if (security == flimflam::kSecurityWpa) {
124 return kWiFiSecurityWpa;
125 } else if (security == flimflam::kSecurityRsn) {
126 return kWiFiSecurityRsn;
127 } else if (security == flimflam::kSecurity8021x) {
128 return kWiFiSecurity8021x;
129 } else if (security == flimflam::kSecurityPsk) {
130 return kWiFiSecurityPsk;
131 } else {
132 return kWiFiSecurityUnknown;
133 }
134}
135
Thieu Le48e6d6d2011-12-06 00:40:27 +0000136void Metrics::RegisterService(const Service *service) {
137 shared_ptr<ServiceMetrics> service_metrics(new ServiceMetrics);
138 services_metrics_[service] = service_metrics;
139 service_metrics->service = service;
140 InitializeCommonServiceMetrics(service);
141 service->InitializeCustomMetrics();
142}
143
144void Metrics::DeregisterService(const Service *service) {
145 services_metrics_.erase(service);
146}
147
148void Metrics::AddServiceStateTransitionTimer(
149 const Service *service,
150 const string &histogram_name,
151 Service::ConnectState start_state,
152 Service::ConnectState stop_state) {
153 ServiceMetricsLookupMap::iterator it = services_metrics_.find(service);
154 if (it == services_metrics_.end()) {
155 VLOG(1) << "service not found";
156 DCHECK(false);
157 return;
158 }
159 ServiceMetrics *service_metrics = it->second.get();
160 CHECK(start_state < stop_state);
161 chromeos_metrics::TimerReporter *timer =
162 new chromeos_metrics::TimerReporter(histogram_name,
163 kTimerHistogramMinMilliseconds,
164 kTimerHistogramMaxMilliseconds,
165 kTimerHistogramNumBuckets);
166 service_metrics->timers.push_back(timer); // passes ownership.
167 service_metrics->start_on_state[start_state].push_back(timer);
168 service_metrics->stop_on_state[stop_state].push_back(timer);
169}
170
171void Metrics::NotifyDefaultServiceChanged(const Service */*service*/) {
172 // TODO(thieule): Handle the case when the default service has changed.
173 // crosbug.com/24438
174}
175
176void Metrics::NotifyServiceStateChanged(const Service *service,
177 Service::ConnectState new_state) {
178 ServiceMetricsLookupMap::iterator it = services_metrics_.find(service);
179 if (it == services_metrics_.end()) {
180 VLOG(1) << "service not found";
181 DCHECK(false);
182 return;
183 }
184 ServiceMetrics *service_metrics = it->second.get();
185 UpdateServiceStateTransitionMetrics(service_metrics, new_state);
186
187 if (new_state == Service::kStateFailure)
188 SendServiceFailure(service);
189
190 if (new_state != Service::kStateReady)
191 return;
192
193 service->SendPostReadyStateMetrics();
194}
195
196string Metrics::GetFullMetricName(const char *metric_name,
197 Technology::Identifier technology_id) {
198 string technology = Technology::NameFromIdentifier(technology_id);
199 technology[0] = base::ToUpperASCII(technology[0]);
200 return base::StringPrintf(metric_name, technology.c_str());
201}
202
203void Metrics::NotifyServiceDisconnect(const Service */*service*/,
204 bool /*manual_disconnect*/) {
205 // TODO(thieule): Handle service disconnects.
206 // crosbug.com/23253
207}
208
209void Metrics::NotifyPower() {
210 // TODO(thieule): Handle suspend and resume.
211 // crosbug.com/24440
212}
213
214bool Metrics::SendEnumToUMA(const string &name, int sample, int max) {
215 return library_->SendEnumToUMA(name, sample, max);
216}
217
218void Metrics::InitializeCommonServiceMetrics(const Service *service) {
219 Technology::Identifier technology = service->technology();
220 string histogram = GetFullMetricName(kMetricTimeToConfigMilliseconds,
221 technology);
222 AddServiceStateTransitionTimer(
223 service,
224 histogram,
225 Service::kStateConfiguring,
226 Service::kStateReady);
227 histogram = GetFullMetricName(kMetricTimeToPortalMilliseconds, technology);
228 AddServiceStateTransitionTimer(
229 service,
230 histogram,
231 Service::kStateReady,
232 Service::kStatePortal);
233 histogram = GetFullMetricName(kMetricTimeToOnlineMilliseconds, technology);
234 AddServiceStateTransitionTimer(
235 service,
236 histogram,
237 Service::kStateReady,
238 Service::kStateOnline);
239}
240
241void Metrics::UpdateServiceStateTransitionMetrics(
242 ServiceMetrics *service_metrics,
243 Service::ConnectState new_state) {
244 TimerReportersList::iterator it;
245 TimerReportersList &start_timers = service_metrics->start_on_state[new_state];
246 for (it = start_timers.begin(); it != start_timers.end(); ++it)
247 (*it)->Start();
248
249 TimerReportersList &stop_timers = service_metrics->stop_on_state[new_state];
250 for (it = stop_timers.begin(); it != stop_timers.end(); ++it) {
251 (*it)->Stop();
252 (*it)->ReportMilliseconds();
253 }
254}
255
256void Metrics::SendServiceFailure(const Service *service) {
257 library_->SendEnumToUMA(kMetricNetworkServiceErrors,
258 service->failure(),
259 kMetricNetworkServiceErrorsMax);
260}
261
262void Metrics::set_library(MetricsLibraryInterface *library) {
263 chromeos_metrics::TimerReporter::set_metrics_lib(library);
264 library_ = library;
265}
266
267} // namespace shill