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()); |
| 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 |