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 #include <sys/file.h> | |
9 | 8 |
10 #include <base/eintr_wrapper.h> | |
11 #include <base/logging.h> | 9 #include <base/logging.h> |
12 | 10 |
| 11 #include "counter.h" |
| 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_FLIMFLAM_MANAGER "org.chromium.flimflam.Manager" | 18 #define DBUS_IFACE_FLIMFLAM_MANAGER "org.chromium.flimflam.Manager" |
19 #define DBUS_IFACE_POWER_MANAGER "org.chromium.PowerManager" | 19 #define DBUS_IFACE_POWER_MANAGER "org.chromium.PowerManager" |
20 #define DBUS_IFACE_SESSION_MANAGER "org.chromium.SessionManagerInterface" | 20 #define DBUS_IFACE_SESSION_MANAGER "org.chromium.SessionManagerInterface" |
21 | 21 |
22 // File to aggregate daily usage before sending to UMA. | 22 // File to aggregate daily usage before sending to UMA. |
(...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
82 #define STATE(name, capname) #name, | 82 #define STATE(name, capname) #name, |
83 #include "power_states.h" | 83 #include "power_states.h" |
84 }; | 84 }; |
85 | 85 |
86 // static | 86 // static |
87 const char* MetricsDaemon::kSessionStates_[] = { | 87 const char* MetricsDaemon::kSessionStates_[] = { |
88 #define STATE(name, capname) #name, | 88 #define STATE(name, capname) #name, |
89 #include "session_states.h" | 89 #include "session_states.h" |
90 }; | 90 }; |
91 | 91 |
| 92 MetricsDaemon::MetricsDaemon() |
| 93 : network_state_(kUnknownNetworkState), |
| 94 power_state_(kUnknownPowerState), |
| 95 session_state_(kUnknownSessionState), |
| 96 user_active_(false), |
| 97 usemon_interval_(0), |
| 98 usemon_source_(NULL) {} |
| 99 |
| 100 MetricsDaemon::~MetricsDaemon() {} |
| 101 |
92 void MetricsDaemon::Run(bool run_as_daemon) { | 102 void MetricsDaemon::Run(bool run_as_daemon) { |
93 if (!run_as_daemon || daemon(0, 0) == 0) { | 103 if (!run_as_daemon || daemon(0, 0) == 0) { |
94 Loop(); | 104 Loop(); |
95 } | 105 } |
96 } | 106 } |
97 | 107 |
98 void MetricsDaemon::Init(bool testing, MetricsLibraryInterface* metrics_lib) { | 108 void MetricsDaemon::Init(bool testing, MetricsLibraryInterface* metrics_lib) { |
99 testing_ = testing; | 109 testing_ = testing; |
100 DCHECK(metrics_lib != NULL); | 110 DCHECK(metrics_lib != NULL); |
101 metrics_lib_ = metrics_lib; | 111 metrics_lib_ = metrics_lib; |
102 daily_use_record_file_ = kDailyUseRecordFile; | 112 daily_use_.reset(new chromeos_metrics::TaggedCounter()); |
| 113 daily_use_->Init(kDailyUseRecordFile, &DailyUseReporter, this); |
103 | 114 |
104 // Don't setup D-Bus and GLib in test mode. | 115 // Don't setup D-Bus and GLib in test mode. |
105 if (testing) | 116 if (testing) |
106 return; | 117 return; |
107 | 118 |
108 g_thread_init(NULL); | 119 g_thread_init(NULL); |
109 g_type_init(); | 120 g_type_init(); |
110 dbus_g_thread_init(); | 121 dbus_g_thread_init(); |
111 | 122 |
112 DBusError error; | 123 DBusError error; |
(...skipping 163 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
276 int seconds = 0; | 287 int seconds = 0; |
277 if (user_active_ && now > user_active_last_) { | 288 if (user_active_ && now > user_active_last_) { |
278 TimeDelta since_active = now - user_active_last_; | 289 TimeDelta since_active = now - user_active_last_; |
279 if (since_active < TimeDelta::FromSeconds( | 290 if (since_active < TimeDelta::FromSeconds( |
280 kUseMonitorIntervalMax + kSecondsPerMinute)) { | 291 kUseMonitorIntervalMax + kSecondsPerMinute)) { |
281 seconds = static_cast<int>(since_active.InSeconds()); | 292 seconds = static_cast<int>(since_active.InSeconds()); |
282 } | 293 } |
283 } | 294 } |
284 TimeDelta since_epoch = now - Time(); | 295 TimeDelta since_epoch = now - Time(); |
285 int day = since_epoch.InDays(); | 296 int day = since_epoch.InDays(); |
286 LogDailyUseRecord(day, seconds); | 297 daily_use_->Update(day, seconds); |
287 | 298 |
288 // Schedules a use monitor on inactive->active transitions and | 299 // Schedules a use monitor on inactive->active transitions and |
289 // unschedules it on active->inactive transitions. | 300 // unschedules it on active->inactive transitions. |
290 if (!user_active_ && active) | 301 if (!user_active_ && active) |
291 ScheduleUseMonitor(kUseMonitorIntervalInit, /* backoff */ false); | 302 ScheduleUseMonitor(kUseMonitorIntervalInit, /* backoff */ false); |
292 else if (user_active_ && !active) | 303 else if (user_active_ && !active) |
293 UnscheduleUseMonitor(); | 304 UnscheduleUseMonitor(); |
294 | 305 |
295 // Remembers the current active state and the time of the last | 306 // Remembers the current active state and the time of the last |
296 // activity update. | 307 // activity update. |
297 user_active_ = active; | 308 user_active_ = active; |
298 user_active_last_ = now; | 309 user_active_last_ = now; |
299 } | 310 } |
300 | 311 |
301 void MetricsDaemon::LogDailyUseRecord(int day, int seconds) { | |
302 // If there's no new active use today and the last record in the | |
303 // usage aggregation file is today, there's nothing to do. | |
304 if (seconds == 0 && day == daily_use_day_last_) | |
305 return; | |
306 | |
307 DLOG(INFO) << "day: " << day << " usage: " << seconds << " seconds"; | |
308 int fd = HANDLE_EINTR(open(daily_use_record_file_, | |
309 O_RDWR | O_CREAT, | |
310 S_IRUSR | S_IWUSR)); | |
311 if (fd < 0) { | |
312 PLOG(WARNING) << "Unable to open the daily use file"; | |
313 return; | |
314 } | |
315 | |
316 bool same_day = false; | |
317 UseRecord record; | |
318 if (HANDLE_EINTR(read(fd, &record, sizeof(record))) == sizeof(record)) { | |
319 if (record.day_ == day) { | |
320 // If there's an existing record for today, aggregates the usage | |
321 // time. | |
322 same_day = true; | |
323 record.seconds_ += seconds; | |
324 } else { | |
325 // If there's an existing record for a day in the past, rounds | |
326 // the usage to the nearest minute and sends it to UMA. | |
327 int minutes = | |
328 (record.seconds_ + kSecondsPerMinute / 2) / kSecondsPerMinute; | |
329 SendMetric(kMetricDailyUseTimeName, minutes, | |
330 kMetricDailyUseTimeMin, | |
331 kMetricDailyUseTimeMax, | |
332 kMetricDailyUseTimeBuckets); | |
333 | |
334 // Truncates the usage file to ensure that no duplicate usage is | |
335 // sent to UMA. | |
336 PLOG_IF(WARNING, HANDLE_EINTR(ftruncate(fd, 0)) != 0); | |
337 } | |
338 } | |
339 | |
340 // Updates the use record in the daily usage file if there's new | |
341 // usage today. | |
342 if (seconds > 0) { | |
343 if (!same_day) { | |
344 record.day_ = day; | |
345 record.seconds_ = seconds; | |
346 } | |
347 // else an already existing record for the same day will be | |
348 // overwritten with updated usage below. | |
349 | |
350 PLOG_IF(WARNING, HANDLE_EINTR(lseek(fd, 0, SEEK_SET)) != 0); | |
351 PLOG_IF(WARNING, | |
352 HANDLE_EINTR(write(fd, &record, sizeof(record))) != | |
353 sizeof(record)); | |
354 } | |
355 | |
356 HANDLE_EINTR(close(fd)); | |
357 | |
358 // Remembers the day of the use record in the usage aggregation file | |
359 // to reduce file I/O. This is not really useful now but potentially | |
360 // allows frequent LogDailyUseRecord calls with no unnecessary I/O | |
361 // overhead. | |
362 daily_use_day_last_ = day; | |
363 } | |
364 | |
365 // static | 312 // static |
366 gboolean MetricsDaemon::UseMonitorStatic(gpointer data) { | 313 gboolean MetricsDaemon::UseMonitorStatic(gpointer data) { |
367 return static_cast<MetricsDaemon*>(data)->UseMonitor() ? TRUE : FALSE; | 314 return static_cast<MetricsDaemon*>(data)->UseMonitor() ? TRUE : FALSE; |
368 } | 315 } |
369 | 316 |
370 bool MetricsDaemon::UseMonitor() { | 317 bool MetricsDaemon::UseMonitor() { |
371 SetUserActiveState(user_active_, Time::Now()); | 318 SetUserActiveState(user_active_, Time::Now()); |
372 | 319 |
373 // If a new monitor source/instance is scheduled, returns false to | 320 // If a new monitor source/instance is scheduled, returns false to |
374 // tell GLib to destroy this monitor source/instance. Returns true | 321 // tell GLib to destroy this monitor source/instance. Returns true |
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
415 // If there's a use monitor scheduled already, destroys it. | 362 // If there's a use monitor scheduled already, destroys it. |
416 if (usemon_source_ == NULL) | 363 if (usemon_source_ == NULL) |
417 return; | 364 return; |
418 | 365 |
419 DLOG(INFO) << "destroying use monitor"; | 366 DLOG(INFO) << "destroying use monitor"; |
420 g_source_destroy(usemon_source_); | 367 g_source_destroy(usemon_source_); |
421 usemon_source_ = NULL; | 368 usemon_source_ = NULL; |
422 usemon_interval_ = 0; | 369 usemon_interval_ = 0; |
423 } | 370 } |
424 | 371 |
| 372 // static |
| 373 void MetricsDaemon::DailyUseReporter(void* handle, int tag, int count) { |
| 374 MetricsDaemon* daemon = static_cast<MetricsDaemon*>(handle); |
| 375 int minutes = (count + kSecondsPerMinute / 2) / kSecondsPerMinute; |
| 376 daemon->SendMetric(kMetricDailyUseTimeName, minutes, |
| 377 kMetricDailyUseTimeMin, |
| 378 kMetricDailyUseTimeMax, |
| 379 kMetricDailyUseTimeBuckets); |
| 380 } |
| 381 |
425 void MetricsDaemon::SendMetric(const std::string& name, int sample, | 382 void MetricsDaemon::SendMetric(const std::string& name, int sample, |
426 int min, int max, int nbuckets) { | 383 int min, int max, int nbuckets) { |
427 DLOG(INFO) << "received metric: " << name << " " << sample << " " | 384 DLOG(INFO) << "received metric: " << name << " " << sample << " " |
428 << min << " " << max << " " << nbuckets; | 385 << min << " " << max << " " << nbuckets; |
429 metrics_lib_->SendToUMA(name, sample, min, max, nbuckets); | 386 metrics_lib_->SendToUMA(name, sample, min, max, nbuckets); |
430 } | 387 } |
OLD | NEW |