blob: c08f835c0d2d990e49204be216f1e0bad11a6907 [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
Thieu Le67370f62012-02-14 23:01:42 +000023const char Metrics::kMetricDisconnect[] = "Network.Shill.%s.Disconnect";
24const int Metrics::kMetricDisconnectMax = 1;
25const int Metrics::kMetricDisconnectMin = 0;
26const int Metrics::kMetricDisconnectNumBuckets = 2;
27
Thieu Le48e6d6d2011-12-06 00:40:27 +000028const char Metrics::kMetricNetworkChannel[] = "Network.Shill.%s.Channel";
29const int Metrics::kMetricNetworkChannelMax = Metrics::kWiFiChannelMax;
Thieu Lead1ec2c2012-01-05 23:39:48 +000030const char Metrics::kMetricNetworkPhyMode[] = "Network.Shill.%s.PhyMode";
31const int Metrics::kMetricNetworkPhyModeMax = Metrics::kWiFiNetworkPhyModeMax;
32const char Metrics::kMetricNetworkSecurity[] = "Network.Shill.%s.Security";
33const int Metrics::kMetricNetworkSecurityMax = Metrics::kWiFiSecurityMax;
Thieu Le48e6d6d2011-12-06 00:40:27 +000034const char Metrics::kMetricNetworkServiceErrors[] =
35 "Network.Shill.ServiceErrors";
36const int Metrics::kMetricNetworkServiceErrorsMax = Service::kFailureMax;
Thieu Lea20cbc22012-01-09 22:01:43 +000037
38const char Metrics::kMetricTimeOnlineSeconds[] = "Network.Shill.%s.TimeOnline";
39const int Metrics::kMetricTimeOnlineSecondsMax = 8 * 60 * 60; // 8 hours
40const int Metrics::kMetricTimeOnlineSecondsMin = 1;
41
42const char Metrics::kMetricTimeToDropSeconds[] = "Network.Shill.TimeToDrop";;
43const int Metrics::kMetricTimeToDropSecondsMax = 8 * 60 * 60; // 8 hours
44const int Metrics::kMetricTimeToDropSecondsMin = 1;
45
Thieu Leb84ba342012-03-02 15:15:19 -080046const char Metrics::kMetricTimeResumeToReadyMilliseconds[] =
47 "Network.Shill.%s.TimeResumeToReady";
Thieu Le48e6d6d2011-12-06 00:40:27 +000048const char Metrics::kMetricTimeToConfigMilliseconds[] =
49 "Network.Shill.%s.TimeToConfig";
50const char Metrics::kMetricTimeToJoinMilliseconds[] =
51 "Network.Shill.%s.TimeToJoin";
52const char Metrics::kMetricTimeToOnlineMilliseconds[] =
53 "Network.Shill.%s.TimeToOnline";
54const char Metrics::kMetricTimeToPortalMilliseconds[] =
55 "Network.Shill.%s.TimeToPortal";
Thieu Lea20cbc22012-01-09 22:01:43 +000056const int Metrics::kTimerHistogramMillisecondsMax = 45 * 1000;
57const int Metrics::kTimerHistogramMillisecondsMin = 1;
Thieu Le48e6d6d2011-12-06 00:40:27 +000058const int Metrics::kTimerHistogramNumBuckets = 50;
59
60// static
61const uint16 Metrics::kWiFiBandwidth5MHz = 5;
62const uint16 Metrics::kWiFiBandwidth20MHz = 20;
63const uint16 Metrics::kWiFiFrequency2412 = 2412;
64const uint16 Metrics::kWiFiFrequency2472 = 2472;
65const uint16 Metrics::kWiFiFrequency2484 = 2484;
66const uint16 Metrics::kWiFiFrequency5170 = 5170;
67const uint16 Metrics::kWiFiFrequency5180 = 5180;
68const uint16 Metrics::kWiFiFrequency5230 = 5230;
69const uint16 Metrics::kWiFiFrequency5240 = 5240;
70const uint16 Metrics::kWiFiFrequency5320 = 5320;
71const uint16 Metrics::kWiFiFrequency5500 = 5500;
72const uint16 Metrics::kWiFiFrequency5700 = 5700;
73const uint16 Metrics::kWiFiFrequency5745 = 5745;
74const uint16 Metrics::kWiFiFrequency5825 = 5825;
75
Thieu Leb84ba342012-03-02 15:15:19 -080076// static
77const char Metrics::kMetricPowerManagerKey[] = "metrics";
78
Thieu Lea20cbc22012-01-09 22:01:43 +000079Metrics::Metrics()
80 : library_(&metrics_library_),
81 last_default_technology_(Technology::kUnknown),
82 was_online_(false),
83 time_online_timer_(new chromeos_metrics::Timer),
Thieu Leb84ba342012-03-02 15:15:19 -080084 time_to_drop_timer_(new chromeos_metrics::Timer),
85 time_resume_to_ready_timer_(new chromeos_metrics::Timer) {
Thieu Le48e6d6d2011-12-06 00:40:27 +000086 metrics_library_.Init();
87 chromeos_metrics::TimerReporter::set_metrics_lib(library_);
88}
89
90Metrics::~Metrics() {}
91
92// static
Thieu Le48e6d6d2011-12-06 00:40:27 +000093Metrics::WiFiChannel Metrics::WiFiFrequencyToChannel(uint16 frequency) {
94 WiFiChannel channel = kWiFiChannelUndef;
95 if (kWiFiFrequency2412 <= frequency && frequency <= kWiFiFrequency2472) {
96 if (((frequency - kWiFiFrequency2412) % kWiFiBandwidth5MHz) == 0)
97 channel = static_cast<WiFiChannel>(
98 kWiFiChannel2412 +
99 (frequency - kWiFiFrequency2412) / kWiFiBandwidth5MHz);
100 } else if (frequency == kWiFiFrequency2484) {
101 channel = kWiFiChannel2484;
102 } else if (kWiFiFrequency5170 <= frequency &&
103 frequency <= kWiFiFrequency5230) {
104 if ((frequency % kWiFiBandwidth20MHz) == 0)
105 channel = static_cast<WiFiChannel>(
106 kWiFiChannel5180 +
107 (frequency - kWiFiFrequency5180) / kWiFiBandwidth20MHz);
108 if ((frequency % kWiFiBandwidth20MHz) == 10)
109 channel = static_cast<WiFiChannel>(
110 kWiFiChannel5170 +
111 (frequency - kWiFiFrequency5170) / kWiFiBandwidth20MHz);
112 } else if (kWiFiFrequency5240 <= frequency &&
113 frequency <= kWiFiFrequency5320) {
114 if (((frequency - kWiFiFrequency5180) % kWiFiBandwidth20MHz) == 0)
115 channel = static_cast<WiFiChannel>(
116 kWiFiChannel5180 +
117 (frequency - kWiFiFrequency5180) / kWiFiBandwidth20MHz);
118 } else if (kWiFiFrequency5500 <= frequency &&
119 frequency <= kWiFiFrequency5700) {
120 if (((frequency - kWiFiFrequency5500) % kWiFiBandwidth20MHz) == 0)
121 channel = static_cast<WiFiChannel>(
122 kWiFiChannel5500 +
123 (frequency - kWiFiFrequency5500) / kWiFiBandwidth20MHz);
124 } else if (kWiFiFrequency5745 <= frequency &&
125 frequency <= kWiFiFrequency5825) {
126 if (((frequency - kWiFiFrequency5745) % kWiFiBandwidth20MHz) == 0)
127 channel = static_cast<WiFiChannel>(
128 kWiFiChannel5745 +
129 (frequency - kWiFiFrequency5745) / kWiFiBandwidth20MHz);
130 }
131 CHECK(kWiFiChannelUndef <= channel && channel < kWiFiChannelMax);
132
133 if (channel == kWiFiChannelUndef)
134 LOG(WARNING) << "no mapping for frequency " << frequency;
135 else
136 VLOG(3) << "map " << frequency << " to " << channel;
137
138 return channel;
139}
140
Thieu Lead1ec2c2012-01-05 23:39:48 +0000141// static
142Metrics::WiFiSecurity Metrics::WiFiSecurityStringToEnum(
143 const std::string &security) {
144 if (security == flimflam::kSecurityNone) {
145 return kWiFiSecurityNone;
146 } else if (security == flimflam::kSecurityWep) {
147 return kWiFiSecurityWep;
148 } else if (security == flimflam::kSecurityWpa) {
149 return kWiFiSecurityWpa;
150 } else if (security == flimflam::kSecurityRsn) {
151 return kWiFiSecurityRsn;
152 } else if (security == flimflam::kSecurity8021x) {
153 return kWiFiSecurity8021x;
154 } else if (security == flimflam::kSecurityPsk) {
155 return kWiFiSecurityPsk;
156 } else {
157 return kWiFiSecurityUnknown;
158 }
159}
160
Thieu Le48e6d6d2011-12-06 00:40:27 +0000161void Metrics::RegisterService(const Service *service) {
162 shared_ptr<ServiceMetrics> service_metrics(new ServiceMetrics);
163 services_metrics_[service] = service_metrics;
164 service_metrics->service = service;
165 InitializeCommonServiceMetrics(service);
166 service->InitializeCustomMetrics();
167}
168
169void Metrics::DeregisterService(const Service *service) {
170 services_metrics_.erase(service);
171}
172
173void Metrics::AddServiceStateTransitionTimer(
174 const Service *service,
175 const string &histogram_name,
176 Service::ConnectState start_state,
177 Service::ConnectState stop_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 CHECK(start_state < stop_state);
186 chromeos_metrics::TimerReporter *timer =
187 new chromeos_metrics::TimerReporter(histogram_name,
Thieu Lea20cbc22012-01-09 22:01:43 +0000188 kTimerHistogramMillisecondsMin,
189 kTimerHistogramMillisecondsMax,
Thieu Le48e6d6d2011-12-06 00:40:27 +0000190 kTimerHistogramNumBuckets);
191 service_metrics->timers.push_back(timer); // passes ownership.
192 service_metrics->start_on_state[start_state].push_back(timer);
193 service_metrics->stop_on_state[stop_state].push_back(timer);
194}
195
Thieu Lea20cbc22012-01-09 22:01:43 +0000196void Metrics::NotifyDefaultServiceChanged(const Service *service) {
197 base::TimeDelta elapsed_seconds;
198
199 Technology::Identifier technology = (service) ? service->technology() :
200 Technology::kUnknown;
201 if (technology != last_default_technology_) {
202 if (last_default_technology_ != Technology::kUnknown) {
203 string histogram = GetFullMetricName(kMetricTimeOnlineSeconds,
204 last_default_technology_);
205 time_online_timer_->GetElapsedTime(&elapsed_seconds);
206 SendToUMA(histogram,
207 elapsed_seconds.InSeconds(),
208 kMetricTimeOnlineSecondsMin,
209 kMetricTimeOnlineSecondsMax,
210 kTimerHistogramNumBuckets);
211 }
212 last_default_technology_ = technology;
213 time_online_timer_->Start();
214 }
215
Thieu Lea20cbc22012-01-09 22:01:43 +0000216 // Ignore changes that are not online/offline transitions; e.g.
217 // switching between wired and wireless. TimeToDrop measures
218 // time online regardless of how we are connected.
219 if ((service == NULL && !was_online_) || (service != NULL && was_online_))
220 return;
221
222 if (service == NULL) {
223 time_to_drop_timer_->GetElapsedTime(&elapsed_seconds);
224 SendToUMA(kMetricTimeToDropSeconds,
225 elapsed_seconds.InSeconds(),
226 kMetricTimeToDropSecondsMin,
227 kMetricTimeToDropSecondsMax,
228 kTimerHistogramNumBuckets);
229 } else {
230 time_to_drop_timer_->Start();
231 }
232
233 was_online_ = (service != NULL);
Thieu Le48e6d6d2011-12-06 00:40:27 +0000234}
235
236void Metrics::NotifyServiceStateChanged(const Service *service,
237 Service::ConnectState new_state) {
238 ServiceMetricsLookupMap::iterator it = services_metrics_.find(service);
239 if (it == services_metrics_.end()) {
240 VLOG(1) << "service not found";
241 DCHECK(false);
242 return;
243 }
244 ServiceMetrics *service_metrics = it->second.get();
245 UpdateServiceStateTransitionMetrics(service_metrics, new_state);
246
247 if (new_state == Service::kStateFailure)
248 SendServiceFailure(service);
249
Paul Stewart20088d82012-02-16 06:58:55 -0800250 if (new_state != Service::kStateConnected)
Thieu Le48e6d6d2011-12-06 00:40:27 +0000251 return;
252
Thieu Leb84ba342012-03-02 15:15:19 -0800253 base::TimeDelta time_resume_to_ready;
254 time_resume_to_ready_timer_->GetElapsedTime(&time_resume_to_ready);
255 time_resume_to_ready_timer_->Reset();
256 service->SendPostReadyStateMetrics(time_resume_to_ready.InMilliseconds());
Thieu Le48e6d6d2011-12-06 00:40:27 +0000257}
258
259string Metrics::GetFullMetricName(const char *metric_name,
260 Technology::Identifier technology_id) {
261 string technology = Technology::NameFromIdentifier(technology_id);
262 technology[0] = base::ToUpperASCII(technology[0]);
263 return base::StringPrintf(metric_name, technology.c_str());
264}
265
Thieu Le67370f62012-02-14 23:01:42 +0000266void Metrics::NotifyServiceDisconnect(const Service *service) {
267 Technology::Identifier technology = service->technology();
268 string histogram = GetFullMetricName(kMetricDisconnect, technology);
269 SendToUMA(histogram,
270 service->explicitly_disconnected(),
271 kMetricDisconnectMin,
272 kMetricDisconnectMax,
273 kMetricDisconnectNumBuckets);
Thieu Le48e6d6d2011-12-06 00:40:27 +0000274}
275
Thieu Leb84ba342012-03-02 15:15:19 -0800276void Metrics::NotifyPowerStateChange(PowerManager::SuspendState new_state) {
277 if (new_state == PowerManagerProxyDelegate::kOn) {
278 time_resume_to_ready_timer_->Start();
279 } else {
280 time_resume_to_ready_timer_->Reset();
281 }
Thieu Le48e6d6d2011-12-06 00:40:27 +0000282}
283
284bool Metrics::SendEnumToUMA(const string &name, int sample, int max) {
285 return library_->SendEnumToUMA(name, sample, max);
286}
287
Thieu Lea20cbc22012-01-09 22:01:43 +0000288bool Metrics::SendToUMA(const string &name, int sample, int min, int max,
289 int num_buckets) {
290 return library_->SendToUMA(name, sample, min, max, num_buckets);
291}
292
Thieu Le48e6d6d2011-12-06 00:40:27 +0000293void Metrics::InitializeCommonServiceMetrics(const Service *service) {
294 Technology::Identifier technology = service->technology();
295 string histogram = GetFullMetricName(kMetricTimeToConfigMilliseconds,
296 technology);
297 AddServiceStateTransitionTimer(
298 service,
299 histogram,
300 Service::kStateConfiguring,
Paul Stewart20088d82012-02-16 06:58:55 -0800301 Service::kStateConnected);
Thieu Le48e6d6d2011-12-06 00:40:27 +0000302 histogram = GetFullMetricName(kMetricTimeToPortalMilliseconds, technology);
303 AddServiceStateTransitionTimer(
304 service,
305 histogram,
Paul Stewart20088d82012-02-16 06:58:55 -0800306 Service::kStateConnected,
Thieu Le48e6d6d2011-12-06 00:40:27 +0000307 Service::kStatePortal);
308 histogram = GetFullMetricName(kMetricTimeToOnlineMilliseconds, technology);
309 AddServiceStateTransitionTimer(
310 service,
311 histogram,
Paul Stewart20088d82012-02-16 06:58:55 -0800312 Service::kStateConnected,
Thieu Le48e6d6d2011-12-06 00:40:27 +0000313 Service::kStateOnline);
314}
315
316void Metrics::UpdateServiceStateTransitionMetrics(
317 ServiceMetrics *service_metrics,
318 Service::ConnectState new_state) {
319 TimerReportersList::iterator it;
320 TimerReportersList &start_timers = service_metrics->start_on_state[new_state];
321 for (it = start_timers.begin(); it != start_timers.end(); ++it)
322 (*it)->Start();
323
324 TimerReportersList &stop_timers = service_metrics->stop_on_state[new_state];
325 for (it = stop_timers.begin(); it != stop_timers.end(); ++it) {
326 (*it)->Stop();
327 (*it)->ReportMilliseconds();
328 }
329}
330
331void Metrics::SendServiceFailure(const Service *service) {
332 library_->SendEnumToUMA(kMetricNetworkServiceErrors,
333 service->failure(),
334 kMetricNetworkServiceErrorsMax);
335}
336
337void Metrics::set_library(MetricsLibraryInterface *library) {
338 chromeos_metrics::TimerReporter::set_metrics_lib(library);
339 library_ = library;
340}
341
342} // namespace shill