| OLD | NEW |
| 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 |
| (...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 88 arraysize(kFetchingIntervalParamNameActiveSuggestionsConsumer), | 88 arraysize(kFetchingIntervalParamNameActiveSuggestionsConsumer), |
| 89 "Fill in all the info for fetching intervals."); | 89 "Fill in all the info for fetching intervals."); |
| 90 | 90 |
| 91 const char* kTriggerTypeNames[] = {"persistent_scheduler_wake_up", "ntp_opened", | 91 const char* kTriggerTypeNames[] = {"persistent_scheduler_wake_up", "ntp_opened", |
| 92 "browser_foregrounded", | 92 "browser_foregrounded", |
| 93 "browser_cold_start"}; | 93 "browser_cold_start"}; |
| 94 | 94 |
| 95 const char* kTriggerTypesParamName = "scheduler_trigger_types"; | 95 const char* kTriggerTypesParamName = "scheduler_trigger_types"; |
| 96 const char* kTriggerTypesParamValueForEmptyList = "-"; | 96 const char* kTriggerTypesParamValueForEmptyList = "-"; |
| 97 | 97 |
| 98 const int kBlockBackgroundFetchesMinutesAfterClearingHistory = 30; |
| 99 |
| 98 // Returns the time interval to use for scheduling remote suggestion fetches for | 100 // Returns the time interval to use for scheduling remote suggestion fetches for |
| 99 // the given interval and user_class. | 101 // the given interval and user_class. |
| 100 base::TimeDelta GetDesiredFetchingInterval( | 102 base::TimeDelta GetDesiredFetchingInterval( |
| 101 FetchingInterval interval, | 103 FetchingInterval interval, |
| 102 UserClassifier::UserClass user_class) { | 104 UserClassifier::UserClass user_class) { |
| 103 DCHECK(interval != FetchingInterval::COUNT); | 105 DCHECK(interval != FetchingInterval::COUNT); |
| 104 const unsigned int index = static_cast<unsigned int>(interval); | 106 const unsigned int index = static_cast<unsigned int>(interval); |
| 105 DCHECK(index < arraysize(kDefaultFetchingIntervalHoursRareNtpUser)); | 107 DCHECK(index < arraysize(kDefaultFetchingIntervalHoursRareNtpUser)); |
| 106 | 108 |
| 107 double default_value_hours = 0.0; | 109 double default_value_hours = 0.0; |
| (...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 184 persistent_scheduler_(persistent_scheduler), | 186 persistent_scheduler_(persistent_scheduler), |
| 185 background_fetch_in_progress_(false), | 187 background_fetch_in_progress_(false), |
| 186 user_classifier_(user_classifier), | 188 user_classifier_(user_classifier), |
| 187 pref_service_(pref_service), | 189 pref_service_(pref_service), |
| 188 clock_(std::move(clock)), | 190 clock_(std::move(clock)), |
| 189 enabled_triggers_(GetEnabledTriggerTypes()) { | 191 enabled_triggers_(GetEnabledTriggerTypes()) { |
| 190 DCHECK(user_classifier); | 192 DCHECK(user_classifier); |
| 191 DCHECK(pref_service); | 193 DCHECK(pref_service); |
| 192 | 194 |
| 193 LoadLastFetchingSchedule(); | 195 LoadLastFetchingSchedule(); |
| 194 | |
| 195 provider_->SetProviderStatusCallback( | |
| 196 base::MakeUnique<RemoteSuggestionsProvider::ProviderStatusCallback>( | |
| 197 base::BindRepeating( | |
| 198 &SchedulingRemoteSuggestionsProvider::OnProviderStatusChanged, | |
| 199 base::Unretained(this)))); | |
| 200 } | 196 } |
| 201 | 197 |
| 202 SchedulingRemoteSuggestionsProvider::~SchedulingRemoteSuggestionsProvider() = | 198 SchedulingRemoteSuggestionsProvider::~SchedulingRemoteSuggestionsProvider() = |
| 203 default; | 199 default; |
| 204 | 200 |
| 205 // static | 201 // static |
| 206 void SchedulingRemoteSuggestionsProvider::RegisterProfilePrefs( | 202 void SchedulingRemoteSuggestionsProvider::RegisterProfilePrefs( |
| 207 PrefRegistrySimple* registry) { | 203 PrefRegistrySimple* registry) { |
| 208 registry->RegisterInt64Pref(prefs::kSnippetPersistentFetchingIntervalWifi, 0); | 204 registry->RegisterInt64Pref(prefs::kSnippetPersistentFetchingIntervalWifi, 0); |
| 209 registry->RegisterInt64Pref(prefs::kSnippetPersistentFetchingIntervalFallback, | 205 registry->RegisterInt64Pref(prefs::kSnippetPersistentFetchingIntervalFallback, |
| 210 0); | 206 0); |
| 211 registry->RegisterInt64Pref(prefs::kSnippetSoftFetchingIntervalOnUsageEvent, | 207 registry->RegisterInt64Pref(prefs::kSnippetSoftFetchingIntervalOnUsageEvent, |
| 212 0); | 208 0); |
| 213 registry->RegisterInt64Pref(prefs::kSnippetLastFetchAttempt, 0); | 209 registry->RegisterInt64Pref(prefs::kSnippetLastFetchAttempt, 0); |
| 214 registry->RegisterInt64Pref(prefs::kSnippetSoftFetchingIntervalOnNtpOpened, | 210 registry->RegisterInt64Pref(prefs::kSnippetSoftFetchingIntervalOnNtpOpened, |
| 215 0); | 211 0); |
| 216 } | 212 } |
| 217 | 213 |
| 214 void SchedulingRemoteSuggestionsProvider::OnProviderActivated() { |
| 215 StartScheduling(); |
| 216 } |
| 217 |
| 218 void SchedulingRemoteSuggestionsProvider::OnProviderDeactivated() { |
| 219 StopScheduling(); |
| 220 } |
| 221 |
| 222 void SchedulingRemoteSuggestionsProvider::OnSuggestionsCleared() { |
| 223 // There are no suggestions, be as eager to fetch as possible. |
| 224 ClearLastFetchAttemptTime(); |
| 225 } |
| 226 |
| 227 void SchedulingRemoteSuggestionsProvider::OnHistoryCleared() { |
| 228 // Due to privacy, we should not fetch for a while (unless the user explicitly |
| 229 // asks for new suggestions) to give sync the time to propagate the changes in |
| 230 // history to the server. |
| 231 background_fetches_allowed_after_ = |
| 232 clock_->Now() + base::TimeDelta::FromMinutes( |
| 233 kBlockBackgroundFetchesMinutesAfterClearingHistory); |
| 234 // After that time elapses, we should fetch as soon as possible. |
| 235 ClearLastFetchAttemptTime(); |
| 236 } |
| 237 |
| 218 void SchedulingRemoteSuggestionsProvider::RescheduleFetching() { | 238 void SchedulingRemoteSuggestionsProvider::RescheduleFetching() { |
| 219 // Force the reschedule by stopping and starting it again. | 239 // Force the reschedule by stopping and starting it again. |
| 220 StopScheduling(); | 240 StopScheduling(); |
| 221 StartScheduling(); | 241 StartScheduling(); |
| 222 } | 242 } |
| 223 | 243 |
| 224 void SchedulingRemoteSuggestionsProvider::OnPersistentSchedulerWakeUp() { | 244 void SchedulingRemoteSuggestionsProvider::OnPersistentSchedulerWakeUp() { |
| 225 RefetchInTheBackgroundIfEnabled(TriggerType::PERSISTENT_SCHEDULER_WAKE_UP); | 245 RefetchInTheBackgroundIfEnabled(TriggerType::PERSISTENT_SCHEDULER_WAKE_UP); |
| 226 } | 246 } |
| 227 | 247 |
| (...skipping 18 matching lines...) Expand all Loading... |
| 246 } | 266 } |
| 247 | 267 |
| 248 void SchedulingRemoteSuggestionsProvider::OnNTPOpened() { | 268 void SchedulingRemoteSuggestionsProvider::OnNTPOpened() { |
| 249 if (!ShouldRefetchInTheBackgroundNow(TriggerType::NTP_OPENED)) { | 269 if (!ShouldRefetchInTheBackgroundNow(TriggerType::NTP_OPENED)) { |
| 250 return; | 270 return; |
| 251 } | 271 } |
| 252 | 272 |
| 253 RefetchInTheBackgroundIfEnabled(TriggerType::NTP_OPENED); | 273 RefetchInTheBackgroundIfEnabled(TriggerType::NTP_OPENED); |
| 254 } | 274 } |
| 255 | 275 |
| 256 void SchedulingRemoteSuggestionsProvider::SetProviderStatusCallback( | |
| 257 std::unique_ptr<ProviderStatusCallback> callback) { | |
| 258 provider_->SetProviderStatusCallback(std::move(callback)); | |
| 259 } | |
| 260 | |
| 261 void SchedulingRemoteSuggestionsProvider::RefetchInTheBackground( | 276 void SchedulingRemoteSuggestionsProvider::RefetchInTheBackground( |
| 262 std::unique_ptr<FetchStatusCallback> callback) { | 277 std::unique_ptr<FetchStatusCallback> callback) { |
| 263 if (background_fetch_in_progress_) { | 278 if (background_fetch_in_progress_) { |
| 264 if (callback) { | 279 if (callback) { |
| 265 callback->Run( | 280 callback->Run( |
| 266 Status(StatusCode::TEMPORARY_ERROR, "Background fetch in progress")); | 281 Status(StatusCode::TEMPORARY_ERROR, "Background fetch in progress")); |
| 267 } | 282 } |
| 268 return; | 283 return; |
| 269 } | 284 } |
| 270 | 285 |
| (...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 337 Category category, | 352 Category category, |
| 338 const DismissedSuggestionsCallback& callback) { | 353 const DismissedSuggestionsCallback& callback) { |
| 339 provider_->GetDismissedSuggestionsForDebugging(category, callback); | 354 provider_->GetDismissedSuggestionsForDebugging(category, callback); |
| 340 } | 355 } |
| 341 | 356 |
| 342 void SchedulingRemoteSuggestionsProvider::ClearDismissedSuggestionsForDebugging( | 357 void SchedulingRemoteSuggestionsProvider::ClearDismissedSuggestionsForDebugging( |
| 343 Category category) { | 358 Category category) { |
| 344 provider_->ClearDismissedSuggestionsForDebugging(category); | 359 provider_->ClearDismissedSuggestionsForDebugging(category); |
| 345 } | 360 } |
| 346 | 361 |
| 347 void SchedulingRemoteSuggestionsProvider::OnProviderStatusChanged( | |
| 348 RemoteSuggestionsProvider::ProviderStatus status) { | |
| 349 switch (status) { | |
| 350 case RemoteSuggestionsProvider::ProviderStatus::ACTIVE: | |
| 351 StartScheduling(); | |
| 352 return; | |
| 353 case RemoteSuggestionsProvider::ProviderStatus::INACTIVE: | |
| 354 StopScheduling(); | |
| 355 return; | |
| 356 } | |
| 357 NOTREACHED(); | |
| 358 } | |
| 359 | |
| 360 void SchedulingRemoteSuggestionsProvider::StartScheduling() { | 362 void SchedulingRemoteSuggestionsProvider::StartScheduling() { |
| 361 FetchingSchedule new_schedule = GetDesiredFetchingSchedule(); | 363 FetchingSchedule new_schedule = GetDesiredFetchingSchedule(); |
| 362 | 364 |
| 363 if (schedule_ == new_schedule) { | 365 if (schedule_ == new_schedule) { |
| 364 // Do not schedule if nothing has changed; | 366 // Do not schedule if nothing has changed; |
| 365 return; | 367 return; |
| 366 } | 368 } |
| 367 | 369 |
| 368 schedule_ = new_schedule; | 370 schedule_ = new_schedule; |
| 369 StoreFetchingSchedule(); | 371 StoreFetchingSchedule(); |
| (...skipping 92 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 462 case TriggerType::BROWSER_FOREGROUNDED: | 464 case TriggerType::BROWSER_FOREGROUNDED: |
| 463 case TriggerType::BROWSER_COLD_START: | 465 case TriggerType::BROWSER_COLD_START: |
| 464 first_allowed_fetch_time = | 466 first_allowed_fetch_time = |
| 465 last_fetch_attempt_time + schedule_.interval_soft_on_usage_event; | 467 last_fetch_attempt_time + schedule_.interval_soft_on_usage_event; |
| 466 break; | 468 break; |
| 467 case TriggerType::PERSISTENT_SCHEDULER_WAKE_UP: | 469 case TriggerType::PERSISTENT_SCHEDULER_WAKE_UP: |
| 468 case TriggerType::COUNT: | 470 case TriggerType::COUNT: |
| 469 NOTREACHED(); | 471 NOTREACHED(); |
| 470 break; | 472 break; |
| 471 } | 473 } |
| 472 return first_allowed_fetch_time <= clock_->Now(); | 474 base::Time now = clock_->Now(); |
| 475 |
| 476 return background_fetches_allowed_after_ <= now && |
| 477 first_allowed_fetch_time <= now; |
| 473 } | 478 } |
| 474 | 479 |
| 475 bool SchedulingRemoteSuggestionsProvider::BackgroundFetchesDisabled( | 480 bool SchedulingRemoteSuggestionsProvider::BackgroundFetchesDisabled( |
| 476 SchedulingRemoteSuggestionsProvider::TriggerType trigger) const { | 481 SchedulingRemoteSuggestionsProvider::TriggerType trigger) const { |
| 477 if (schedule_.is_empty()) { | 482 if (schedule_.is_empty()) { |
| 478 return true; // Background fetches are disabled in general. | 483 return true; // Background fetches are disabled in general. |
| 479 } | 484 } |
| 480 | 485 |
| 481 if (enabled_triggers_.count(trigger) == 0) { | 486 if (enabled_triggers_.count(trigger) == 0) { |
| 482 return true; // Background fetches for |trigger| are not enabled. | 487 return true; // Background fetches for |trigger| are not enabled. |
| (...skipping 29 matching lines...) Expand all Loading... |
| 512 // Reschedule after a fetch. The persistent schedule is applied only after a | 517 // Reschedule after a fetch. The persistent schedule is applied only after a |
| 513 // successful fetch. After a failed fetch, we want to keep the previous | 518 // successful fetch. After a failed fetch, we want to keep the previous |
| 514 // persistent schedule intact so that we eventually get a persistent | 519 // persistent schedule intact so that we eventually get a persistent |
| 515 // fallback fetch (if the wifi persistent fetches keep failing). | 520 // fallback fetch (if the wifi persistent fetches keep failing). |
| 516 if (fetch_status.code != StatusCode::SUCCESS) { | 521 if (fetch_status.code != StatusCode::SUCCESS) { |
| 517 return; | 522 return; |
| 518 } | 523 } |
| 519 ApplyPersistentFetchingSchedule(); | 524 ApplyPersistentFetchingSchedule(); |
| 520 } | 525 } |
| 521 | 526 |
| 527 void SchedulingRemoteSuggestionsProvider::ClearLastFetchAttemptTime() { |
| 528 pref_service_->ClearPref(prefs::kSnippetLastFetchAttempt); |
| 529 } |
| 530 |
| 522 std::set<SchedulingRemoteSuggestionsProvider::TriggerType> | 531 std::set<SchedulingRemoteSuggestionsProvider::TriggerType> |
| 523 SchedulingRemoteSuggestionsProvider::GetEnabledTriggerTypes() { | 532 SchedulingRemoteSuggestionsProvider::GetEnabledTriggerTypes() { |
| 524 static_assert(static_cast<unsigned int>(TriggerType::COUNT) == | 533 static_assert(static_cast<unsigned int>(TriggerType::COUNT) == |
| 525 arraysize(kTriggerTypeNames), | 534 arraysize(kTriggerTypeNames), |
| 526 "Fill in names for trigger types."); | 535 "Fill in names for trigger types."); |
| 527 | 536 |
| 528 std::string param_value = base::GetFieldTrialParamValueByFeature( | 537 std::string param_value = base::GetFieldTrialParamValueByFeature( |
| 529 ntp_snippets::kArticleSuggestionsFeature, kTriggerTypesParamName); | 538 ntp_snippets::kArticleSuggestionsFeature, kTriggerTypesParamName); |
| 530 if (param_value == kTriggerTypesParamValueForEmptyList) { | 539 if (param_value == kTriggerTypesParamValueForEmptyList) { |
| 531 return std::set<TriggerType>(); | 540 return std::set<TriggerType>(); |
| (...skipping 26 matching lines...) Expand all Loading... |
| 558 return enabled_types; | 567 return enabled_types; |
| 559 } | 568 } |
| 560 | 569 |
| 561 std::set<SchedulingRemoteSuggestionsProvider::TriggerType> | 570 std::set<SchedulingRemoteSuggestionsProvider::TriggerType> |
| 562 SchedulingRemoteSuggestionsProvider::GetDefaultEnabledTriggerTypes() { | 571 SchedulingRemoteSuggestionsProvider::GetDefaultEnabledTriggerTypes() { |
| 563 return {TriggerType::PERSISTENT_SCHEDULER_WAKE_UP, TriggerType::NTP_OPENED, | 572 return {TriggerType::PERSISTENT_SCHEDULER_WAKE_UP, TriggerType::NTP_OPENED, |
| 564 TriggerType::BROWSER_FOREGROUNDED}; | 573 TriggerType::BROWSER_FOREGROUNDED}; |
| 565 } | 574 } |
| 566 | 575 |
| 567 } // namespace ntp_snippets | 576 } // namespace ntp_snippets |
| OLD | NEW |