blob: 9bc7e9e51d07fc15981137d91bab243ece090190 [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
Thieu Le48e6d6d2011-12-06 00:40:27 +00007#include <base/string_util.h>
8#include <base/stringprintf.h>
Thieu Lead1ec2c2012-01-05 23:39:48 +00009#include <chromeos/dbus/service_constants.h>
Darin Petkov58f0b6d2012-06-12 12:52:30 +020010#include <metrics/bootstat.h>
Thieu Le48e6d6d2011-12-06 00:40:27 +000011
Wade Guthried4977f22012-08-22 12:37:54 -070012#include "shill/ieee80211.h"
Paul Stewartff845fc2012-08-07 07:28:44 -070013#include "shill/link_monitor.h"
Christopher Wileyb691efd2012-08-09 13:51:51 -070014#include "shill/logging.h"
Thieu Le48e6d6d2011-12-06 00:40:27 +000015#include "shill/wifi_service.h"
16
17using std::string;
18using std::tr1::shared_ptr;
19
20namespace shill {
21
Thieu Le48e6d6d2011-12-06 00:40:27 +000022// static
Thieu Lec31e6f92012-08-03 13:08:58 -070023// Our disconnect enumeration values are 0 (System Disconnect) and
24// 1 (User Disconnect), see histograms.xml, but Chrome needs a minimum
25// enum value of 1 and the minimum number of buckets needs to be 3 (see
26// histogram.h). Instead of remapping System Disconnect to 1 and
27// User Disconnect to 2, we can just leave the enumerated values as-is
28// because Chrome implicitly creates a [0-1) bucket for us. Using Min=1,
29// Max=2 and NumBuckets=3 gives us the following three buckets:
30// [0-1), [1-2), [2-INT_MAX). We end up with an extra bucket [2-INT_MAX)
31// that we can safely ignore.
Thieu Le67370f62012-02-14 23:01:42 +000032const char Metrics::kMetricDisconnect[] = "Network.Shill.%s.Disconnect";
Thieu Lec31e6f92012-08-03 13:08:58 -070033const int Metrics::kMetricDisconnectMax = 2;
34const int Metrics::kMetricDisconnectMin = 1;
35const int Metrics::kMetricDisconnectNumBuckets = 3;
Thieu Le67370f62012-02-14 23:01:42 +000036
Thieu Le48e6d6d2011-12-06 00:40:27 +000037const char Metrics::kMetricNetworkChannel[] = "Network.Shill.%s.Channel";
38const int Metrics::kMetricNetworkChannelMax = Metrics::kWiFiChannelMax;
Thieu Lead1ec2c2012-01-05 23:39:48 +000039const char Metrics::kMetricNetworkPhyMode[] = "Network.Shill.%s.PhyMode";
40const int Metrics::kMetricNetworkPhyModeMax = Metrics::kWiFiNetworkPhyModeMax;
41const char Metrics::kMetricNetworkSecurity[] = "Network.Shill.%s.Security";
42const int Metrics::kMetricNetworkSecurityMax = Metrics::kWiFiSecurityMax;
Thieu Le48e6d6d2011-12-06 00:40:27 +000043const char Metrics::kMetricNetworkServiceErrors[] =
44 "Network.Shill.ServiceErrors";
45const int Metrics::kMetricNetworkServiceErrorsMax = Service::kFailureMax;
Thieu Lea20cbc22012-01-09 22:01:43 +000046
47const char Metrics::kMetricTimeOnlineSeconds[] = "Network.Shill.%s.TimeOnline";
48const int Metrics::kMetricTimeOnlineSecondsMax = 8 * 60 * 60; // 8 hours
49const int Metrics::kMetricTimeOnlineSecondsMin = 1;
50
51const char Metrics::kMetricTimeToDropSeconds[] = "Network.Shill.TimeToDrop";;
52const int Metrics::kMetricTimeToDropSecondsMax = 8 * 60 * 60; // 8 hours
53const int Metrics::kMetricTimeToDropSecondsMin = 1;
54
Thieu Leb84ba342012-03-02 15:15:19 -080055const char Metrics::kMetricTimeResumeToReadyMilliseconds[] =
56 "Network.Shill.%s.TimeResumeToReady";
Thieu Le48e6d6d2011-12-06 00:40:27 +000057const char Metrics::kMetricTimeToConfigMilliseconds[] =
58 "Network.Shill.%s.TimeToConfig";
59const char Metrics::kMetricTimeToJoinMilliseconds[] =
60 "Network.Shill.%s.TimeToJoin";
61const char Metrics::kMetricTimeToOnlineMilliseconds[] =
62 "Network.Shill.%s.TimeToOnline";
63const char Metrics::kMetricTimeToPortalMilliseconds[] =
64 "Network.Shill.%s.TimeToPortal";
Thieu Lea20cbc22012-01-09 22:01:43 +000065const int Metrics::kTimerHistogramMillisecondsMax = 45 * 1000;
66const int Metrics::kTimerHistogramMillisecondsMin = 1;
Thieu Le48e6d6d2011-12-06 00:40:27 +000067const int Metrics::kTimerHistogramNumBuckets = 50;
68
Thieu Le85e050b2012-03-13 15:04:38 -070069const char Metrics::kMetricPortalAttempts[] =
70 "Network.Shill.%s.PortalAttempts";
71const int Metrics::kMetricPortalAttemptsMax =
72 PortalDetector::kMaxRequestAttempts;
73const int Metrics::kMetricPortalAttemptsMin = 1;
74const int Metrics::kMetricPortalAttemptsNumBuckets =
75 Metrics::kMetricPortalAttemptsMax;
76
77const char Metrics::kMetricPortalAttemptsToOnline[] =
78 "Network.Shill.%s.PortalAttemptsToOnline";
79const int Metrics::kMetricPortalAttemptsToOnlineMax = 100;
80const int Metrics::kMetricPortalAttemptsToOnlineMin = 1;
81const int Metrics::kMetricPortalAttemptsToOnlineNumBuckets = 10;
82
83const char Metrics::kMetricPortalResult[] = "Network.Shill.%s.PortalResult";
84
Thieu Le48e6d6d2011-12-06 00:40:27 +000085// static
86const uint16 Metrics::kWiFiBandwidth5MHz = 5;
87const uint16 Metrics::kWiFiBandwidth20MHz = 20;
88const uint16 Metrics::kWiFiFrequency2412 = 2412;
89const uint16 Metrics::kWiFiFrequency2472 = 2472;
90const uint16 Metrics::kWiFiFrequency2484 = 2484;
91const uint16 Metrics::kWiFiFrequency5170 = 5170;
92const uint16 Metrics::kWiFiFrequency5180 = 5180;
93const uint16 Metrics::kWiFiFrequency5230 = 5230;
94const uint16 Metrics::kWiFiFrequency5240 = 5240;
95const uint16 Metrics::kWiFiFrequency5320 = 5320;
96const uint16 Metrics::kWiFiFrequency5500 = 5500;
97const uint16 Metrics::kWiFiFrequency5700 = 5700;
98const uint16 Metrics::kWiFiFrequency5745 = 5745;
99const uint16 Metrics::kWiFiFrequency5825 = 5825;
100
Thieu Leb84ba342012-03-02 15:15:19 -0800101// static
102const char Metrics::kMetricPowerManagerKey[] = "metrics";
103
Paul Stewartff845fc2012-08-07 07:28:44 -0700104// static
105const char Metrics::kMetricLinkMonitorFailure[] =
106 "Network.Shill.%s.LinkMonitorFailure";
107const char Metrics::kMetricLinkMonitorResponseTimeSample[] =
108 "Network.Shill.%s.LinkMonitorResponseTimeSample";
Paul Stewart0443aa52012-08-09 10:43:50 -0700109const unsigned int Metrics::kMetricLinkMonitorResponseTimeSampleMin = 0;
110const unsigned int Metrics::kMetricLinkMonitorResponseTimeSampleMax =
Paul Stewartff845fc2012-08-07 07:28:44 -0700111 LinkMonitor::kTestPeriodMilliseconds;
112const int Metrics::kMetricLinkMonitorResponseTimeSampleNumBuckets = 50;
Paul Stewart0443aa52012-08-09 10:43:50 -0700113const char Metrics::kMetricLinkMonitorSecondsToFailure[] =
114 "Network.Shill.%s.LinkMonitorSecondsToFailure";
115const unsigned int Metrics::kMetricLinkMonitorSecondsToFailureMin = 0;
116const unsigned int Metrics::kMetricLinkMonitorSecondsToFailureMax = 7200;
117const int Metrics::kMetricLinkMonitorSecondsToFailureNumBuckets = 50;
118const char Metrics::kMetricLinkMonitorBroadcastErrorsAtFailure[] =
119 "Network.Shill.%s.LinkMonitorBroadcastErrorsAtFailure";
120const char Metrics::kMetricLinkMonitorUnicastErrorsAtFailure[] =
121 "Network.Shill.%s.LinkMonitorUnicastErrorsAtFailure";
122const unsigned int Metrics::kMetricLinkMonitorErrorCountMin = 0;
123const unsigned int Metrics::kMetricLinkMonitorErrorCountMax =
124 LinkMonitor::kFailureThreshold;
125const int Metrics::kMetricLinkMonitorErrorCountNumBuckets =
126 LinkMonitor::kFailureThreshold + 1;
Paul Stewartff845fc2012-08-07 07:28:44 -0700127
Wade Guthried4977f22012-08-22 12:37:54 -0700128// static
129const char Metrics::kMetricLinkClientDisconnectReason[] =
130 "Network.Shill.WiFi.ClientDisconnectReason";
131const char Metrics::kMetricLinkApDisconnectReason[] =
132 "Network.Shill.WiFi.ApDisconnectReason";
133const char Metrics::kMetricLinkClientDisconnectType[] =
134 "Network.Shill.WiFi.ClientDisconnectType";
135const char Metrics::kMetricLinkApDisconnectType[] =
136 "Network.Shill.WiFi.ApDisconnectType";
137
138
Thieu Lea20cbc22012-01-09 22:01:43 +0000139Metrics::Metrics()
140 : library_(&metrics_library_),
141 last_default_technology_(Technology::kUnknown),
142 was_online_(false),
143 time_online_timer_(new chromeos_metrics::Timer),
Thieu Leb84ba342012-03-02 15:15:19 -0800144 time_to_drop_timer_(new chromeos_metrics::Timer),
Darin Petkov58f0b6d2012-06-12 12:52:30 +0200145 time_resume_to_ready_timer_(new chromeos_metrics::Timer),
146 collect_bootstats_(true) {
Thieu Le48e6d6d2011-12-06 00:40:27 +0000147 metrics_library_.Init();
148 chromeos_metrics::TimerReporter::set_metrics_lib(library_);
149}
150
151Metrics::~Metrics() {}
152
153// static
Thieu Le48e6d6d2011-12-06 00:40:27 +0000154Metrics::WiFiChannel Metrics::WiFiFrequencyToChannel(uint16 frequency) {
155 WiFiChannel channel = kWiFiChannelUndef;
156 if (kWiFiFrequency2412 <= frequency && frequency <= kWiFiFrequency2472) {
157 if (((frequency - kWiFiFrequency2412) % kWiFiBandwidth5MHz) == 0)
158 channel = static_cast<WiFiChannel>(
159 kWiFiChannel2412 +
160 (frequency - kWiFiFrequency2412) / kWiFiBandwidth5MHz);
161 } else if (frequency == kWiFiFrequency2484) {
162 channel = kWiFiChannel2484;
163 } else if (kWiFiFrequency5170 <= frequency &&
164 frequency <= kWiFiFrequency5230) {
165 if ((frequency % kWiFiBandwidth20MHz) == 0)
166 channel = static_cast<WiFiChannel>(
167 kWiFiChannel5180 +
168 (frequency - kWiFiFrequency5180) / kWiFiBandwidth20MHz);
169 if ((frequency % kWiFiBandwidth20MHz) == 10)
170 channel = static_cast<WiFiChannel>(
171 kWiFiChannel5170 +
172 (frequency - kWiFiFrequency5170) / kWiFiBandwidth20MHz);
173 } else if (kWiFiFrequency5240 <= frequency &&
174 frequency <= kWiFiFrequency5320) {
175 if (((frequency - kWiFiFrequency5180) % kWiFiBandwidth20MHz) == 0)
176 channel = static_cast<WiFiChannel>(
177 kWiFiChannel5180 +
178 (frequency - kWiFiFrequency5180) / kWiFiBandwidth20MHz);
179 } else if (kWiFiFrequency5500 <= frequency &&
180 frequency <= kWiFiFrequency5700) {
181 if (((frequency - kWiFiFrequency5500) % kWiFiBandwidth20MHz) == 0)
182 channel = static_cast<WiFiChannel>(
183 kWiFiChannel5500 +
184 (frequency - kWiFiFrequency5500) / kWiFiBandwidth20MHz);
185 } else if (kWiFiFrequency5745 <= frequency &&
186 frequency <= kWiFiFrequency5825) {
187 if (((frequency - kWiFiFrequency5745) % kWiFiBandwidth20MHz) == 0)
188 channel = static_cast<WiFiChannel>(
189 kWiFiChannel5745 +
190 (frequency - kWiFiFrequency5745) / kWiFiBandwidth20MHz);
191 }
192 CHECK(kWiFiChannelUndef <= channel && channel < kWiFiChannelMax);
193
194 if (channel == kWiFiChannelUndef)
195 LOG(WARNING) << "no mapping for frequency " << frequency;
196 else
Ben Chanfad4a0b2012-04-18 15:49:59 -0700197 SLOG(Metrics, 3) << "map " << frequency << " to " << channel;
Thieu Le48e6d6d2011-12-06 00:40:27 +0000198
199 return channel;
200}
201
Thieu Lead1ec2c2012-01-05 23:39:48 +0000202// static
203Metrics::WiFiSecurity Metrics::WiFiSecurityStringToEnum(
204 const std::string &security) {
205 if (security == flimflam::kSecurityNone) {
206 return kWiFiSecurityNone;
207 } else if (security == flimflam::kSecurityWep) {
208 return kWiFiSecurityWep;
209 } else if (security == flimflam::kSecurityWpa) {
210 return kWiFiSecurityWpa;
211 } else if (security == flimflam::kSecurityRsn) {
212 return kWiFiSecurityRsn;
213 } else if (security == flimflam::kSecurity8021x) {
214 return kWiFiSecurity8021x;
215 } else if (security == flimflam::kSecurityPsk) {
216 return kWiFiSecurityPsk;
217 } else {
218 return kWiFiSecurityUnknown;
219 }
220}
221
Thieu Le85e050b2012-03-13 15:04:38 -0700222// static
223Metrics::PortalResult Metrics::PortalDetectionResultToEnum(
224 const PortalDetector::Result &result) {
225 DCHECK(result.final);
226 PortalResult retval = kPortalResultUnknown;
227 // The only time we should end a successful portal detection is when we're
228 // in the Content phase. If we end with kStatusSuccess in any other phase,
229 // then this indicates that something bad has happened.
230 switch (result.phase) {
231 case PortalDetector::kPhaseDNS:
232 if (result.status == PortalDetector::kStatusFailure)
233 retval = kPortalResultDNSFailure;
234 else if (result.status == PortalDetector::kStatusTimeout)
235 retval = kPortalResultDNSTimeout;
236 else
237 LOG(DFATAL) << __func__ << ": Final result status " << result.status
238 << " is not allowed in the DNS phase";
239 break;
240
241 case PortalDetector::kPhaseConnection:
242 if (result.status == PortalDetector::kStatusFailure)
243 retval = kPortalResultConnectionFailure;
244 else if (result.status == PortalDetector::kStatusTimeout)
245 retval = kPortalResultConnectionTimeout;
246 else
247 LOG(DFATAL) << __func__ << ": Final result status " << result.status
248 << " is not allowed in the Connection phase";
249 break;
250
251 case PortalDetector::kPhaseHTTP:
252 if (result.status == PortalDetector::kStatusFailure)
253 retval = kPortalResultHTTPFailure;
254 else if (result.status == PortalDetector::kStatusTimeout)
255 retval = kPortalResultHTTPTimeout;
256 else
257 LOG(DFATAL) << __func__ << ": Final result status " << result.status
258 << " is not allowed in the HTTP phase";
259 break;
260
261 case PortalDetector::kPhaseContent:
262 if (result.status == PortalDetector::kStatusSuccess)
263 retval = kPortalResultSuccess;
264 else if (result.status == PortalDetector::kStatusFailure)
265 retval = kPortalResultContentFailure;
266 else if (result.status == PortalDetector::kStatusTimeout)
267 retval = kPortalResultContentTimeout;
268 else
269 LOG(DFATAL) << __func__ << ": Final result status " << result.status
270 << " is not allowed in the Content phase";
271 break;
272
273 case PortalDetector::kPhaseUnknown:
274 retval = kPortalResultUnknown;
275 break;
276
277 default:
278 LOG(DFATAL) << __func__ << ": Invalid phase " << result.phase;
279 break;
280 }
281
282 return retval;
283}
284
Thieu Le48e6d6d2011-12-06 00:40:27 +0000285void Metrics::RegisterService(const Service *service) {
286 shared_ptr<ServiceMetrics> service_metrics(new ServiceMetrics);
287 services_metrics_[service] = service_metrics;
288 service_metrics->service = service;
289 InitializeCommonServiceMetrics(service);
290 service->InitializeCustomMetrics();
291}
292
293void Metrics::DeregisterService(const Service *service) {
294 services_metrics_.erase(service);
295}
296
297void Metrics::AddServiceStateTransitionTimer(
298 const Service *service,
299 const string &histogram_name,
300 Service::ConnectState start_state,
301 Service::ConnectState stop_state) {
302 ServiceMetricsLookupMap::iterator it = services_metrics_.find(service);
303 if (it == services_metrics_.end()) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700304 SLOG(Metrics, 1) << "service not found";
Thieu Le48e6d6d2011-12-06 00:40:27 +0000305 DCHECK(false);
306 return;
307 }
308 ServiceMetrics *service_metrics = it->second.get();
309 CHECK(start_state < stop_state);
310 chromeos_metrics::TimerReporter *timer =
311 new chromeos_metrics::TimerReporter(histogram_name,
Thieu Lea20cbc22012-01-09 22:01:43 +0000312 kTimerHistogramMillisecondsMin,
313 kTimerHistogramMillisecondsMax,
Thieu Le48e6d6d2011-12-06 00:40:27 +0000314 kTimerHistogramNumBuckets);
315 service_metrics->timers.push_back(timer); // passes ownership.
316 service_metrics->start_on_state[start_state].push_back(timer);
317 service_metrics->stop_on_state[stop_state].push_back(timer);
318}
319
Thieu Lea20cbc22012-01-09 22:01:43 +0000320void Metrics::NotifyDefaultServiceChanged(const Service *service) {
321 base::TimeDelta elapsed_seconds;
322
323 Technology::Identifier technology = (service) ? service->technology() :
324 Technology::kUnknown;
325 if (technology != last_default_technology_) {
326 if (last_default_technology_ != Technology::kUnknown) {
327 string histogram = GetFullMetricName(kMetricTimeOnlineSeconds,
328 last_default_technology_);
329 time_online_timer_->GetElapsedTime(&elapsed_seconds);
330 SendToUMA(histogram,
331 elapsed_seconds.InSeconds(),
332 kMetricTimeOnlineSecondsMin,
333 kMetricTimeOnlineSecondsMax,
334 kTimerHistogramNumBuckets);
335 }
336 last_default_technology_ = technology;
337 time_online_timer_->Start();
338 }
339
Thieu Lea20cbc22012-01-09 22:01:43 +0000340 // Ignore changes that are not online/offline transitions; e.g.
341 // switching between wired and wireless. TimeToDrop measures
342 // time online regardless of how we are connected.
343 if ((service == NULL && !was_online_) || (service != NULL && was_online_))
344 return;
345
346 if (service == NULL) {
347 time_to_drop_timer_->GetElapsedTime(&elapsed_seconds);
348 SendToUMA(kMetricTimeToDropSeconds,
349 elapsed_seconds.InSeconds(),
350 kMetricTimeToDropSecondsMin,
351 kMetricTimeToDropSecondsMax,
352 kTimerHistogramNumBuckets);
353 } else {
354 time_to_drop_timer_->Start();
355 }
356
357 was_online_ = (service != NULL);
Thieu Le48e6d6d2011-12-06 00:40:27 +0000358}
359
360void Metrics::NotifyServiceStateChanged(const Service *service,
361 Service::ConnectState new_state) {
362 ServiceMetricsLookupMap::iterator it = services_metrics_.find(service);
363 if (it == services_metrics_.end()) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700364 SLOG(Metrics, 1) << "service not found";
Thieu Le48e6d6d2011-12-06 00:40:27 +0000365 DCHECK(false);
366 return;
367 }
368 ServiceMetrics *service_metrics = it->second.get();
369 UpdateServiceStateTransitionMetrics(service_metrics, new_state);
370
371 if (new_state == Service::kStateFailure)
372 SendServiceFailure(service);
373
Darin Petkov58f0b6d2012-06-12 12:52:30 +0200374 if (collect_bootstats_) {
375 bootstat_log(
376 StringPrintf("network-%s-%s",
377 Technology::NameFromIdentifier(
378 service->technology()).c_str(),
379 service->GetStateString().c_str()).c_str());
380 }
381
Paul Stewart20088d82012-02-16 06:58:55 -0800382 if (new_state != Service::kStateConnected)
Thieu Le48e6d6d2011-12-06 00:40:27 +0000383 return;
384
Thieu Leb84ba342012-03-02 15:15:19 -0800385 base::TimeDelta time_resume_to_ready;
386 time_resume_to_ready_timer_->GetElapsedTime(&time_resume_to_ready);
387 time_resume_to_ready_timer_->Reset();
388 service->SendPostReadyStateMetrics(time_resume_to_ready.InMilliseconds());
Thieu Le48e6d6d2011-12-06 00:40:27 +0000389}
390
391string Metrics::GetFullMetricName(const char *metric_name,
392 Technology::Identifier technology_id) {
393 string technology = Technology::NameFromIdentifier(technology_id);
394 technology[0] = base::ToUpperASCII(technology[0]);
395 return base::StringPrintf(metric_name, technology.c_str());
396}
397
Thieu Le67370f62012-02-14 23:01:42 +0000398void Metrics::NotifyServiceDisconnect(const Service *service) {
399 Technology::Identifier technology = service->technology();
400 string histogram = GetFullMetricName(kMetricDisconnect, technology);
401 SendToUMA(histogram,
402 service->explicitly_disconnected(),
403 kMetricDisconnectMin,
404 kMetricDisconnectMax,
405 kMetricDisconnectNumBuckets);
Thieu Le48e6d6d2011-12-06 00:40:27 +0000406}
407
Thieu Leb84ba342012-03-02 15:15:19 -0800408void Metrics::NotifyPowerStateChange(PowerManager::SuspendState new_state) {
409 if (new_state == PowerManagerProxyDelegate::kOn) {
410 time_resume_to_ready_timer_->Start();
411 } else {
412 time_resume_to_ready_timer_->Reset();
413 }
Thieu Le48e6d6d2011-12-06 00:40:27 +0000414}
415
Paul Stewartff845fc2012-08-07 07:28:44 -0700416void Metrics::NotifyLinkMonitorFailure(
Paul Stewart0443aa52012-08-09 10:43:50 -0700417 Technology::Identifier technology,
418 LinkMonitorFailure failure,
419 unsigned int seconds_to_failure,
420 unsigned int broadcast_error_count,
421 unsigned int unicast_error_count) {
Paul Stewartff845fc2012-08-07 07:28:44 -0700422 string histogram = GetFullMetricName(kMetricLinkMonitorFailure,
423 technology);
424 SendEnumToUMA(histogram, failure, kLinkMonitorFailureMax);
Paul Stewart0443aa52012-08-09 10:43:50 -0700425
426 if (failure == kLinkMonitorFailureThresholdReached) {
427 if (seconds_to_failure > kMetricLinkMonitorSecondsToFailureMax) {
428 seconds_to_failure = kMetricLinkMonitorSecondsToFailureMax;
429 }
430 histogram = GetFullMetricName(kMetricLinkMonitorSecondsToFailure,
431 technology);
432 SendToUMA(histogram,
433 seconds_to_failure,
434 kMetricLinkMonitorSecondsToFailureMin,
435 kMetricLinkMonitorSecondsToFailureMax,
436 kMetricLinkMonitorSecondsToFailureNumBuckets);
437 histogram = GetFullMetricName(kMetricLinkMonitorBroadcastErrorsAtFailure,
438 technology);
439 SendToUMA(histogram,
440 broadcast_error_count,
441 kMetricLinkMonitorErrorCountMin,
442 kMetricLinkMonitorErrorCountMax,
443 kMetricLinkMonitorErrorCountNumBuckets);
444 histogram = GetFullMetricName(kMetricLinkMonitorUnicastErrorsAtFailure,
445 technology);
446 SendToUMA(histogram,
447 unicast_error_count,
448 kMetricLinkMonitorErrorCountMin,
449 kMetricLinkMonitorErrorCountMax,
450 kMetricLinkMonitorErrorCountNumBuckets);
451 }
Paul Stewartff845fc2012-08-07 07:28:44 -0700452}
453
454void Metrics::NotifyLinkMonitorResponseTimeSampleAdded(
455 Technology::Identifier technology,
456 unsigned int response_time_milliseconds) {
457 string histogram = GetFullMetricName(kMetricLinkMonitorResponseTimeSample,
458 technology);
459 SendToUMA(histogram,
460 response_time_milliseconds,
461 kMetricLinkMonitorResponseTimeSampleMin,
462 kMetricLinkMonitorResponseTimeSampleMax,
463 kMetricLinkMonitorResponseTimeSampleNumBuckets);
464}
465
Wade Guthried4977f22012-08-22 12:37:54 -0700466void Metrics::Notify80211Disconnect(WiFiDisconnectByWhom by_whom,
467 IEEE_80211::WiFiReasonCode reason) {
468 string metric_disconnect_reason;
469 string metric_disconnect_type;
470 WiFiStatusType type;
471
472 if (by_whom == kDisconnectedByAp) {
473 metric_disconnect_reason = kMetricLinkApDisconnectReason;
474 metric_disconnect_type = kMetricLinkApDisconnectType;
475 type = kStatusCodeTypeByAp;
476 } else {
477 metric_disconnect_reason = kMetricLinkClientDisconnectReason;
478 metric_disconnect_type = kMetricLinkClientDisconnectType;
479 switch(reason) {
480 case IEEE_80211::kReasonCodeSenderHasLeft:
481 case IEEE_80211::kReasonCodeDisassociatedHasLeft:
482 type = kStatusCodeTypeByUser;
483 break;
484
485 case IEEE_80211::kReasonCodeInactivity:
486 type = kStatusCodeTypeConsideredDead;
487 break;
488
489 default:
490 type = kStatusCodeTypeByClient;
491 break;
492 }
493 }
494 SendEnumToUMA(metric_disconnect_reason, reason,
495 IEEE_80211::kStatusCodeMax);
496 SendEnumToUMA(metric_disconnect_type, type, kStatusCodeTypeMax);
497}
498
Thieu Le48e6d6d2011-12-06 00:40:27 +0000499bool Metrics::SendEnumToUMA(const string &name, int sample, int max) {
500 return library_->SendEnumToUMA(name, sample, max);
501}
502
Thieu Lea20cbc22012-01-09 22:01:43 +0000503bool Metrics::SendToUMA(const string &name, int sample, int min, int max,
504 int num_buckets) {
505 return library_->SendToUMA(name, sample, min, max, num_buckets);
506}
507
Thieu Le48e6d6d2011-12-06 00:40:27 +0000508void Metrics::InitializeCommonServiceMetrics(const Service *service) {
509 Technology::Identifier technology = service->technology();
510 string histogram = GetFullMetricName(kMetricTimeToConfigMilliseconds,
511 technology);
512 AddServiceStateTransitionTimer(
513 service,
514 histogram,
515 Service::kStateConfiguring,
Paul Stewart20088d82012-02-16 06:58:55 -0800516 Service::kStateConnected);
Thieu Le48e6d6d2011-12-06 00:40:27 +0000517 histogram = GetFullMetricName(kMetricTimeToPortalMilliseconds, technology);
518 AddServiceStateTransitionTimer(
519 service,
520 histogram,
Paul Stewart20088d82012-02-16 06:58:55 -0800521 Service::kStateConnected,
Thieu Le48e6d6d2011-12-06 00:40:27 +0000522 Service::kStatePortal);
523 histogram = GetFullMetricName(kMetricTimeToOnlineMilliseconds, technology);
524 AddServiceStateTransitionTimer(
525 service,
526 histogram,
Paul Stewart20088d82012-02-16 06:58:55 -0800527 Service::kStateConnected,
Thieu Le48e6d6d2011-12-06 00:40:27 +0000528 Service::kStateOnline);
529}
530
531void Metrics::UpdateServiceStateTransitionMetrics(
532 ServiceMetrics *service_metrics,
533 Service::ConnectState new_state) {
534 TimerReportersList::iterator it;
535 TimerReportersList &start_timers = service_metrics->start_on_state[new_state];
536 for (it = start_timers.begin(); it != start_timers.end(); ++it)
537 (*it)->Start();
538
539 TimerReportersList &stop_timers = service_metrics->stop_on_state[new_state];
540 for (it = stop_timers.begin(); it != stop_timers.end(); ++it) {
541 (*it)->Stop();
542 (*it)->ReportMilliseconds();
543 }
544}
545
546void Metrics::SendServiceFailure(const Service *service) {
547 library_->SendEnumToUMA(kMetricNetworkServiceErrors,
548 service->failure(),
549 kMetricNetworkServiceErrorsMax);
550}
551
552void Metrics::set_library(MetricsLibraryInterface *library) {
553 chromeos_metrics::TimerReporter::set_metrics_lib(library);
554 library_ = library;
555}
556
557} // namespace shill