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

Side by Side Diff: components/ntp_snippets/ntp_snippets_service.cc

Issue 2000233002: [NTP Snippets] Unschedule fetches when the service should be disabled (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@SnippetsDB
Patch Set: Please only look at ntp_snippets_service.*, the rest is because of the merge gone bad. Created 4 years, 7 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 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/ntp_snippets_service.h" 5 #include "components/ntp_snippets/ntp_snippets_service.h"
6 6
7 #include <algorithm> 7 #include <algorithm>
8 #include <iterator> 8 #include <iterator>
9 #include <utility> 9 #include <utility>
10 10
11 #include "base/command_line.h" 11 #include "base/command_line.h"
12 #include "base/files/file_path.h" 12 #include "base/files/file_path.h"
13 #include "base/files/file_util.h" 13 #include "base/files/file_util.h"
14 #include "base/location.h" 14 #include "base/location.h"
15 #include "base/metrics/histogram_macros.h" 15 #include "base/metrics/histogram_macros.h"
16 #include "base/metrics/sparse_histogram.h" 16 #include "base/metrics/sparse_histogram.h"
17 #include "base/path_service.h" 17 #include "base/path_service.h"
18 #include "base/strings/string_number_conversions.h" 18 #include "base/strings/string_number_conversions.h"
19 #include "base/task_runner_util.h" 19 #include "base/task_runner_util.h"
20 #include "base/time/time.h" 20 #include "base/time/time.h"
21 #include "base/values.h" 21 #include "base/values.h"
22 #include "components/image_fetcher/image_fetcher.h" 22 #include "components/image_fetcher/image_fetcher.h"
23 #include "components/ntp_snippets/ntp_snippets_constants.h" 23 #include "components/ntp_snippets/ntp_snippets_constants.h"
24 #include "components/ntp_snippets/ntp_snippets_database.h"
24 #include "components/ntp_snippets/pref_names.h" 25 #include "components/ntp_snippets/pref_names.h"
25 #include "components/ntp_snippets/switches.h" 26 #include "components/ntp_snippets/switches.h"
26 #include "components/prefs/pref_registry_simple.h" 27 #include "components/prefs/pref_registry_simple.h"
27 #include "components/prefs/pref_service.h" 28 #include "components/prefs/pref_service.h"
28 #include "components/suggestions/proto/suggestions.pb.h" 29 #include "components/suggestions/proto/suggestions.pb.h"
29 #include "components/sync_driver/sync_service.h" 30 #include "components/sync_driver/sync_service.h"
30 #include "components/variations/variations_associated_data.h" 31 #include "components/variations/variations_associated_data.h"
31 #include "ui/gfx/image/image.h" 32 #include "ui/gfx/image/image.h"
32 33
33 using image_fetcher::ImageFetcher; 34 using image_fetcher::ImageFetcher;
(...skipping 116 matching lines...) Expand 10 before | Expand all | Expand 10 after
150 std::set<std::string> hosts; 151 std::set<std::string> hosts;
151 for (int i = 0; i < suggestions.suggestions_size(); ++i) { 152 for (int i = 0; i < suggestions.suggestions_size(); ++i) {
152 const ChromeSuggestion& suggestion = suggestions.suggestions(i); 153 const ChromeSuggestion& suggestion = suggestions.suggestions(i);
153 GURL url(suggestion.url()); 154 GURL url(suggestion.url());
154 if (url.is_valid()) 155 if (url.is_valid())
155 hosts.insert(url.host()); 156 hosts.insert(url.host());
156 } 157 }
157 return hosts; 158 return hosts;
158 } 159 }
159 160
160 std::unique_ptr<base::ListValue> SnippetsToListValue(
161 const NTPSnippet::PtrVector& snippets) {
162 std::unique_ptr<base::ListValue> list(new base::ListValue);
163 for (const auto& snippet : snippets) {
164 std::unique_ptr<base::DictionaryValue> dict = snippet->ToDictionary();
165 list->Append(std::move(dict));
166 }
167 return list;
168 }
169
170 void InsertAllIDs(const NTPSnippet::PtrVector& snippets, 161 void InsertAllIDs(const NTPSnippet::PtrVector& snippets,
171 std::set<std::string>* ids) { 162 std::set<std::string>* ids) {
172 for (const std::unique_ptr<NTPSnippet>& snippet : snippets) { 163 for (const std::unique_ptr<NTPSnippet>& snippet : snippets) {
173 ids->insert(snippet->id()); 164 ids->insert(snippet->id());
174 for (const SnippetSource& source : snippet->sources()) 165 for (const SnippetSource& source : snippet->sources())
175 ids->insert(source.url.spec()); 166 ids->insert(source.url.spec());
176 } 167 }
177 } 168 }
178 169
170 void EraseNullptrs(NTPSnippet::PtrVector* snippets) {
171 snippets->erase(
172 std::remove_if(
173 snippets->begin(), snippets->end(),
174 [](const std::unique_ptr<NTPSnippet>& snippet) { return !snippet; }),
175 snippets->end());
176 }
177
179 void WrapImageFetchedCallback( 178 void WrapImageFetchedCallback(
180 const NTPSnippetsService::ImageFetchedCallback& callback, 179 const NTPSnippetsService::ImageFetchedCallback& callback,
181 const GURL& snippet_id_url, 180 const GURL& snippet_id_url,
182 const gfx::Image& image) { 181 const gfx::Image& image) {
183 callback.Run(snippet_id_url.spec(), image); 182 callback.Run(snippet_id_url.spec(), image);
184 } 183 }
185 184
186 } // namespace 185 } // namespace
187 186
188 NTPSnippetsService::NTPSnippetsService( 187 NTPSnippetsService::NTPSnippetsService(
189 PrefService* pref_service, 188 PrefService* pref_service,
190 sync_driver::SyncService* sync_service, 189 sync_driver::SyncService* sync_service,
191 SuggestionsService* suggestions_service, 190 SuggestionsService* suggestions_service,
192 scoped_refptr<base::SequencedTaskRunner> file_task_runner,
193 const std::string& application_language_code, 191 const std::string& application_language_code,
194 NTPSnippetsScheduler* scheduler, 192 NTPSnippetsScheduler* scheduler,
195 std::unique_ptr<NTPSnippetsFetcher> snippets_fetcher, 193 std::unique_ptr<NTPSnippetsFetcher> snippets_fetcher,
196 std::unique_ptr<ImageFetcher> image_fetcher) 194 std::unique_ptr<ImageFetcher> image_fetcher,
195 std::unique_ptr<NTPSnippetsDatabase> database)
197 : state_(State::NOT_INITED), 196 : state_(State::NOT_INITED),
198 enabled_(false), 197 explicitly_disabled_(false),
199 pref_service_(pref_service), 198 pref_service_(pref_service),
200 sync_service_(sync_service), 199 sync_service_(sync_service),
201 sync_service_observer_(this), 200 sync_service_observer_(this),
202 suggestions_service_(suggestions_service), 201 suggestions_service_(suggestions_service),
203 file_task_runner_(file_task_runner),
204 application_language_code_(application_language_code), 202 application_language_code_(application_language_code),
205 scheduler_(scheduler), 203 scheduler_(scheduler),
206 snippets_fetcher_(std::move(snippets_fetcher)), 204 snippets_fetcher_(std::move(snippets_fetcher)),
207 image_fetcher_(std::move(image_fetcher)) { 205 image_fetcher_(std::move(image_fetcher)),
206 database_(std::move(database)) {
208 snippets_fetcher_->SetCallback(base::Bind( 207 snippets_fetcher_->SetCallback(base::Bind(
209 &NTPSnippetsService::OnFetchFinished, base::Unretained(this))); 208 &NTPSnippetsService::OnFetchFinished, base::Unretained(this)));
210 209
211 // |sync_service_| can be null in tests or if sync is disabled. 210 // |sync_service_| can be null in tests or if sync is disabled.
212 if (sync_service_) 211 if (sync_service_)
213 sync_service_observer_.Add(sync_service_); 212 sync_service_observer_.Add(sync_service_);
214 } 213 }
215 214
216 NTPSnippetsService::~NTPSnippetsService() { 215 NTPSnippetsService::~NTPSnippetsService() {
217 DCHECK(state_ == State::NOT_INITED || state_ == State::SHUT_DOWN); 216 DCHECK(state_ == State::NOT_INITED || state_ == State::SHUT_DOWN);
218 } 217 }
219 218
220 // static 219 // static
221 void NTPSnippetsService::RegisterProfilePrefs(PrefRegistrySimple* registry) { 220 void NTPSnippetsService::RegisterProfilePrefs(PrefRegistrySimple* registry) {
222 registry->RegisterListPref(prefs::kSnippets); 221 registry->RegisterListPref(prefs::kSnippets);
223 registry->RegisterListPref(prefs::kDiscardedSnippets); 222 registry->RegisterListPref(prefs::kDiscardedSnippets);
224 registry->RegisterListPref(prefs::kSnippetHosts); 223 registry->RegisterListPref(prefs::kSnippetHosts);
225 } 224 }
226 225
227 void NTPSnippetsService::Init(bool enabled) { 226 void NTPSnippetsService::Init(bool enabled) {
228 DCHECK(state_ == State::NOT_INITED); 227 explicitly_disabled_ = !enabled;
229 state_ = State::INITED; 228 EnterState(!explicitly_disabled_ ? State::INITED : State::DISABLED);
230
231 enabled_ = enabled;
232 if (enabled_) {
233 // |suggestions_service_| can be null in tests.
234 if (snippets_fetcher_->UsesHostRestrictions() && suggestions_service_) {
235 suggestions_service_subscription_ = suggestions_service_->AddCallback(
236 base::Bind(&NTPSnippetsService::OnSuggestionsChanged,
237 base::Unretained(this)));
238 }
239
240 // Get any existing snippets immediately from prefs.
241 LoadDiscardedSnippetsFromPrefs();
242 LoadSnippetsFromPrefs();
243
244 // If we don't have any snippets yet, start a fetch.
245 if (snippets_.empty())
246 FetchSnippets();
247 }
248
249 RescheduleFetching();
250 } 229 }
251 230
231 // Inherited from KeyedService.
252 void NTPSnippetsService::Shutdown() { 232 void NTPSnippetsService::Shutdown() {
253 DCHECK(state_ == State::INITED); 233 EnterState(State::SHUT_DOWN);
254 state_ = State::SHUT_DOWN;
255 234
256 FOR_EACH_OBSERVER(NTPSnippetsServiceObserver, observers_, 235 FOR_EACH_OBSERVER(NTPSnippetsServiceObserver, observers_,
257 NTPSnippetsServiceShutdown()); 236 NTPSnippetsServiceShutdown());
237 expiry_timer_.Stop();
258 suggestions_service_subscription_.reset(); 238 suggestions_service_subscription_.reset();
259 enabled_ = false;
260 } 239 }
261 240
262 void NTPSnippetsService::FetchSnippets() { 241 void NTPSnippetsService::FetchSnippets() {
263 FetchSnippetsFromHosts(GetSuggestionsHosts()); 242 FetchSnippetsFromHosts(GetSuggestionsHosts());
264 } 243 }
265 244
266 void NTPSnippetsService::FetchSnippetsFromHosts( 245 void NTPSnippetsService::FetchSnippetsFromHosts(
267 const std::set<std::string>& hosts) { 246 const std::set<std::string>& hosts) {
247 if (!ready())
248 return;
268 snippets_fetcher_->FetchSnippetsFromHosts(hosts, application_language_code_, 249 snippets_fetcher_->FetchSnippetsFromHosts(hosts, application_language_code_,
269 kMaxSnippetCount); 250 kMaxSnippetCount);
270 } 251 }
271 252
272 void NTPSnippetsService::RescheduleFetching() { 253 void NTPSnippetsService::RescheduleFetching() {
273 // The scheduler only exists on Android so far, it's null on other platforms. 254 // The scheduler only exists on Android so far, it's null on other platforms.
274 if (!scheduler_) 255 if (!scheduler_)
275 return; 256 return;
276 257
277 if (enabled_) { 258 if (ready()) {
278 base::Time now = base::Time::Now(); 259 base::Time now = base::Time::Now();
279 scheduler_->Schedule( 260 scheduler_->Schedule(
280 GetFetchingIntervalWifiCharging(), GetFetchingIntervalWifi(now), 261 GetFetchingIntervalWifiCharging(), GetFetchingIntervalWifi(now),
281 GetFetchingIntervalFallback(), GetRescheduleTime(now)); 262 GetFetchingIntervalFallback(), GetRescheduleTime(now));
282 } else { 263 } else {
283 scheduler_->Unschedule(); 264 scheduler_->Unschedule();
284 } 265 }
285 } 266 }
286 267
287 void NTPSnippetsService::FetchSnippetImage( 268 void NTPSnippetsService::FetchSnippetImage(
(...skipping 13 matching lines...) Expand all
301 const NTPSnippet& snippet = *it->get(); 282 const NTPSnippet& snippet = *it->get();
302 // TODO(treib): Make ImageFetcher take a string instead of a GURL as an 283 // TODO(treib): Make ImageFetcher take a string instead of a GURL as an
303 // identifier. 284 // identifier.
304 image_fetcher_->StartOrQueueNetworkRequest( 285 image_fetcher_->StartOrQueueNetworkRequest(
305 GURL(snippet.id()), snippet.salient_image_url(), 286 GURL(snippet.id()), snippet.salient_image_url(),
306 base::Bind(WrapImageFetchedCallback, callback)); 287 base::Bind(WrapImageFetchedCallback, callback));
307 // TODO(treib): Cache/persist the snippet image. 288 // TODO(treib): Cache/persist the snippet image.
308 } 289 }
309 290
310 void NTPSnippetsService::ClearSnippets() { 291 void NTPSnippetsService::ClearSnippets() {
292 // snippets-internals can call ClearSnippets while the service is ready.
Marc Treib 2016/05/25 14:47:32 Er, isn't it acceptable for anyone to call ClearSn
dgn 2016/06/03 19:02:24 True, removed that comment.
293 if (!ready() && state_ != State::DISABLED)
294 return;
295
296 if (snippets_.empty())
297 return;
298
299 database_->Delete(snippets_);
311 snippets_.clear(); 300 snippets_.clear();
312 301
313 StoreSnippetsToPrefs(); 302 DVLOG(1) << "[ClearSnippets] NTPSnippetsServiceLoaded";
314
315 FOR_EACH_OBSERVER(NTPSnippetsServiceObserver, observers_, 303 FOR_EACH_OBSERVER(NTPSnippetsServiceObserver, observers_,
316 NTPSnippetsServiceLoaded()); 304 NTPSnippetsServiceLoaded());
317 } 305 }
318 306
319 std::set<std::string> NTPSnippetsService::GetSuggestionsHosts() const { 307 std::set<std::string> NTPSnippetsService::GetSuggestionsHosts() const {
320 // |suggestions_service_| can be null in tests. 308 // |suggestions_service_| can be null in tests.
321 if (!suggestions_service_) 309 if (!suggestions_service_)
322 return std::set<std::string>(); 310 return std::set<std::string>();
323 311
324 // TODO(treib) this should just call GetSnippetHostsFromPrefs 312 // TODO(treib): This should just call GetSnippetHostsFromPrefs.
325 return GetSuggestionsHostsImpl( 313 return GetSuggestionsHostsImpl(
326 suggestions_service_->GetSuggestionsDataFromCache()); 314 suggestions_service_->GetSuggestionsDataFromCache());
327 } 315 }
328 316
329 bool NTPSnippetsService::DiscardSnippet(const std::string& snippet_id) { 317 bool NTPSnippetsService::DiscardSnippet(const std::string& snippet_id) {
318 if (!ready())
319 return false;
320
330 auto it = 321 auto it =
331 std::find_if(snippets_.begin(), snippets_.end(), 322 std::find_if(snippets_.begin(), snippets_.end(),
332 [&snippet_id](const std::unique_ptr<NTPSnippet>& snippet) { 323 [&snippet_id](const std::unique_ptr<NTPSnippet>& snippet) {
333 return snippet->id() == snippet_id; 324 return snippet->id() == snippet_id;
334 }); 325 });
335 if (it == snippets_.end()) 326 if (it == snippets_.end())
336 return false; 327 return false;
328
329 (*it)->set_discarded(true);
330
331 database_->Save(**it);
332
337 discarded_snippets_.push_back(std::move(*it)); 333 discarded_snippets_.push_back(std::move(*it));
338 snippets_.erase(it); 334 snippets_.erase(it);
339 StoreDiscardedSnippetsToPrefs(); 335
340 StoreSnippetsToPrefs();
341 FOR_EACH_OBSERVER(NTPSnippetsServiceObserver, observers_, 336 FOR_EACH_OBSERVER(NTPSnippetsServiceObserver, observers_,
342 NTPSnippetsServiceLoaded()); 337 NTPSnippetsServiceLoaded());
343 return true; 338 return true;
344 } 339 }
345 340
346 void NTPSnippetsService::ClearDiscardedSnippets() { 341 void NTPSnippetsService::ClearDiscardedSnippets() {
342 if (!ready())
343 return;
344
345 database_->Delete(discarded_snippets_);
347 discarded_snippets_.clear(); 346 discarded_snippets_.clear();
348 StoreDiscardedSnippetsToPrefs(); 347
349 FetchSnippets(); 348 FetchSnippets();
350 } 349 }
351 350
352 void NTPSnippetsService::AddObserver(NTPSnippetsServiceObserver* observer) { 351 void NTPSnippetsService::AddObserver(NTPSnippetsServiceObserver* observer) {
353 observers_.AddObserver(observer); 352 observers_.AddObserver(observer);
354 } 353 }
355 354
356 void NTPSnippetsService::RemoveObserver(NTPSnippetsServiceObserver* observer) { 355 void NTPSnippetsService::RemoveObserver(NTPSnippetsServiceObserver* observer) {
357 observers_.RemoveObserver(observer); 356 observers_.RemoveObserver(observer);
358 } 357 }
359 358
359 DisabledReason NTPSnippetsService::GetDisabledReason() {
360 if (explicitly_disabled_)
361 return DisabledReason::EXPLICITLY_DISABLED;
362
363 if (!sync_service_ || !sync_service_->CanSyncStart()) {
364 DVLOG(1) << "[GetDisabledReason] Sync disabled";
365 return DisabledReason::HISTORY_SYNC_DISABLED;
366 }
367
368 if (!sync_service_->IsSyncActive() || !sync_service_->ConfigurationDone()) {
Marc Treib 2016/05/25 14:47:32 I think the ConfigurationDone check is redundant -
dgn 2016/06/03 19:02:24 When the sync options are modified, IsSyncActive()
369 DVLOG(1) << "[GetDisabledReason] config not done";
370 return DisabledReason::HISTORY_SYNC_STATE_UNKNOWN;
371 }
372
373 if (!sync_service_->GetActiveDataTypes().Has(
374 syncer::HISTORY_DELETE_DIRECTIVES)) {
375 DVLOG(1) << "[GetDisabledReason] History sync disabled";
376 return DisabledReason::HISTORY_SYNC_DISABLED;
377 }
378
379 DVLOG(1) << "[GetDisabledReason] Enabled!";
380 return DisabledReason::NONE;
381 }
382
360 // static 383 // static
361 int NTPSnippetsService::GetMaxSnippetCountForTesting() { 384 int NTPSnippetsService::GetMaxSnippetCountForTesting() {
362 return kMaxSnippetCount; 385 return kMaxSnippetCount;
363 } 386 }
364 387
365 //////////////////////////////////////////////////////////////////////////////// 388 ////////////////////////////////////////////////////////////////////////////////
366 // Private methods 389 // Private methods
367 390
368 // sync_driver::SyncServiceObserver implementation. 391 // sync_driver::SyncServiceObserver implementation.
369 void NTPSnippetsService::OnStateChanged() { 392 void NTPSnippetsService::OnStateChanged() {
370 if (IsSyncStateIncompatible()) { 393 DVLOG(1) << "[OnStateChanged]";
371 ClearSnippets(); 394 EnterState(GetStateForDependenciesStatus());
Marc Treib 2016/05/25 14:47:32 Can we get here before the DB is loaded? If so, pl
dgn 2016/06/03 19:02:24 Done.
372 FOR_EACH_OBSERVER(NTPSnippetsServiceObserver, observers_, 395 }
373 NTPSnippetsServiceDisabled()); 396
397 void NTPSnippetsService::OnDatabaseLoaded(NTPSnippet::PtrVector snippets) {
398 if (state_ == State::SHUT_DOWN)
374 return; 399 return;
400
401 DCHECK(snippets_.empty());
402 DCHECK(discarded_snippets_.empty());
403 for (std::unique_ptr<NTPSnippet>& snippet : snippets) {
404 if (snippet->is_discarded())
405 discarded_snippets_.emplace_back(std::move(snippet));
406 else
407 snippets_.emplace_back(std::move(snippet));
408 }
409 std::sort(snippets_.begin(), snippets_.end(),
410 [](const std::unique_ptr<NTPSnippet>& lhs,
411 const std::unique_ptr<NTPSnippet>& rhs) {
412 return lhs->score() > rhs->score();
413 });
414
415 if (!snippets_.empty()) {
416 DVLOG(1) << "[OnDatabaseLoaded] got snippets";
417 LoadingSnippetsFinished();
375 } 418 }
376 419
377 // TODO(dgn): When the data sources change, we may want to not fetch here, 420 EnterState(GetStateForDependenciesStatus());
378 // as we will get notified of changes from the snippet sources as well, and
379 // start multiple fetches.
380 FetchSnippets();
381 } 421 }
382 422
383 void NTPSnippetsService::OnSuggestionsChanged( 423 void NTPSnippetsService::OnSuggestionsChanged(
384 const SuggestionsProfile& suggestions) { 424 const SuggestionsProfile& suggestions) {
425 DCHECK(ready() || state_ == State::DISABLED);
426
385 std::set<std::string> hosts = GetSuggestionsHostsImpl(suggestions); 427 std::set<std::string> hosts = GetSuggestionsHostsImpl(suggestions);
386 if (hosts == GetSnippetHostsFromPrefs()) 428 if (hosts == GetSnippetHostsFromPrefs())
387 return; 429 return;
388 430
389 // Remove existing snippets that aren't in the suggestions anymore. 431 // Remove existing snippets that aren't in the suggestions anymore.
390 // TODO(treib,maybelle): If there is another source with an allowed host, 432 // TODO(treib,maybelle): If there is another source with an allowed host,
391 // then we should fall back to that. 433 // then we should fall back to that.
392 snippets_.erase( 434 // First, move them over into |to_delete|.
393 std::remove_if(snippets_.begin(), snippets_.end(), 435 NTPSnippet::PtrVector to_delete;
394 [&hosts](const std::unique_ptr<NTPSnippet>& snippet) { 436 for (std::unique_ptr<NTPSnippet>& snippet : snippets_) {
395 return !hosts.count(snippet->best_source().url.host()); 437 if (!hosts.count(snippet->best_source().url.host()))
396 }), 438 to_delete.emplace_back(std::move(snippet));
397 snippets_.end()); 439 }
440 EraseNullptrs(&snippets_);
441 // Then delete the removed snippets from the database.
442 database_->Delete(to_delete);
398 443
399 StoreSnippetsToPrefs();
400 StoreSnippetHostsToPrefs(hosts); 444 StoreSnippetHostsToPrefs(hosts);
401 445
446 DVLOG(1) << "[OnSuggestionsChanged] NTPSnippetsServiceLoaded";
402 FOR_EACH_OBSERVER(NTPSnippetsServiceObserver, observers_, 447 FOR_EACH_OBSERVER(NTPSnippetsServiceObserver, observers_,
403 NTPSnippetsServiceLoaded()); 448 NTPSnippetsServiceLoaded());
404 449
405 FetchSnippetsFromHosts(hosts); 450 FetchSnippetsFromHosts(hosts);
406 } 451 }
407 452
408 void NTPSnippetsService::OnFetchFinished( 453 void NTPSnippetsService::OnFetchFinished(
409 NTPSnippetsFetcher::OptionalSnippets snippets) { 454 NTPSnippetsFetcher::OptionalSnippets snippets) {
455 if (!ready())
456 return;
457
410 if (snippets) { 458 if (snippets) {
411 // Sparse histogram used because the number of snippets is small (bound by 459 // Sparse histogram used because the number of snippets is small (bound by
412 // kMaxSnippetCount). 460 // kMaxSnippetCount).
413 DCHECK_LE(snippets->size(), static_cast<size_t>(kMaxSnippetCount)); 461 DCHECK_LE(snippets->size(), static_cast<size_t>(kMaxSnippetCount));
462 DVLOG(1) << "[OnFetchFinished] histogram -> NumArticlesFetched";
414 UMA_HISTOGRAM_SPARSE_SLOWLY("NewTabPage.Snippets.NumArticlesFetched", 463 UMA_HISTOGRAM_SPARSE_SLOWLY("NewTabPage.Snippets.NumArticlesFetched",
415 snippets->size()); 464 snippets->size());
416 MergeSnippets(std::move(*snippets)); 465 MergeSnippets(std::move(*snippets));
417 } 466 }
467
468 DVLOG(1) << "[OnFetchFinished]";
418 LoadingSnippetsFinished(); 469 LoadingSnippetsFinished();
419 } 470 }
420 471
421 void NTPSnippetsService::MergeSnippets(NTPSnippet::PtrVector new_snippets) { 472 void NTPSnippetsService::MergeSnippets(NTPSnippet::PtrVector new_snippets) {
473 DCHECK(ready());
474
422 // Remove new snippets that we already have, or that have been discarded. 475 // Remove new snippets that we already have, or that have been discarded.
423 std::set<std::string> old_snippet_ids; 476 std::set<std::string> old_snippet_ids;
424 InsertAllIDs(discarded_snippets_, &old_snippet_ids); 477 InsertAllIDs(discarded_snippets_, &old_snippet_ids);
425 InsertAllIDs(snippets_, &old_snippet_ids); 478 InsertAllIDs(snippets_, &old_snippet_ids);
426 new_snippets.erase( 479 new_snippets.erase(
427 std::remove_if( 480 std::remove_if(
428 new_snippets.begin(), new_snippets.end(), 481 new_snippets.begin(), new_snippets.end(),
429 [&old_snippet_ids](const std::unique_ptr<NTPSnippet>& snippet) { 482 [&old_snippet_ids](const std::unique_ptr<NTPSnippet>& snippet) {
430 if (old_snippet_ids.count(snippet->id())) 483 if (old_snippet_ids.count(snippet->id()))
431 return true; 484 return true;
(...skipping 23 matching lines...) Expand all
455 int num_new_snippets = new_snippets.size(); 508 int num_new_snippets = new_snippets.size();
456 // Remove snippets that do not have all the info we need to display it to 509 // Remove snippets that do not have all the info we need to display it to
457 // the user. 510 // the user.
458 new_snippets.erase( 511 new_snippets.erase(
459 std::remove_if(new_snippets.begin(), new_snippets.end(), 512 std::remove_if(new_snippets.begin(), new_snippets.end(),
460 [](const std::unique_ptr<NTPSnippet>& snippet) { 513 [](const std::unique_ptr<NTPSnippet>& snippet) {
461 return !snippet->is_complete(); 514 return !snippet->is_complete();
462 }), 515 }),
463 new_snippets.end()); 516 new_snippets.end());
464 int num_snippets_discarded = num_new_snippets - new_snippets.size(); 517 int num_snippets_discarded = num_new_snippets - new_snippets.size();
518 DVLOG(1) << "[MergeSnippets] histogram -> IncompleteSnippetsAfterFetch";
465 UMA_HISTOGRAM_BOOLEAN("NewTabPage.Snippets.IncompleteSnippetsAfterFetch", 519 UMA_HISTOGRAM_BOOLEAN("NewTabPage.Snippets.IncompleteSnippetsAfterFetch",
466 num_snippets_discarded > 0); 520 num_snippets_discarded > 0);
467 if (num_snippets_discarded > 0) { 521 if (num_snippets_discarded > 0) {
522 DVLOG(1) << "[MergeSnippets] histogram -> NumIncompleteSnippets";
468 UMA_HISTOGRAM_SPARSE_SLOWLY("NewTabPage.Snippets.NumIncompleteSnippets", 523 UMA_HISTOGRAM_SPARSE_SLOWLY("NewTabPage.Snippets.NumIncompleteSnippets",
469 num_snippets_discarded); 524 num_snippets_discarded);
470 } 525 }
471 } 526 }
527
528 // Save the new snippets to the DB.
529 database_->Save(new_snippets);
530
472 // Insert the new snippets at the front. 531 // Insert the new snippets at the front.
473 snippets_.insert(snippets_.begin(), 532 snippets_.insert(snippets_.begin(),
474 std::make_move_iterator(new_snippets.begin()), 533 std::make_move_iterator(new_snippets.begin()),
475 std::make_move_iterator(new_snippets.end())); 534 std::make_move_iterator(new_snippets.end()));
476 } 535 }
477 536
478 void NTPSnippetsService::LoadSnippetsFromPrefs() {
479 NTPSnippet::PtrVector prefs_snippets;
480 bool success = NTPSnippet::AddFromListValue(
481 *pref_service_->GetList(prefs::kSnippets), &prefs_snippets);
482 DCHECK(success) << "Failed to parse snippets from prefs";
483 MergeSnippets(std::move(prefs_snippets));
484 LoadingSnippetsFinished();
485 }
486
487 void NTPSnippetsService::StoreSnippetsToPrefs() {
488 pref_service_->Set(prefs::kSnippets, *SnippetsToListValue(snippets_));
489 }
490
491 void NTPSnippetsService::LoadDiscardedSnippetsFromPrefs() {
492 discarded_snippets_.clear();
493 bool success = NTPSnippet::AddFromListValue(
494 *pref_service_->GetList(prefs::kDiscardedSnippets), &discarded_snippets_);
495 DCHECK(success) << "Failed to parse discarded snippets from prefs";
496 }
497
498 void NTPSnippetsService::StoreDiscardedSnippetsToPrefs() {
499 pref_service_->Set(prefs::kDiscardedSnippets,
500 *SnippetsToListValue(discarded_snippets_));
501 }
502
503 std::set<std::string> NTPSnippetsService::GetSnippetHostsFromPrefs() const { 537 std::set<std::string> NTPSnippetsService::GetSnippetHostsFromPrefs() const {
504 std::set<std::string> hosts; 538 std::set<std::string> hosts;
505 const base::ListValue* list = pref_service_->GetList(prefs::kSnippetHosts); 539 const base::ListValue* list = pref_service_->GetList(prefs::kSnippetHosts);
506 for (const base::Value* value : *list) { 540 for (const base::Value* value : *list) {
507 std::string str; 541 std::string str;
508 bool success = value->GetAsString(&str); 542 bool success = value->GetAsString(&str);
509 DCHECK(success) << "Failed to parse snippet host from prefs"; 543 DCHECK(success) << "Failed to parse snippet host from prefs";
510 hosts.insert(std::move(str)); 544 hosts.insert(std::move(str));
511 } 545 }
512 return hosts; 546 return hosts;
513 } 547 }
514 548
515 void NTPSnippetsService::StoreSnippetHostsToPrefs( 549 void NTPSnippetsService::StoreSnippetHostsToPrefs(
516 const std::set<std::string>& hosts) { 550 const std::set<std::string>& hosts) {
517 base::ListValue list; 551 base::ListValue list;
518 for (const std::string& host : hosts) 552 for (const std::string& host : hosts)
519 list.AppendString(host); 553 list.AppendString(host);
520 pref_service_->Set(prefs::kSnippetHosts, list); 554 pref_service_->Set(prefs::kSnippetHosts, list);
521 } 555 }
522 556
523 void NTPSnippetsService::LoadingSnippetsFinished() { 557 void NTPSnippetsService::LoadingSnippetsFinished() {
558 DCHECK(ready() || state_ == State::INITED);
559
524 // Remove expired snippets. 560 // Remove expired snippets.
525 base::Time expiry = base::Time::Now(); 561 base::Time expiry = base::Time::Now();
526 562
527 snippets_.erase( 563 // Move expired snippets over into |to_delete|.
528 std::remove_if(snippets_.begin(), snippets_.end(), 564 NTPSnippet::PtrVector to_delete;
529 [&expiry](const std::unique_ptr<NTPSnippet>& snippet) { 565 for (std::unique_ptr<NTPSnippet>& snippet : snippets_) {
530 return snippet->expiry_date() <= expiry; 566 if (snippet->expiry_date() <= expiry)
531 }), 567 to_delete.emplace_back(std::move(snippet));
532 snippets_.end()); 568 }
569 EraseNullptrs(&snippets_);
533 570
534 // If there are more snippets now than we want to show, drop the extra ones 571 // If there are still more snippets than we want to show, move the extra ones
535 // from the end of the list. 572 // over into |to_delete| as well.
536 if (snippets_.size() > kMaxSnippetCount) 573 if (snippets_.size() > kMaxSnippetCount) {
574 to_delete.insert(
575 to_delete.end(),
576 std::make_move_iterator(snippets_.begin() + kMaxSnippetCount),
577 std::make_move_iterator(snippets_.end()));
537 snippets_.resize(kMaxSnippetCount); 578 snippets_.resize(kMaxSnippetCount);
579 }
538 580
539 StoreSnippetsToPrefs(); 581 // Move expired discarded snippets over into |to_delete| as well.
582 for (std::unique_ptr<NTPSnippet>& snippet : discarded_snippets_) {
583 if (snippet->expiry_date() <= expiry)
584 to_delete.emplace_back(std::move(snippet));
585 }
586 EraseNullptrs(&discarded_snippets_);
540 587
541 discarded_snippets_.erase( 588 // Finally, actually delete the removed snippets from the DB.
542 std::remove_if(discarded_snippets_.begin(), discarded_snippets_.end(), 589 database_->Delete(to_delete);
543 [&expiry](const std::unique_ptr<NTPSnippet>& snippet) {
544 return snippet->expiry_date() <= expiry;
545 }),
546 discarded_snippets_.end());
547 StoreDiscardedSnippetsToPrefs();
548 590
591 DVLOG(1) << "[LoadingSnippetsFinished] NTPSnippetsServiceLoaded -> Histogram "
592 "NumArticles";
549 UMA_HISTOGRAM_SPARSE_SLOWLY("NewTabPage.Snippets.NumArticles", 593 UMA_HISTOGRAM_SPARSE_SLOWLY("NewTabPage.Snippets.NumArticles",
550 snippets_.size()); 594 snippets_.size());
551 if (snippets_.empty() && !discarded_snippets_.empty()) { 595 if (snippets_.empty() && !discarded_snippets_.empty()) {
596 DVLOG(1) << "[LoadingSnippetsFinished] NTPSnippetsServiceLoaded -> "
597 "Histogram NumArticlesZeroDueToDiscarded";
552 UMA_HISTOGRAM_COUNTS("NewTabPage.Snippets.NumArticlesZeroDueToDiscarded", 598 UMA_HISTOGRAM_COUNTS("NewTabPage.Snippets.NumArticlesZeroDueToDiscarded",
553 discarded_snippets_.size()); 599 discarded_snippets_.size());
554 } 600 }
555 601
556 FOR_EACH_OBSERVER(NTPSnippetsServiceObserver, observers_, 602 FOR_EACH_OBSERVER(NTPSnippetsServiceObserver, observers_,
557 NTPSnippetsServiceLoaded()); 603 NTPSnippetsServiceLoaded());
558 604
559 // If there are any snippets left, schedule a timer for the next expiry. 605 // If there are any snippets left, schedule a timer for the next expiry.
560 if (snippets_.empty() && discarded_snippets_.empty()) 606 if (snippets_.empty() && discarded_snippets_.empty())
561 return; 607 return;
562 608
563 base::Time next_expiry = base::Time::Max(); 609 base::Time next_expiry = base::Time::Max();
564 for (const auto& snippet : snippets_) { 610 for (const auto& snippet : snippets_) {
565 if (snippet->expiry_date() < next_expiry) 611 if (snippet->expiry_date() < next_expiry)
566 next_expiry = snippet->expiry_date(); 612 next_expiry = snippet->expiry_date();
567 } 613 }
568 for (const auto& snippet : discarded_snippets_) { 614 for (const auto& snippet : discarded_snippets_) {
569 if (snippet->expiry_date() < next_expiry) 615 if (snippet->expiry_date() < next_expiry)
570 next_expiry = snippet->expiry_date(); 616 next_expiry = snippet->expiry_date();
571 } 617 }
572 DCHECK_GT(next_expiry, expiry); 618 DCHECK_GT(next_expiry, expiry);
573 expiry_timer_.Start(FROM_HERE, next_expiry - expiry, 619 expiry_timer_.Start(FROM_HERE, next_expiry - expiry,
574 base::Bind(&NTPSnippetsService::LoadingSnippetsFinished, 620 base::Bind(&NTPSnippetsService::LoadingSnippetsFinished,
575 base::Unretained(this))); 621 base::Unretained(this)));
576 } 622 }
577 623
578 bool NTPSnippetsService::IsSyncStateIncompatible() { 624 void NTPSnippetsService::LoadFromDB() {
579 if (!sync_service_ || !sync_service_->CanSyncStart()) 625 database_->Load(base::Bind(&NTPSnippetsService::OnDatabaseLoaded,
580 return true; 626 base::Unretained(this)));
581 if (!sync_service_->IsSyncActive() || !sync_service_->ConfigurationDone()) 627 }
582 return false; // Sync service is not initialized, yet not disabled. 628
583 return !sync_service_->GetActiveDataTypes().Has( 629 void NTPSnippetsService::Enable() {
584 syncer::HISTORY_DELETE_DIRECTIVES); 630 // We might already have snippets from loading the DB and want to avoid a
631 // double load.
632 if (snippets_.empty())
633 FetchSnippets();
634
635 // If host restrictions are enabled, register for host list updates.
636 // |suggestions_service_| can be null in tests.
637 if (snippets_fetcher_->UsesHostRestrictions() && suggestions_service_) {
638 suggestions_service_subscription_ =
639 suggestions_service_->AddCallback(base::Bind(
640 &NTPSnippetsService::OnSuggestionsChanged, base::Unretained(this)));
641 }
642 RescheduleFetching();
643 }
644
645 void NTPSnippetsService::Disable() {
646 ClearSnippets();
647
648 suggestions_service_subscription_.reset();
649 RescheduleFetching();
650 FOR_EACH_OBSERVER(NTPSnippetsServiceObserver, observers_,
651 NTPSnippetsServiceDisabled());
652 }
653
654 State NTPSnippetsService::GetStateForDependenciesStatus() {
655 DisabledReason dr = GetDisabledReason();
656
657 if (dr == DisabledReason::NONE)
658 return State::READY;
659
660 // HistorySync is not initialized yet, so we don't know what the actual state
661 // is. However, because we retreived the previous snippets from the database,
662 // if we got something, we know that the service was previously enabled, so
663 // we just restore that state. If things changed, |OnStateChanged| will call
664 // this function again to fix the state.
665 if (dr == DisabledReason::HISTORY_SYNC_STATE_UNKNOWN) {
666 DVLOG(1) << "Sync configuration not done, continuing based on the current "
667 "state.";
668 return snippets_.empty() ? State::DISABLED : State::READY;
669 }
670
671 return State::DISABLED;
672 }
673
674 void NTPSnippetsService::EnterState(State state) {
675 switch (state) {
676 case State::NOT_INITED:
677 // Initial state, it should not be possible to get back there.
678 NOTREACHED();
679 return;
680
681 case State::INITED:
682 DCHECK(state_ == State::NOT_INITED);
683 state_ = State::INITED;
684 LoadFromDB();
685 DVLOG(1) << "Entering state: INITED";
686 return;
687
688 case State::READY:
689 DCHECK(state_ == State::INITED || state_ == State::READY ||
690 state_ == State::DISABLED);
691 if (state_ == State::READY)
692 return;
693
694 DVLOG(1) << "Entering state: READY";
695 state_ = State::READY;
696 Enable();
697 return;
698
699 case State::DISABLED:
700 DCHECK(state_ == State::NOT_INITED || state_ == State::READY ||
701 state_ == State::DISABLED || state_ == State::INITED);
702 if (state_ == State::DISABLED)
703 return;
704
705 DVLOG(1) << "Entering state: DISABLED";
706 state_ = State::DISABLED;
707 Disable();
708 return;
709
710 case State::SHUT_DOWN:
711 DCHECK(state_ == State::INITED || state_ == State::DISABLED ||
712 state_ == State::READY);
713 DVLOG(1) << "Entering state: SHUT_DOWN";
714 state_ = State::SHUT_DOWN;
715 return;
716 }
585 } 717 }
586 718
587 } // namespace ntp_snippets 719 } // namespace ntp_snippets
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698