OLD | NEW |
---|---|
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 } |
OLD | NEW |