blob: 629a10c0e4e4b38e2fcc11b260decdbd3a698173 [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;
Thieu Lea20cbc22012-01-09 22:01:43 +000032
33const char Metrics::kMetricTimeOnlineSeconds[] = "Network.Shill.%s.TimeOnline";
34const int Metrics::kMetricTimeOnlineSecondsMax = 8 * 60 * 60; // 8 hours
35const int Metrics::kMetricTimeOnlineSecondsMin = 1;
36
37const char Metrics::kMetricTimeToDropSeconds[] = "Network.Shill.TimeToDrop";;
38const int Metrics::kMetricTimeToDropSecondsMax = 8 * 60 * 60; // 8 hours
39const int Metrics::kMetricTimeToDropSecondsMin = 1;
40
Thieu Le48e6d6d2011-12-06 00:40:27 +000041const char Metrics::kMetricTimeToConfigMilliseconds[] =
42 "Network.Shill.%s.TimeToConfig";
43const char Metrics::kMetricTimeToJoinMilliseconds[] =
44 "Network.Shill.%s.TimeToJoin";
45const char Metrics::kMetricTimeToOnlineMilliseconds[] =
46 "Network.Shill.%s.TimeToOnline";
47const char Metrics::kMetricTimeToPortalMilliseconds[] =
48 "Network.Shill.%s.TimeToPortal";
Thieu Lea20cbc22012-01-09 22:01:43 +000049const int Metrics::kTimerHistogramMillisecondsMax = 45 * 1000;
50const int Metrics::kTimerHistogramMillisecondsMin = 1;
Thieu Le48e6d6d2011-12-06 00:40:27 +000051const int Metrics::kTimerHistogramNumBuckets = 50;
52
53// static
54const uint16 Metrics::kWiFiBandwidth5MHz = 5;
55const uint16 Metrics::kWiFiBandwidth20MHz = 20;
56const uint16 Metrics::kWiFiFrequency2412 = 2412;
57const uint16 Metrics::kWiFiFrequency2472 = 2472;
58const uint16 Metrics::kWiFiFrequency2484 = 2484;
59const uint16 Metrics::kWiFiFrequency5170 = 5170;
60const uint16 Metrics::kWiFiFrequency5180 = 5180;
61const uint16 Metrics::kWiFiFrequency5230 = 5230;
62const uint16 Metrics::kWiFiFrequency5240 = 5240;
63const uint16 Metrics::kWiFiFrequency5320 = 5320;
64const uint16 Metrics::kWiFiFrequency5500 = 5500;
65const uint16 Metrics::kWiFiFrequency5700 = 5700;
66const uint16 Metrics::kWiFiFrequency5745 = 5745;
67const uint16 Metrics::kWiFiFrequency5825 = 5825;
68
Thieu Lea20cbc22012-01-09 22:01:43 +000069Metrics::Metrics()
70 : library_(&metrics_library_),
71 last_default_technology_(Technology::kUnknown),
72 was_online_(false),
73 time_online_timer_(new chromeos_metrics::Timer),
74 time_to_drop_timer_(new chromeos_metrics::Timer) {
Thieu Le48e6d6d2011-12-06 00:40:27 +000075 metrics_library_.Init();
76 chromeos_metrics::TimerReporter::set_metrics_lib(library_);
77}
78
79Metrics::~Metrics() {}
80
81// static
Thieu Le48e6d6d2011-12-06 00:40:27 +000082Metrics::WiFiChannel Metrics::WiFiFrequencyToChannel(uint16 frequency) {
83 WiFiChannel channel = kWiFiChannelUndef;
84 if (kWiFiFrequency2412 <= frequency && frequency <= kWiFiFrequency2472) {
85 if (((frequency - kWiFiFrequency2412) % kWiFiBandwidth5MHz) == 0)
86 channel = static_cast<WiFiChannel>(
87 kWiFiChannel2412 +
88 (frequency - kWiFiFrequency2412) / kWiFiBandwidth5MHz);
89 } else if (frequency == kWiFiFrequency2484) {
90 channel = kWiFiChannel2484;
91 } else if (kWiFiFrequency5170 <= frequency &&
92 frequency <= kWiFiFrequency5230) {
93 if ((frequency % kWiFiBandwidth20MHz) == 0)
94 channel = static_cast<WiFiChannel>(
95 kWiFiChannel5180 +
96 (frequency - kWiFiFrequency5180) / kWiFiBandwidth20MHz);
97 if ((frequency % kWiFiBandwidth20MHz) == 10)
98 channel = static_cast<WiFiChannel>(
99 kWiFiChannel5170 +
100 (frequency - kWiFiFrequency5170) / kWiFiBandwidth20MHz);
101 } else if (kWiFiFrequency5240 <= frequency &&
102 frequency <= kWiFiFrequency5320) {
103 if (((frequency - kWiFiFrequency5180) % kWiFiBandwidth20MHz) == 0)
104 channel = static_cast<WiFiChannel>(
105 kWiFiChannel5180 +
106 (frequency - kWiFiFrequency5180) / kWiFiBandwidth20MHz);
107 } else if (kWiFiFrequency5500 <= frequency &&
108 frequency <= kWiFiFrequency5700) {
109 if (((frequency - kWiFiFrequency5500) % kWiFiBandwidth20MHz) == 0)
110 channel = static_cast<WiFiChannel>(
111 kWiFiChannel5500 +
112 (frequency - kWiFiFrequency5500) / kWiFiBandwidth20MHz);
113 } else if (kWiFiFrequency5745 <= frequency &&
114 frequency <= kWiFiFrequency5825) {
115 if (((frequency - kWiFiFrequency5745) % kWiFiBandwidth20MHz) == 0)
116 channel = static_cast<WiFiChannel>(
117 kWiFiChannel5745 +
118 (frequency - kWiFiFrequency5745) / kWiFiBandwidth20MHz);
119 }
120 CHECK(kWiFiChannelUndef <= channel && channel < kWiFiChannelMax);
121
122 if (channel == kWiFiChannelUndef)
123 LOG(WARNING) << "no mapping for frequency " << frequency;
124 else
125 VLOG(3) << "map " << frequency << " to " << channel;
126
127 return channel;
128}
129
Thieu Lead1ec2c2012-01-05 23:39:48 +0000130// static
131Metrics::WiFiSecurity Metrics::WiFiSecurityStringToEnum(
132 const std::string &security) {
133 if (security == flimflam::kSecurityNone) {
134 return kWiFiSecurityNone;
135 } else if (security == flimflam::kSecurityWep) {
136 return kWiFiSecurityWep;
137 } else if (security == flimflam::kSecurityWpa) {
138 return kWiFiSecurityWpa;
139 } else if (security == flimflam::kSecurityRsn) {
140 return kWiFiSecurityRsn;
141 } else if (security == flimflam::kSecurity8021x) {
142 return kWiFiSecurity8021x;
143 } else if (security == flimflam::kSecurityPsk) {
144 return kWiFiSecurityPsk;
145 } else {
146 return kWiFiSecurityUnknown;
147 }
148}
149
Thieu Le48e6d6d2011-12-06 00:40:27 +0000150void Metrics::RegisterService(const Service *service) {
151 shared_ptr<ServiceMetrics> service_metrics(new ServiceMetrics);
152 services_metrics_[service] = service_metrics;
153 service_metrics->service = service;
154 InitializeCommonServiceMetrics(service);
155 service->InitializeCustomMetrics();
156}
157
158void Metrics::DeregisterService(const Service *service) {
159 services_metrics_.erase(service);
160}
161
162void Metrics::AddServiceStateTransitionTimer(
163 const Service *service,
164 const string &histogram_name,
165 Service::ConnectState start_state,
166 Service::ConnectState stop_state) {
167 ServiceMetricsLookupMap::iterator it = services_metrics_.find(service);
168 if (it == services_metrics_.end()) {
169 VLOG(1) << "service not found";
170 DCHECK(false);
171 return;
172 }
173 ServiceMetrics *service_metrics = it->second.get();
174 CHECK(start_state < stop_state);
175 chromeos_metrics::TimerReporter *timer =
176 new chromeos_metrics::TimerReporter(histogram_name,
Thieu Lea20cbc22012-01-09 22:01:43 +0000177 kTimerHistogramMillisecondsMin,
178 kTimerHistogramMillisecondsMax,
Thieu Le48e6d6d2011-12-06 00:40:27 +0000179 kTimerHistogramNumBuckets);
180 service_metrics->timers.push_back(timer); // passes ownership.
181 service_metrics->start_on_state[start_state].push_back(timer);
182 service_metrics->stop_on_state[stop_state].push_back(timer);
183}
184
Thieu Lea20cbc22012-01-09 22:01:43 +0000185void Metrics::NotifyDefaultServiceChanged(const Service *service) {
186 base::TimeDelta elapsed_seconds;
187
188 Technology::Identifier technology = (service) ? service->technology() :
189 Technology::kUnknown;
190 if (technology != last_default_technology_) {
191 if (last_default_technology_ != Technology::kUnknown) {
192 string histogram = GetFullMetricName(kMetricTimeOnlineSeconds,
193 last_default_technology_);
194 time_online_timer_->GetElapsedTime(&elapsed_seconds);
195 SendToUMA(histogram,
196 elapsed_seconds.InSeconds(),
197 kMetricTimeOnlineSecondsMin,
198 kMetricTimeOnlineSecondsMax,
199 kTimerHistogramNumBuckets);
200 }
201 last_default_technology_ = technology;
202 time_online_timer_->Start();
203 }
204
205 // TODO(thieule): Ignore changes when suspending.
206 // crosbug.com/24440
207
208 // Ignore changes that are not online/offline transitions; e.g.
209 // switching between wired and wireless. TimeToDrop measures
210 // time online regardless of how we are connected.
211 if ((service == NULL && !was_online_) || (service != NULL && was_online_))
212 return;
213
214 if (service == NULL) {
215 time_to_drop_timer_->GetElapsedTime(&elapsed_seconds);
216 SendToUMA(kMetricTimeToDropSeconds,
217 elapsed_seconds.InSeconds(),
218 kMetricTimeToDropSecondsMin,
219 kMetricTimeToDropSecondsMax,
220 kTimerHistogramNumBuckets);
221 } else {
222 time_to_drop_timer_->Start();
223 }
224
225 was_online_ = (service != NULL);
Thieu Le48e6d6d2011-12-06 00:40:27 +0000226}
227
228void Metrics::NotifyServiceStateChanged(const Service *service,
229 Service::ConnectState new_state) {
230 ServiceMetricsLookupMap::iterator it = services_metrics_.find(service);
231 if (it == services_metrics_.end()) {
232 VLOG(1) << "service not found";
233 DCHECK(false);
234 return;
235 }
236 ServiceMetrics *service_metrics = it->second.get();
237 UpdateServiceStateTransitionMetrics(service_metrics, new_state);
238
239 if (new_state == Service::kStateFailure)
240 SendServiceFailure(service);
241
242 if (new_state != Service::kStateReady)
243 return;
244
245 service->SendPostReadyStateMetrics();
246}
247
248string Metrics::GetFullMetricName(const char *metric_name,
249 Technology::Identifier technology_id) {
250 string technology = Technology::NameFromIdentifier(technology_id);
251 technology[0] = base::ToUpperASCII(technology[0]);
252 return base::StringPrintf(metric_name, technology.c_str());
253}
254
255void Metrics::NotifyServiceDisconnect(const Service */*service*/,
256 bool /*manual_disconnect*/) {
257 // TODO(thieule): Handle service disconnects.
258 // crosbug.com/23253
259}
260
261void Metrics::NotifyPower() {
262 // TODO(thieule): Handle suspend and resume.
263 // crosbug.com/24440
264}
265
266bool Metrics::SendEnumToUMA(const string &name, int sample, int max) {
267 return library_->SendEnumToUMA(name, sample, max);
268}
269
Thieu Lea20cbc22012-01-09 22:01:43 +0000270bool Metrics::SendToUMA(const string &name, int sample, int min, int max,
271 int num_buckets) {
272 return library_->SendToUMA(name, sample, min, max, num_buckets);
273}
274
Thieu Le48e6d6d2011-12-06 00:40:27 +0000275void Metrics::InitializeCommonServiceMetrics(const Service *service) {
276 Technology::Identifier technology = service->technology();
277 string histogram = GetFullMetricName(kMetricTimeToConfigMilliseconds,
278 technology);
279 AddServiceStateTransitionTimer(
280 service,
281 histogram,
282 Service::kStateConfiguring,
283 Service::kStateReady);
284 histogram = GetFullMetricName(kMetricTimeToPortalMilliseconds, technology);
285 AddServiceStateTransitionTimer(
286 service,
287 histogram,
288 Service::kStateReady,
289 Service::kStatePortal);
290 histogram = GetFullMetricName(kMetricTimeToOnlineMilliseconds, technology);
291 AddServiceStateTransitionTimer(
292 service,
293 histogram,
294 Service::kStateReady,
295 Service::kStateOnline);
296}
297
298void Metrics::UpdateServiceStateTransitionMetrics(
299 ServiceMetrics *service_metrics,
300 Service::ConnectState new_state) {
301 TimerReportersList::iterator it;
302 TimerReportersList &start_timers = service_metrics->start_on_state[new_state];
303 for (it = start_timers.begin(); it != start_timers.end(); ++it)
304 (*it)->Start();
305
306 TimerReportersList &stop_timers = service_metrics->stop_on_state[new_state];
307 for (it = stop_timers.begin(); it != stop_timers.end(); ++it) {
308 (*it)->Stop();
309 (*it)->ReportMilliseconds();
310 }
311}
312
313void Metrics::SendServiceFailure(const Service *service) {
314 library_->SendEnumToUMA(kMetricNetworkServiceErrors,
315 service->failure(),
316 kMetricNetworkServiceErrorsMax);
317}
318
319void Metrics::set_library(MetricsLibraryInterface *library) {
320 chromeos_metrics::TimerReporter::set_metrics_lib(library);
321 library_ = library;
322}
323
324} // namespace shill