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

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

Issue 2788413003: Add SiteEngagementService::GetAllDetails(), to return detailed scores. (Closed)
Patch Set: Cleanups Created 3 years, 8 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>
12 11
13 #include "base/command_line.h" 12 #include "base/command_line.h"
14 #include "base/memory/ptr_util.h" 13 #include "base/memory/ptr_util.h"
15 #include "base/metrics/field_trial.h" 14 #include "base/metrics/field_trial.h"
16 #include "base/strings/string_util.h" 15 #include "base/strings/string_util.h"
17 #include "base/time/clock.h" 16 #include "base/time/clock.h"
18 #include "base/time/default_clock.h" 17 #include "base/time/default_clock.h"
19 #include "base/time/time.h" 18 #include "base/time/time.h"
20 #include "base/values.h" 19 #include "base/values.h"
21 #include "chrome/browser/banners/app_banner_settings_helper.h" 20 #include "chrome/browser/banners/app_banner_settings_helper.h"
(...skipping 23 matching lines...) Expand all
45 namespace { 44 namespace {
46 45
47 const int FOUR_WEEKS_IN_DAYS = 28; 46 const int FOUR_WEEKS_IN_DAYS = 28;
48 47
49 // Global bool to ensure we only update the parameters from variations once. 48 // Global bool to ensure we only update the parameters from variations once.
50 bool g_updated_from_variations = false; 49 bool g_updated_from_variations = false;
51 50
52 // Length of time between metrics logging. 51 // Length of time between metrics logging.
53 const int kMetricsIntervalInMinutes = 60; 52 const int kMetricsIntervalInMinutes = 60;
54 53
55 std::unique_ptr<ContentSettingsForOneType> GetEngagementContentSettings( 54 // Returns the combined list of origins which either have site engagement
56 HostContentSettingsMap* settings_map) { 55 // data stored, or have other settings that would provide a score bonus.
57 std::unique_ptr<ContentSettingsForOneType> engagement_settings( 56 std::set<GURL> GetEngagementOriginsFromContentSettings(Profile* profile) {
58 new ContentSettingsForOneType); 57 HostContentSettingsMap* settings_map =
58 HostContentSettingsMapFactory::GetForProfile(profile);
59
60 ContentSettingsForOneType content_settings_list;
61 std::set<GURL> urls;
62
63 // Fetch site engagement content settings.
59 settings_map->GetSettingsForOneType(CONTENT_SETTINGS_TYPE_SITE_ENGAGEMENT, 64 settings_map->GetSettingsForOneType(CONTENT_SETTINGS_TYPE_SITE_ENGAGEMENT,
60 std::string(), engagement_settings.get()); 65 content_settings::ResourceIdentifier(),
61 return engagement_settings; 66 &content_settings_list);
67 for (const auto& site : content_settings_list) {
dominickn 2017/04/10 04:41:26 Nit: no braces
Wez 2017/04/10 21:18:09 Done, though note that other areas of Chromium ten
68 urls.insert(GURL(site.primary_pattern.ToString()));
69 }
70
71 // Fetch notifications allowed content settings.
72 settings_map->GetSettingsForOneType(CONTENT_SETTINGS_TYPE_NOTIFICATIONS,
73 content_settings::ResourceIdentifier(),
74 &content_settings_list);
75 for (const auto& site : content_settings_list) {
76 if (site.setting == CONTENT_SETTING_ALLOW)
dominickn 2017/04/10 04:41:26 Should this be != ?
Wez 2017/04/10 21:18:09 Yup; and of course my simple test wouldn't catch t
77 continue;
78 urls.insert(GURL(site.primary_pattern.ToString()));
79 }
80
81 return urls;
62 } 82 }
63 83
64 // Only accept a navigation event for engagement if it is one of: 84 // Only accept a navigation event for engagement if it is one of:
65 // a. direct typed navigation 85 // a. direct typed navigation
66 // b. clicking on an omnibox suggestion brought up by typing a keyword 86 // b. clicking on an omnibox suggestion brought up by typing a keyword
67 // c. clicking on a bookmark or opening a bookmark app 87 // c. clicking on a bookmark or opening a bookmark app
68 // d. a custom search engine keyword search (e.g. Wikipedia search box added as 88 // d. a custom search engine keyword search (e.g. Wikipedia search box added as
69 // search engine). 89 // search engine).
70 bool IsEngagementNavigation(ui::PageTransition transition) { 90 bool IsEngagementNavigation(ui::PageTransition transition) {
71 return ui::PageTransitionCoreTypeIs(transition, ui::PAGE_TRANSITION_TYPED) || 91 return ui::PageTransitionCoreTypeIs(transition, ui::PAGE_TRANSITION_TYPED) ||
(...skipping 25 matching lines...) Expand all
97 base::FieldTrialList::FindFullName(kEngagementParams); 117 base::FieldTrialList::FindFullName(kEngagementParams);
98 return !base::StartsWith(group_name, "Disabled", 118 return !base::StartsWith(group_name, "Disabled",
99 base::CompareCase::SENSITIVE); 119 base::CompareCase::SENSITIVE);
100 } 120 }
101 121
102 // static 122 // static
103 double SiteEngagementService::GetScoreFromSettings( 123 double SiteEngagementService::GetScoreFromSettings(
104 HostContentSettingsMap* settings, 124 HostContentSettingsMap* settings,
105 const GURL& origin) { 125 const GURL& origin) {
106 auto clock = base::MakeUnique<base::DefaultClock>(); 126 auto clock = base::MakeUnique<base::DefaultClock>();
107 return SiteEngagementScore(clock.get(), origin, settings) 127 return SiteEngagementScore(clock.get(), origin, settings).GetTotalScore();
108 .GetScore();
109 } 128 }
110 129
111 SiteEngagementService::SiteEngagementService(Profile* profile) 130 SiteEngagementService::SiteEngagementService(Profile* profile)
112 : SiteEngagementService(profile, base::MakeUnique<base::DefaultClock>()) { 131 : SiteEngagementService(profile, base::MakeUnique<base::DefaultClock>()) {
113 content::BrowserThread::PostAfterStartupTask( 132 content::BrowserThread::PostAfterStartupTask(
114 FROM_HERE, content::BrowserThread::GetTaskRunnerForThread( 133 FROM_HERE, content::BrowserThread::GetTaskRunnerForThread(
115 content::BrowserThread::UI), 134 content::BrowserThread::UI),
116 base::Bind(&SiteEngagementService::AfterStartupTask, 135 base::Bind(&SiteEngagementService::AfterStartupTask,
117 weak_factory_.GetWeakPtr())); 136 weak_factory_.GetWeakPtr()));
118 137
(...skipping 13 matching lines...) Expand all
132 } 151 }
133 152
134 blink::mojom::EngagementLevel 153 blink::mojom::EngagementLevel
135 SiteEngagementService::GetEngagementLevel(const GURL& url) const { 154 SiteEngagementService::GetEngagementLevel(const GURL& url) const {
136 if (IsLastEngagementStale()) 155 if (IsLastEngagementStale())
137 CleanupEngagementScores(true); 156 CleanupEngagementScores(true);
138 157
139 return CreateEngagementScore(url).GetEngagementLevel(); 158 return CreateEngagementScore(url).GetEngagementLevel();
140 } 159 }
141 160
142 std::map<GURL, double> SiteEngagementService::GetScoreMap() const { 161 std::vector<mojom::SiteEngagementDetails> SiteEngagementService::GetAllDetails()
143 HostContentSettingsMap* settings_map = 162 const {
144 HostContentSettingsMapFactory::GetForProfile(profile_); 163 std::set<GURL> origins = GetEngagementOriginsFromContentSettings(profile_);
145 std::unique_ptr<ContentSettingsForOneType> engagement_settings =
146 GetEngagementContentSettings(settings_map);
147 164
148 std::map<GURL, double> score_map; 165 std::vector<mojom::SiteEngagementDetails> details;
149 for (const auto& site : *engagement_settings) { 166 details.reserve(origins.size());
150 GURL origin(site.primary_pattern.ToString()); 167 for (const GURL& origin : origins) {
151 if (!origin.is_valid()) 168 if (!origin.is_valid())
152 continue; 169 continue;
170 details.push_back(GetDetails(origin));
171 }
153 172
173 return details;
174 }
175
176 std::map<GURL, double> SiteEngagementService::GetScoreMap() const {
177 std::map<GURL, double> score_map;
178 for (const GURL& origin : GetEngagementOriginsFromContentSettings(profile_)) {
179 if (!origin.is_valid())
180 continue;
154 score_map[origin] = GetScore(origin); 181 score_map[origin] = GetScore(origin);
155 } 182 }
156
157 return score_map; 183 return score_map;
158 } 184 }
159 185
160 void SiteEngagementService::HandleNotificationInteraction(const GURL& url) { 186 void SiteEngagementService::HandleNotificationInteraction(const GURL& url) {
161 if (!ShouldRecordEngagement(url)) 187 if (!ShouldRecordEngagement(url))
162 return; 188 return;
163 189
164 SiteEngagementMetrics::RecordEngagement( 190 SiteEngagementMetrics::RecordEngagement(
165 SiteEngagementMetrics::ENGAGEMENT_NOTIFICATION_INTERACTION); 191 SiteEngagementMetrics::ENGAGEMENT_NOTIFICATION_INTERACTION);
166 AddPoints(url, SiteEngagementScore::GetNotificationInteractionPoints()); 192 AddPoints(url, SiteEngagementScore::GetNotificationInteractionPoints());
(...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after
237 SiteEngagementService::Helper* helper) { 263 SiteEngagementService::Helper* helper) {
238 helpers_.insert(helper); 264 helpers_.insert(helper);
239 } 265 }
240 266
241 void SiteEngagementService::HelperDeleted( 267 void SiteEngagementService::HelperDeleted(
242 SiteEngagementService::Helper* helper) { 268 SiteEngagementService::Helper* helper) {
243 helpers_.erase(helper); 269 helpers_.erase(helper);
244 } 270 }
245 271
246 double SiteEngagementService::GetScore(const GURL& url) const { 272 double SiteEngagementService::GetScore(const GURL& url) const {
273 return GetDetails(url).total_score;
274 }
275
276 mojom::SiteEngagementDetails SiteEngagementService::GetDetails(
277 const GURL& url) const {
247 // Ensure that if engagement is stale, we clean things up before fetching the 278 // Ensure that if engagement is stale, we clean things up before fetching the
248 // score. 279 // score.
249 if (IsLastEngagementStale()) 280 if (IsLastEngagementStale())
250 CleanupEngagementScores(true); 281 CleanupEngagementScores(true);
251 282
252 return CreateEngagementScore(url).GetScore(); 283 return CreateEngagementScore(url).GetDetails();
253 } 284 }
254 285
255 double SiteEngagementService::GetTotalEngagementPoints() const { 286 double SiteEngagementService::GetTotalEngagementPoints() const {
256 std::map<GURL, double> score_map = GetScoreMap(); 287 std::map<GURL, double> score_map = GetScoreMap();
257 288
258 double total_score = 0; 289 double total_score = 0;
259 for (const auto& value : score_map) 290 for (const auto& value : score_map)
260 total_score += value.second; 291 total_score += value.second;
261 292
262 return total_score; 293 return total_score;
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after
308 339
309 void SiteEngagementService::AfterStartupTask() { 340 void SiteEngagementService::AfterStartupTask() {
310 // Check if we need to reset last engagement times on startup - we want to 341 // Check if we need to reset last engagement times on startup - we want to
311 // avoid doing this in AddPoints() if possible. It is still necessary to check 342 // avoid doing this in AddPoints() if possible. It is still necessary to check
312 // in AddPoints for people who never restart Chrome, but leave it open and 343 // in AddPoints for people who never restart Chrome, but leave it open and
313 // their computer on standby. 344 // their computer on standby.
314 CleanupEngagementScores(IsLastEngagementStale()); 345 CleanupEngagementScores(IsLastEngagementStale());
315 RecordMetrics(); 346 RecordMetrics();
316 } 347 }
317 348
318 void SiteEngagementService::CleanupEngagementScores( 349 void SiteEngagementService::CleanupEngagementScores(
dominickn 2017/04/10 04:41:26 This cleanup method doesn't need to iterate over o
Wez 2017/04/10 21:18:09 Done.
319 bool update_last_engagement_time) const { 350 bool update_last_engagement_time) const {
320 HostContentSettingsMap* settings_map =
321 HostContentSettingsMapFactory::GetForProfile(profile_);
322 std::unique_ptr<ContentSettingsForOneType> engagement_settings =
323 GetEngagementContentSettings(settings_map);
324
325 // We want to rebase last engagement times relative to MaxDecaysPerScore 351 // We want to rebase last engagement times relative to MaxDecaysPerScore
326 // periods of decay in the past. 352 // periods of decay in the past.
327 base::Time now = clock_->Now(); 353 base::Time now = clock_->Now();
328 base::Time last_engagement_time = GetLastEngagementTime(); 354 base::Time last_engagement_time = GetLastEngagementTime();
329 base::Time rebase_time = now - GetMaxDecayPeriod(); 355 base::Time rebase_time = now - GetMaxDecayPeriod();
330 base::Time new_last_engagement_time; 356 base::Time new_last_engagement_time;
331 357
332 // If |update_last_engagement_time| is true, we must have either: 358 // If |update_last_engagement_time| is true, we must have either:
333 // a) last_engagement_time is in the future; OR 359 // a) last_engagement_time is in the future; OR
334 // b) last_engagement_time < rebase_time < now 360 // b) last_engagement_time < rebase_time < now
335 DCHECK(!update_last_engagement_time || last_engagement_time >= now || 361 DCHECK(!update_last_engagement_time || last_engagement_time >= now ||
336 (last_engagement_time < rebase_time && rebase_time < now)); 362 (last_engagement_time < rebase_time && rebase_time < now));
337 363
338 // Cap |last_engagement_time| at |now| if it is in the future. This ensures 364 // Cap |last_engagement_time| at |now| if it is in the future. This ensures
339 // that we use sane offsets when a user has adjusted their clock backwards and 365 // that we use sane offsets when a user has adjusted their clock backwards and
340 // have a mix of scores prior to and after |now|. 366 // have a mix of scores prior to and after |now|.
341 if (last_engagement_time > now) 367 if (last_engagement_time > now)
342 last_engagement_time = now; 368 last_engagement_time = now;
343 369
344 for (const auto& site : *engagement_settings) { 370 HostContentSettingsMap* settings_map =
345 GURL origin(site.primary_pattern.ToString()); 371 HostContentSettingsMapFactory::GetForProfile(profile_);
346 372 for (const GURL& origin : GetEngagementOriginsFromContentSettings(profile_)) {
347 if (origin.is_valid()) { 373 if (origin.is_valid()) {
348 SiteEngagementScore score = CreateEngagementScore(origin); 374 SiteEngagementScore score = CreateEngagementScore(origin);
349 if (update_last_engagement_time) { 375 if (update_last_engagement_time) {
350 // Catch cases of users moving their clocks, or a potential race where 376 // Catch cases of users moving their clocks, or a potential race where
351 // a score content setting is written out to prefs, but the updated 377 // a score content setting is written out to prefs, but the updated
352 // |last_engagement_time| was not written, as both are lossy 378 // |last_engagement_time| was not written, as both are lossy
353 // preferences. |rebase_time| is strictly in the past, so any score with 379 // preferences. |rebase_time| is strictly in the past, so any score with
354 // a last updated time in the future is caught by this branch. 380 // a last updated time in the future is caught by this branch.
355 if (score.last_engagement_time() > rebase_time) { 381 if (score.last_engagement_time() > rebase_time) {
356 score.set_last_engagement_time(now); 382 score.set_last_engagement_time(now);
(...skipping 12 matching lines...) Expand all
369 last_engagement_time - score.last_engagement_time(); 395 last_engagement_time - score.last_engagement_time();
370 base::Time rebase_score_time = rebase_time - offset; 396 base::Time rebase_score_time = rebase_time - offset;
371 score.set_last_engagement_time(rebase_score_time); 397 score.set_last_engagement_time(rebase_score_time);
372 } 398 }
373 399
374 if (score.last_engagement_time() > new_last_engagement_time) 400 if (score.last_engagement_time() > new_last_engagement_time)
375 new_last_engagement_time = score.last_engagement_time(); 401 new_last_engagement_time = score.last_engagement_time();
376 score.Commit(); 402 score.Commit();
377 } 403 }
378 404
379 if (score.GetScore() > SiteEngagementScore::GetScoreCleanupThreshold()) 405 if (score.GetTotalScore() >
406 SiteEngagementScore::GetScoreCleanupThreshold())
380 continue; 407 continue;
381 } 408 }
382 409
383 // This origin has a score of 0. Wipe it from content settings. 410 // This origin has a score of 0. Wipe it from content settings.
384 settings_map->SetWebsiteSettingDefaultScope( 411 settings_map->SetWebsiteSettingDefaultScope(
385 origin, GURL(), CONTENT_SETTINGS_TYPE_SITE_ENGAGEMENT, std::string(), 412 origin, GURL(), CONTENT_SETTINGS_TYPE_SITE_ENGAGEMENT, std::string(),
386 nullptr); 413 nullptr);
387 } 414 }
388 415
389 // Set the last engagement time to be consistent with the scores. This will 416 // Set the last engagement time to be consistent with the scores. This will
(...skipping 180 matching lines...) Expand 10 before | Expand all | Expand 10 after
570 const GURL& origin) const { 597 const GURL& origin) const {
571 // If we are in incognito, |settings| will automatically have the data from 598 // If we are in incognito, |settings| will automatically have the data from
572 // the original profile migrated in, so all engagement scores in incognito 599 // the original profile migrated in, so all engagement scores in incognito
573 // will be initialised to the values from the original profile. 600 // will be initialised to the values from the original profile.
574 return SiteEngagementScore( 601 return SiteEngagementScore(
575 clock_.get(), origin, 602 clock_.get(), origin,
576 HostContentSettingsMapFactory::GetForProfile(profile_)); 603 HostContentSettingsMapFactory::GetForProfile(profile_));
577 } 604 }
578 605
579 int SiteEngagementService::OriginsWithMaxDailyEngagement() const { 606 int SiteEngagementService::OriginsWithMaxDailyEngagement() const {
580 HostContentSettingsMap* settings_map =
581 HostContentSettingsMapFactory::GetForProfile(profile_);
582 std::unique_ptr<ContentSettingsForOneType> engagement_settings =
583 GetEngagementContentSettings(settings_map);
584
585 int total_origins = 0; 607 int total_origins = 0;
586 608
587 // We cannot call GetScoreMap as we need the score objects, not raw scores. 609 // We cannot call GetScoreMap as we need the score objects, not raw scores.
588 for (const auto& site : *engagement_settings) { 610 for (const GURL& origin : GetEngagementOriginsFromContentSettings(profile_)) {
dominickn 2017/04/10 04:41:26 An origin can't possibly get maximum daily engagem
Wez 2017/04/10 21:18:09 Done.
589 GURL origin(site.primary_pattern.ToString());
590 if (!origin.is_valid()) 611 if (!origin.is_valid())
591 continue; 612 continue;
592 613
593 if (CreateEngagementScore(origin).MaxPointsPerDayAdded()) 614 if (CreateEngagementScore(origin).MaxPointsPerDayAdded())
594 ++total_origins; 615 ++total_origins;
595 } 616 }
596 617
597 return total_origins; 618 return total_origins;
598 } 619 }
599 620
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after
648 // under the origin in history. If this new last visit date is long enough 669 // under the origin in history. If this new last visit date is long enough
649 // in the past, the next time the origin's engagement is accessed the 670 // in the past, the next time the origin's engagement is accessed the
650 // automatic decay will kick in - i.e. a double decay will have occurred. 671 // automatic decay will kick in - i.e. a double decay will have occurred.
651 // To prevent this, compute the decay that would have taken place since the 672 // To prevent this, compute the decay that would have taken place since the
652 // new last visit and add it to the engagement at this point. When the 673 // new last visit and add it to the engagement at this point. When the
653 // engagement is next accessed, it will decay back to the proportionally 674 // engagement is next accessed, it will decay back to the proportionally
654 // reduced value rather than being decayed once here, and then once again 675 // reduced value rather than being decayed once here, and then once again
655 // when it is next accessed. 676 // when it is next accessed.
656 SiteEngagementScore engagement_score = CreateEngagementScore(origin); 677 SiteEngagementScore engagement_score = CreateEngagementScore(origin);
657 678
658 double new_score = proportion_remaining * engagement_score.GetScore(); 679 double new_score = proportion_remaining * engagement_score.raw_score();
659 int hours_since_engagement = (now - last_visit).InHours(); 680 int hours_since_engagement = (now - last_visit).InHours();
660 int periods = 681 int periods =
661 hours_since_engagement / SiteEngagementScore::GetDecayPeriodInHours(); 682 hours_since_engagement / SiteEngagementScore::GetDecayPeriodInHours();
662 new_score += periods * SiteEngagementScore::GetDecayPoints(); 683 new_score += periods * SiteEngagementScore::GetDecayPoints();
663 new_score *= pow(1.0 / SiteEngagementScore::GetDecayProportion(), periods); 684 new_score *= pow(1.0 / SiteEngagementScore::GetDecayProportion(), periods);
664 685
665 double score = std::min(SiteEngagementScore::kMaxPoints, new_score); 686 double score = std::min(SiteEngagementScore::kMaxPoints, new_score);
666 engagement_score.Reset(score, last_visit); 687 engagement_score.Reset(score, last_visit);
667 if (!engagement_score.last_shortcut_launch_time().is_null() && 688 if (!engagement_score.last_shortcut_launch_time().is_null() &&
668 engagement_score.last_shortcut_launch_time() > last_visit) { 689 engagement_score.last_shortcut_launch_time() > last_visit) {
669 engagement_score.set_last_shortcut_launch_time(last_visit); 690 engagement_score.set_last_shortcut_launch_time(last_visit);
670 } 691 }
671 692
672 engagement_score.Commit(); 693 engagement_score.Commit();
673 } 694 }
674 695
675 SetLastEngagementTime(now); 696 SetLastEngagementTime(now);
676 } 697 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698