Pin Chrome's shortcut to the Win10 Start menu on install and OS upgrade.
[chromium-blink-merge.git] / chrome / browser / profiles / profile_metrics.cc
blob4c2fd615a8892cb52badc8321866f608c1b171d9
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "chrome/browser/profiles/profile_metrics.h"
7 #include "base/files/file_path.h"
8 #include "base/logging.h"
9 #include "base/metrics/histogram.h"
10 #include "chrome/browser/browser_process.h"
11 #include "chrome/browser/profiles/profile.h"
12 #include "chrome/browser/profiles/profile_info_cache.h"
13 #include "chrome/browser/profiles/profile_manager.h"
14 #include "chrome/browser/signin/chrome_signin_helper.h"
15 #include "chrome/browser/ui/browser_finder.h"
16 #include "chrome/common/chrome_constants.h"
17 #include "chrome/installer/util/google_update_settings.h"
18 #include "content/public/browser/browser_thread.h"
19 #include "content/public/browser/user_metrics.h"
21 namespace {
23 #if defined(OS_WIN) || defined(OS_MACOSX)
24 const int kMaximumReportedProfileCount = 5;
25 #endif
27 const int kMaximumDaysOfDisuse = 4 * 7; // Should be integral number of weeks.
29 size_t number_of_profile_switches_ = 0;
31 // Enum for tracking the state of profiles being switched to.
32 enum ProfileOpenState {
33 // Profile being switched to is already opened and has browsers opened.
34 PROFILE_OPENED = 0,
35 // Profile being switched to is already opened but has no browsers opened.
36 PROFILE_OPENED_NO_BROWSER,
37 // Profile being switched to is not opened.
38 PROFILE_UNOPENED
41 ProfileOpenState GetProfileOpenState(
42 ProfileManager* manager,
43 const base::FilePath& path) {
44 Profile* profile_switched_to = manager->GetProfileByPath(path);
46 if (!profile_switched_to) {
47 return PROFILE_UNOPENED;
50 if (chrome::GetTotalBrowserCountForProfile(profile_switched_to) > 0) {
51 return PROFILE_OPENED;
54 return PROFILE_OPENED_NO_BROWSER;
57 ProfileMetrics::ProfileType GetProfileType(
58 const base::FilePath& profile_path) {
59 DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
60 ProfileMetrics::ProfileType metric = ProfileMetrics::SECONDARY;
61 ProfileManager* manager = g_browser_process->profile_manager();
62 base::FilePath user_data_dir;
63 // In unittests, we do not always have a profile_manager so check.
64 if (manager) {
65 user_data_dir = manager->user_data_dir();
67 if (profile_path == user_data_dir.AppendASCII(chrome::kInitialProfile)) {
68 metric = ProfileMetrics::ORIGINAL;
70 return metric;
73 void LogLockedProfileInformation(ProfileManager* manager) {
74 const ProfileInfoCache& info_cache = manager->GetProfileInfoCache();
75 size_t number_of_profiles = info_cache.GetNumberOfProfiles();
77 base::Time now = base::Time::Now();
78 const int kMinutesInProfileValidDuration =
79 base::TimeDelta::FromDays(28).InMinutes();
80 for (size_t i = 0; i < number_of_profiles; ++i) {
81 // Find when locked profiles were locked
82 if (info_cache.ProfileIsSigninRequiredAtIndex(i)) {
83 base::TimeDelta time_since_lock = now -
84 info_cache.GetProfileActiveTimeAtIndex(i);
85 // Specifying 100 buckets for the histogram to get a higher level of
86 // granularity in the reported data, given the large number of possible
87 // values (kMinutesInProfileValidDuration > 40,000).
88 UMA_HISTOGRAM_CUSTOM_COUNTS("Profile.LockedProfilesDuration",
89 time_since_lock.InMinutes(),
91 kMinutesInProfileValidDuration,
92 100);
97 bool HasProfileAtIndexBeenActiveSince(const ProfileInfoCache& info_cache,
98 int index,
99 const base::Time& active_limit) {
100 #if !defined(OS_ANDROID) && !defined(OS_IOS)
101 // TODO(mlerman): iOS and Android should set an ActiveTime in the
102 // ProfileInfoCache. (see ProfileManager::OnBrowserSetLastActive)
103 if (info_cache.GetProfileActiveTimeAtIndex(index) < active_limit)
104 return false;
105 #endif
106 return true;
109 } // namespace
111 enum ProfileAvatar {
112 AVATAR_GENERIC = 0, // The names for avatar icons
113 AVATAR_GENERIC_AQUA,
114 AVATAR_GENERIC_BLUE,
115 AVATAR_GENERIC_GREEN,
116 AVATAR_GENERIC_ORANGE,
117 AVATAR_GENERIC_PURPLE,
118 AVATAR_GENERIC_RED,
119 AVATAR_GENERIC_YELLOW,
120 AVATAR_SECRET_AGENT,
121 AVATAR_SUPERHERO,
122 AVATAR_VOLLEYBALL, // 10
123 AVATAR_BUSINESSMAN,
124 AVATAR_NINJA,
125 AVATAR_ALIEN,
126 AVATAR_AWESOME,
127 AVATAR_FLOWER,
128 AVATAR_PIZZA,
129 AVATAR_SOCCER,
130 AVATAR_BURGER,
131 AVATAR_CAT,
132 AVATAR_CUPCAKE, // 20
133 AVATAR_DOG,
134 AVATAR_HORSE,
135 AVATAR_MARGARITA,
136 AVATAR_NOTE,
137 AVATAR_SUN_CLOUD,
138 AVATAR_PLACEHOLDER,
139 AVATAR_UNKNOWN, // 27
140 AVATAR_GAIA, // 28
141 NUM_PROFILE_AVATAR_METRICS
144 bool ProfileMetrics::CountProfileInformation(ProfileManager* manager,
145 ProfileCounts* counts) {
146 const ProfileInfoCache& info_cache = manager->GetProfileInfoCache();
147 size_t number_of_profiles = info_cache.GetNumberOfProfiles();
148 counts->total = number_of_profiles;
150 // Ignore other metrics if we have no profiles.
151 if (!number_of_profiles)
152 return false;
154 // Maximum age for "active" profile is 4 weeks.
155 base::Time oldest = base::Time::Now() -
156 base::TimeDelta::FromDays(kMaximumDaysOfDisuse);
158 for (size_t i = 0; i < number_of_profiles; ++i) {
159 if (!HasProfileAtIndexBeenActiveSince(info_cache, i, oldest)) {
160 counts->unused++;
161 } else {
162 if (info_cache.ProfileIsSupervisedAtIndex(i))
163 counts->supervised++;
164 if (info_cache.ProfileIsAuthenticatedAtIndex(i)) {
165 counts->signedin++;
166 if (info_cache.IsUsingGAIAPictureOfProfileAtIndex(i))
167 counts->gaia_icon++;
168 if (info_cache.ProfileIsAuthErrorAtIndex(i))
169 counts->auth_errors++;
173 return true;
176 void ProfileMetrics::UpdateReportedProfilesStatistics(ProfileManager* manager) {
177 #if defined(OS_WIN) || defined(OS_MACOSX)
178 ProfileCounts counts;
179 if (CountProfileInformation(manager, &counts)) {
180 size_t limited_total = counts.total;
181 size_t limited_signedin = counts.signedin;
182 if (limited_total > kMaximumReportedProfileCount) {
183 limited_total = kMaximumReportedProfileCount + 1;
184 limited_signedin =
185 (int)((float)(counts.signedin * limited_total)
186 / counts.total + 0.5);
188 UpdateReportedOSProfileStatistics(limited_total, limited_signedin);
190 #endif
193 void ProfileMetrics::LogNumberOfProfileSwitches() {
194 UMA_HISTOGRAM_COUNTS_100("Profile.NumberOfSwitches",
195 number_of_profile_switches_);
198 // The OS_MACOSX implementation of this function is in profile_metrics_mac.mm.
199 #if defined(OS_WIN)
200 void ProfileMetrics::UpdateReportedOSProfileStatistics(
201 size_t active, size_t signedin) {
202 GoogleUpdateSettings::UpdateProfileCounts(active, signedin);
204 #endif
206 void ProfileMetrics::LogNumberOfProfiles(ProfileManager* manager) {
207 ProfileCounts counts;
208 bool success = CountProfileInformation(manager, &counts);
209 UMA_HISTOGRAM_COUNTS_100("Profile.NumberOfProfiles", counts.total);
211 // Ignore other metrics if we have no profiles.
212 if (success) {
213 UMA_HISTOGRAM_COUNTS_100("Profile.NumberOfManagedProfiles",
214 counts.supervised);
215 UMA_HISTOGRAM_COUNTS_100("Profile.PercentageOfManagedProfiles",
216 100 * counts.supervised / counts.total);
217 UMA_HISTOGRAM_COUNTS_100("Profile.NumberOfSignedInProfiles",
218 counts.signedin);
219 UMA_HISTOGRAM_COUNTS_100("Profile.NumberOfUnusedProfiles",
220 counts.unused);
221 UMA_HISTOGRAM_COUNTS_100("Profile.NumberOfSignedInProfilesWithGAIAIcons",
222 counts.gaia_icon);
223 UMA_HISTOGRAM_COUNTS_100("Profile.NumberOfProfilesWithAuthErrors",
224 counts.auth_errors);
226 LogLockedProfileInformation(manager);
228 #if defined(OS_WIN) || defined(OS_MACOSX)
229 UpdateReportedOSProfileStatistics(counts.total, counts.signedin);
230 #endif
234 void ProfileMetrics::LogProfileAddNewUser(ProfileAdd metric) {
235 DCHECK(metric < NUM_PROFILE_ADD_METRICS);
236 UMA_HISTOGRAM_ENUMERATION("Profile.AddNewUser", metric,
237 NUM_PROFILE_ADD_METRICS);
238 UMA_HISTOGRAM_ENUMERATION("Profile.NetUserCount", ADD_NEW_USER,
239 NUM_PROFILE_NET_METRICS);
242 void ProfileMetrics::LogProfileAvatarSelection(size_t icon_index) {
243 DCHECK(icon_index < NUM_PROFILE_AVATAR_METRICS);
244 ProfileAvatar icon_name = AVATAR_UNKNOWN;
245 switch (icon_index) {
246 case 0:
247 icon_name = AVATAR_GENERIC;
248 break;
249 case 1:
250 icon_name = AVATAR_GENERIC_AQUA;
251 break;
252 case 2:
253 icon_name = AVATAR_GENERIC_BLUE;
254 break;
255 case 3:
256 icon_name = AVATAR_GENERIC_GREEN;
257 break;
258 case 4:
259 icon_name = AVATAR_GENERIC_ORANGE;
260 break;
261 case 5:
262 icon_name = AVATAR_GENERIC_PURPLE;
263 break;
264 case 6:
265 icon_name = AVATAR_GENERIC_RED;
266 break;
267 case 7:
268 icon_name = AVATAR_GENERIC_YELLOW;
269 break;
270 case 8:
271 icon_name = AVATAR_SECRET_AGENT;
272 break;
273 case 9:
274 icon_name = AVATAR_SUPERHERO;
275 break;
276 case 10:
277 icon_name = AVATAR_VOLLEYBALL;
278 break;
279 case 11:
280 icon_name = AVATAR_BUSINESSMAN;
281 break;
282 case 12:
283 icon_name = AVATAR_NINJA;
284 break;
285 case 13:
286 icon_name = AVATAR_ALIEN;
287 break;
288 case 14:
289 icon_name = AVATAR_AWESOME;
290 break;
291 case 15:
292 icon_name = AVATAR_FLOWER;
293 break;
294 case 16:
295 icon_name = AVATAR_PIZZA;
296 break;
297 case 17:
298 icon_name = AVATAR_SOCCER;
299 break;
300 case 18:
301 icon_name = AVATAR_BURGER;
302 break;
303 case 19:
304 icon_name = AVATAR_CAT;
305 break;
306 case 20:
307 icon_name = AVATAR_CUPCAKE;
308 break;
309 case 21:
310 icon_name = AVATAR_DOG;
311 break;
312 case 22:
313 icon_name = AVATAR_HORSE;
314 break;
315 case 23:
316 icon_name = AVATAR_MARGARITA;
317 break;
318 case 24:
319 icon_name = AVATAR_NOTE;
320 break;
321 case 25:
322 icon_name = AVATAR_SUN_CLOUD;
323 break;
324 case 26:
325 icon_name = AVATAR_PLACEHOLDER;
326 break;
327 case 28:
328 icon_name = AVATAR_GAIA;
329 break;
330 default: // We should never actually get here.
331 NOTREACHED();
332 break;
334 UMA_HISTOGRAM_ENUMERATION("Profile.Avatar", icon_name,
335 NUM_PROFILE_AVATAR_METRICS);
338 void ProfileMetrics::LogProfileDeleteUser(ProfileDelete metric) {
339 DCHECK(metric < NUM_DELETE_PROFILE_METRICS);
340 UMA_HISTOGRAM_ENUMERATION("Profile.DeleteProfileAction", metric,
341 NUM_DELETE_PROFILE_METRICS);
342 if (metric != DELETE_PROFILE_USER_MANAGER_SHOW_WARNING &&
343 metric != DELETE_PROFILE_SETTINGS_SHOW_WARNING) {
344 // If a user was actually deleted, update the net user count.
345 UMA_HISTOGRAM_ENUMERATION("Profile.NetUserCount", PROFILE_DELETED,
346 NUM_PROFILE_NET_METRICS);
350 void ProfileMetrics::LogProfileOpenMethod(ProfileOpen metric) {
351 DCHECK(metric < NUM_PROFILE_OPEN_METRICS);
352 UMA_HISTOGRAM_ENUMERATION("Profile.OpenMethod", metric,
353 NUM_PROFILE_OPEN_METRICS);
356 void ProfileMetrics::LogProfileSwitch(
357 ProfileOpen metric,
358 ProfileManager* manager,
359 const base::FilePath& profile_path) {
360 DCHECK(metric < NUM_PROFILE_OPEN_METRICS);
361 ProfileOpenState open_state = GetProfileOpenState(manager, profile_path);
362 switch (open_state) {
363 case PROFILE_OPENED:
364 UMA_HISTOGRAM_ENUMERATION(
365 "Profile.OpenMethod.ToOpenedProfile",
366 metric,
367 NUM_PROFILE_OPEN_METRICS);
368 break;
369 case PROFILE_OPENED_NO_BROWSER:
370 UMA_HISTOGRAM_ENUMERATION(
371 "Profile.OpenMethod.ToOpenedProfileWithoutBrowser",
372 metric,
373 NUM_PROFILE_OPEN_METRICS);
374 break;
375 case PROFILE_UNOPENED:
376 UMA_HISTOGRAM_ENUMERATION(
377 "Profile.OpenMethod.ToUnopenedProfile",
378 metric,
379 NUM_PROFILE_OPEN_METRICS);
380 break;
381 default:
382 // There are no other possible values.
383 NOTREACHED();
384 break;
387 ++number_of_profile_switches_;
388 // The LogOpenMethod histogram aggregates data from profile switches as well
389 // as opening of profile related UI elements.
390 LogProfileOpenMethod(metric);
393 void ProfileMetrics::LogProfileSwitchGaia(ProfileGaia metric) {
394 if (metric == GAIA_OPT_IN)
395 LogProfileAvatarSelection(AVATAR_GAIA);
396 UMA_HISTOGRAM_ENUMERATION("Profile.SwitchGaiaPhotoSettings",
397 metric,
398 NUM_PROFILE_GAIA_METRICS);
401 void ProfileMetrics::LogProfileSyncInfo(ProfileSync metric) {
402 DCHECK(metric < NUM_PROFILE_SYNC_METRICS);
403 UMA_HISTOGRAM_ENUMERATION("Profile.SyncCustomize", metric,
404 NUM_PROFILE_SYNC_METRICS);
407 void ProfileMetrics::LogProfileAuthResult(ProfileAuth metric) {
408 UMA_HISTOGRAM_ENUMERATION("Profile.AuthResult", metric,
409 NUM_PROFILE_AUTH_METRICS);
412 void ProfileMetrics::LogProfileDesktopMenu(
413 ProfileDesktopMenu metric,
414 signin::GAIAServiceType gaia_service) {
415 // The first parameter to the histogram needs to be literal, because of the
416 // optimized implementation of |UMA_HISTOGRAM_ENUMERATION|. Do not attempt
417 // to refactor.
418 switch (gaia_service) {
419 case signin::GAIA_SERVICE_TYPE_NONE:
420 UMA_HISTOGRAM_ENUMERATION("Profile.DesktopMenu.NonGAIA", metric,
421 NUM_PROFILE_DESKTOP_MENU_METRICS);
422 break;
423 case signin::GAIA_SERVICE_TYPE_SIGNOUT:
424 UMA_HISTOGRAM_ENUMERATION("Profile.DesktopMenu.GAIASignout", metric,
425 NUM_PROFILE_DESKTOP_MENU_METRICS);
426 break;
427 case signin::GAIA_SERVICE_TYPE_INCOGNITO:
428 UMA_HISTOGRAM_ENUMERATION("Profile.DesktopMenu.GAIAIncognito",
429 metric, NUM_PROFILE_DESKTOP_MENU_METRICS);
430 break;
431 case signin::GAIA_SERVICE_TYPE_ADDSESSION:
432 UMA_HISTOGRAM_ENUMERATION("Profile.DesktopMenu.GAIAAddSession", metric,
433 NUM_PROFILE_DESKTOP_MENU_METRICS);
434 break;
435 case signin::GAIA_SERVICE_TYPE_REAUTH:
436 UMA_HISTOGRAM_ENUMERATION("Profile.DesktopMenu.GAIAReAuth", metric,
437 NUM_PROFILE_DESKTOP_MENU_METRICS);
438 break;
439 case signin::GAIA_SERVICE_TYPE_SIGNUP:
440 UMA_HISTOGRAM_ENUMERATION("Profile.DesktopMenu.GAIASignup", metric,
441 NUM_PROFILE_DESKTOP_MENU_METRICS);
442 break;
443 case signin::GAIA_SERVICE_TYPE_DEFAULT:
444 UMA_HISTOGRAM_ENUMERATION("Profile.DesktopMenu.GAIADefault", metric,
445 NUM_PROFILE_DESKTOP_MENU_METRICS);
446 break;
450 void ProfileMetrics::LogProfileDelete(bool profile_was_signed_in) {
451 UMA_HISTOGRAM_BOOLEAN("Profile.Delete", profile_was_signed_in);
454 void ProfileMetrics::LogProfileNewAvatarMenuNotYou(
455 ProfileNewAvatarMenuNotYou metric) {
456 DCHECK_LT(metric, NUM_PROFILE_AVATAR_MENU_NOT_YOU_METRICS);
457 UMA_HISTOGRAM_ENUMERATION("Profile.NewAvatarMenu.NotYou", metric,
458 NUM_PROFILE_AVATAR_MENU_NOT_YOU_METRICS);
461 void ProfileMetrics::LogProfileNewAvatarMenuSignin(
462 ProfileNewAvatarMenuSignin metric) {
463 DCHECK_LT(metric, NUM_PROFILE_AVATAR_MENU_SIGNIN_METRICS);
464 UMA_HISTOGRAM_ENUMERATION("Profile.NewAvatarMenu.Signin", metric,
465 NUM_PROFILE_AVATAR_MENU_SIGNIN_METRICS);
468 void ProfileMetrics::LogProfileNewAvatarMenuUpgrade(
469 ProfileNewAvatarMenuUpgrade metric) {
470 DCHECK_LT(metric, NUM_PROFILE_AVATAR_MENU_UPGRADE_METRICS);
471 UMA_HISTOGRAM_ENUMERATION("Profile.NewAvatarMenu.Upgrade", metric,
472 NUM_PROFILE_AVATAR_MENU_UPGRADE_METRICS);
475 void ProfileMetrics::LogTimeToOpenUserManager(
476 const base::TimeDelta& time_to_open) {
477 UMA_HISTOGRAM_TIMES("Profile.TimeToOpenUserManager", time_to_open);
480 #if defined(OS_ANDROID)
481 void ProfileMetrics::LogProfileAndroidAccountManagementMenu(
482 ProfileAndroidAccountManagementMenu metric,
483 signin::GAIAServiceType gaia_service) {
484 // The first parameter to the histogram needs to be literal, because of the
485 // optimized implementation of |UMA_HISTOGRAM_ENUMERATION|. Do not attempt
486 // to refactor.
487 switch (gaia_service) {
488 case signin::GAIA_SERVICE_TYPE_NONE:
489 UMA_HISTOGRAM_ENUMERATION(
490 "Profile.AndroidAccountManagementMenu.NonGAIA",
491 metric,
492 NUM_PROFILE_ANDROID_ACCOUNT_MANAGEMENT_MENU_METRICS);
493 break;
494 case signin::GAIA_SERVICE_TYPE_SIGNOUT:
495 UMA_HISTOGRAM_ENUMERATION(
496 "Profile.AndroidAccountManagementMenu.GAIASignout",
497 metric,
498 NUM_PROFILE_ANDROID_ACCOUNT_MANAGEMENT_MENU_METRICS);
499 break;
500 case signin::GAIA_SERVICE_TYPE_INCOGNITO:
501 UMA_HISTOGRAM_ENUMERATION(
502 "Profile.AndroidAccountManagementMenu.GAIASignoutIncognito",
503 metric,
504 NUM_PROFILE_ANDROID_ACCOUNT_MANAGEMENT_MENU_METRICS);
505 break;
506 case signin::GAIA_SERVICE_TYPE_ADDSESSION:
507 UMA_HISTOGRAM_ENUMERATION(
508 "Profile.AndroidAccountManagementMenu.GAIAAddSession",
509 metric,
510 NUM_PROFILE_ANDROID_ACCOUNT_MANAGEMENT_MENU_METRICS);
511 break;
512 case signin::GAIA_SERVICE_TYPE_REAUTH:
513 UMA_HISTOGRAM_ENUMERATION(
514 "Profile.AndroidAccountManagementMenu.GAIAReAuth",
515 metric,
516 NUM_PROFILE_ANDROID_ACCOUNT_MANAGEMENT_MENU_METRICS);
517 break;
518 case signin::GAIA_SERVICE_TYPE_SIGNUP:
519 UMA_HISTOGRAM_ENUMERATION(
520 "Profile.AndroidAccountManagementMenu.GAIASignup",
521 metric,
522 NUM_PROFILE_ANDROID_ACCOUNT_MANAGEMENT_MENU_METRICS);
523 break;
524 case signin::GAIA_SERVICE_TYPE_DEFAULT:
525 UMA_HISTOGRAM_ENUMERATION(
526 "Profile.AndroidAccountManagementMenu.GAIADefault",
527 metric,
528 NUM_PROFILE_ANDROID_ACCOUNT_MANAGEMENT_MENU_METRICS);
529 break;
532 #endif // defined(OS_ANDROID)
534 void ProfileMetrics::LogProfileLaunch(Profile* profile) {
535 base::FilePath profile_path = profile->GetPath();
536 UMA_HISTOGRAM_ENUMERATION("Profile.LaunchBrowser",
537 GetProfileType(profile_path),
538 NUM_PROFILE_TYPE_METRICS);
540 if (profile->IsSupervised()) {
541 content::RecordAction(
542 base::UserMetricsAction("ManagedMode_NewManagedUserWindow"));
546 void ProfileMetrics::LogProfileSyncSignIn(const base::FilePath& profile_path) {
547 UMA_HISTOGRAM_ENUMERATION("Profile.SyncSignIn",
548 GetProfileType(profile_path),
549 NUM_PROFILE_TYPE_METRICS);
552 void ProfileMetrics::LogProfileUpdate(const base::FilePath& profile_path) {
553 UMA_HISTOGRAM_ENUMERATION("Profile.Update",
554 GetProfileType(profile_path),
555 NUM_PROFILE_TYPE_METRICS);