blob: 578f596d340ec4802b61fb64aa1ba6d4eebee53e [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;
Paul Stewart23b393a2012-09-25 21:21:06 -070046const char Metrics::kMetricNetworkSignalStrength[] =
47 "Network.Shill.%s.SignalStrength";
48const int Metrics::kMetricNetworkSignalStrengthMax = 200;
49const int Metrics::kMetricNetworkSignalStrengthMin = 0;
50const int Metrics::kMetricNetworkSignalStrengthNumBuckets = 40;
Thieu Lea20cbc22012-01-09 22:01:43 +000051
52const char Metrics::kMetricTimeOnlineSeconds[] = "Network.Shill.%s.TimeOnline";
53const int Metrics::kMetricTimeOnlineSecondsMax = 8 * 60 * 60; // 8 hours
54const int Metrics::kMetricTimeOnlineSecondsMin = 1;
55
56const char Metrics::kMetricTimeToDropSeconds[] = "Network.Shill.TimeToDrop";;
57const int Metrics::kMetricTimeToDropSecondsMax = 8 * 60 * 60; // 8 hours
58const int Metrics::kMetricTimeToDropSecondsMin = 1;
59
Thieu Leb84ba342012-03-02 15:15:19 -080060const char Metrics::kMetricTimeResumeToReadyMilliseconds[] =
61 "Network.Shill.%s.TimeResumeToReady";
Thieu Le48e6d6d2011-12-06 00:40:27 +000062const char Metrics::kMetricTimeToConfigMilliseconds[] =
63 "Network.Shill.%s.TimeToConfig";
64const char Metrics::kMetricTimeToJoinMilliseconds[] =
65 "Network.Shill.%s.TimeToJoin";
66const char Metrics::kMetricTimeToOnlineMilliseconds[] =
67 "Network.Shill.%s.TimeToOnline";
68const char Metrics::kMetricTimeToPortalMilliseconds[] =
69 "Network.Shill.%s.TimeToPortal";
Thieu Lea20cbc22012-01-09 22:01:43 +000070const int Metrics::kTimerHistogramMillisecondsMax = 45 * 1000;
71const int Metrics::kTimerHistogramMillisecondsMin = 1;
Thieu Le48e6d6d2011-12-06 00:40:27 +000072const int Metrics::kTimerHistogramNumBuckets = 50;
73
Thieu Le85e050b2012-03-13 15:04:38 -070074const char Metrics::kMetricPortalAttempts[] =
75 "Network.Shill.%s.PortalAttempts";
76const int Metrics::kMetricPortalAttemptsMax =
77 PortalDetector::kMaxRequestAttempts;
78const int Metrics::kMetricPortalAttemptsMin = 1;
79const int Metrics::kMetricPortalAttemptsNumBuckets =
80 Metrics::kMetricPortalAttemptsMax;
81
82const char Metrics::kMetricPortalAttemptsToOnline[] =
83 "Network.Shill.%s.PortalAttemptsToOnline";
84const int Metrics::kMetricPortalAttemptsToOnlineMax = 100;
85const int Metrics::kMetricPortalAttemptsToOnlineMin = 1;
86const int Metrics::kMetricPortalAttemptsToOnlineNumBuckets = 10;
87
88const char Metrics::kMetricPortalResult[] = "Network.Shill.%s.PortalResult";
89
Arman Uguray6d528f12012-09-13 13:44:55 -070090const char Metrics::kMetricTerminationActionResult[] =
91 "Network.Shill.TerminationActionResult";
92
Thieu Le48e6d6d2011-12-06 00:40:27 +000093// static
94const uint16 Metrics::kWiFiBandwidth5MHz = 5;
95const uint16 Metrics::kWiFiBandwidth20MHz = 20;
96const uint16 Metrics::kWiFiFrequency2412 = 2412;
97const uint16 Metrics::kWiFiFrequency2472 = 2472;
98const uint16 Metrics::kWiFiFrequency2484 = 2484;
99const uint16 Metrics::kWiFiFrequency5170 = 5170;
100const uint16 Metrics::kWiFiFrequency5180 = 5180;
101const uint16 Metrics::kWiFiFrequency5230 = 5230;
102const uint16 Metrics::kWiFiFrequency5240 = 5240;
103const uint16 Metrics::kWiFiFrequency5320 = 5320;
104const uint16 Metrics::kWiFiFrequency5500 = 5500;
105const uint16 Metrics::kWiFiFrequency5700 = 5700;
106const uint16 Metrics::kWiFiFrequency5745 = 5745;
107const uint16 Metrics::kWiFiFrequency5825 = 5825;
108
Thieu Leb84ba342012-03-02 15:15:19 -0800109// static
110const char Metrics::kMetricPowerManagerKey[] = "metrics";
111
Paul Stewartff845fc2012-08-07 07:28:44 -0700112// static
113const char Metrics::kMetricLinkMonitorFailure[] =
114 "Network.Shill.%s.LinkMonitorFailure";
115const char Metrics::kMetricLinkMonitorResponseTimeSample[] =
116 "Network.Shill.%s.LinkMonitorResponseTimeSample";
Paul Stewartf1961f82012-09-11 20:45:39 -0700117const int Metrics::kMetricLinkMonitorResponseTimeSampleMin = 0;
118const int Metrics::kMetricLinkMonitorResponseTimeSampleMax =
Paul Stewartff845fc2012-08-07 07:28:44 -0700119 LinkMonitor::kTestPeriodMilliseconds;
120const int Metrics::kMetricLinkMonitorResponseTimeSampleNumBuckets = 50;
Paul Stewart0443aa52012-08-09 10:43:50 -0700121const char Metrics::kMetricLinkMonitorSecondsToFailure[] =
122 "Network.Shill.%s.LinkMonitorSecondsToFailure";
Paul Stewartf1961f82012-09-11 20:45:39 -0700123const int Metrics::kMetricLinkMonitorSecondsToFailureMin = 0;
124const int Metrics::kMetricLinkMonitorSecondsToFailureMax = 7200;
Paul Stewart0443aa52012-08-09 10:43:50 -0700125const int Metrics::kMetricLinkMonitorSecondsToFailureNumBuckets = 50;
126const char Metrics::kMetricLinkMonitorBroadcastErrorsAtFailure[] =
127 "Network.Shill.%s.LinkMonitorBroadcastErrorsAtFailure";
128const char Metrics::kMetricLinkMonitorUnicastErrorsAtFailure[] =
129 "Network.Shill.%s.LinkMonitorUnicastErrorsAtFailure";
Paul Stewartf1961f82012-09-11 20:45:39 -0700130const int Metrics::kMetricLinkMonitorErrorCountMin = 0;
131const int Metrics::kMetricLinkMonitorErrorCountMax =
Paul Stewart0443aa52012-08-09 10:43:50 -0700132 LinkMonitor::kFailureThreshold;
133const int Metrics::kMetricLinkMonitorErrorCountNumBuckets =
134 LinkMonitor::kFailureThreshold + 1;
Paul Stewartff845fc2012-08-07 07:28:44 -0700135
Wade Guthried4977f22012-08-22 12:37:54 -0700136// static
137const char Metrics::kMetricLinkClientDisconnectReason[] =
138 "Network.Shill.WiFi.ClientDisconnectReason";
139const char Metrics::kMetricLinkApDisconnectReason[] =
140 "Network.Shill.WiFi.ApDisconnectReason";
141const char Metrics::kMetricLinkClientDisconnectType[] =
142 "Network.Shill.WiFi.ClientDisconnectType";
143const char Metrics::kMetricLinkApDisconnectType[] =
144 "Network.Shill.WiFi.ApDisconnectType";
145
146
Thieu Lea20cbc22012-01-09 22:01:43 +0000147Metrics::Metrics()
148 : library_(&metrics_library_),
149 last_default_technology_(Technology::kUnknown),
150 was_online_(false),
151 time_online_timer_(new chromeos_metrics::Timer),
Thieu Leb84ba342012-03-02 15:15:19 -0800152 time_to_drop_timer_(new chromeos_metrics::Timer),
Darin Petkov58f0b6d2012-06-12 12:52:30 +0200153 time_resume_to_ready_timer_(new chromeos_metrics::Timer),
154 collect_bootstats_(true) {
Thieu Le48e6d6d2011-12-06 00:40:27 +0000155 metrics_library_.Init();
156 chromeos_metrics::TimerReporter::set_metrics_lib(library_);
157}
158
159Metrics::~Metrics() {}
160
161// static
Thieu Le48e6d6d2011-12-06 00:40:27 +0000162Metrics::WiFiChannel Metrics::WiFiFrequencyToChannel(uint16 frequency) {
163 WiFiChannel channel = kWiFiChannelUndef;
164 if (kWiFiFrequency2412 <= frequency && frequency <= kWiFiFrequency2472) {
165 if (((frequency - kWiFiFrequency2412) % kWiFiBandwidth5MHz) == 0)
166 channel = static_cast<WiFiChannel>(
167 kWiFiChannel2412 +
168 (frequency - kWiFiFrequency2412) / kWiFiBandwidth5MHz);
169 } else if (frequency == kWiFiFrequency2484) {
170 channel = kWiFiChannel2484;
171 } else if (kWiFiFrequency5170 <= frequency &&
172 frequency <= kWiFiFrequency5230) {
173 if ((frequency % kWiFiBandwidth20MHz) == 0)
174 channel = static_cast<WiFiChannel>(
175 kWiFiChannel5180 +
176 (frequency - kWiFiFrequency5180) / kWiFiBandwidth20MHz);
177 if ((frequency % kWiFiBandwidth20MHz) == 10)
178 channel = static_cast<WiFiChannel>(
179 kWiFiChannel5170 +
180 (frequency - kWiFiFrequency5170) / kWiFiBandwidth20MHz);
181 } else if (kWiFiFrequency5240 <= frequency &&
182 frequency <= kWiFiFrequency5320) {
183 if (((frequency - kWiFiFrequency5180) % kWiFiBandwidth20MHz) == 0)
184 channel = static_cast<WiFiChannel>(
185 kWiFiChannel5180 +
186 (frequency - kWiFiFrequency5180) / kWiFiBandwidth20MHz);
187 } else if (kWiFiFrequency5500 <= frequency &&
188 frequency <= kWiFiFrequency5700) {
189 if (((frequency - kWiFiFrequency5500) % kWiFiBandwidth20MHz) == 0)
190 channel = static_cast<WiFiChannel>(
191 kWiFiChannel5500 +
192 (frequency - kWiFiFrequency5500) / kWiFiBandwidth20MHz);
193 } else if (kWiFiFrequency5745 <= frequency &&
194 frequency <= kWiFiFrequency5825) {
195 if (((frequency - kWiFiFrequency5745) % kWiFiBandwidth20MHz) == 0)
196 channel = static_cast<WiFiChannel>(
197 kWiFiChannel5745 +
198 (frequency - kWiFiFrequency5745) / kWiFiBandwidth20MHz);
199 }
200 CHECK(kWiFiChannelUndef <= channel && channel < kWiFiChannelMax);
201
202 if (channel == kWiFiChannelUndef)
203 LOG(WARNING) << "no mapping for frequency " << frequency;
204 else
Ben Chanfad4a0b2012-04-18 15:49:59 -0700205 SLOG(Metrics, 3) << "map " << frequency << " to " << channel;
Thieu Le48e6d6d2011-12-06 00:40:27 +0000206
207 return channel;
208}
209
Thieu Lead1ec2c2012-01-05 23:39:48 +0000210// static
211Metrics::WiFiSecurity Metrics::WiFiSecurityStringToEnum(
212 const std::string &security) {
213 if (security == flimflam::kSecurityNone) {
214 return kWiFiSecurityNone;
215 } else if (security == flimflam::kSecurityWep) {
216 return kWiFiSecurityWep;
217 } else if (security == flimflam::kSecurityWpa) {
218 return kWiFiSecurityWpa;
219 } else if (security == flimflam::kSecurityRsn) {
220 return kWiFiSecurityRsn;
221 } else if (security == flimflam::kSecurity8021x) {
222 return kWiFiSecurity8021x;
223 } else if (security == flimflam::kSecurityPsk) {
224 return kWiFiSecurityPsk;
225 } else {
226 return kWiFiSecurityUnknown;
227 }
228}
229
Thieu Le85e050b2012-03-13 15:04:38 -0700230// static
231Metrics::PortalResult Metrics::PortalDetectionResultToEnum(
232 const PortalDetector::Result &result) {
233 DCHECK(result.final);
234 PortalResult retval = kPortalResultUnknown;
235 // The only time we should end a successful portal detection is when we're
236 // in the Content phase. If we end with kStatusSuccess in any other phase,
237 // then this indicates that something bad has happened.
238 switch (result.phase) {
239 case PortalDetector::kPhaseDNS:
240 if (result.status == PortalDetector::kStatusFailure)
241 retval = kPortalResultDNSFailure;
242 else if (result.status == PortalDetector::kStatusTimeout)
243 retval = kPortalResultDNSTimeout;
244 else
245 LOG(DFATAL) << __func__ << ": Final result status " << result.status
246 << " is not allowed in the DNS phase";
247 break;
248
249 case PortalDetector::kPhaseConnection:
250 if (result.status == PortalDetector::kStatusFailure)
251 retval = kPortalResultConnectionFailure;
252 else if (result.status == PortalDetector::kStatusTimeout)
253 retval = kPortalResultConnectionTimeout;
254 else
255 LOG(DFATAL) << __func__ << ": Final result status " << result.status
256 << " is not allowed in the Connection phase";
257 break;
258
259 case PortalDetector::kPhaseHTTP:
260 if (result.status == PortalDetector::kStatusFailure)
261 retval = kPortalResultHTTPFailure;
262 else if (result.status == PortalDetector::kStatusTimeout)
263 retval = kPortalResultHTTPTimeout;
264 else
265 LOG(DFATAL) << __func__ << ": Final result status " << result.status
266 << " is not allowed in the HTTP phase";
267 break;
268
269 case PortalDetector::kPhaseContent:
270 if (result.status == PortalDetector::kStatusSuccess)
271 retval = kPortalResultSuccess;
272 else if (result.status == PortalDetector::kStatusFailure)
273 retval = kPortalResultContentFailure;
274 else if (result.status == PortalDetector::kStatusTimeout)
275 retval = kPortalResultContentTimeout;
276 else
277 LOG(DFATAL) << __func__ << ": Final result status " << result.status
278 << " is not allowed in the Content phase";
279 break;
280
281 case PortalDetector::kPhaseUnknown:
282 retval = kPortalResultUnknown;
283 break;
284
285 default:
286 LOG(DFATAL) << __func__ << ": Invalid phase " << result.phase;
287 break;
288 }
289
290 return retval;
291}
292
Thieu Le48e6d6d2011-12-06 00:40:27 +0000293void Metrics::RegisterService(const Service *service) {
294 shared_ptr<ServiceMetrics> service_metrics(new ServiceMetrics);
295 services_metrics_[service] = service_metrics;
296 service_metrics->service = service;
297 InitializeCommonServiceMetrics(service);
298 service->InitializeCustomMetrics();
299}
300
301void Metrics::DeregisterService(const Service *service) {
302 services_metrics_.erase(service);
303}
304
305void Metrics::AddServiceStateTransitionTimer(
306 const Service *service,
307 const string &histogram_name,
308 Service::ConnectState start_state,
309 Service::ConnectState stop_state) {
310 ServiceMetricsLookupMap::iterator it = services_metrics_.find(service);
311 if (it == services_metrics_.end()) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700312 SLOG(Metrics, 1) << "service not found";
Thieu Le48e6d6d2011-12-06 00:40:27 +0000313 DCHECK(false);
314 return;
315 }
316 ServiceMetrics *service_metrics = it->second.get();
317 CHECK(start_state < stop_state);
318 chromeos_metrics::TimerReporter *timer =
319 new chromeos_metrics::TimerReporter(histogram_name,
Thieu Lea20cbc22012-01-09 22:01:43 +0000320 kTimerHistogramMillisecondsMin,
321 kTimerHistogramMillisecondsMax,
Thieu Le48e6d6d2011-12-06 00:40:27 +0000322 kTimerHistogramNumBuckets);
323 service_metrics->timers.push_back(timer); // passes ownership.
324 service_metrics->start_on_state[start_state].push_back(timer);
325 service_metrics->stop_on_state[stop_state].push_back(timer);
326}
327
Thieu Lea20cbc22012-01-09 22:01:43 +0000328void Metrics::NotifyDefaultServiceChanged(const Service *service) {
329 base::TimeDelta elapsed_seconds;
330
331 Technology::Identifier technology = (service) ? service->technology() :
332 Technology::kUnknown;
333 if (technology != last_default_technology_) {
334 if (last_default_technology_ != Technology::kUnknown) {
335 string histogram = GetFullMetricName(kMetricTimeOnlineSeconds,
336 last_default_technology_);
337 time_online_timer_->GetElapsedTime(&elapsed_seconds);
338 SendToUMA(histogram,
339 elapsed_seconds.InSeconds(),
340 kMetricTimeOnlineSecondsMin,
341 kMetricTimeOnlineSecondsMax,
342 kTimerHistogramNumBuckets);
343 }
344 last_default_technology_ = technology;
345 time_online_timer_->Start();
346 }
347
Thieu Lea20cbc22012-01-09 22:01:43 +0000348 // Ignore changes that are not online/offline transitions; e.g.
349 // switching between wired and wireless. TimeToDrop measures
350 // time online regardless of how we are connected.
351 if ((service == NULL && !was_online_) || (service != NULL && was_online_))
352 return;
353
354 if (service == NULL) {
355 time_to_drop_timer_->GetElapsedTime(&elapsed_seconds);
356 SendToUMA(kMetricTimeToDropSeconds,
357 elapsed_seconds.InSeconds(),
358 kMetricTimeToDropSecondsMin,
359 kMetricTimeToDropSecondsMax,
360 kTimerHistogramNumBuckets);
361 } else {
362 time_to_drop_timer_->Start();
363 }
364
365 was_online_ = (service != NULL);
Thieu Le48e6d6d2011-12-06 00:40:27 +0000366}
367
368void Metrics::NotifyServiceStateChanged(const Service *service,
369 Service::ConnectState new_state) {
370 ServiceMetricsLookupMap::iterator it = services_metrics_.find(service);
371 if (it == services_metrics_.end()) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700372 SLOG(Metrics, 1) << "service not found";
Thieu Le48e6d6d2011-12-06 00:40:27 +0000373 DCHECK(false);
374 return;
375 }
376 ServiceMetrics *service_metrics = it->second.get();
377 UpdateServiceStateTransitionMetrics(service_metrics, new_state);
378
379 if (new_state == Service::kStateFailure)
380 SendServiceFailure(service);
381
Darin Petkov58f0b6d2012-06-12 12:52:30 +0200382 if (collect_bootstats_) {
383 bootstat_log(
384 StringPrintf("network-%s-%s",
385 Technology::NameFromIdentifier(
386 service->technology()).c_str(),
387 service->GetStateString().c_str()).c_str());
388 }
389
Paul Stewart20088d82012-02-16 06:58:55 -0800390 if (new_state != Service::kStateConnected)
Thieu Le48e6d6d2011-12-06 00:40:27 +0000391 return;
392
Thieu Leb84ba342012-03-02 15:15:19 -0800393 base::TimeDelta time_resume_to_ready;
394 time_resume_to_ready_timer_->GetElapsedTime(&time_resume_to_ready);
395 time_resume_to_ready_timer_->Reset();
396 service->SendPostReadyStateMetrics(time_resume_to_ready.InMilliseconds());
Thieu Le48e6d6d2011-12-06 00:40:27 +0000397}
398
399string Metrics::GetFullMetricName(const char *metric_name,
400 Technology::Identifier technology_id) {
401 string technology = Technology::NameFromIdentifier(technology_id);
402 technology[0] = base::ToUpperASCII(technology[0]);
403 return base::StringPrintf(metric_name, technology.c_str());
404}
405
Thieu Le67370f62012-02-14 23:01:42 +0000406void Metrics::NotifyServiceDisconnect(const Service *service) {
407 Technology::Identifier technology = service->technology();
408 string histogram = GetFullMetricName(kMetricDisconnect, technology);
409 SendToUMA(histogram,
410 service->explicitly_disconnected(),
411 kMetricDisconnectMin,
412 kMetricDisconnectMax,
413 kMetricDisconnectNumBuckets);
Thieu Le48e6d6d2011-12-06 00:40:27 +0000414}
415
Thieu Leb84ba342012-03-02 15:15:19 -0800416void Metrics::NotifyPowerStateChange(PowerManager::SuspendState new_state) {
417 if (new_state == PowerManagerProxyDelegate::kOn) {
418 time_resume_to_ready_timer_->Start();
419 } else {
420 time_resume_to_ready_timer_->Reset();
421 }
Thieu Le48e6d6d2011-12-06 00:40:27 +0000422}
423
Paul Stewartff845fc2012-08-07 07:28:44 -0700424void Metrics::NotifyLinkMonitorFailure(
Paul Stewart0443aa52012-08-09 10:43:50 -0700425 Technology::Identifier technology,
426 LinkMonitorFailure failure,
Paul Stewartf1961f82012-09-11 20:45:39 -0700427 int seconds_to_failure,
428 int broadcast_error_count,
429 int unicast_error_count) {
Paul Stewartff845fc2012-08-07 07:28:44 -0700430 string histogram = GetFullMetricName(kMetricLinkMonitorFailure,
431 technology);
432 SendEnumToUMA(histogram, failure, kLinkMonitorFailureMax);
Paul Stewart0443aa52012-08-09 10:43:50 -0700433
434 if (failure == kLinkMonitorFailureThresholdReached) {
435 if (seconds_to_failure > kMetricLinkMonitorSecondsToFailureMax) {
436 seconds_to_failure = kMetricLinkMonitorSecondsToFailureMax;
437 }
438 histogram = GetFullMetricName(kMetricLinkMonitorSecondsToFailure,
439 technology);
440 SendToUMA(histogram,
441 seconds_to_failure,
442 kMetricLinkMonitorSecondsToFailureMin,
443 kMetricLinkMonitorSecondsToFailureMax,
444 kMetricLinkMonitorSecondsToFailureNumBuckets);
445 histogram = GetFullMetricName(kMetricLinkMonitorBroadcastErrorsAtFailure,
446 technology);
447 SendToUMA(histogram,
448 broadcast_error_count,
449 kMetricLinkMonitorErrorCountMin,
450 kMetricLinkMonitorErrorCountMax,
451 kMetricLinkMonitorErrorCountNumBuckets);
452 histogram = GetFullMetricName(kMetricLinkMonitorUnicastErrorsAtFailure,
453 technology);
454 SendToUMA(histogram,
455 unicast_error_count,
456 kMetricLinkMonitorErrorCountMin,
457 kMetricLinkMonitorErrorCountMax,
458 kMetricLinkMonitorErrorCountNumBuckets);
459 }
Paul Stewartff845fc2012-08-07 07:28:44 -0700460}
461
462void Metrics::NotifyLinkMonitorResponseTimeSampleAdded(
463 Technology::Identifier technology,
Paul Stewartf1961f82012-09-11 20:45:39 -0700464 int response_time_milliseconds) {
Paul Stewartff845fc2012-08-07 07:28:44 -0700465 string histogram = GetFullMetricName(kMetricLinkMonitorResponseTimeSample,
466 technology);
467 SendToUMA(histogram,
468 response_time_milliseconds,
469 kMetricLinkMonitorResponseTimeSampleMin,
470 kMetricLinkMonitorResponseTimeSampleMax,
471 kMetricLinkMonitorResponseTimeSampleNumBuckets);
472}
473
Wade Guthried4977f22012-08-22 12:37:54 -0700474void Metrics::Notify80211Disconnect(WiFiDisconnectByWhom by_whom,
475 IEEE_80211::WiFiReasonCode reason) {
476 string metric_disconnect_reason;
477 string metric_disconnect_type;
478 WiFiStatusType type;
479
480 if (by_whom == kDisconnectedByAp) {
481 metric_disconnect_reason = kMetricLinkApDisconnectReason;
482 metric_disconnect_type = kMetricLinkApDisconnectType;
483 type = kStatusCodeTypeByAp;
484 } else {
485 metric_disconnect_reason = kMetricLinkClientDisconnectReason;
486 metric_disconnect_type = kMetricLinkClientDisconnectType;
487 switch(reason) {
488 case IEEE_80211::kReasonCodeSenderHasLeft:
489 case IEEE_80211::kReasonCodeDisassociatedHasLeft:
490 type = kStatusCodeTypeByUser;
491 break;
492
493 case IEEE_80211::kReasonCodeInactivity:
494 type = kStatusCodeTypeConsideredDead;
495 break;
496
497 default:
498 type = kStatusCodeTypeByClient;
499 break;
500 }
501 }
502 SendEnumToUMA(metric_disconnect_reason, reason,
503 IEEE_80211::kStatusCodeMax);
504 SendEnumToUMA(metric_disconnect_type, type, kStatusCodeTypeMax);
505}
506
Thieu Le48e6d6d2011-12-06 00:40:27 +0000507bool Metrics::SendEnumToUMA(const string &name, int sample, int max) {
508 return library_->SendEnumToUMA(name, sample, max);
509}
510
Thieu Lea20cbc22012-01-09 22:01:43 +0000511bool Metrics::SendToUMA(const string &name, int sample, int min, int max,
512 int num_buckets) {
513 return library_->SendToUMA(name, sample, min, max, num_buckets);
514}
515
Thieu Le48e6d6d2011-12-06 00:40:27 +0000516void Metrics::InitializeCommonServiceMetrics(const Service *service) {
517 Technology::Identifier technology = service->technology();
518 string histogram = GetFullMetricName(kMetricTimeToConfigMilliseconds,
519 technology);
520 AddServiceStateTransitionTimer(
521 service,
522 histogram,
523 Service::kStateConfiguring,
Paul Stewart20088d82012-02-16 06:58:55 -0800524 Service::kStateConnected);
Thieu Le48e6d6d2011-12-06 00:40:27 +0000525 histogram = GetFullMetricName(kMetricTimeToPortalMilliseconds, technology);
526 AddServiceStateTransitionTimer(
527 service,
528 histogram,
Paul Stewart20088d82012-02-16 06:58:55 -0800529 Service::kStateConnected,
Thieu Le48e6d6d2011-12-06 00:40:27 +0000530 Service::kStatePortal);
531 histogram = GetFullMetricName(kMetricTimeToOnlineMilliseconds, technology);
532 AddServiceStateTransitionTimer(
533 service,
534 histogram,
Paul Stewart20088d82012-02-16 06:58:55 -0800535 Service::kStateConnected,
Thieu Le48e6d6d2011-12-06 00:40:27 +0000536 Service::kStateOnline);
537}
538
539void Metrics::UpdateServiceStateTransitionMetrics(
540 ServiceMetrics *service_metrics,
541 Service::ConnectState new_state) {
542 TimerReportersList::iterator it;
543 TimerReportersList &start_timers = service_metrics->start_on_state[new_state];
544 for (it = start_timers.begin(); it != start_timers.end(); ++it)
545 (*it)->Start();
546
547 TimerReportersList &stop_timers = service_metrics->stop_on_state[new_state];
548 for (it = stop_timers.begin(); it != stop_timers.end(); ++it) {
549 (*it)->Stop();
550 (*it)->ReportMilliseconds();
551 }
552}
553
554void Metrics::SendServiceFailure(const Service *service) {
555 library_->SendEnumToUMA(kMetricNetworkServiceErrors,
556 service->failure(),
557 kMetricNetworkServiceErrorsMax);
558}
559
560void Metrics::set_library(MetricsLibraryInterface *library) {
561 chromeos_metrics::TimerReporter::set_metrics_lib(library);
562 library_ = library;
563}
564
565} // namespace shill