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

Side by Side Diff: chrome/browser/engagement/site_engagement_service.cc

Issue 2427343002: Make the site engagement service more robust to clock changes and time inconsistencies. (Closed)
Patch Set: Address nit Created 4 years, 2 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 "chrome/browser/engagement/site_engagement_service.h" 5 #include "chrome/browser/engagement/site_engagement_service.h"
6 6
7 #include <stddef.h> 7 #include <stddef.h>
8 8
9 #include <algorithm> 9 #include <algorithm>
10 #include <utility> 10 #include <utility>
(...skipping 271 matching lines...) Expand 10 before | Expand all | Expand 10 after
282 // Check if we need to reset last engagement times on startup - we want to 282 // Check if we need to reset last engagement times on startup - we want to
283 // avoid doing this in AddPoints() if possible. It is still necessary to check 283 // avoid doing this in AddPoints() if possible. It is still necessary to check
284 // in AddPoints for people who never restart Chrome, but leave it open and 284 // in AddPoints for people who never restart Chrome, but leave it open and
285 // their computer on standby. 285 // their computer on standby.
286 CleanupEngagementScores(IsLastEngagementStale()); 286 CleanupEngagementScores(IsLastEngagementStale());
287 RecordMetrics(); 287 RecordMetrics();
288 } 288 }
289 289
290 void SiteEngagementService::CleanupEngagementScores( 290 void SiteEngagementService::CleanupEngagementScores(
291 bool update_last_engagement_time) const { 291 bool update_last_engagement_time) const {
292 // This method should not be called with |update_last_engagement_time| = true
293 // if the last engagement time isn't stale.
294 DCHECK(!update_last_engagement_time || IsLastEngagementStale());
295
296 HostContentSettingsMap* settings_map = 292 HostContentSettingsMap* settings_map =
297 HostContentSettingsMapFactory::GetForProfile(profile_); 293 HostContentSettingsMapFactory::GetForProfile(profile_);
298 std::unique_ptr<ContentSettingsForOneType> engagement_settings = 294 std::unique_ptr<ContentSettingsForOneType> engagement_settings =
299 GetEngagementContentSettings(settings_map); 295 GetEngagementContentSettings(settings_map);
300 296
301 // We want to rebase last engagement times relative to MaxDecaysPerScore 297 // We want to rebase last engagement times relative to MaxDecaysPerScore
302 // periods of decay in the past. 298 // periods of decay in the past.
303 base::Time now = clock_->Now(); 299 base::Time now = clock_->Now();
304 base::Time last_engagement_time = GetLastEngagementTime(); 300 base::Time last_engagement_time = GetLastEngagementTime();
305 base::Time rebase_time = now - GetMaxDecayPeriod(); 301 base::Time rebase_time = now - GetMaxDecayPeriod();
306 base::Time new_last_engagement_time; 302 base::Time new_last_engagement_time;
303
304 // If |update_last_engagement_time| is true, we must have either:
305 // a) last_engagement_time is in the future; OR
306 // b) last_engagement_time < rebase_time < now
307 DCHECK(!update_last_engagement_time || last_engagement_time >= now ||
308 (last_engagement_time < rebase_time && rebase_time < now));
309
310 // Cap |last_engagement_time| at |now| if it is in the future. This ensures
311 // that we use sane offsets when a user has adjusted their clock backwards and
312 // have a mix of scores prior to and after |now|.
313 if (last_engagement_time > now)
314 last_engagement_time = now;
315
307 for (const auto& site : *engagement_settings) { 316 for (const auto& site : *engagement_settings) {
308 GURL origin(site.primary_pattern.ToString()); 317 GURL origin(site.primary_pattern.ToString());
309 318
310 if (origin.is_valid()) { 319 if (origin.is_valid()) {
311 SiteEngagementScore score = CreateEngagementScore(origin); 320 SiteEngagementScore score = CreateEngagementScore(origin);
312 if (update_last_engagement_time) { 321 if (update_last_engagement_time) {
313 // Work out the offset between this score's last engagement time and the 322 // Catch cases of users moving their clocks, or a potential race where
314 // last time the service recorded any engagement. Set the score's last 323 // a score content setting is written out to prefs, but the updated
315 // engagement time to rebase_time - offset to preserve its state, 324 // |last_engagement_time| was not written, as both are lossy
316 // relative to the rebase date. This ensures that the score will decay 325 // preferences. |rebase_time| is strictly in the past, so any score with
317 // the next time it is used, but will not decay too much. 326 // a last updated time in the future is caught by this branch.
318 DCHECK_LE(score.last_engagement_time(), rebase_time); 327 if (score.last_engagement_time() > rebase_time) {
319 base::TimeDelta offset = 328 score.set_last_engagement_time(now);
320 last_engagement_time - score.last_engagement_time(); 329 } else if (score.last_engagement_time() > last_engagement_time) {
321 base::Time rebase_score_time = rebase_time - offset; 330 // This score is newer than |last_engagement_time|, but older than
322 score.set_last_engagement_time(rebase_score_time); 331 // |rebase_time|. It should still be rebased with no offset as we
323 if (rebase_score_time > new_last_engagement_time) 332 // don't accurately know what the offset should be.
324 new_last_engagement_time = rebase_score_time; 333 score.set_last_engagement_time(rebase_time);
334 } else {
335 // Work out the offset between this score's last engagement time and
336 // the last time the service recorded any engagement. Set the score's
337 // last engagement time to rebase_time - offset to preserve its state,
338 // relative to the rebase date. This ensures that the score will decay
339 // the next time it is used, but will not decay too much.
340 base::TimeDelta offset =
341 last_engagement_time - score.last_engagement_time();
342 base::Time rebase_score_time = rebase_time - offset;
343 score.set_last_engagement_time(rebase_score_time);
344 }
325 345
346 if (score.last_engagement_time() > new_last_engagement_time)
347 new_last_engagement_time = score.last_engagement_time();
326 score.Commit(); 348 score.Commit();
327 } 349 }
328 350
329 if (score.GetScore() > SiteEngagementScore::GetScoreCleanupThreshold()) 351 if (score.GetScore() > SiteEngagementScore::GetScoreCleanupThreshold())
330 continue; 352 continue;
331 } 353 }
332 354
333 // This origin has a score of 0. Wipe it from content settings. 355 // This origin has a score of 0. Wipe it from content settings.
334 settings_map->SetWebsiteSettingDefaultScope( 356 settings_map->SetWebsiteSettingDefaultScope(
335 origin, GURL(), CONTENT_SETTINGS_TYPE_SITE_ENGAGEMENT, std::string(), 357 origin, GURL(), CONTENT_SETTINGS_TYPE_SITE_ENGAGEMENT, std::string(),
(...skipping 125 matching lines...) Expand 10 before | Expand all | Expand 10 after
461 SiteEngagementMetrics::RecordEngagement(type); 483 SiteEngagementMetrics::RecordEngagement(type);
462 AddPoints(url, SiteEngagementScore::GetUserInputPoints()); 484 AddPoints(url, SiteEngagementScore::GetUserInputPoints());
463 485
464 RecordMetrics(); 486 RecordMetrics();
465 FOR_EACH_OBSERVER( 487 FOR_EACH_OBSERVER(
466 SiteEngagementObserver, observer_list_, 488 SiteEngagementObserver, observer_list_,
467 OnEngagementIncreased(web_contents, url, GetScore(url))); 489 OnEngagementIncreased(web_contents, url, GetScore(url)));
468 } 490 }
469 491
470 bool SiteEngagementService::IsLastEngagementStale() const { 492 bool SiteEngagementService::IsLastEngagementStale() const {
471 // This only happens when Chrome is first run and the user has never recorded 493 // Only happens on first run when no engagement has ever been recorded.
472 // any engagement.
473 base::Time last_engagement_time = GetLastEngagementTime(); 494 base::Time last_engagement_time = GetLastEngagementTime();
474 if (last_engagement_time.is_null()) 495 if (last_engagement_time.is_null())
475 return false; 496 return false;
476 497
477 return (clock_->Now() - last_engagement_time) >= GetStalePeriod(); 498 // Stale is either too *far* back, or any amount *forward* in time. This could
499 // occur due to a changed clock, or extended non-use of the browser.
500 return (clock_->Now() - last_engagement_time) >= GetStalePeriod() ||
501 (clock_->Now() < last_engagement_time);
478 } 502 }
479 503
480 void SiteEngagementService::OnURLsDeleted( 504 void SiteEngagementService::OnURLsDeleted(
481 history::HistoryService* history_service, 505 history::HistoryService* history_service,
482 bool all_history, 506 bool all_history,
483 bool expired, 507 bool expired,
484 const history::URLRows& deleted_rows, 508 const history::URLRows& deleted_rows,
485 const std::set<GURL>& favicon_urls) { 509 const std::set<GURL>& favicon_urls) {
486 std::multiset<GURL> origins; 510 std::multiset<GURL> origins;
487 for (const history::URLRow& row : deleted_rows) 511 for (const history::URLRow& row : deleted_rows)
(...skipping 109 matching lines...) Expand 10 before | Expand all | Expand 10 after
597 if (!engagement_score.last_shortcut_launch_time().is_null() && 621 if (!engagement_score.last_shortcut_launch_time().is_null() &&
598 engagement_score.last_shortcut_launch_time() > last_visit) { 622 engagement_score.last_shortcut_launch_time() > last_visit) {
599 engagement_score.set_last_shortcut_launch_time(last_visit); 623 engagement_score.set_last_shortcut_launch_time(last_visit);
600 } 624 }
601 625
602 engagement_score.Commit(); 626 engagement_score.Commit();
603 } 627 }
604 628
605 SetLastEngagementTime(now); 629 SetLastEngagementTime(now);
606 } 630 }
OLDNEW
« no previous file with comments | « chrome/browser/engagement/site_engagement_service.h ('k') | chrome/browser/engagement/site_engagement_service_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698