Home | History | Annotate | Download | only in metrics
      1 // Copyright 2014 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "components/metrics/daily_event.h"
      6 
      7 #include "base/i18n/time_formatting.h"
      8 #include "base/metrics/histogram.h"
      9 #include "base/prefs/pref_registry_simple.h"
     10 #include "base/prefs/pref_service.h"
     11 
     12 namespace metrics {
     13 
     14 namespace {
     15 
     16 enum IntervalType {
     17   FIRST_RUN,
     18   DAY_ELAPSED,
     19   CLOCK_CHANGED,
     20   NUM_INTERVAL_TYPES
     21 };
     22 
     23 void RecordIntervalTypeHistogram(const std::string& histogram_name,
     24                                  IntervalType type) {
     25   base::Histogram::FactoryGet(
     26       histogram_name,
     27       1,
     28       NUM_INTERVAL_TYPES,
     29       NUM_INTERVAL_TYPES + 1,
     30       base::HistogramBase::kUmaTargetedHistogramFlag)->Add(type);
     31 }
     32 
     33 }  // namespace
     34 
     35 DailyEvent::Observer::Observer() {
     36 }
     37 
     38 DailyEvent::Observer::~Observer() {
     39 }
     40 
     41 DailyEvent::DailyEvent(PrefService* pref_service,
     42                        const char* pref_name,
     43                        const std::string& histogram_name)
     44     : pref_service_(pref_service),
     45       pref_name_(pref_name),
     46       histogram_name_(histogram_name) {
     47 }
     48 
     49 DailyEvent::~DailyEvent() {
     50 }
     51 
     52 // static
     53 void DailyEvent::RegisterPref(PrefRegistrySimple* registry,
     54                               const char* pref_name) {
     55   registry->RegisterInt64Pref(pref_name, base::Time().ToInternalValue());
     56 }
     57 
     58 void DailyEvent::AddObserver(scoped_ptr<DailyEvent::Observer> observer) {
     59   DVLOG(2) << "DailyEvent observer added.";
     60   DCHECK(last_fired_.is_null());
     61   observers_.push_back(observer.release());
     62 }
     63 
     64 void DailyEvent::CheckInterval() {
     65   base::Time now = base::Time::Now();
     66   if (last_fired_.is_null()) {
     67     // The first time we call CheckInterval, we read the time stored in prefs.
     68     last_fired_ = base::Time::FromInternalValue(
     69         pref_service_->GetInt64(pref_name_));
     70     DVLOG(1) << "DailyEvent time loaded: "
     71              << base::TimeFormatShortDateAndTime(last_fired_);
     72     if (last_fired_.is_null()) {
     73       DVLOG(1) << "DailyEvent first run.";
     74       RecordIntervalTypeHistogram(pref_name_, FIRST_RUN);
     75       OnInterval(now);
     76       return;
     77     }
     78   }
     79   int days_elapsed = (now - last_fired_).InDays();
     80   if (days_elapsed >= 1) {
     81     DVLOG(1) << "DailyEvent day elapsed.";
     82     RecordIntervalTypeHistogram(pref_name_, DAY_ELAPSED);
     83     OnInterval(now);
     84   } else if (days_elapsed <= -1) {
     85     // The "last fired" time is more than a day in the future, so the clock
     86     // must have been changed.
     87     DVLOG(1) << "DailyEvent clock change detected.";
     88     RecordIntervalTypeHistogram(pref_name_, CLOCK_CHANGED);
     89     OnInterval(now);
     90   }
     91 }
     92 
     93 void DailyEvent::OnInterval(base::Time now) {
     94   DCHECK(!now.is_null());
     95   last_fired_ = now;
     96   pref_service_->SetInt64(pref_name_, last_fired_.ToInternalValue());
     97 
     98   // Notify all observers
     99   for (ScopedVector<DailyEvent::Observer>::iterator it = observers_.begin();
    100        it != observers_.end();
    101        ++it) {
    102     (*it)->OnDailyEvent();
    103   }
    104 }
    105 
    106 }  // namespace metrics
    107