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 12namespace metrics { 13 14namespace { 15 16enum IntervalType { 17 FIRST_RUN, 18 DAY_ELAPSED, 19 CLOCK_CHANGED, 20 NUM_INTERVAL_TYPES 21}; 22 23void 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 35DailyEvent::Observer::Observer() { 36} 37 38DailyEvent::Observer::~Observer() { 39} 40 41DailyEvent::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 49DailyEvent::~DailyEvent() { 50} 51 52// static 53void DailyEvent::RegisterPref(PrefRegistrySimple* registry, 54 const char* pref_name) { 55 registry->RegisterInt64Pref(pref_name, base::Time().ToInternalValue()); 56} 57 58void 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 64void 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 93void 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