Chromium Code Reviews| OLD | NEW |
|---|---|
| 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 |
| 20 namespace { | |
| 21 | |
| 22 // Note: Keep in sync with the corresponding enum in histograms.xml. Never | |
| 23 // remove values, and only insert new values at the end. | |
| 24 enum DoodleConfigDownloadOutcome { | |
| 25 OUTCOME_NEW_DOODLE, | |
| 26 OUTCOME_REVALIDATED_DOODLE, | |
| 27 OUTCOME_CHANGED_DOODLE, | |
| 28 OUTCOME_NO_DOODLE, | |
| 29 OUTCOME_EXPIRED, | |
| 30 OUTCOME_DOWNLOAD_ERROR, | |
| 31 OUTCOME_PARSING_ERROR, | |
| 32 // Insert new values here! | |
| 33 OUTCOME_COUNT | |
| 34 }; | |
| 35 | |
| 36 bool DownloadOutcomeIsSuccess(DoodleConfigDownloadOutcome outcome) { | |
| 37 switch (outcome) { | |
| 38 case OUTCOME_NEW_DOODLE: | |
| 39 case OUTCOME_REVALIDATED_DOODLE: | |
| 40 case OUTCOME_CHANGED_DOODLE: | |
| 41 case OUTCOME_NO_DOODLE: | |
| 42 return true; | |
| 43 case OUTCOME_EXPIRED: | |
| 44 case OUTCOME_DOWNLOAD_ERROR: | |
| 45 case OUTCOME_PARSING_ERROR: | |
| 46 return false; | |
| 47 case OUTCOME_COUNT: | |
| 48 NOTREACHED(); | |
| 49 } | |
| 50 return false; | |
| 51 } | |
| 52 | |
| 53 } // namespace | |
| 54 | |
| 19 // static | 55 // static |
| 20 void DoodleService::RegisterProfilePrefs(PrefRegistrySimple* pref_registry) { | 56 void DoodleService::RegisterProfilePrefs(PrefRegistrySimple* pref_registry) { |
| 21 pref_registry->RegisterDictionaryPref(prefs::kCachedConfig, | 57 pref_registry->RegisterDictionaryPref(prefs::kCachedConfig, |
| 22 new base::DictionaryValue(), | 58 new base::DictionaryValue(), |
| 23 PrefRegistry::LOSSY_PREF); | 59 PrefRegistry::LOSSY_PREF); |
| 24 pref_registry->RegisterInt64Pref(prefs::kCachedConfigExpiry, 0, | 60 pref_registry->RegisterInt64Pref(prefs::kCachedConfigExpiry, 0, |
| 25 PrefRegistry::LOSSY_PREF); | 61 PrefRegistry::LOSSY_PREF); |
| 26 } | 62 } |
| 27 | 63 |
| 28 DoodleService::DoodleService(PrefService* pref_service, | 64 DoodleService::DoodleService(PrefService* pref_service, |
| 29 std::unique_ptr<DoodleFetcher> fetcher, | 65 std::unique_ptr<DoodleFetcher> fetcher, |
| 30 std::unique_ptr<base::OneShotTimer> expiry_timer, | 66 std::unique_ptr<base::OneShotTimer> expiry_timer, |
| 31 std::unique_ptr<base::Clock> clock) | 67 std::unique_ptr<base::Clock> clock, |
| 68 std::unique_ptr<base::TickClock> tick_clock) | |
| 32 : pref_service_(pref_service), | 69 : pref_service_(pref_service), |
| 33 fetcher_(std::move(fetcher)), | 70 fetcher_(std::move(fetcher)), |
| 34 expiry_timer_(std::move(expiry_timer)), | 71 expiry_timer_(std::move(expiry_timer)), |
| 35 clock_(std::move(clock)) { | 72 clock_(std::move(clock)), |
| 73 tick_clock_(std::move(tick_clock)) { | |
| 36 DCHECK(pref_service_); | 74 DCHECK(pref_service_); |
| 37 DCHECK(fetcher_); | 75 DCHECK(fetcher_); |
| 38 DCHECK(expiry_timer_); | 76 DCHECK(expiry_timer_); |
| 39 DCHECK(clock_); | 77 DCHECK(clock_); |
| 78 DCHECK(tick_clock_); | |
| 40 | 79 |
| 41 base::Time expiry_date = base::Time::FromInternalValue( | 80 base::Time expiry_date = base::Time::FromInternalValue( |
| 42 pref_service_->GetInt64(prefs::kCachedConfigExpiry)); | 81 pref_service_->GetInt64(prefs::kCachedConfigExpiry)); |
| 43 base::Optional<DoodleConfig> config = DoodleConfig::FromDictionary( | 82 base::Optional<DoodleConfig> config = DoodleConfig::FromDictionary( |
| 44 *pref_service_->GetDictionary(prefs::kCachedConfig), base::nullopt); | 83 *pref_service_->GetDictionary(prefs::kCachedConfig), base::nullopt); |
| 45 UpdateCachedConfig(expiry_date - clock_->Now(), config); | 84 DoodleState state = |
| 85 config.has_value() ? DoodleState::AVAILABLE : DoodleState::NO_DOODLE; | |
| 86 UpdateCachedConfig(/*download_time=*/base::nullopt, state, | |
| 87 expiry_date - clock_->Now(), config); | |
| 46 } | 88 } |
| 47 | 89 |
| 48 DoodleService::~DoodleService() = default; | 90 DoodleService::~DoodleService() = default; |
| 49 | 91 |
| 50 void DoodleService::Shutdown() {} | 92 void DoodleService::Shutdown() {} |
| 51 | 93 |
| 52 void DoodleService::AddObserver(Observer* observer) { | 94 void DoodleService::AddObserver(Observer* observer) { |
| 53 observers_.AddObserver(observer); | 95 observers_.AddObserver(observer); |
| 54 } | 96 } |
| 55 | 97 |
| 56 void DoodleService::RemoveObserver(Observer* observer) { | 98 void DoodleService::RemoveObserver(Observer* observer) { |
| 57 observers_.RemoveObserver(observer); | 99 observers_.RemoveObserver(observer); |
| 58 } | 100 } |
| 59 | 101 |
| 60 void DoodleService::Refresh() { | 102 void DoodleService::Refresh() { |
| 61 fetcher_->FetchDoodle( | 103 fetcher_->FetchDoodle(base::BindOnce(&DoodleService::DoodleFetched, |
| 62 base::BindOnce(&DoodleService::DoodleFetched, base::Unretained(this))); | 104 base::Unretained(this), |
| 105 tick_clock_->NowTicks())); | |
| 63 } | 106 } |
| 64 | 107 |
| 65 void DoodleService::DoodleFetched( | 108 void DoodleService::DoodleFetched( |
| 109 base::TimeTicks start_time, | |
| 66 DoodleState state, | 110 DoodleState state, |
| 67 base::TimeDelta time_to_live, | 111 base::TimeDelta time_to_live, |
| 68 const base::Optional<DoodleConfig>& doodle_config) { | 112 const base::Optional<DoodleConfig>& doodle_config) { |
| 69 UpdateCachedConfig(time_to_live, doodle_config); | 113 base::TimeDelta download_time = tick_clock_->NowTicks() - start_time; |
| 114 UpdateCachedConfig(download_time, state, time_to_live, doodle_config); | |
| 70 } | 115 } |
| 71 | 116 |
| 72 void DoodleService::UpdateCachedConfig( | 117 void DoodleService::UpdateCachedConfig( |
| 118 base::Optional<base::TimeDelta> download_time, | |
| 119 DoodleState state, | |
| 73 base::TimeDelta time_to_live, | 120 base::TimeDelta time_to_live, |
| 74 const base::Optional<DoodleConfig>& doodle_config) { | 121 const base::Optional<DoodleConfig>& doodle_config) { |
|
fhorschig
2017/03/21 15:26:27
80 lines and nested ifs make this really hard to r
| |
| 75 // Handle the case where the new config is already expired. | 122 // Handle the case where the new config is already expired. |
| 76 bool expired = time_to_live <= base::TimeDelta(); | 123 bool expired = time_to_live <= base::TimeDelta(); |
| 77 const base::Optional<DoodleConfig>& new_config = | 124 const base::Optional<DoodleConfig>& new_config = |
| 78 expired ? base::nullopt : doodle_config; | 125 expired ? base::nullopt : doodle_config; |
| 79 | 126 |
| 127 DoodleConfigDownloadOutcome outcome = OUTCOME_COUNT; | |
| 128 | |
| 80 // If the config changed, update our cache and notify observers. | 129 // 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 | 130 // Note that this checks both for existence changes as well as changes of the |
| 82 // configs themselves. | 131 // configs themselves. |
| 83 if (cached_config_ != new_config) { | 132 if (cached_config_ != new_config) { |
|
fhorschig
2017/03/21 15:26:27
Can we consider putting this branch into a new fun
Marc Treib
2017/03/21 16:10:45
Hm. Maaaybe there's a sensible way to split this u
| |
| 133 bool had_config_before = cached_config_.has_value(); | |
| 134 | |
| 84 cached_config_ = new_config; | 135 cached_config_ = new_config; |
| 85 | 136 |
| 86 if (cached_config_.has_value()) { | 137 if (cached_config_.has_value()) { |
| 138 outcome = had_config_before ? OUTCOME_CHANGED_DOODLE : OUTCOME_NEW_DOODLE; | |
| 139 | |
| 87 pref_service_->Set(prefs::kCachedConfig, *cached_config_->ToDictionary()); | 140 pref_service_->Set(prefs::kCachedConfig, *cached_config_->ToDictionary()); |
| 88 base::Time expiry_date = clock_->Now() + time_to_live; | 141 base::Time expiry_date = clock_->Now() + time_to_live; |
| 89 pref_service_->SetInt64(prefs::kCachedConfigExpiry, | 142 pref_service_->SetInt64(prefs::kCachedConfigExpiry, |
| 90 expiry_date.ToInternalValue()); | 143 expiry_date.ToInternalValue()); |
| 91 } else { | 144 } else { |
| 145 outcome = OUTCOME_NO_DOODLE; | |
| 146 | |
| 92 pref_service_->ClearPref(prefs::kCachedConfig); | 147 pref_service_->ClearPref(prefs::kCachedConfig); |
| 93 pref_service_->ClearPref(prefs::kCachedConfigExpiry); | 148 pref_service_->ClearPref(prefs::kCachedConfigExpiry); |
| 94 } | 149 } |
| 95 | 150 |
| 96 for (auto& observer : observers_) { | 151 for (auto& observer : observers_) { |
| 97 observer.OnDoodleConfigUpdated(cached_config_); | 152 observer.OnDoodleConfigUpdated(cached_config_); |
| 98 } | 153 } |
| 154 } else { | |
| 155 outcome = cached_config_.has_value() ? OUTCOME_REVALIDATED_DOODLE | |
| 156 : OUTCOME_NO_DOODLE; | |
| 157 } | |
| 158 | |
| 159 // If the update came from the network, record metrics. | |
| 160 DCHECK(outcome != OUTCOME_COUNT); | |
|
fhorschig
2017/03/21 15:26:27
Is there any chance this couldn't have happened?
Marc Treib
2017/03/21 16:10:46
Nope, hence the DCHECK.
| |
| 161 if (download_time.has_value()) { | |
| 162 // Determine the final outcome. ERROR or EXPIRED override NO_DOODLE. | |
|
fhorschig
2017/03/21 15:26:27
So this complete branch is basically dead for one
Marc Treib
2017/03/21 16:10:45
Good point.
fhorschig
2017/03/21 16:41:34
Not dead but very unused for one call.
that's onl
Marc Treib
2017/03/21 16:48:59
Pulled it all out into a separate DetermineDownloa
| |
| 163 switch (state) { | |
| 164 case DoodleState::AVAILABLE: | |
| 165 case DoodleState::NO_DOODLE: | |
| 166 if (expired) { | |
| 167 outcome = OUTCOME_EXPIRED; | |
| 168 } | |
| 169 break; | |
| 170 | |
| 171 case DoodleState::DOWNLOAD_ERROR: | |
| 172 outcome = OUTCOME_DOWNLOAD_ERROR; | |
| 173 break; | |
| 174 | |
| 175 case DoodleState::PARSING_ERROR: | |
| 176 outcome = OUTCOME_PARSING_ERROR; | |
| 177 break; | |
| 178 } | |
| 179 | |
| 180 UMA_HISTOGRAM_ENUMERATION("Doodle.ConfigDownloadOutcome", outcome, | |
| 181 OUTCOME_COUNT); | |
| 182 | |
| 183 if (DownloadOutcomeIsSuccess(outcome)) { | |
| 184 UMA_HISTOGRAM_MEDIUM_TIMES("Doodle.ConfigDownloadTime", | |
| 185 download_time.value()); | |
| 186 } | |
| 99 } | 187 } |
| 100 | 188 |
| 101 // Even if the configs are identical, the time-to-live might have changed. | 189 // Even if the configs are identical, the time-to-live might have changed. |
| 102 // (Re-)schedule the cache expiry. | 190 // (Re-)schedule the cache expiry. |
| 103 if (cached_config_.has_value()) { | 191 if (cached_config_.has_value()) { |
| 104 expiry_timer_->Start( | 192 expiry_timer_->Start( |
| 105 FROM_HERE, time_to_live, | 193 FROM_HERE, time_to_live, |
| 106 base::Bind(&DoodleService::DoodleExpired, base::Unretained(this))); | 194 base::Bind(&DoodleService::DoodleExpired, base::Unretained(this))); |
| 107 } else { | 195 } else { |
| 108 expiry_timer_->Stop(); | 196 expiry_timer_->Stop(); |
| 109 } | 197 } |
| 110 } | 198 } |
| 111 | 199 |
| 112 void DoodleService::DoodleExpired() { | 200 void DoodleService::DoodleExpired() { |
| 113 DCHECK(cached_config_.has_value()); | 201 DCHECK(cached_config_.has_value()); |
| 114 UpdateCachedConfig(base::TimeDelta(), base::nullopt); | 202 UpdateCachedConfig(/*download_time=*/base::nullopt, DoodleState::NO_DOODLE, |
| 203 base::TimeDelta(), base::nullopt); | |
| 115 } | 204 } |
| 116 | 205 |
| 117 } // namespace doodle | 206 } // namespace doodle |
| OLD | NEW |