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

Side by Side Diff: components/ntp_snippets/remote/scheduling_remote_suggestions_provider.cc

Issue 2626433005: [Background fetching] Configure and report fetching triggers (Closed)
Patch Set: Created 3 years, 11 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 2016 The Chromium Authors. All rights reserved. 1 // Copyright 2016 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/ntp_snippets/remote/scheduling_remote_suggestions_provider. h" 5 #include "components/ntp_snippets/remote/scheduling_remote_suggestions_provider. h"
6 6
7 #include <random> 7 #include <random>
8 #include <string> 8 #include <string>
9 #include <utility> 9 #include <utility>
10 10
11 #include "base/memory/ptr_util.h" 11 #include "base/memory/ptr_util.h"
12 #include "base/metrics/histogram_macros.h"
13 #include "base/strings/string_split.h"
12 #include "base/time/clock.h" 14 #include "base/time/clock.h"
13 #include "components/ntp_snippets/features.h" 15 #include "components/ntp_snippets/features.h"
14 #include "components/ntp_snippets/pref_names.h" 16 #include "components/ntp_snippets/pref_names.h"
15 #include "components/ntp_snippets/remote/persistent_scheduler.h" 17 #include "components/ntp_snippets/remote/persistent_scheduler.h"
16 #include "components/ntp_snippets/status.h" 18 #include "components/ntp_snippets/status.h"
17 #include "components/ntp_snippets/user_classifier.h" 19 #include "components/ntp_snippets/user_classifier.h"
18 #include "components/prefs/pref_registry_simple.h" 20 #include "components/prefs/pref_registry_simple.h"
19 #include "components/prefs/pref_service.h" 21 #include "components/prefs/pref_service.h"
20 #include "components/variations/variations_associated_data.h" 22 #include "components/variations/variations_associated_data.h"
21 23
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after
58 static_cast<unsigned int>(FetchingInterval::COUNT) == 60 static_cast<unsigned int>(FetchingInterval::COUNT) ==
59 arraysize(kDefaultFetchingIntervalActiveSuggestionsConsumer) && 61 arraysize(kDefaultFetchingIntervalActiveSuggestionsConsumer) &&
60 static_cast<unsigned int>(FetchingInterval::COUNT) == 62 static_cast<unsigned int>(FetchingInterval::COUNT) ==
61 arraysize(kFetchingIntervalParamNameRareNtpUser) && 63 arraysize(kFetchingIntervalParamNameRareNtpUser) &&
62 static_cast<unsigned int>(FetchingInterval::COUNT) == 64 static_cast<unsigned int>(FetchingInterval::COUNT) ==
63 arraysize(kFetchingIntervalParamNameActiveNtpUser) && 65 arraysize(kFetchingIntervalParamNameActiveNtpUser) &&
64 static_cast<unsigned int>(FetchingInterval::COUNT) == 66 static_cast<unsigned int>(FetchingInterval::COUNT) ==
65 arraysize(kFetchingIntervalParamNameActiveSuggestionsConsumer), 67 arraysize(kFetchingIntervalParamNameActiveSuggestionsConsumer),
66 "Fill in all the info for fetching intervals."); 68 "Fill in all the info for fetching intervals.");
67 69
70 const char* kTriggerTypeNames[] = {"persistent_scheduler_wake_up", "ntp_opened",
71 "browser_foregrounded",
72 "browser_cold_start"};
73
74 const char* kTriggerTypesParamName = "scheduler_trigger_types";
75 const char* kDefaultTriggerTypes =
76 "persistent_scheduler_wake_up,ntp_opened,browser_foregrounded";
77
68 base::TimeDelta GetDesiredFetchingInterval( 78 base::TimeDelta GetDesiredFetchingInterval(
69 FetchingInterval interval, 79 FetchingInterval interval,
70 UserClassifier::UserClass user_class) { 80 UserClassifier::UserClass user_class) {
71 double default_value_hours = 0.0; 81 double default_value_hours = 0.0;
72 82
73 DCHECK(interval != FetchingInterval::COUNT); 83 DCHECK(interval != FetchingInterval::COUNT);
74 const unsigned int index = static_cast<unsigned int>(interval); 84 const unsigned int index = static_cast<unsigned int>(interval);
75 DCHECK(index < arraysize(kDefaultFetchingIntervalRareNtpUser)); 85 DCHECK(index < arraysize(kDefaultFetchingIntervalRareNtpUser));
76 86
77 const char* param_name = nullptr; 87 const char* param_name = nullptr;
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after
118 const FetchingSchedule& other) const { 128 const FetchingSchedule& other) const {
119 return !operator==(other); 129 return !operator==(other);
120 } 130 }
121 131
122 bool SchedulingRemoteSuggestionsProvider::FetchingSchedule::is_empty() const { 132 bool SchedulingRemoteSuggestionsProvider::FetchingSchedule::is_empty() const {
123 return interval_persistent_wifi.is_zero() && 133 return interval_persistent_wifi.is_zero() &&
124 interval_persistent_fallback.is_zero() && 134 interval_persistent_fallback.is_zero() &&
125 interval_soft_on_usage_event.is_zero(); 135 interval_soft_on_usage_event.is_zero();
126 } 136 }
127 137
138 // These values are written to logs. New enum values can be added, but existing
139 // enums must never be renumbered or deleted and reused. When adding new
140 // entries, also update the array |kTriggerTypeNames| above.
141 enum class SchedulingRemoteSuggestionsProvider::TriggerType {
142 PERSISTENT_SCHEDULER_WAKE_UP = 0,
143 NTP_OPENED = 1,
144 BROWSER_FOREGROUNDED = 2,
145 BROWSER_COLD_START = 3,
146 COUNT
147 };
148
128 SchedulingRemoteSuggestionsProvider::SchedulingRemoteSuggestionsProvider( 149 SchedulingRemoteSuggestionsProvider::SchedulingRemoteSuggestionsProvider(
129 Observer* observer, 150 Observer* observer,
130 std::unique_ptr<RemoteSuggestionsProvider> provider, 151 std::unique_ptr<RemoteSuggestionsProvider> provider,
131 PersistentScheduler* persistent_scheduler, 152 PersistentScheduler* persistent_scheduler,
132 const UserClassifier* user_classifier, 153 const UserClassifier* user_classifier,
133 PrefService* pref_service, 154 PrefService* pref_service,
134 std::unique_ptr<base::Clock> clock) 155 std::unique_ptr<base::Clock> clock)
135 : RemoteSuggestionsProvider(observer), 156 : RemoteSuggestionsProvider(observer),
136 RemoteSuggestionsScheduler(), 157 RemoteSuggestionsScheduler(),
137 provider_(std::move(provider)), 158 provider_(std::move(provider)),
138 persistent_scheduler_(persistent_scheduler), 159 persistent_scheduler_(persistent_scheduler),
139 background_fetch_in_progress_(false), 160 background_fetch_in_progress_(false),
140 user_classifier_(user_classifier), 161 user_classifier_(user_classifier),
141 pref_service_(pref_service), 162 pref_service_(pref_service),
142 clock_(std::move(clock)) { 163 clock_(std::move(clock)),
164 enabled_triggers_(GetEnabledTriggerTypes()) {
143 DCHECK(user_classifier); 165 DCHECK(user_classifier);
144 DCHECK(pref_service); 166 DCHECK(pref_service);
145 167
146 LoadLastFetchingSchedule(); 168 LoadLastFetchingSchedule();
147 169
148 provider_->SetProviderStatusCallback( 170 provider_->SetProviderStatusCallback(
149 base::MakeUnique<RemoteSuggestionsProvider::ProviderStatusCallback>( 171 base::MakeUnique<RemoteSuggestionsProvider::ProviderStatusCallback>(
150 base::BindRepeating( 172 base::BindRepeating(
151 &SchedulingRemoteSuggestionsProvider::OnProviderStatusChanged, 173 &SchedulingRemoteSuggestionsProvider::OnProviderStatusChanged,
152 base::Unretained(this)))); 174 base::Unretained(this))));
(...skipping 13 matching lines...) Expand all
166 registry->RegisterInt64Pref(prefs::kSnippetLastFetchAttempt, 0); 188 registry->RegisterInt64Pref(prefs::kSnippetLastFetchAttempt, 0);
167 } 189 }
168 190
169 void SchedulingRemoteSuggestionsProvider::RescheduleFetching() { 191 void SchedulingRemoteSuggestionsProvider::RescheduleFetching() {
170 // Force the reschedule by stopping and starting it again. 192 // Force the reschedule by stopping and starting it again.
171 StopScheduling(); 193 StopScheduling();
172 StartScheduling(); 194 StartScheduling();
173 } 195 }
174 196
175 void SchedulingRemoteSuggestionsProvider::OnPersistentSchedulerWakeUp() { 197 void SchedulingRemoteSuggestionsProvider::OnPersistentSchedulerWakeUp() {
176 if (BackgroundFetchesDisabled()) { 198 RefetchInTheBackgroundIfEnabled(TriggerType::PERSISTENT_SCHEDULER_WAKE_UP);
177 return;
178 }
179
180 RefetchInTheBackground(/*callback=*/nullptr);
181 } 199 }
182 200
183 void SchedulingRemoteSuggestionsProvider::OnBrowserForegrounded() { 201 void SchedulingRemoteSuggestionsProvider::OnBrowserForegrounded() {
184 // TODO(jkrcal): Consider that this is called whenever we open or return to an 202 // TODO(jkrcal): Consider that this is called whenever we open or return to an
185 // Activity. Therefore, keep work light for fast start up calls. 203 // Activity. Therefore, keep work light for fast start up calls.
186 // TODO(jkrcal): Implement. 204 RefetchInTheBackgroundIfEnabled(TriggerType::BROWSER_FOREGROUNDED);
187 } 205 }
188 206
189 void SchedulingRemoteSuggestionsProvider::OnBrowserColdStart() { 207 void SchedulingRemoteSuggestionsProvider::OnBrowserColdStart() {
190 // TODO(fhorschig|jkrcal): Consider that work here must be kept light for fast 208 // TODO(fhorschig|jkrcal): Consider that work here must be kept light for fast
191 // cold start ups. 209 // cold start ups.
192 // TODO(jkrcal): Implement. 210 RefetchInTheBackgroundIfEnabled(TriggerType::BROWSER_COLD_START);
193 } 211 }
194 212
195 void SchedulingRemoteSuggestionsProvider::OnNTPOpened() { 213 void SchedulingRemoteSuggestionsProvider::OnNTPOpened() {
196 if (BackgroundFetchesDisabled() || !ShouldRefetchInTheBackgroundNow()) { 214 if (!ShouldRefetchInTheBackgroundNow()) {
tschumann 2017/01/10 14:28:16 this is asymmetric to the other triggers. Shouldn'
jkrcal 2017/01/10 18:52:27 Oops, sure. Thanks!
197 return; 215 return;
198 } 216 }
199 217
200 RefetchInTheBackground(/*callback=*/nullptr); 218 RefetchInTheBackgroundIfEnabled(TriggerType::NTP_OPENED);
201 } 219 }
202 220
203 void SchedulingRemoteSuggestionsProvider::SetProviderStatusCallback( 221 void SchedulingRemoteSuggestionsProvider::SetProviderStatusCallback(
204 std::unique_ptr<ProviderStatusCallback> callback) { 222 std::unique_ptr<ProviderStatusCallback> callback) {
205 provider_->SetProviderStatusCallback(std::move(callback)); 223 provider_->SetProviderStatusCallback(std::move(callback));
206 } 224 }
207 225
208 void SchedulingRemoteSuggestionsProvider::RefetchInTheBackground( 226 void SchedulingRemoteSuggestionsProvider::RefetchInTheBackground(
209 std::unique_ptr<FetchStatusCallback> callback) { 227 std::unique_ptr<FetchStatusCallback> callback) {
210 if (background_fetch_in_progress_) { 228 if (background_fetch_in_progress_) {
(...skipping 158 matching lines...) Expand 10 before | Expand all | Expand 10 after
369 pref_service_->SetInt64(prefs::kSnippetPersistentFetchingIntervalWifi, 387 pref_service_->SetInt64(prefs::kSnippetPersistentFetchingIntervalWifi,
370 schedule_.interval_persistent_wifi.ToInternalValue()); 388 schedule_.interval_persistent_wifi.ToInternalValue());
371 pref_service_->SetInt64( 389 pref_service_->SetInt64(
372 prefs::kSnippetPersistentFetchingIntervalFallback, 390 prefs::kSnippetPersistentFetchingIntervalFallback,
373 schedule_.interval_persistent_fallback.ToInternalValue()); 391 schedule_.interval_persistent_fallback.ToInternalValue());
374 pref_service_->SetInt64( 392 pref_service_->SetInt64(
375 prefs::kSnippetSoftFetchingIntervalOnUsageEvent, 393 prefs::kSnippetSoftFetchingIntervalOnUsageEvent,
376 schedule_.interval_soft_on_usage_event.ToInternalValue()); 394 schedule_.interval_soft_on_usage_event.ToInternalValue());
377 } 395 }
378 396
379 bool SchedulingRemoteSuggestionsProvider::BackgroundFetchesDisabled() const { 397 void SchedulingRemoteSuggestionsProvider::RefetchInTheBackgroundIfEnabled(
380 return schedule_.is_empty(); 398 SchedulingRemoteSuggestionsProvider::TriggerType trigger) {
399 if (BackgroundFetchesDisabled(trigger)) {
400 return;
401 }
402
403 UMA_HISTOGRAM_ENUMERATION(
404 "NewTabPage.ContentSuggestions.BackgroundFetchTrigger",
405 static_cast<int>(trigger), static_cast<int>(TriggerType::COUNT));
406
407 RefetchInTheBackground(/*callback=*/nullptr);
381 } 408 }
382 409
383 bool SchedulingRemoteSuggestionsProvider::ShouldRefetchInTheBackgroundNow() { 410 bool SchedulingRemoteSuggestionsProvider::ShouldRefetchInTheBackgroundNow() {
384 base::Time first_allowed_fetch_time = 411 base::Time first_allowed_fetch_time =
385 base::Time::FromInternalValue( 412 base::Time::FromInternalValue(
386 pref_service_->GetInt64(prefs::kSnippetLastFetchAttempt)) + 413 pref_service_->GetInt64(prefs::kSnippetLastFetchAttempt)) +
387 schedule_.interval_soft_on_usage_event; 414 schedule_.interval_soft_on_usage_event;
388 return first_allowed_fetch_time <= clock_->Now(); 415 return first_allowed_fetch_time <= clock_->Now();
389 } 416 }
390 417
418 bool SchedulingRemoteSuggestionsProvider::BackgroundFetchesDisabled(
419 SchedulingRemoteSuggestionsProvider::TriggerType trigger) const {
420 if (schedule_.is_empty()) {
421 return true; // Background fetches are disabled in general.
422 }
423
424 if (enabled_triggers_.count(trigger) == 0) {
425 return true; // Background fetches for |trigger| are not enabled.
426 }
427 return false;
428 }
429
391 void SchedulingRemoteSuggestionsProvider::FetchFinished( 430 void SchedulingRemoteSuggestionsProvider::FetchFinished(
392 const FetchDoneCallback& callback, 431 const FetchDoneCallback& callback,
393 Status fetch_status, 432 Status fetch_status,
394 std::vector<ContentSuggestion> suggestions) { 433 std::vector<ContentSuggestion> suggestions) {
395 OnFetchCompleted(fetch_status); 434 OnFetchCompleted(fetch_status);
396 if (callback) { 435 if (callback) {
397 callback.Run(fetch_status, std::move(suggestions)); 436 callback.Run(fetch_status, std::move(suggestions));
398 } 437 }
399 } 438 }
400 439
(...skipping 15 matching lines...) Expand all
416 // Reschedule after a fetch. The persistent schedule is applied only after a 455 // Reschedule after a fetch. The persistent schedule is applied only after a
417 // successful fetch. After a failed fetch, we want to keep the previous 456 // successful fetch. After a failed fetch, we want to keep the previous
418 // persistent schedule intact so that we eventually get a persistent 457 // persistent schedule intact so that we eventually get a persistent
419 // fallback fetch (if the wifi persistent fetches keep failing). 458 // fallback fetch (if the wifi persistent fetches keep failing).
420 if (fetch_status.code != StatusCode::SUCCESS) { 459 if (fetch_status.code != StatusCode::SUCCESS) {
421 return; 460 return;
422 } 461 }
423 ApplyPersistentFetchingSchedule(); 462 ApplyPersistentFetchingSchedule();
424 } 463 }
425 464
465 std::set<SchedulingRemoteSuggestionsProvider::TriggerType>
466 SchedulingRemoteSuggestionsProvider::GetEnabledTriggerTypes() {
467 std::string param_value = variations::GetVariationParamValueByFeature(
468 ntp_snippets::kArticleSuggestionsFeature, kTriggerTypesParamName);
469
470 std::set<TriggerType> enabled_types;
471 if (ParseEnabledTriggerTypes(param_value, &enabled_types)) {
472 return enabled_types;
473 }
474
475 DLOG(WARNING) << "Failed to parse variation param " << kTriggerTypesParamName
476 << " with string value " << param_value
477 << " into a comma-separated list of keywords. "
478 "Falling back to default value of "
479 << kDefaultTriggerTypes;
480
481 if (ParseEnabledTriggerTypes(kDefaultTriggerTypes, &enabled_types)) {
482 return enabled_types;
483 }
484
485 DLOG(WARNING) << "Invalid default value for param " << kTriggerTypesParamName;
tschumann 2017/01/10 14:28:16 this should be a DCHECK(), no? Actually, if you're
jkrcal 2017/01/10 18:52:27 Done.
486 return std::set<TriggerType>();
487 }
488
489 bool SchedulingRemoteSuggestionsProvider::ParseEnabledTriggerTypes(
490 const std::string& param_value,
491 std::set<TriggerType>* out) {
492 static_assert(static_cast<unsigned int>(TriggerType::COUNT) ==
493 arraysize(kTriggerTypeNames),
494 "Fill in names for trigger types.");
tschumann 2017/01/10 14:28:16 hmm... i wonder if it wouldn't be cleaner to have
jkrcal 2017/01/10 18:52:27 To me, it seems that I would then need to iterate
tschumann 2017/01/12 12:44:20 no, there's no way I know of to iterate over them.
jkrcal 2017/01/12 15:35:28 ok, I adapted the unit-tests as you proposed.
495
496 std::vector<std::string> tokens = base::SplitString(
497 param_value, ",", base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY);
498 for (const auto& token : tokens) {
499 auto it = std::find(std::begin(kTriggerTypeNames),
500 std::end(kTriggerTypeNames), token);
501 if (it == std::end(kTriggerTypeNames)) {
502 DLOG(WARNING) << "Unknown token " << token << " found in the parameter "
503 << kTriggerTypesParamName << ".";
504 out->clear();
tschumann 2017/01/10 14:28:16 this seems a bit brittle. Honestly, I wouldn't wor
jkrcal 2017/01/10 18:52:27 Done.
505 return false;
506 }
507
508 // Add the enabled type represented by |token| into the result set.
509 out->insert(static_cast<TriggerType>(it - std::begin(kTriggerTypeNames)));
510 }
511 return true;
512 }
513
426 } // namespace ntp_snippets 514 } // namespace ntp_snippets
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698