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

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

Issue 2082953002: Prevent site engagement scores from decaying when Chrome isn't in use. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 4 years, 6 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>
11 #include <vector> 11 #include <vector>
12 12
13 #include "base/command_line.h" 13 #include "base/command_line.h"
14 #include "base/memory/ptr_util.h" 14 #include "base/memory/ptr_util.h"
15 #include "base/metrics/field_trial.h" 15 #include "base/metrics/field_trial.h"
16 #include "base/strings/string_util.h" 16 #include "base/strings/string_util.h"
17 #include "base/time/clock.h" 17 #include "base/time/clock.h"
18 #include "base/time/default_clock.h" 18 #include "base/time/default_clock.h"
19 #include "base/time/time.h" 19 #include "base/time/time.h"
20 #include "base/values.h" 20 #include "base/values.h"
21 #include "chrome/browser/banners/app_banner_settings_helper.h" 21 #include "chrome/browser/banners/app_banner_settings_helper.h"
22 #include "chrome/browser/content_settings/host_content_settings_map_factory.h" 22 #include "chrome/browser/content_settings/host_content_settings_map_factory.h"
23 #include "chrome/browser/engagement/site_engagement_eviction_policy.h" 23 #include "chrome/browser/engagement/site_engagement_eviction_policy.h"
24 #include "chrome/browser/engagement/site_engagement_metrics.h" 24 #include "chrome/browser/engagement/site_engagement_metrics.h"
25 #include "chrome/browser/engagement/site_engagement_score.h" 25 #include "chrome/browser/engagement/site_engagement_score.h"
26 #include "chrome/browser/engagement/site_engagement_service_factory.h" 26 #include "chrome/browser/engagement/site_engagement_service_factory.h"
27 #include "chrome/browser/history/history_service_factory.h" 27 #include "chrome/browser/history/history_service_factory.h"
28 #include "chrome/browser/profiles/profile.h"
28 #include "chrome/common/chrome_switches.h" 29 #include "chrome/common/chrome_switches.h"
30 #include "chrome/common/pref_names.h"
29 #include "components/content_settings/core/browser/host_content_settings_map.h" 31 #include "components/content_settings/core/browser/host_content_settings_map.h"
30 #include "components/content_settings/core/common/content_settings_pattern.h" 32 #include "components/content_settings/core/common/content_settings_pattern.h"
31 #include "components/history/core/browser/history_service.h" 33 #include "components/history/core/browser/history_service.h"
34 #include "components/prefs/pref_service.h"
32 #include "content/public/browser/browser_thread.h" 35 #include "content/public/browser/browser_thread.h"
33 #include "content/public/browser/web_contents.h" 36 #include "content/public/browser/web_contents.h"
34 #include "url/gurl.h" 37 #include "url/gurl.h"
35 38
36 namespace { 39 namespace {
37 40
38 const int FOUR_WEEKS_IN_DAYS = 28; 41 const int FOUR_WEEKS_IN_DAYS = 28;
39 42
40 // Global bool to ensure we only update the parameters from variations once. 43 // Global bool to ensure we only update the parameters from variations once.
41 bool g_updated_from_variations = false; 44 bool g_updated_from_variations = false;
(...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after
111 base::Bind(&SiteEngagementService::AfterStartupTask, 114 base::Bind(&SiteEngagementService::AfterStartupTask,
112 weak_factory_.GetWeakPtr())); 115 weak_factory_.GetWeakPtr()));
113 116
114 if (!g_updated_from_variations) { 117 if (!g_updated_from_variations) {
115 SiteEngagementScore::UpdateFromVariations(kEngagementParams); 118 SiteEngagementScore::UpdateFromVariations(kEngagementParams);
116 g_updated_from_variations = true; 119 g_updated_from_variations = true;
117 } 120 }
118 } 121 }
119 122
120 SiteEngagementService::~SiteEngagementService() { 123 SiteEngagementService::~SiteEngagementService() {
124 // Persist the last engagement time to disk.
125 profile_->GetPrefs()->SetInt64(prefs::kSiteEngagementLastUpdateTime,
126 last_engagement_time_.ToInternalValue());
127
121 history::HistoryService* history = HistoryServiceFactory::GetForProfile( 128 history::HistoryService* history = HistoryServiceFactory::GetForProfile(
122 profile_, ServiceAccessType::IMPLICIT_ACCESS); 129 profile_, ServiceAccessType::IMPLICIT_ACCESS);
123 if (history) 130 if (history)
124 history->RemoveObserver(this); 131 history->RemoveObserver(this);
125 } 132 }
126 133
127 SiteEngagementService::EngagementLevel 134 SiteEngagementService::EngagementLevel
128 SiteEngagementService::GetEngagementLevel(const GURL& url) const { 135 SiteEngagementService::GetEngagementLevel(const GURL& url) const {
129 DCHECK_LT(SiteEngagementScore::GetMediumEngagementBoundary(), 136 DCHECK_LT(SiteEngagementScore::GetMediumEngagementBoundary(),
130 SiteEngagementScore::GetHighEngagementBoundary()); 137 SiteEngagementScore::GetHighEngagementBoundary());
(...skipping 92 matching lines...) Expand 10 before | Expand all | Expand 10 after
223 double total_score = 0; 230 double total_score = 0;
224 for (const auto& value : score_map) 231 for (const auto& value : score_map)
225 total_score += value.second; 232 total_score += value.second;
226 233
227 return total_score; 234 return total_score;
228 } 235 }
229 236
230 SiteEngagementService::SiteEngagementService(Profile* profile, 237 SiteEngagementService::SiteEngagementService(Profile* profile,
231 std::unique_ptr<base::Clock> clock) 238 std::unique_ptr<base::Clock> clock)
232 : profile_(profile), clock_(std::move(clock)), weak_factory_(this) { 239 : profile_(profile), clock_(std::move(clock)), weak_factory_(this) {
240 // Read in the last engagement time (or a null time on first run) from disk.
241 last_engagement_time_ = base::Time::FromInternalValue(
242 profile->GetPrefs()->GetInt64(prefs::kSiteEngagementLastUpdateTime));
243
233 // May be null in tests. 244 // May be null in tests.
234 history::HistoryService* history = HistoryServiceFactory::GetForProfile( 245 history::HistoryService* history = HistoryServiceFactory::GetForProfile(
235 profile, ServiceAccessType::IMPLICIT_ACCESS); 246 profile, ServiceAccessType::IMPLICIT_ACCESS);
236 if (history) 247 if (history)
237 history->AddObserver(this); 248 history->AddObserver(this);
238 } 249 }
239 250
240 void SiteEngagementService::AddPoints(const GURL& url, double points) { 251 void SiteEngagementService::AddPoints(const GURL& url, double points) {
252 // Trigger a cleanup and date adjustment if it has been a substantial length
253 // of time since *any* engagement was recorded by the service. This will
254 // ensure that we do not decay scores when the user did not use the browser.
255 // IsLastEngagementObsolete is tested separately so that we do not run cleanup
256 // in this method unless absolutely necessary.
257 if (IsLastEngagementObsolete())
258 CleanupEngagementScores(true);
259
241 SiteEngagementScore score = CreateEngagementScore(url); 260 SiteEngagementScore score = CreateEngagementScore(url);
242
243 score.AddPoints(points); 261 score.AddPoints(points);
244 score.Commit(); 262 score.Commit();
263
264 last_engagement_time_ = score.last_engagement_time();
245 } 265 }
246 266
247 void SiteEngagementService::AfterStartupTask() { 267 void SiteEngagementService::AfterStartupTask() {
248 CleanupEngagementScores(); 268 // Check if we need to reset last engagement times on startup - we want to
269 // avoid doing this in AddPoints() if possible. It is still necessary to check
270 // in AddPoints for people who never restart Chrome, but leave it open and
271 // their computer on standby.
272 CleanupEngagementScores(IsLastEngagementObsolete());
249 RecordMetrics(); 273 RecordMetrics();
250 } 274 }
251 275
252 void SiteEngagementService::CleanupEngagementScores() { 276 void SiteEngagementService::CleanupEngagementScores(
calamity 2016/06/23 05:18:40 It might be worth renaming this method now since i
dominickn 2016/06/27 02:53:35 I think Cleanup is still the right name for the me
277 bool update_last_engagement_time) {
278 // This method should not be called with |update_last_engagement_time| = true
279 // if the last engagement time isn't obsolete.
280 DCHECK(!update_last_engagement_time || IsLastEngagementObsolete());
281
253 HostContentSettingsMap* settings_map = 282 HostContentSettingsMap* settings_map =
254 HostContentSettingsMapFactory::GetForProfile(profile_); 283 HostContentSettingsMapFactory::GetForProfile(profile_);
255 std::unique_ptr<ContentSettingsForOneType> engagement_settings = 284 std::unique_ptr<ContentSettingsForOneType> engagement_settings =
256 GetEngagementContentSettings(settings_map); 285 GetEngagementContentSettings(settings_map);
257 286
287 base::Time now = clock_->Now();
258 for (const auto& site : *engagement_settings) { 288 for (const auto& site : *engagement_settings) {
259 GURL origin(site.primary_pattern.ToString()); 289 GURL origin(site.primary_pattern.ToString());
260 if (origin.is_valid() && GetScore(origin) != 0) 290 SiteEngagementScore score = CreateEngagementScore(origin);
291
292 if (origin.is_valid()) {
293 if (update_last_engagement_time) {
294 // Work out the offset between this score's last engagement time and the
295 // last time the service recorded any engagement. Set the score's last
296 // engagement time to now - offset to preserve its state, but relative
297 // to now.
298 base::TimeDelta offset =
299 last_engagement_time_ - score.last_engagement_time();
300 score.set_last_engagement_time(now - offset);
calamity 2016/06/23 05:18:40 I think that all scores should be rebased to the o
dominickn 2016/06/27 02:53:35 Done.
301 }
302
303 if (score.GetScore() != 0) {
304 score.Commit();
261 continue; 305 continue;
306 }
307 }
262 308
309 // This origin has a score of 0. Wipe it from content settings.
263 settings_map->SetWebsiteSettingDefaultScope( 310 settings_map->SetWebsiteSettingDefaultScope(
264 origin, GURL(), CONTENT_SETTINGS_TYPE_SITE_ENGAGEMENT, std::string(), 311 origin, GURL(), CONTENT_SETTINGS_TYPE_SITE_ENGAGEMENT, std::string(),
265 nullptr); 312 nullptr);
266 } 313 }
314
315 // Set the last engagement time to now for consistency and to ensure we do not
316 // double-reset. Persist the time to disk.
317 last_engagement_time_ = now;
318 profile_->GetPrefs()->SetInt64(prefs::kSiteEngagementLastUpdateTime,
319 last_engagement_time_.ToInternalValue());
267 } 320 }
268 321
269 void SiteEngagementService::RecordMetrics() { 322 void SiteEngagementService::RecordMetrics() {
270 base::Time now = clock_->Now(); 323 base::Time now = clock_->Now();
271 if (last_metrics_time_.is_null() || 324 if (last_metrics_time_.is_null() ||
272 (now - last_metrics_time_).InMinutes() >= kMetricsIntervalInMinutes) { 325 (now - last_metrics_time_).InMinutes() >= kMetricsIntervalInMinutes) {
273 last_metrics_time_ = now; 326 last_metrics_time_ = now;
274 std::map<GURL, double> score_map = GetScoreMap(); 327 std::map<GURL, double> score_map = GetScoreMap();
275 328
276 int origins_with_max_engagement = OriginsWithMaxEngagement(score_map); 329 int origins_with_max_engagement = OriginsWithMaxEngagement(score_map);
(...skipping 15 matching lines...) Expand all
292 345
293 SiteEngagementMetrics::RecordOriginsWithMaxDailyEngagement( 346 SiteEngagementMetrics::RecordOriginsWithMaxDailyEngagement(
294 OriginsWithMaxDailyEngagement()); 347 OriginsWithMaxDailyEngagement());
295 SiteEngagementMetrics::RecordOriginsWithMaxEngagement( 348 SiteEngagementMetrics::RecordOriginsWithMaxEngagement(
296 origins_with_max_engagement); 349 origins_with_max_engagement);
297 SiteEngagementMetrics::RecordPercentOriginsWithMaxEngagement( 350 SiteEngagementMetrics::RecordPercentOriginsWithMaxEngagement(
298 percent_origins_with_max_engagement); 351 percent_origins_with_max_engagement);
299 } 352 }
300 } 353 }
301 354
355 bool SiteEngagementService::IsLastEngagementObsolete() {
356 // This only happens when Chrome is first run and the user has never recorded
357 // any engagement.
358 if (last_engagement_time_.is_null())
359 return false;
360
361 // Last engagement is obsolete when more than
362 // OBSOLETE_LAST_ENGAGEMENT_PERIOD_IN_HOURS have passed.
363 return (clock_->Now() - last_engagement_time_) >=
364 base::TimeDelta::FromHours(
365 SiteEngagementScore::GetObsoleteLastEngagementPeriodInHours());
366 }
367
302 double SiteEngagementService::GetMedianEngagement( 368 double SiteEngagementService::GetMedianEngagement(
303 const std::map<GURL, double>& score_map) const { 369 const std::map<GURL, double>& score_map) const {
304 if (score_map.size() == 0) 370 if (score_map.size() == 0)
305 return 0; 371 return 0;
306 372
307 std::vector<double> scores; 373 std::vector<double> scores;
308 scores.reserve(score_map.size()); 374 scores.reserve(score_map.size());
309 for (const auto& value : score_map) 375 for (const auto& value : score_map)
310 scores.push_back(value.second); 376 scores.push_back(value.second);
311 377
(...skipping 165 matching lines...) Expand 10 before | Expand all | Expand 10 after
477 (proportion_remaining * engagement_score.GetScore()) + undecay); 543 (proportion_remaining * engagement_score.GetScore()) + undecay);
478 engagement_score.Reset(score, last_visit); 544 engagement_score.Reset(score, last_visit);
479 if (!engagement_score.last_shortcut_launch_time().is_null() 545 if (!engagement_score.last_shortcut_launch_time().is_null()
480 && engagement_score.last_shortcut_launch_time() > last_visit) { 546 && engagement_score.last_shortcut_launch_time() > last_visit) {
481 engagement_score.set_last_shortcut_launch_time(last_visit); 547 engagement_score.set_last_shortcut_launch_time(last_visit);
482 } 548 }
483 549
484 engagement_score.Commit(); 550 engagement_score.Commit();
485 } 551 }
486 } 552 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698