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

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

Issue 1368533004: Add UMA metrics to the site engagement service. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@time-on-site
Patch Set: Addressing reviewer feedback. Adding more testing Created 5 years, 2 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 <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
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
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
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 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698