Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(833)

Side by Side Diff: components/doodle/doodle_service.cc

Issue 2760253003: [Doodle] Record UMA for DoodleConfig download outcome and time (Closed)
Patch Set: tests Created 3 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright 2017 The Chromium Authors. All rights reserved. 1 // Copyright 2017 The Chromium 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 "components/doodle/doodle_service.h" 5 #include "components/doodle/doodle_service.h"
6 6
7 #include <utility> 7 #include <utility>
8 8
9 #include "base/bind.h" 9 #include "base/bind.h"
10 #include "base/metrics/histogram_macros.h"
10 #include "base/time/time.h" 11 #include "base/time/time.h"
11 #include "base/values.h" 12 #include "base/values.h"
12 #include "components/doodle/pref_names.h" 13 #include "components/doodle/pref_names.h"
13 #include "components/prefs/pref_registry.h" 14 #include "components/prefs/pref_registry.h"
14 #include "components/prefs/pref_registry_simple.h" 15 #include "components/prefs/pref_registry_simple.h"
15 #include "components/prefs/pref_service.h" 16 #include "components/prefs/pref_service.h"
16 17
17 namespace doodle { 18 namespace doodle {
18 19
19 // static 20 // static
20 void DoodleService::RegisterProfilePrefs(PrefRegistrySimple* pref_registry) { 21 void DoodleService::RegisterProfilePrefs(PrefRegistrySimple* pref_registry) {
21 pref_registry->RegisterDictionaryPref(prefs::kCachedConfig, 22 pref_registry->RegisterDictionaryPref(prefs::kCachedConfig,
22 new base::DictionaryValue(), 23 new base::DictionaryValue(),
23 PrefRegistry::LOSSY_PREF); 24 PrefRegistry::LOSSY_PREF);
24 pref_registry->RegisterInt64Pref(prefs::kCachedConfigExpiry, 0, 25 pref_registry->RegisterInt64Pref(prefs::kCachedConfigExpiry, 0,
25 PrefRegistry::LOSSY_PREF); 26 PrefRegistry::LOSSY_PREF);
26 } 27 }
27 28
28 DoodleService::DoodleService(PrefService* pref_service, 29 DoodleService::DoodleService(PrefService* pref_service,
29 std::unique_ptr<DoodleFetcher> fetcher, 30 std::unique_ptr<DoodleFetcher> fetcher,
30 std::unique_ptr<base::OneShotTimer> expiry_timer, 31 std::unique_ptr<base::OneShotTimer> expiry_timer,
31 std::unique_ptr<base::Clock> clock) 32 std::unique_ptr<base::Clock> clock,
33 std::unique_ptr<base::TickClock> tick_clock)
32 : pref_service_(pref_service), 34 : pref_service_(pref_service),
33 fetcher_(std::move(fetcher)), 35 fetcher_(std::move(fetcher)),
34 expiry_timer_(std::move(expiry_timer)), 36 expiry_timer_(std::move(expiry_timer)),
35 clock_(std::move(clock)) { 37 clock_(std::move(clock)),
38 tick_clock_(std::move(tick_clock)) {
36 DCHECK(pref_service_); 39 DCHECK(pref_service_);
37 DCHECK(fetcher_); 40 DCHECK(fetcher_);
38 DCHECK(expiry_timer_); 41 DCHECK(expiry_timer_);
39 DCHECK(clock_); 42 DCHECK(clock_);
43 DCHECK(tick_clock_);
40 44
41 base::Time expiry_date = base::Time::FromInternalValue( 45 base::Time expiry_date = base::Time::FromInternalValue(
42 pref_service_->GetInt64(prefs::kCachedConfigExpiry)); 46 pref_service_->GetInt64(prefs::kCachedConfigExpiry));
43 base::Optional<DoodleConfig> config = DoodleConfig::FromDictionary( 47 base::Optional<DoodleConfig> config = DoodleConfig::FromDictionary(
44 *pref_service_->GetDictionary(prefs::kCachedConfig), base::nullopt); 48 *pref_service_->GetDictionary(prefs::kCachedConfig), base::nullopt);
45 UpdateCachedConfig(expiry_date - clock_->Now(), config); 49 DoodleState state =
50 config.has_value() ? DoodleState::AVAILABLE : DoodleState::NO_DOODLE;
51 HandleNewConfig(state, expiry_date - clock_->Now(), config);
46 } 52 }
47 53
48 DoodleService::~DoodleService() = default; 54 DoodleService::~DoodleService() = default;
49 55
50 void DoodleService::Shutdown() {} 56 void DoodleService::Shutdown() {}
51 57
52 void DoodleService::AddObserver(Observer* observer) { 58 void DoodleService::AddObserver(Observer* observer) {
53 observers_.AddObserver(observer); 59 observers_.AddObserver(observer);
54 } 60 }
55 61
56 void DoodleService::RemoveObserver(Observer* observer) { 62 void DoodleService::RemoveObserver(Observer* observer) {
57 observers_.RemoveObserver(observer); 63 observers_.RemoveObserver(observer);
58 } 64 }
59 65
60 void DoodleService::Refresh() { 66 void DoodleService::Refresh() {
61 fetcher_->FetchDoodle( 67 fetcher_->FetchDoodle(base::BindOnce(&DoodleService::DoodleFetched,
62 base::BindOnce(&DoodleService::DoodleFetched, base::Unretained(this))); 68 base::Unretained(this),
69 tick_clock_->NowTicks()));
70 }
71
72 // static
73 bool DoodleService::DownloadOutcomeIsSuccess(DownloadOutcome outcome) {
74 switch (outcome) {
75 case OUTCOME_NEW_DOODLE:
76 case OUTCOME_REVALIDATED_DOODLE:
77 case OUTCOME_CHANGED_DOODLE:
78 case OUTCOME_NO_DOODLE:
79 return true;
80 case OUTCOME_EXPIRED:
81 case OUTCOME_DOWNLOAD_ERROR:
82 case OUTCOME_PARSING_ERROR:
83 return false;
84 case OUTCOME_COUNT:
85 NOTREACHED();
86 }
87 return false;
88 }
89
90 // static
91 void DoodleService::RecordDownloadMetrics(DownloadOutcome outcome,
92 base::TimeDelta download_time) {
93 UMA_HISTOGRAM_ENUMERATION("Doodle.ConfigDownloadOutcome", outcome,
94 OUTCOME_COUNT);
95
96 if (DownloadOutcomeIsSuccess(outcome)) {
97 UMA_HISTOGRAM_MEDIUM_TIMES("Doodle.ConfigDownloadTime", download_time);
98 }
99 }
100
101 // static
102 DoodleService::DownloadOutcome DoodleService::DetermineDownloadOutcome(
103 const base::Optional<DoodleConfig>& old_config,
104 const base::Optional<DoodleConfig>& new_config,
105 DoodleState state,
106 bool expired) {
107 // First, handle error cases: *_ERROR or EXPIRED override other outcomes.
108 switch (state) {
109 case DoodleState::AVAILABLE:
110 if (expired) {
111 return OUTCOME_EXPIRED;
112 }
113 break;
114
115 case DoodleState::NO_DOODLE:
116 break;
117
118 case DoodleState::DOWNLOAD_ERROR:
119 return OUTCOME_DOWNLOAD_ERROR;
120
121 case DoodleState::PARSING_ERROR:
122 return OUTCOME_PARSING_ERROR;
123 }
124
125 if (!new_config.has_value()) {
126 return OUTCOME_NO_DOODLE;
127 }
128 if (!old_config.has_value()) {
129 return OUTCOME_NEW_DOODLE;
130 }
131 if (old_config.value() != new_config.value()) {
132 return OUTCOME_CHANGED_DOODLE;
133 }
134 return OUTCOME_REVALIDATED_DOODLE;
63 } 135 }
64 136
65 void DoodleService::DoodleFetched( 137 void DoodleService::DoodleFetched(
138 base::TimeTicks start_time,
66 DoodleState state, 139 DoodleState state,
67 base::TimeDelta time_to_live, 140 base::TimeDelta time_to_live,
68 const base::Optional<DoodleConfig>& doodle_config) { 141 const base::Optional<DoodleConfig>& doodle_config) {
69 UpdateCachedConfig(time_to_live, doodle_config); 142 base::TimeDelta download_time = tick_clock_->NowTicks() - start_time;
143 DownloadOutcome outcome = HandleNewConfig(state, time_to_live, doodle_config);
144 RecordDownloadMetrics(outcome, download_time);
70 } 145 }
71 146
72 void DoodleService::UpdateCachedConfig( 147 DoodleService::DownloadOutcome DoodleService::HandleNewConfig(
148 DoodleState state,
73 base::TimeDelta time_to_live, 149 base::TimeDelta time_to_live,
74 const base::Optional<DoodleConfig>& doodle_config) { 150 const base::Optional<DoodleConfig>& doodle_config) {
75 // Handle the case where the new config is already expired. 151 // Handle the case where the new config is already expired.
76 bool expired = time_to_live <= base::TimeDelta(); 152 bool expired = time_to_live <= base::TimeDelta();
77 const base::Optional<DoodleConfig>& new_config = 153 const base::Optional<DoodleConfig>& new_config =
78 expired ? base::nullopt : doodle_config; 154 expired ? base::nullopt : doodle_config;
79 155
156 // Determine the download outcome *before* updating the cached config.
157 DownloadOutcome outcome =
158 DetermineDownloadOutcome(cached_config_, new_config, state, expired);
159
80 // If the config changed, update our cache and notify observers. 160 // If the config changed, update our cache and notify observers.
81 // Note that this checks both for existence changes as well as changes of the 161 // Note that this checks both for existence changes as well as changes of the
82 // configs themselves. 162 // configs themselves.
83 if (cached_config_ != new_config) { 163 if (cached_config_ != new_config) {
84 cached_config_ = new_config; 164 UpdateCachedConfig(time_to_live, new_config);
85
86 if (cached_config_.has_value()) {
87 pref_service_->Set(prefs::kCachedConfig, *cached_config_->ToDictionary());
88 base::Time expiry_date = clock_->Now() + time_to_live;
89 pref_service_->SetInt64(prefs::kCachedConfigExpiry,
90 expiry_date.ToInternalValue());
91 } else {
92 pref_service_->ClearPref(prefs::kCachedConfig);
93 pref_service_->ClearPref(prefs::kCachedConfigExpiry);
94 }
95 165
96 for (auto& observer : observers_) { 166 for (auto& observer : observers_) {
97 observer.OnDoodleConfigUpdated(cached_config_); 167 observer.OnDoodleConfigUpdated(cached_config_);
98 } 168 }
99 } 169 }
100 170
101 // Even if the configs are identical, the time-to-live might have changed. 171 // Even if the configs are identical, the time-to-live might have changed.
102 // (Re-)schedule the cache expiry. 172 // (Re-)schedule the cache expiry.
103 if (cached_config_.has_value()) { 173 if (cached_config_.has_value()) {
104 expiry_timer_->Start( 174 expiry_timer_->Start(
105 FROM_HERE, time_to_live, 175 FROM_HERE, time_to_live,
106 base::Bind(&DoodleService::DoodleExpired, base::Unretained(this))); 176 base::Bind(&DoodleService::DoodleExpired, base::Unretained(this)));
107 } else { 177 } else {
108 expiry_timer_->Stop(); 178 expiry_timer_->Stop();
109 } 179 }
180
181 return outcome;
182 }
183
184 void DoodleService::UpdateCachedConfig(
185 base::TimeDelta time_to_live,
186 const base::Optional<DoodleConfig>& new_config) {
187 DCHECK(cached_config_ != new_config);
188
189 cached_config_ = new_config;
190
191 if (cached_config_.has_value()) {
192 pref_service_->Set(prefs::kCachedConfig, *cached_config_->ToDictionary());
193 base::Time expiry_date = clock_->Now() + time_to_live;
194 pref_service_->SetInt64(prefs::kCachedConfigExpiry,
195 expiry_date.ToInternalValue());
196 } else {
197 pref_service_->ClearPref(prefs::kCachedConfig);
198 pref_service_->ClearPref(prefs::kCachedConfigExpiry);
199 }
110 } 200 }
111 201
112 void DoodleService::DoodleExpired() { 202 void DoodleService::DoodleExpired() {
113 DCHECK(cached_config_.has_value()); 203 DCHECK(cached_config_.has_value());
114 UpdateCachedConfig(base::TimeDelta(), base::nullopt); 204 HandleNewConfig(DoodleState::NO_DOODLE, base::TimeDelta(), base::nullopt);
115 } 205 }
116 206
117 } // namespace doodle 207 } // namespace doodle
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698