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