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 <utility>
8 
9 #include "base/metrics/histogram.h"
10 #include "components/prefs/pref_registry_simple.h"
11 #include "components/prefs/pref_service.h"
12 
13 namespace metrics {
14 
15 namespace {
16 
RecordIntervalTypeHistogram(const std::string & histogram_name,DailyEvent::IntervalType type)17 void RecordIntervalTypeHistogram(const std::string& histogram_name,
18                                  DailyEvent::IntervalType type) {
19   const int num_types = static_cast<int>(DailyEvent::IntervalType::NUM_TYPES);
20   base::Histogram::FactoryGet(histogram_name, 1, num_types, num_types + 1,
21                               base::HistogramBase::kUmaTargetedHistogramFlag)
22       ->Add(static_cast<int>(type));
23 }
24 
25 }  // namespace
26 
Observer()27 DailyEvent::Observer::Observer() {
28 }
29 
~Observer()30 DailyEvent::Observer::~Observer() {
31 }
32 
DailyEvent(PrefService * pref_service,const char * pref_name,const std::string & histogram_name)33 DailyEvent::DailyEvent(PrefService* pref_service,
34                        const char* pref_name,
35                        const std::string& histogram_name)
36     : pref_service_(pref_service),
37       pref_name_(pref_name),
38       histogram_name_(histogram_name) {
39 }
40 
~DailyEvent()41 DailyEvent::~DailyEvent() {
42 }
43 
44 // static
RegisterPref(PrefRegistrySimple * registry,const char * pref_name)45 void DailyEvent::RegisterPref(PrefRegistrySimple* registry,
46                               const char* pref_name) {
47   registry->RegisterInt64Pref(pref_name, 0);
48 }
49 
AddObserver(std::unique_ptr<DailyEvent::Observer> observer)50 void DailyEvent::AddObserver(std::unique_ptr<DailyEvent::Observer> observer) {
51   DVLOG(2) << "DailyEvent observer added.";
52   DCHECK(last_fired_.is_null());
53   observers_.push_back(std::move(observer));
54 }
55 
CheckInterval()56 void DailyEvent::CheckInterval() {
57   base::Time now = base::Time::Now();
58   if (last_fired_.is_null()) {
59     // The first time we call CheckInterval, we read the time stored in prefs.
60     last_fired_ = base::Time() + base::TimeDelta::FromMicroseconds(
61                                      pref_service_->GetInt64(pref_name_));
62 
63     DVLOG(1) << "DailyEvent time loaded: " << last_fired_;
64     if (last_fired_.is_null()) {
65       DVLOG(1) << "DailyEvent first run.";
66       RecordIntervalTypeHistogram(histogram_name_, IntervalType::FIRST_RUN);
67       OnInterval(now, IntervalType::FIRST_RUN);
68       return;
69     }
70   }
71   int days_elapsed = (now - last_fired_).InDays();
72   if (days_elapsed >= 1) {
73     DVLOG(1) << "DailyEvent day elapsed.";
74     RecordIntervalTypeHistogram(histogram_name_, IntervalType::DAY_ELAPSED);
75     OnInterval(now, IntervalType::DAY_ELAPSED);
76   } else if (days_elapsed <= -1) {
77     // The "last fired" time is more than a day in the future, so the clock
78     // must have been changed.
79     DVLOG(1) << "DailyEvent clock change detected.";
80     RecordIntervalTypeHistogram(histogram_name_, IntervalType::CLOCK_CHANGED);
81     OnInterval(now, IntervalType::CLOCK_CHANGED);
82   }
83 }
84 
OnInterval(base::Time now,IntervalType type)85 void DailyEvent::OnInterval(base::Time now, IntervalType type) {
86   DCHECK(!now.is_null());
87   last_fired_ = now;
88   pref_service_->SetInt64(pref_name_,
89                           last_fired_.since_origin().InMicroseconds());
90 
91   for (auto it = observers_.begin(); it != observers_.end(); ++it) {
92     (*it)->OnDailyEvent(type);
93   }
94 }
95 
96 }  // namespace metrics
97