OLD | NEW |
1 // Copyright (c) 2010 The Chromium OS Authors. All rights reserved. | 1 // Copyright (c) 2010 The Chromium OS Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "metrics_daemon.h" | 5 #include "metrics_daemon.h" |
6 | 6 |
7 #include <dbus/dbus-glib-lowlevel.h> | 7 #include <dbus/dbus-glib-lowlevel.h> |
8 | 8 |
9 #include <base/logging.h> | 9 #include <base/logging.h> |
10 | 10 |
11 #include "counter.h" | 11 #include "counter.h" |
12 | 12 |
13 using base::Time; | 13 using base::Time; |
14 using base::TimeDelta; | 14 using base::TimeDelta; |
15 using base::TimeTicks; | 15 using base::TimeTicks; |
16 | 16 |
17 #define SAFE_MESSAGE(e) (e.message ? e.message : "unknown error") | 17 #define SAFE_MESSAGE(e) (e.message ? e.message : "unknown error") |
| 18 #define DBUS_IFACE_CRASH_REPORTER "org.chromium.CrashReporter" |
18 #define DBUS_IFACE_FLIMFLAM_MANAGER "org.chromium.flimflam.Manager" | 19 #define DBUS_IFACE_FLIMFLAM_MANAGER "org.chromium.flimflam.Manager" |
19 #define DBUS_IFACE_POWER_MANAGER "org.chromium.PowerManager" | 20 #define DBUS_IFACE_POWER_MANAGER "org.chromium.PowerManager" |
20 #define DBUS_IFACE_SESSION_MANAGER "org.chromium.SessionManagerInterface" | 21 #define DBUS_IFACE_SESSION_MANAGER "org.chromium.SessionManagerInterface" |
21 | 22 |
22 // File to aggregate daily usage before sending to UMA. | 23 // File to aggregate daily usage before sending to UMA. |
23 // TODO(petkov): This file should probably live in a user-specific stateful | 24 // TODO(petkov): This file should probably live in a user-specific stateful |
24 // location, e.g., /home/chronos/user. | 25 // location, e.g., /home/chronos/user. |
25 static const char kDailyUseRecordFile[] = "/var/log/metrics/daily-usage"; | 26 static const char kDailyUseRecordFile[] = "/var/log/metrics/daily-usage"; |
| 27 static const char kUserCrashIntervalRecordFile[] = |
| 28 "/var/log/metrics/user-crash-interval"; |
26 | 29 |
27 static const int kSecondsPerMinute = 60; | 30 static const int kSecondsPerMinute = 60; |
28 static const int kMinutesPerHour = 60; | 31 static const int kMinutesPerHour = 60; |
29 static const int kHoursPerDay = 24; | 32 static const int kHoursPerDay = 24; |
30 static const int kMinutesPerDay = kHoursPerDay * kMinutesPerHour; | 33 static const int kMinutesPerDay = kHoursPerDay * kMinutesPerHour; |
| 34 static const int kSecondsPerDay = kSecondsPerMinute * kMinutesPerDay; |
| 35 static const int kDaysPerWeek = 7; |
| 36 static const int kSecondsPerWeek = kSecondsPerDay * kDaysPerWeek; |
31 | 37 |
32 // The daily use monitor is scheduled to a 1-minute interval after | 38 // The daily use monitor is scheduled to a 1-minute interval after |
33 // initial user activity and then it's exponentially backed off to | 39 // initial user activity and then it's exponentially backed off to |
34 // 10-minute intervals. Although not required, the back off is | 40 // 10-minute intervals. Although not required, the back off is |
35 // implemented because the histogram buckets are spaced exponentially | 41 // implemented because the histogram buckets are spaced exponentially |
36 // anyway and to avoid too frequent metrics daemon process wake-ups | 42 // anyway and to avoid too frequent metrics daemon process wake-ups |
37 // and file I/O. | 43 // and file I/O. |
38 static const int kUseMonitorIntervalInit = 1 * kSecondsPerMinute; | 44 static const int kUseMonitorIntervalInit = 1 * kSecondsPerMinute; |
39 static const int kUseMonitorIntervalMax = 10 * kSecondsPerMinute; | 45 static const int kUseMonitorIntervalMax = 10 * kSecondsPerMinute; |
40 | 46 |
41 // static metrics parameters. | 47 // static metrics parameters. |
42 const char MetricsDaemon::kMetricDailyUseTimeName[] = | 48 const char MetricsDaemon::kMetricDailyUseTimeName[] = |
43 "Logging.DailyUseTime"; | 49 "Logging.DailyUseTime"; |
44 const int MetricsDaemon::kMetricDailyUseTimeMin = 1; | 50 const int MetricsDaemon::kMetricDailyUseTimeMin = 1; |
45 const int MetricsDaemon::kMetricDailyUseTimeMax = kMinutesPerDay; | 51 const int MetricsDaemon::kMetricDailyUseTimeMax = kMinutesPerDay; |
46 const int MetricsDaemon::kMetricDailyUseTimeBuckets = 50; | 52 const int MetricsDaemon::kMetricDailyUseTimeBuckets = 50; |
47 | 53 |
48 const char MetricsDaemon::kMetricTimeToNetworkDropName[] = | 54 const char MetricsDaemon::kMetricTimeToNetworkDropName[] = |
49 "Network.TimeToDrop"; | 55 "Network.TimeToDrop"; |
50 const int MetricsDaemon::kMetricTimeToNetworkDropMin = 1; | 56 const int MetricsDaemon::kMetricTimeToNetworkDropMin = 1; |
51 const int MetricsDaemon::kMetricTimeToNetworkDropMax = | 57 const int MetricsDaemon::kMetricTimeToNetworkDropMax = |
52 8 /* hours */ * kMinutesPerHour * kSecondsPerMinute; | 58 8 /* hours */ * kMinutesPerHour * kSecondsPerMinute; |
53 const int MetricsDaemon::kMetricTimeToNetworkDropBuckets = 50; | 59 const int MetricsDaemon::kMetricTimeToNetworkDropBuckets = 50; |
54 | 60 |
| 61 const char MetricsDaemon::kMetricUserCrashIntervalName[] = |
| 62 "Logging.UserCrashInterval"; |
| 63 const int MetricsDaemon::kMetricUserCrashIntervalMin = 1; |
| 64 const int MetricsDaemon::kMetricUserCrashIntervalMax = 4 * kSecondsPerWeek; |
| 65 const int MetricsDaemon::kMetricUserCrashIntervalBuckets = 50; |
| 66 |
55 // static | 67 // static |
56 const char* MetricsDaemon::kDBusMatches_[] = { | 68 const char* MetricsDaemon::kDBusMatches_[] = { |
57 "type='signal'," | 69 "type='signal'," |
| 70 "interface='" DBUS_IFACE_CRASH_REPORTER "'," |
| 71 "path='/'," |
| 72 "member='UserCrash'", |
| 73 |
| 74 "type='signal'," |
58 "sender='org.chromium.flimflam'," | 75 "sender='org.chromium.flimflam'," |
59 "interface='" DBUS_IFACE_FLIMFLAM_MANAGER "'," | 76 "interface='" DBUS_IFACE_FLIMFLAM_MANAGER "'," |
60 "path='/'," | 77 "path='/'," |
61 "member='StateChanged'", | 78 "member='StateChanged'", |
62 | 79 |
63 "type='signal'," | 80 "type='signal'," |
64 "interface='" DBUS_IFACE_POWER_MANAGER "'," | 81 "interface='" DBUS_IFACE_POWER_MANAGER "'," |
65 "path='/'", | 82 "path='/'", |
66 | 83 |
67 "type='signal'," | 84 "type='signal'," |
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
104 Loop(); | 121 Loop(); |
105 } | 122 } |
106 } | 123 } |
107 | 124 |
108 void MetricsDaemon::Init(bool testing, MetricsLibraryInterface* metrics_lib) { | 125 void MetricsDaemon::Init(bool testing, MetricsLibraryInterface* metrics_lib) { |
109 testing_ = testing; | 126 testing_ = testing; |
110 DCHECK(metrics_lib != NULL); | 127 DCHECK(metrics_lib != NULL); |
111 metrics_lib_ = metrics_lib; | 128 metrics_lib_ = metrics_lib; |
112 daily_use_.reset(new chromeos_metrics::TaggedCounter()); | 129 daily_use_.reset(new chromeos_metrics::TaggedCounter()); |
113 daily_use_->Init(kDailyUseRecordFile, &DailyUseReporter, this); | 130 daily_use_->Init(kDailyUseRecordFile, &DailyUseReporter, this); |
| 131 user_crash_interval_.reset(new chromeos_metrics::TaggedCounter()); |
| 132 user_crash_interval_->Init(kUserCrashIntervalRecordFile, |
| 133 &UserCrashIntervalReporter, this); |
114 | 134 |
115 // Don't setup D-Bus and GLib in test mode. | 135 // Don't setup D-Bus and GLib in test mode. |
116 if (testing) | 136 if (testing) |
117 return; | 137 return; |
118 | 138 |
119 g_thread_init(NULL); | 139 g_thread_init(NULL); |
120 g_type_init(); | 140 g_type_init(); |
121 dbus_g_thread_init(); | 141 dbus_g_thread_init(); |
122 | 142 |
123 DBusError error; | 143 DBusError error; |
124 dbus_error_init(&error); | 144 dbus_error_init(&error); |
125 | 145 |
126 DBusConnection* connection = dbus_bus_get(DBUS_BUS_SYSTEM, &error); | 146 DBusConnection* connection = dbus_bus_get(DBUS_BUS_SYSTEM, &error); |
127 LOG_IF(FATAL, dbus_error_is_set(&error)) << | 147 LOG_IF(FATAL, dbus_error_is_set(&error)) << |
128 "No D-Bus connection: " << SAFE_MESSAGE(error); | 148 "No D-Bus connection: " << SAFE_MESSAGE(error); |
129 | 149 |
130 dbus_connection_setup_with_g_main(connection, NULL); | 150 dbus_connection_setup_with_g_main(connection, NULL); |
131 | 151 |
132 // Registers D-Bus matches for the signals we would like to catch. | 152 // Registers D-Bus matches for the signals we would like to catch. |
133 for (unsigned int m = 0; m < sizeof(kDBusMatches_) / sizeof(char*); m++) { | 153 for (unsigned int m = 0; m < arraysize(kDBusMatches_); m++) { |
134 const char* match = kDBusMatches_[m]; | 154 const char* match = kDBusMatches_[m]; |
135 DLOG(INFO) << "adding dbus match: " << match; | 155 DLOG(INFO) << "adding dbus match: " << match; |
136 dbus_bus_add_match(connection, match, &error); | 156 dbus_bus_add_match(connection, match, &error); |
137 LOG_IF(FATAL, dbus_error_is_set(&error)) << | 157 LOG_IF(FATAL, dbus_error_is_set(&error)) << |
138 "unable to add a match: " << SAFE_MESSAGE(error); | 158 "unable to add a match: " << SAFE_MESSAGE(error); |
139 } | 159 } |
140 | 160 |
141 // Adds the D-Bus filter routine to be called back whenever one of | 161 // Adds the D-Bus filter routine to be called back whenever one of |
142 // the registered D-Bus matches is successful. The daemon is not | 162 // the registered D-Bus matches is successful. The daemon is not |
143 // activated for D-Bus messages that don't match. | 163 // activated for D-Bus messages that don't match. |
(...skipping 20 matching lines...) Expand all Loading... |
164 } | 184 } |
165 | 185 |
166 // Signal messages always have interfaces. | 186 // Signal messages always have interfaces. |
167 const char* interface = dbus_message_get_interface(message); | 187 const char* interface = dbus_message_get_interface(message); |
168 CHECK(interface != NULL); | 188 CHECK(interface != NULL); |
169 | 189 |
170 MetricsDaemon* daemon = static_cast<MetricsDaemon*>(user_data); | 190 MetricsDaemon* daemon = static_cast<MetricsDaemon*>(user_data); |
171 | 191 |
172 DBusMessageIter iter; | 192 DBusMessageIter iter; |
173 dbus_message_iter_init(message, &iter); | 193 dbus_message_iter_init(message, &iter); |
174 if (strcmp(interface, DBUS_IFACE_FLIMFLAM_MANAGER) == 0) { | 194 if (strcmp(interface, DBUS_IFACE_CRASH_REPORTER) == 0) { |
| 195 CHECK(strcmp(dbus_message_get_member(message), |
| 196 "UserCrash") == 0); |
| 197 daemon->ProcessUserCrash(); |
| 198 } else if (strcmp(interface, DBUS_IFACE_FLIMFLAM_MANAGER) == 0) { |
175 CHECK(strcmp(dbus_message_get_member(message), | 199 CHECK(strcmp(dbus_message_get_member(message), |
176 "StateChanged") == 0); | 200 "StateChanged") == 0); |
177 | 201 |
178 char* state_name; | 202 char* state_name; |
179 dbus_message_iter_get_basic(&iter, &state_name); | 203 dbus_message_iter_get_basic(&iter, &state_name); |
180 daemon->NetStateChanged(state_name, ticks); | 204 daemon->NetStateChanged(state_name, ticks); |
181 } else if (strcmp(interface, DBUS_IFACE_POWER_MANAGER) == 0) { | 205 } else if (strcmp(interface, DBUS_IFACE_POWER_MANAGER) == 0) { |
182 const char* member = dbus_message_get_member(message); | 206 const char* member = dbus_message_get_member(message); |
183 if (strcmp(member, "ScreenIsLocked") == 0) { | 207 if (strcmp(member, "ScreenIsLocked") == 0) { |
184 daemon->SetUserActiveState(false, now); | 208 daemon->SetUserActiveState(false, now); |
(...skipping 103 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
288 if (user_active_ && now > user_active_last_) { | 312 if (user_active_ && now > user_active_last_) { |
289 TimeDelta since_active = now - user_active_last_; | 313 TimeDelta since_active = now - user_active_last_; |
290 if (since_active < TimeDelta::FromSeconds( | 314 if (since_active < TimeDelta::FromSeconds( |
291 kUseMonitorIntervalMax + kSecondsPerMinute)) { | 315 kUseMonitorIntervalMax + kSecondsPerMinute)) { |
292 seconds = static_cast<int>(since_active.InSeconds()); | 316 seconds = static_cast<int>(since_active.InSeconds()); |
293 } | 317 } |
294 } | 318 } |
295 TimeDelta since_epoch = now - Time(); | 319 TimeDelta since_epoch = now - Time(); |
296 int day = since_epoch.InDays(); | 320 int day = since_epoch.InDays(); |
297 daily_use_->Update(day, seconds); | 321 daily_use_->Update(day, seconds); |
| 322 user_crash_interval_->Update(0, seconds); |
298 | 323 |
299 // Schedules a use monitor on inactive->active transitions and | 324 // Schedules a use monitor on inactive->active transitions and |
300 // unschedules it on active->inactive transitions. | 325 // unschedules it on active->inactive transitions. |
301 if (!user_active_ && active) | 326 if (!user_active_ && active) |
302 ScheduleUseMonitor(kUseMonitorIntervalInit, /* backoff */ false); | 327 ScheduleUseMonitor(kUseMonitorIntervalInit, /* backoff */ false); |
303 else if (user_active_ && !active) | 328 else if (user_active_ && !active) |
304 UnscheduleUseMonitor(); | 329 UnscheduleUseMonitor(); |
305 | 330 |
306 // Remembers the current active state and the time of the last | 331 // Remembers the current active state and the time of the last |
307 // activity update. | 332 // activity update. |
308 user_active_ = active; | 333 user_active_ = active; |
309 user_active_last_ = now; | 334 user_active_last_ = now; |
310 } | 335 } |
311 | 336 |
| 337 void MetricsDaemon::ProcessUserCrash() { |
| 338 // Counts the active use time up to now. |
| 339 SetUserActiveState(user_active_, Time::Now()); |
| 340 |
| 341 // Reports the active use time since the last crash and resets it. |
| 342 user_crash_interval_->Flush(); |
| 343 } |
| 344 |
312 // static | 345 // static |
313 gboolean MetricsDaemon::UseMonitorStatic(gpointer data) { | 346 gboolean MetricsDaemon::UseMonitorStatic(gpointer data) { |
314 return static_cast<MetricsDaemon*>(data)->UseMonitor() ? TRUE : FALSE; | 347 return static_cast<MetricsDaemon*>(data)->UseMonitor() ? TRUE : FALSE; |
315 } | 348 } |
316 | 349 |
317 bool MetricsDaemon::UseMonitor() { | 350 bool MetricsDaemon::UseMonitor() { |
318 SetUserActiveState(user_active_, Time::Now()); | 351 SetUserActiveState(user_active_, Time::Now()); |
319 | 352 |
320 // If a new monitor source/instance is scheduled, returns false to | 353 // If a new monitor source/instance is scheduled, returns false to |
321 // tell GLib to destroy this monitor source/instance. Returns true | 354 // tell GLib to destroy this monitor source/instance. Returns true |
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
364 return; | 397 return; |
365 | 398 |
366 DLOG(INFO) << "destroying use monitor"; | 399 DLOG(INFO) << "destroying use monitor"; |
367 g_source_destroy(usemon_source_); | 400 g_source_destroy(usemon_source_); |
368 usemon_source_ = NULL; | 401 usemon_source_ = NULL; |
369 usemon_interval_ = 0; | 402 usemon_interval_ = 0; |
370 } | 403 } |
371 | 404 |
372 // static | 405 // static |
373 void MetricsDaemon::DailyUseReporter(void* handle, int tag, int count) { | 406 void MetricsDaemon::DailyUseReporter(void* handle, int tag, int count) { |
| 407 if (count <= 0) |
| 408 return; |
| 409 |
374 MetricsDaemon* daemon = static_cast<MetricsDaemon*>(handle); | 410 MetricsDaemon* daemon = static_cast<MetricsDaemon*>(handle); |
375 int minutes = (count + kSecondsPerMinute / 2) / kSecondsPerMinute; | 411 int minutes = (count + kSecondsPerMinute / 2) / kSecondsPerMinute; |
376 daemon->SendMetric(kMetricDailyUseTimeName, minutes, | 412 daemon->SendMetric(kMetricDailyUseTimeName, minutes, |
377 kMetricDailyUseTimeMin, | 413 kMetricDailyUseTimeMin, |
378 kMetricDailyUseTimeMax, | 414 kMetricDailyUseTimeMax, |
379 kMetricDailyUseTimeBuckets); | 415 kMetricDailyUseTimeBuckets); |
380 } | 416 } |
381 | 417 |
| 418 // static |
| 419 void MetricsDaemon::UserCrashIntervalReporter(void* handle, |
| 420 int tag, int count) { |
| 421 MetricsDaemon* daemon = static_cast<MetricsDaemon*>(handle); |
| 422 daemon->SendMetric(kMetricUserCrashIntervalName, count, |
| 423 kMetricUserCrashIntervalMin, |
| 424 kMetricUserCrashIntervalMax, |
| 425 kMetricUserCrashIntervalBuckets); |
| 426 } |
| 427 |
382 void MetricsDaemon::SendMetric(const std::string& name, int sample, | 428 void MetricsDaemon::SendMetric(const std::string& name, int sample, |
383 int min, int max, int nbuckets) { | 429 int min, int max, int nbuckets) { |
384 DLOG(INFO) << "received metric: " << name << " " << sample << " " | 430 DLOG(INFO) << "received metric: " << name << " " << sample << " " |
385 << min << " " << max << " " << nbuckets; | 431 << min << " " << max << " " << nbuckets; |
386 metrics_lib_->SendToUMA(name, sample, min, max, nbuckets); | 432 metrics_lib_->SendToUMA(name, sample, min, max, nbuckets); |
387 } | 433 } |
OLD | NEW |