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 |