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

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

Issue 2557363002: [NTP Snippets] Refactor background scheduling for remote suggestions (Closed)
Patch Set: Created 4 years 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 2015 The Chromium Authors. All rights reserved. 1 // Copyright 2015 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/remote_suggestions_provider.h" 5 #include "components/ntp_snippets/remote/remote_suggestions_provider.h"
6 6
7 #include <algorithm> 7 #include <algorithm>
8 #include <iterator> 8 #include <iterator>
9 #include <utility> 9 #include <utility>
10 10
(...skipping 10 matching lines...) Expand all
21 #include "base/task_runner_util.h" 21 #include "base/task_runner_util.h"
22 #include "base/time/time.h" 22 #include "base/time/time.h"
23 #include "base/values.h" 23 #include "base/values.h"
24 #include "components/data_use_measurement/core/data_use_user_data.h" 24 #include "components/data_use_measurement/core/data_use_user_data.h"
25 #include "components/history/core/browser/history_service.h" 25 #include "components/history/core/browser/history_service.h"
26 #include "components/image_fetcher/image_decoder.h" 26 #include "components/image_fetcher/image_decoder.h"
27 #include "components/image_fetcher/image_fetcher.h" 27 #include "components/image_fetcher/image_fetcher.h"
28 #include "components/ntp_snippets/features.h" 28 #include "components/ntp_snippets/features.h"
29 #include "components/ntp_snippets/pref_names.h" 29 #include "components/ntp_snippets/pref_names.h"
30 #include "components/ntp_snippets/remote/remote_suggestions_database.h" 30 #include "components/ntp_snippets/remote/remote_suggestions_database.h"
31 #include "components/ntp_snippets/remote/remote_suggestions_scheduler.h"
31 #include "components/ntp_snippets/switches.h" 32 #include "components/ntp_snippets/switches.h"
32 #include "components/ntp_snippets/user_classifier.h" 33 #include "components/ntp_snippets/user_classifier.h"
33 #include "components/prefs/pref_registry_simple.h" 34 #include "components/prefs/pref_registry_simple.h"
34 #include "components/prefs/pref_service.h" 35 #include "components/prefs/pref_service.h"
35 #include "components/variations/variations_associated_data.h" 36 #include "components/variations/variations_associated_data.h"
36 #include "grit/components_strings.h" 37 #include "grit/components_strings.h"
37 #include "ui/base/l10n/l10n_util.h" 38 #include "ui/base/l10n/l10n_util.h"
38 #include "ui/gfx/image/image.h" 39 #include "ui/gfx/image/image.h"
39 40
40 namespace ntp_snippets { 41 namespace ntp_snippets {
41 42
42 namespace { 43 namespace {
43 44
44 // Number of snippets requested to the server. Consider replacing sparse UMA 45 // Number of snippets requested to the server. Consider replacing sparse UMA
45 // histograms with COUNTS() if this number increases beyond 50. 46 // histograms with COUNTS() if this number increases beyond 50.
46 const int kMaxSnippetCount = 10; 47 const int kMaxSnippetCount = 10;
47 48
48 // Number of archived snippets we keep around in memory. 49 // Number of archived snippets we keep around in memory.
49 const int kMaxArchivedSnippetCount = 200; 50 const int kMaxArchivedSnippetCount = 200;
50 51
51 // Default values for fetching intervals, fallback and wifi.
52 const double kDefaultFetchingIntervalRareNtpUser[] = {48.0, 24.0};
53 const double kDefaultFetchingIntervalActiveNtpUser[] = {24.0, 6.0};
54 const double kDefaultFetchingIntervalActiveSuggestionsConsumer[] = {24.0, 6.0};
55
56 // Variation parameters than can override the default fetching intervals.
57 const char* kFetchingIntervalParamNameRareNtpUser[] = {
58 "fetching_interval_hours-fallback-rare_ntp_user",
59 "fetching_interval_hours-wifi-rare_ntp_user"};
60 const char* kFetchingIntervalParamNameActiveNtpUser[] = {
61 "fetching_interval_hours-fallback-active_ntp_user",
62 "fetching_interval_hours-wifi-active_ntp_user"};
63 const char* kFetchingIntervalParamNameActiveSuggestionsConsumer[] = {
64 "fetching_interval_hours-fallback-active_suggestions_consumer",
65 "fetching_interval_hours-wifi-active_suggestions_consumer"};
66
67 // Keys for storing CategoryContent info in prefs. 52 // Keys for storing CategoryContent info in prefs.
68 const char kCategoryContentId[] = "id"; 53 const char kCategoryContentId[] = "id";
69 const char kCategoryContentTitle[] = "title"; 54 const char kCategoryContentTitle[] = "title";
70 const char kCategoryContentProvidedByServer[] = "provided_by_server"; 55 const char kCategoryContentProvidedByServer[] = "provided_by_server";
71 const char kCategoryContentAllowFetchingMore[] = "allow_fetching_more"; 56 const char kCategoryContentAllowFetchingMore[] = "allow_fetching_more";
72 57
73 // TODO(treib): Remove after M57. 58 // TODO(treib): Remove after M57.
74 const char kDeprecatedSnippetHostsPref[] = "ntp_snippets.hosts"; 59 const char kDeprecatedSnippetHostsPref[] = "ntp_snippets.hosts";
75 60
76 base::TimeDelta GetFetchingInterval(bool is_wifi,
77 UserClassifier::UserClass user_class) {
78 double value_hours = 0.0;
79
80 const int index = is_wifi ? 1 : 0;
81 const char* param_name = "";
82 switch (user_class) {
83 case UserClassifier::UserClass::RARE_NTP_USER:
84 value_hours = kDefaultFetchingIntervalRareNtpUser[index];
85 param_name = kFetchingIntervalParamNameRareNtpUser[index];
86 break;
87 case UserClassifier::UserClass::ACTIVE_NTP_USER:
88 value_hours = kDefaultFetchingIntervalActiveNtpUser[index];
89 param_name = kFetchingIntervalParamNameActiveNtpUser[index];
90 break;
91 case UserClassifier::UserClass::ACTIVE_SUGGESTIONS_CONSUMER:
92 value_hours = kDefaultFetchingIntervalActiveSuggestionsConsumer[index];
93 param_name = kFetchingIntervalParamNameActiveSuggestionsConsumer[index];
94 break;
95 }
96
97 // The default value can be overridden by a variation parameter.
98 std::string param_value_str = variations::GetVariationParamValueByFeature(
99 ntp_snippets::kArticleSuggestionsFeature, param_name);
100 if (!param_value_str.empty()) {
101 double param_value_hours = 0.0;
102 if (base::StringToDouble(param_value_str, &param_value_hours)) {
103 value_hours = param_value_hours;
104 } else {
105 LOG(WARNING) << "Invalid value for variation parameter " << param_name;
106 }
107 }
108
109 return base::TimeDelta::FromSecondsD(value_hours * 3600.0);
110 }
111
112 std::unique_ptr<std::vector<std::string>> GetSnippetIDVector( 61 std::unique_ptr<std::vector<std::string>> GetSnippetIDVector(
113 const NTPSnippet::PtrVector& snippets) { 62 const NTPSnippet::PtrVector& snippets) {
114 auto result = base::MakeUnique<std::vector<std::string>>(); 63 auto result = base::MakeUnique<std::vector<std::string>>();
115 for (const auto& snippet : snippets) { 64 for (const auto& snippet : snippets) {
116 result->push_back(snippet->id()); 65 result->push_back(snippet->id());
117 } 66 }
118 return result; 67 return result;
119 } 68 }
120 69
121 bool HasIntersection(const std::vector<std::string>& a, 70 bool HasIntersection(const std::vector<std::string>& a,
(...skipping 97 matching lines...) Expand 10 before | Expand all | Expand 10 after
219 } 168 }
220 169
221 } // namespace 170 } // namespace
222 171
223 RemoteSuggestionsProvider::RemoteSuggestionsProvider( 172 RemoteSuggestionsProvider::RemoteSuggestionsProvider(
224 Observer* observer, 173 Observer* observer,
225 CategoryFactory* category_factory, 174 CategoryFactory* category_factory,
226 PrefService* pref_service, 175 PrefService* pref_service,
227 const std::string& application_language_code, 176 const std::string& application_language_code,
228 const UserClassifier* user_classifier, 177 const UserClassifier* user_classifier,
229 NTPSnippetsScheduler* scheduler, 178 RemoteSuggestionsHardScheduler* hard_scheduler,
230 std::unique_ptr<NTPSnippetsFetcher> snippets_fetcher, 179 std::unique_ptr<NTPSnippetsFetcher> snippets_fetcher,
231 std::unique_ptr<image_fetcher::ImageFetcher> image_fetcher, 180 std::unique_ptr<image_fetcher::ImageFetcher> image_fetcher,
232 std::unique_ptr<image_fetcher::ImageDecoder> image_decoder, 181 std::unique_ptr<image_fetcher::ImageDecoder> image_decoder,
233 std::unique_ptr<RemoteSuggestionsDatabase> database, 182 std::unique_ptr<RemoteSuggestionsDatabase> database,
234 std::unique_ptr<RemoteSuggestionsStatusService> status_service) 183 std::unique_ptr<RemoteSuggestionsStatusService> status_service)
235 : ContentSuggestionsProvider(observer, category_factory), 184 : ContentSuggestionsProvider(observer, category_factory),
236 state_(State::NOT_INITED), 185 state_(State::NOT_INITED),
237 pref_service_(pref_service), 186 pref_service_(pref_service),
238 articles_category_( 187 articles_category_(
239 category_factory->FromKnownCategory(KnownCategories::ARTICLES)), 188 category_factory->FromKnownCategory(KnownCategories::ARTICLES)),
240 application_language_code_(application_language_code), 189 application_language_code_(application_language_code),
241 user_classifier_(user_classifier), 190 user_classifier_(user_classifier),
242 scheduler_(scheduler), 191 scheduler_(hard_scheduler,
192 this /* scheduler_updater */,
Marc Treib 2016/12/08 16:14:58 /*scheduler_updater=*/this That said, it's a bit
jkrcal 2016/12/09 09:20:38 Fair enough. Removed it from the constructor and a
193 user_classifier,
194 pref_service),
243 snippets_fetcher_(std::move(snippets_fetcher)), 195 snippets_fetcher_(std::move(snippets_fetcher)),
244 image_fetcher_(std::move(image_fetcher)), 196 image_fetcher_(std::move(image_fetcher)),
245 image_decoder_(std::move(image_decoder)), 197 image_decoder_(std::move(image_decoder)),
246 database_(std::move(database)), 198 database_(std::move(database)),
247 status_service_(std::move(status_service)), 199 status_service_(std::move(status_service)),
248 fetch_when_ready_(false), 200 fetch_when_ready_(false),
249 nuke_when_initialized_(false), 201 nuke_when_initialized_(false),
250 thumbnail_requests_throttler_( 202 thumbnail_requests_throttler_(
251 pref_service, 203 pref_service,
252 RequestThrottler::RequestType::CONTENT_SUGGESTION_THUMBNAIL) { 204 RequestThrottler::RequestType::CONTENT_SUGGESTION_THUMBNAIL) {
(...skipping 27 matching lines...) Expand all
280 } 232 }
281 233
282 RemoteSuggestionsProvider::~RemoteSuggestionsProvider() = default; 234 RemoteSuggestionsProvider::~RemoteSuggestionsProvider() = default;
283 235
284 // static 236 // static
285 void RemoteSuggestionsProvider::RegisterProfilePrefs( 237 void RemoteSuggestionsProvider::RegisterProfilePrefs(
286 PrefRegistrySimple* registry) { 238 PrefRegistrySimple* registry) {
287 // TODO(treib): Remove after M57. 239 // TODO(treib): Remove after M57.
288 registry->RegisterListPref(kDeprecatedSnippetHostsPref); 240 registry->RegisterListPref(kDeprecatedSnippetHostsPref);
289 registry->RegisterListPref(prefs::kRemoteSuggestionCategories); 241 registry->RegisterListPref(prefs::kRemoteSuggestionCategories);
290 registry->RegisterInt64Pref(prefs::kSnippetBackgroundFetchingIntervalWifi, 0);
291 registry->RegisterInt64Pref(prefs::kSnippetBackgroundFetchingIntervalFallback,
292 0);
293 242
243 RemoteSuggestionsScheduler::RegisterProfilePrefs(registry);
294 RemoteSuggestionsStatusService::RegisterProfilePrefs(registry); 244 RemoteSuggestionsStatusService::RegisterProfilePrefs(registry);
295 } 245 }
296 246
297 void RemoteSuggestionsProvider::FetchSnippetsInTheBackground() { 247 void RemoteSuggestionsProvider::UpdateRemoteSuggestionsBySchedule() {
298 FetchSnippets(/*interactive_request=*/false); 248 FetchSnippets(/*interactive_request=*/false);
299 } 249 }
300 250
301 void RemoteSuggestionsProvider::FetchSnippetsForAllCategories() { 251 void RemoteSuggestionsProvider::FetchSnippetsForAllCategories() {
302 // TODO(markusheintz): Investigate whether we can call the Fetch method 252 // TODO(markusheintz): Investigate whether we can call the Fetch method
303 // instead of the FetchSnippets. 253 // instead of the FetchSnippets.
304 FetchSnippets(/*interactive_request=*/true); 254 FetchSnippets(/*interactive_request=*/true);
305 } 255 }
306 256
307 void RemoteSuggestionsProvider::FetchSnippets(bool interactive_request) { 257 void RemoteSuggestionsProvider::FetchSnippets(bool interactive_request) {
(...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after
375 void RemoteSuggestionsProvider::MarkEmptyCategoriesAsLoading() { 325 void RemoteSuggestionsProvider::MarkEmptyCategoriesAsLoading() {
376 for (const auto& item : category_contents_) { 326 for (const auto& item : category_contents_) {
377 Category category = item.first; 327 Category category = item.first;
378 const CategoryContent& content = item.second; 328 const CategoryContent& content = item.second;
379 if (content.snippets.empty()) { 329 if (content.snippets.empty()) {
380 UpdateCategoryStatus(category, CategoryStatus::AVAILABLE_LOADING); 330 UpdateCategoryStatus(category, CategoryStatus::AVAILABLE_LOADING);
381 } 331 }
382 } 332 }
383 } 333 }
384 334
385 void RemoteSuggestionsProvider::RescheduleFetching(bool force) {
386 // The scheduler only exists on Android so far, it's null on other platforms.
387 if (!scheduler_) {
388 return;
389 }
390
391 if (ready()) {
392 base::TimeDelta old_interval_wifi = base::TimeDelta::FromInternalValue(
393 pref_service_->GetInt64(prefs::kSnippetBackgroundFetchingIntervalWifi));
394 base::TimeDelta old_interval_fallback =
395 base::TimeDelta::FromInternalValue(pref_service_->GetInt64(
396 prefs::kSnippetBackgroundFetchingIntervalFallback));
397 UserClassifier::UserClass user_class = user_classifier_->GetUserClass();
398 base::TimeDelta interval_wifi =
399 GetFetchingInterval(/*is_wifi=*/true, user_class);
400 base::TimeDelta interval_fallback =
401 GetFetchingInterval(/*is_wifi=*/false, user_class);
402 if (force || interval_wifi != old_interval_wifi ||
403 interval_fallback != old_interval_fallback) {
404 scheduler_->Schedule(interval_wifi, interval_fallback);
405 pref_service_->SetInt64(prefs::kSnippetBackgroundFetchingIntervalWifi,
406 interval_wifi.ToInternalValue());
407 pref_service_->SetInt64(prefs::kSnippetBackgroundFetchingIntervalFallback,
408 interval_fallback.ToInternalValue());
409 }
410 } else {
411 // If we're NOT_INITED, we don't know whether to schedule or unschedule.
412 // If |force| is false, all is well: We'll reschedule on the next state
413 // change anyway. If it's true, then unschedule here, to make sure that the
414 // next reschedule actually happens.
415 if (state_ != State::NOT_INITED || force) {
416 scheduler_->Unschedule();
417 pref_service_->ClearPref(prefs::kSnippetBackgroundFetchingIntervalWifi);
418 pref_service_->ClearPref(
419 prefs::kSnippetBackgroundFetchingIntervalFallback);
420 }
421 }
422 }
423
424 CategoryStatus RemoteSuggestionsProvider::GetCategoryStatus(Category category) { 335 CategoryStatus RemoteSuggestionsProvider::GetCategoryStatus(Category category) {
425 auto content_it = category_contents_.find(category); 336 auto content_it = category_contents_.find(category);
426 DCHECK(content_it != category_contents_.end()); 337 DCHECK(content_it != category_contents_.end());
427 return content_it->second.status; 338 return content_it->second.status;
428 } 339 }
429 340
430 CategoryInfo RemoteSuggestionsProvider::GetCategoryInfo(Category category) { 341 CategoryInfo RemoteSuggestionsProvider::GetCategoryInfo(Category category) {
431 auto content_it = category_contents_.find(category); 342 auto content_it = category_contents_.find(category);
432 DCHECK(content_it != category_contents_.end()); 343 DCHECK(content_it != category_contents_.end());
433 return content_it->second.info; 344 return content_it->second.info;
(...skipping 332 matching lines...) Expand 10 before | Expand all | Expand 10 after
766 if (content.snippets.empty() && !content.dismissed.empty()) { 677 if (content.snippets.empty() && !content.dismissed.empty()) {
767 UMA_HISTOGRAM_COUNTS("NewTabPage.Snippets.NumArticlesZeroDueToDiscarded", 678 UMA_HISTOGRAM_COUNTS("NewTabPage.Snippets.NumArticlesZeroDueToDiscarded",
768 content.dismissed.size()); 679 content.dismissed.size());
769 } 680 }
770 681
771 // Reschedule after a successful fetch. This resets all currently scheduled 682 // Reschedule after a successful fetch. This resets all currently scheduled
772 // fetches, to make sure the fallback interval triggers only if no wifi fetch 683 // fetches, to make sure the fallback interval triggers only if no wifi fetch
773 // succeeded, and also that we don't do a background fetch immediately after 684 // succeeded, and also that we don't do a background fetch immediately after
774 // a user-initiated one. 685 // a user-initiated one.
775 if (fetched_categories) { 686 if (fetched_categories) {
776 RescheduleFetching(true); 687 scheduler_.OnSuccessfulUpdate();
777 } 688 }
778 } 689 }
779 690
780 void RemoteSuggestionsProvider::ArchiveSnippets( 691 void RemoteSuggestionsProvider::ArchiveSnippets(
781 CategoryContent* content, 692 CategoryContent* content,
782 NTPSnippet::PtrVector* to_archive) { 693 NTPSnippet::PtrVector* to_archive) {
783 // Archive previous snippets - move them at the beginning of the list. 694 // Archive previous snippets - move them at the beginning of the list.
784 content->archived.insert(content->archived.begin(), 695 content->archived.insert(content->archived.begin(),
785 std::make_move_iterator(to_archive->begin()), 696 std::make_move_iterator(to_archive->begin()),
786 std::make_move_iterator(to_archive->end())); 697 std::make_move_iterator(to_archive->end()));
(...skipping 340 matching lines...) Expand 10 before | Expand all | Expand 10 after
1127 // Initial state, it should not be possible to get back there. 1038 // Initial state, it should not be possible to get back there.
1128 NOTREACHED(); 1039 NOTREACHED();
1129 break; 1040 break;
1130 1041
1131 case State::READY: 1042 case State::READY:
1132 DCHECK(state_ == State::NOT_INITED || state_ == State::DISABLED); 1043 DCHECK(state_ == State::NOT_INITED || state_ == State::DISABLED);
1133 1044
1134 DVLOG(1) << "Entering state: READY"; 1045 DVLOG(1) << "Entering state: READY";
1135 state_ = State::READY; 1046 state_ = State::READY;
1136 EnterStateReady(); 1047 EnterStateReady();
1048 scheduler_.Schedule();
1137 break; 1049 break;
1138 1050
1139 case State::DISABLED: 1051 case State::DISABLED:
1140 DCHECK(state_ == State::NOT_INITED || state_ == State::READY); 1052 DCHECK(state_ == State::NOT_INITED || state_ == State::READY);
1141 1053
1142 DVLOG(1) << "Entering state: DISABLED"; 1054 DVLOG(1) << "Entering state: DISABLED";
1143 state_ = State::DISABLED; 1055 state_ = State::DISABLED;
1144 EnterStateDisabled(); 1056 EnterStateDisabled();
1057 scheduler_.Unschedule();
1145 break; 1058 break;
1146 1059
1147 case State::ERROR_OCCURRED: 1060 case State::ERROR_OCCURRED:
1148 DVLOG(1) << "Entering state: ERROR_OCCURRED"; 1061 DVLOG(1) << "Entering state: ERROR_OCCURRED";
1149 state_ = State::ERROR_OCCURRED; 1062 state_ = State::ERROR_OCCURRED;
1150 EnterStateError(); 1063 EnterStateError();
1064 scheduler_.Unschedule();
1151 break; 1065 break;
1152 1066
1153 case State::COUNT: 1067 case State::COUNT:
1154 NOTREACHED(); 1068 NOTREACHED();
1155 break; 1069 break;
1156 } 1070 }
1157
1158 // Schedule or un-schedule background fetching after each state change.
1159 RescheduleFetching(false);
1160 } 1071 }
1161 1072
1162 void RemoteSuggestionsProvider::NotifyNewSuggestions( 1073 void RemoteSuggestionsProvider::NotifyNewSuggestions(
1163 Category category, 1074 Category category,
1164 const CategoryContent& content) { 1075 const CategoryContent& content) {
1165 DCHECK(IsCategoryStatusAvailable(content.status)); 1076 DCHECK(IsCategoryStatusAvailable(content.status));
1166 1077
1167 std::vector<ContentSuggestion> result = 1078 std::vector<ContentSuggestion> result =
1168 ConvertToContentSuggestions(category, content.snippets); 1079 ConvertToContentSuggestions(category, content.snippets);
1169 1080
(...skipping 162 matching lines...) Expand 10 before | Expand all | Expand 10 after
1332 RemoteSuggestionsProvider::CategoryContent::CategoryContent(CategoryContent&&) = 1243 RemoteSuggestionsProvider::CategoryContent::CategoryContent(CategoryContent&&) =
1333 default; 1244 default;
1334 1245
1335 RemoteSuggestionsProvider::CategoryContent::~CategoryContent() = default; 1246 RemoteSuggestionsProvider::CategoryContent::~CategoryContent() = default;
1336 1247
1337 RemoteSuggestionsProvider::CategoryContent& 1248 RemoteSuggestionsProvider::CategoryContent&
1338 RemoteSuggestionsProvider::CategoryContent::operator=(CategoryContent&&) = 1249 RemoteSuggestionsProvider::CategoryContent::operator=(CategoryContent&&) =
1339 default; 1250 default;
1340 1251
1341 } // namespace ntp_snippets 1252 } // namespace ntp_snippets
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698