Chromium Code Reviews| 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 <algorithm> | 7 #include <algorithm> |
| 8 #include <cmath> | 8 #include <cmath> |
| 9 #include <vector> | |
| 9 | 10 |
| 10 #include "base/command_line.h" | 11 #include "base/command_line.h" |
| 11 #include "base/time/clock.h" | 12 #include "base/time/clock.h" |
| 12 #include "base/time/default_clock.h" | 13 #include "base/time/default_clock.h" |
| 13 #include "base/values.h" | 14 #include "base/values.h" |
| 14 #include "chrome/browser/content_settings/host_content_settings_map_factory.h" | 15 #include "chrome/browser/content_settings/host_content_settings_map_factory.h" |
| 15 #include "chrome/browser/engagement/site_engagement_helper.h" | 16 #include "chrome/browser/engagement/site_engagement_helper.h" |
| 16 #include "chrome/browser/engagement/site_engagement_service_factory.h" | 17 #include "chrome/browser/engagement/site_engagement_service_factory.h" |
| 17 #include "chrome/common/chrome_switches.h" | 18 #include "chrome/common/chrome_switches.h" |
| 18 #include "components/content_settings/core/browser/host_content_settings_map.h" | 19 #include "components/content_settings/core/browser/host_content_settings_map.h" |
| 19 #include "components/content_settings/core/common/content_settings_pattern.h" | 20 #include "components/content_settings/core/common/content_settings_pattern.h" |
| 20 #include "content/public/browser/browser_thread.h" | 21 #include "content/public/browser/browser_thread.h" |
| 21 #include "url/gurl.h" | 22 #include "url/gurl.h" |
| 22 | 23 |
| 23 namespace { | 24 namespace { |
| 24 | 25 |
| 26 // Length of time between metrics logging. | |
| 27 const base::TimeDelta metrics_interval = base::TimeDelta::FromMinutes(60); | |
| 28 | |
| 25 // Delta within which to consider scores equal. | 29 // Delta within which to consider scores equal. |
| 26 const double kScoreDelta = 0.001; | 30 const double kScoreDelta = 0.001; |
| 27 | 31 |
| 28 // Delta within which to consider internal time values equal. Internal time | 32 // Delta within which to consider internal time values equal. Internal time |
| 29 // values are in microseconds, so this delta comes out at one second. | 33 // values are in microseconds, so this delta comes out at one second. |
| 30 const double kTimeDelta = 1000000; | 34 const double kTimeDelta = 1000000; |
| 31 | 35 |
| 32 scoped_ptr<ContentSettingsForOneType> GetEngagementContentSettings( | 36 scoped_ptr<ContentSettingsForOneType> GetEngagementContentSettings( |
| 33 HostContentSettingsMap* settings_map) { | 37 HostContentSettingsMap* settings_map) { |
| 34 scoped_ptr<ContentSettingsForOneType> engagement_settings( | 38 scoped_ptr<ContentSettingsForOneType> engagement_settings( |
| (...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 106 double to_add = | 110 double to_add = |
| 107 std::min(kMaxPoints - raw_score_, kMaxPointsPerDay - points_added_today_); | 111 std::min(kMaxPoints - raw_score_, kMaxPointsPerDay - points_added_today_); |
| 108 to_add = std::min(to_add, points); | 112 to_add = std::min(to_add, points); |
| 109 | 113 |
| 110 points_added_today_ += to_add; | 114 points_added_today_ += to_add; |
| 111 raw_score_ += to_add; | 115 raw_score_ += to_add; |
| 112 | 116 |
| 113 last_engagement_time_ = now; | 117 last_engagement_time_ = now; |
| 114 } | 118 } |
| 115 | 119 |
| 120 bool SiteEngagementScore::MaxPointsPerDayAdded() { | |
| 121 if (!last_engagement_time_.is_null() && | |
| 122 clock_->Now().LocalMidnight() != last_engagement_time_.LocalMidnight()) { | |
| 123 return false; | |
| 124 } | |
| 125 | |
| 126 return points_added_today_ == kMaxPointsPerDay; | |
| 127 } | |
| 128 | |
| 116 bool SiteEngagementScore::UpdateScoreDict(base::DictionaryValue* score_dict) { | 129 bool SiteEngagementScore::UpdateScoreDict(base::DictionaryValue* score_dict) { |
| 117 double raw_score_orig = 0; | 130 double raw_score_orig = 0; |
| 118 double points_added_today_orig = 0; | 131 double points_added_today_orig = 0; |
| 119 double last_engagement_time_internal_orig = 0; | 132 double last_engagement_time_internal_orig = 0; |
| 120 | 133 |
| 121 score_dict->GetDouble(kRawScoreKey, &raw_score_orig); | 134 score_dict->GetDouble(kRawScoreKey, &raw_score_orig); |
| 122 score_dict->GetDouble(kPointsAddedTodayKey, &points_added_today_orig); | 135 score_dict->GetDouble(kPointsAddedTodayKey, &points_added_today_orig); |
| 123 score_dict->GetDouble(kLastEngagementTimeKey, | 136 score_dict->GetDouble(kLastEngagementTimeKey, |
| 124 &last_engagement_time_internal_orig); | 137 &last_engagement_time_internal_orig); |
| 125 bool changed = | 138 bool changed = |
| (...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 170 bool SiteEngagementService::IsEnabled() { | 183 bool SiteEngagementService::IsEnabled() { |
| 171 return base::CommandLine::ForCurrentProcess()->HasSwitch( | 184 return base::CommandLine::ForCurrentProcess()->HasSwitch( |
| 172 switches::kEnableSiteEngagementService); | 185 switches::kEnableSiteEngagementService); |
| 173 } | 186 } |
| 174 | 187 |
| 175 SiteEngagementService::SiteEngagementService(Profile* profile) | 188 SiteEngagementService::SiteEngagementService(Profile* profile) |
| 176 : SiteEngagementService(profile, make_scoped_ptr(new base::DefaultClock)) { | 189 : SiteEngagementService(profile, make_scoped_ptr(new base::DefaultClock)) { |
| 177 content::BrowserThread::PostAfterStartupTask( | 190 content::BrowserThread::PostAfterStartupTask( |
| 178 FROM_HERE, content::BrowserThread::GetMessageLoopProxyForThread( | 191 FROM_HERE, content::BrowserThread::GetMessageLoopProxyForThread( |
| 179 content::BrowserThread::UI), | 192 content::BrowserThread::UI), |
| 180 base::Bind(&SiteEngagementService::CleanupEngagementScores, | 193 base::Bind(&SiteEngagementService::AfterStartupTask, |
| 181 weak_factory_.GetWeakPtr())); | 194 weak_factory_.GetWeakPtr())); |
| 182 } | 195 } |
| 183 | 196 |
| 184 SiteEngagementService::~SiteEngagementService() { | 197 SiteEngagementService::~SiteEngagementService() { |
| 185 } | 198 } |
| 186 | 199 |
| 187 void SiteEngagementService::HandleNavigation(const GURL& url, | 200 void SiteEngagementService::HandleNavigation(const GURL& url, |
| 188 ui::PageTransition transition) { | 201 ui::PageTransition transition) { |
| 202 SiteEngagementMetrics::RecordEngagement( | |
| 203 SiteEngagementMetrics::ENGAGEMENT_NAVIGATION); | |
| 189 AddPoints(url, SiteEngagementScore::kNavigationPoints); | 204 AddPoints(url, SiteEngagementScore::kNavigationPoints); |
| 205 RecordMetrics(); | |
| 190 } | 206 } |
| 191 | 207 |
| 192 void SiteEngagementService::HandleUserInput(const GURL& url) { | 208 void SiteEngagementService::HandleUserInput( |
| 209 const GURL& url, | |
| 210 SiteEngagementMetrics::EngagementType type) { | |
| 211 SiteEngagementMetrics::RecordEngagement(type); | |
| 193 AddPoints(url, SiteEngagementScore::kUserInputPoints); | 212 AddPoints(url, SiteEngagementScore::kUserInputPoints); |
| 213 RecordMetrics(); | |
| 194 } | 214 } |
| 195 | 215 |
| 196 double SiteEngagementService::GetScore(const GURL& url) { | 216 double SiteEngagementService::GetScore(const GURL& url) { |
| 197 HostContentSettingsMap* settings_map = | 217 HostContentSettingsMap* settings_map = |
| 198 HostContentSettingsMapFactory::GetForProfile(profile_); | 218 HostContentSettingsMapFactory::GetForProfile(profile_); |
| 199 scoped_ptr<base::DictionaryValue> score_dict = | 219 scoped_ptr<base::DictionaryValue> score_dict = |
| 200 GetScoreDictForOrigin(settings_map, url); | 220 GetScoreDictForOrigin(settings_map, url); |
| 201 SiteEngagementScore score(clock_.get(), *score_dict); | 221 SiteEngagementScore score(clock_.get(), *score_dict); |
| 202 | 222 |
| 203 return score.Score(); | 223 return score.Score(); |
| 204 } | 224 } |
| 205 | 225 |
| 206 double SiteEngagementService::GetTotalEngagementPoints() { | 226 double SiteEngagementService::GetTotalEngagementPoints() { |
| 207 HostContentSettingsMap* settings_map = | 227 std::map<GURL, double> score_map = GetScoreMap(); |
| 208 HostContentSettingsMapFactory::GetForProfile(profile_); | |
| 209 scoped_ptr<ContentSettingsForOneType> engagement_settings = | |
| 210 GetEngagementContentSettings(settings_map); | |
| 211 | 228 |
| 212 double total_score = 0; | 229 double total_score = 0; |
| 213 for (const auto& site : *engagement_settings) { | 230 for (const auto& value : score_map) |
| 214 GURL origin(site.primary_pattern.ToString()); | 231 total_score += value.second; |
| 215 if (!origin.is_valid()) | |
| 216 continue; | |
| 217 | 232 |
| 218 scoped_ptr<base::DictionaryValue> score_dict = | |
| 219 GetScoreDictForOrigin(settings_map, origin); | |
| 220 SiteEngagementScore score(clock_.get(), *score_dict); | |
| 221 total_score += score.Score(); | |
| 222 } | |
| 223 return total_score; | 233 return total_score; |
| 224 } | 234 } |
| 225 | 235 |
| 226 std::map<GURL, double> SiteEngagementService::GetScoreMap() { | 236 std::map<GURL, double> SiteEngagementService::GetScoreMap() { |
| 227 HostContentSettingsMap* settings_map = | 237 HostContentSettingsMap* settings_map = |
| 228 HostContentSettingsMapFactory::GetForProfile(profile_); | 238 HostContentSettingsMapFactory::GetForProfile(profile_); |
| 229 scoped_ptr<ContentSettingsForOneType> engagement_settings = | 239 scoped_ptr<ContentSettingsForOneType> engagement_settings = |
| 230 GetEngagementContentSettings(settings_map); | 240 GetEngagementContentSettings(settings_map); |
| 231 | 241 |
| 232 std::map<GURL, double> score_map; | 242 std::map<GURL, double> score_map; |
| (...skipping 28 matching lines...) Expand all Loading... | |
| 261 ContentSettingsPattern::FromURLNoWildcard(url)); | 271 ContentSettingsPattern::FromURLNoWildcard(url)); |
| 262 if (!pattern.IsValid()) | 272 if (!pattern.IsValid()) |
| 263 return; | 273 return; |
| 264 | 274 |
| 265 settings_map->SetWebsiteSetting(pattern, ContentSettingsPattern::Wildcard(), | 275 settings_map->SetWebsiteSetting(pattern, ContentSettingsPattern::Wildcard(), |
| 266 CONTENT_SETTINGS_TYPE_SITE_ENGAGEMENT, | 276 CONTENT_SETTINGS_TYPE_SITE_ENGAGEMENT, |
| 267 std::string(), score_dict.release()); | 277 std::string(), score_dict.release()); |
| 268 } | 278 } |
| 269 } | 279 } |
| 270 | 280 |
| 281 void SiteEngagementService::AfterStartupTask() { | |
| 282 CleanupEngagementScores(); | |
| 283 RecordMetrics(); | |
| 284 } | |
| 285 | |
| 271 void SiteEngagementService::CleanupEngagementScores() { | 286 void SiteEngagementService::CleanupEngagementScores() { |
| 272 HostContentSettingsMap* settings_map = | 287 HostContentSettingsMap* settings_map = |
| 273 HostContentSettingsMapFactory::GetForProfile(profile_); | 288 HostContentSettingsMapFactory::GetForProfile(profile_); |
| 274 scoped_ptr<ContentSettingsForOneType> engagement_settings = | 289 scoped_ptr<ContentSettingsForOneType> engagement_settings = |
| 275 GetEngagementContentSettings(settings_map); | 290 GetEngagementContentSettings(settings_map); |
| 276 | 291 |
| 277 for (const auto& site : *engagement_settings) { | 292 for (const auto& site : *engagement_settings) { |
| 278 GURL origin(site.primary_pattern.ToString()); | 293 GURL origin(site.primary_pattern.ToString()); |
| 279 if (origin.is_valid()) { | 294 if (origin.is_valid()) { |
| 280 scoped_ptr<base::DictionaryValue> score_dict = | 295 scoped_ptr<base::DictionaryValue> score_dict = |
| 281 GetScoreDictForOrigin(settings_map, origin); | 296 GetScoreDictForOrigin(settings_map, origin); |
| 282 SiteEngagementScore score(clock_.get(), *score_dict); | 297 SiteEngagementScore score(clock_.get(), *score_dict); |
| 283 if (score.Score() != 0) | 298 if (score.Score() != 0) |
| 284 continue; | 299 continue; |
| 285 } | 300 } |
| 286 | 301 |
| 287 settings_map->SetWebsiteSetting( | 302 settings_map->SetWebsiteSetting( |
| 288 site.primary_pattern, ContentSettingsPattern::Wildcard(), | 303 site.primary_pattern, ContentSettingsPattern::Wildcard(), |
| 289 CONTENT_SETTINGS_TYPE_SITE_ENGAGEMENT, std::string(), nullptr); | 304 CONTENT_SETTINGS_TYPE_SITE_ENGAGEMENT, std::string(), nullptr); |
| 290 } | 305 } |
| 291 } | 306 } |
| 292 | 307 |
| 308 void SiteEngagementService::RecordMetrics() { | |
| 309 base::Time now = clock_->Now(); | |
| 310 if (last_metrics_time_.is_null() || | |
| 311 now - last_metrics_time_ >= metrics_interval) { | |
| 312 last_metrics_time_ = now; | |
| 313 std::map<GURL, double> score_map = GetScoreMap(); | |
| 314 | |
| 315 int origins_with_max_engagement = OriginsWithMaxEngagement(score_map); | |
| 316 int total_origins = score_map.size(); | |
| 317 int percent_origins_with_max_engagement = | |
| 318 (total_origins == 0 ? 0 : (origins_with_max_engagement * 100) / | |
| 319 total_origins); | |
| 320 | |
| 321 double total_engagement = GetTotalEngagementPoints(); | |
| 322 double mean_engagement = | |
| 323 (total_origins == 0 ? 0 : total_engagement / total_origins); | |
| 324 | |
| 325 SiteEngagementMetrics::RecordTotalOriginsEngaged(total_origins); | |
| 326 SiteEngagementMetrics::RecordTotalSiteEngagement(total_engagement); | |
| 327 SiteEngagementMetrics::RecordMeanEngagement(mean_engagement); | |
| 328 SiteEngagementMetrics::RecordMedianEngagement( | |
| 329 GetMedianEngagement(score_map)); | |
| 330 SiteEngagementMetrics::RecordEngagementScores(score_map); | |
| 331 | |
| 332 SiteEngagementMetrics::RecordOriginsWithMaxDailyEngagement( | |
| 333 OriginsWithMaxDailyEngagement()); | |
| 334 SiteEngagementMetrics::RecordOriginsWithMaxEngagement( | |
| 335 origins_with_max_engagement); | |
| 336 SiteEngagementMetrics::RecordPercentOriginsWithMaxEngagement( | |
| 337 percent_origins_with_max_engagement); | |
| 338 } | |
| 339 } | |
| 340 | |
| 341 double SiteEngagementService::GetMedianEngagement( | |
| 342 std::map<GURL, double>& score_map) { | |
| 343 if (score_map.size() == 0) | |
| 344 return 0; | |
| 345 | |
| 346 std::vector<double> scores; | |
| 347 scores.reserve(score_map.size()); | |
| 348 for (const auto& value : score_map) | |
| 349 scores.push_back(value.second); | |
| 350 | |
| 351 // Calculate the median as the middle value of the sorted engagement scores | |
| 352 // if there are an odd number of scores, or the average of the two middle | |
| 353 // scores otherwise. | |
| 354 std::sort(scores.begin(), scores.end()); | |
|
calamity
2015/10/02 05:31:18
Consider using std::nth_element to compute the med
dominickn
2015/10/02 06:06:17
I think this is a bit too micro-optimisation-ish t
| |
| 355 size_t mid = scores.size() / 2; | |
| 356 if (scores.size() % 2 == 1) | |
| 357 return scores[mid]; | |
| 358 else | |
| 359 return (scores[mid - 1] + scores[mid]) / 2; | |
| 360 } | |
| 361 | |
| 362 int SiteEngagementService::OriginsWithMaxDailyEngagement() { | |
| 363 HostContentSettingsMap* settings_map = | |
| 364 HostContentSettingsMapFactory::GetForProfile(profile_); | |
| 365 scoped_ptr<ContentSettingsForOneType> engagement_settings = | |
| 366 GetEngagementContentSettings(settings_map); | |
| 367 | |
| 368 int total_origins = 0; | |
| 369 | |
| 370 // We cannot call GetScoreMap as we need the score objects, not raw scores. | |
| 371 for (const auto& site : *engagement_settings) { | |
| 372 GURL origin(site.primary_pattern.ToString()); | |
| 373 if (!origin.is_valid()) | |
| 374 continue; | |
| 375 | |
| 376 scoped_ptr<base::DictionaryValue> score_dict = | |
| 377 GetScoreDictForOrigin(settings_map, origin); | |
| 378 SiteEngagementScore score(clock_.get(), *score_dict); | |
| 379 if (score.MaxPointsPerDayAdded()) | |
| 380 ++total_origins; | |
| 381 } | |
| 382 | |
| 383 return total_origins; | |
| 384 } | |
| 385 | |
| 386 int SiteEngagementService::OriginsWithMaxEngagement( | |
| 387 std::map<GURL, double>& score_map) { | |
| 388 int total_origins = 0; | |
| 389 | |
| 390 for (const auto& value : score_map) | |
| 391 if (value.second == SiteEngagementScore::kMaxPoints) | |
| 392 ++total_origins; | |
| 393 | |
| 394 return total_origins; | |
| 395 } | |
| OLD | NEW |