| 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 |