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.
4 
5 #include "chrome/browser/profiles/profile_metrics.h"
6 
7 #include <vector>
8 
9 #include "base/check_op.h"
10 #include "base/files/file_path.h"
11 #include "base/metrics/histogram_functions.h"
12 #include "base/metrics/user_metrics.h"
13 #include "base/notreached.h"
14 #include "build/build_config.h"
15 #include "chrome/browser/browser_process.h"
16 #include "chrome/browser/profiles/profile.h"
17 #include "chrome/browser/profiles/profile_attributes_entry.h"
18 #include "chrome/browser/profiles/profile_attributes_storage.h"
19 #include "chrome/browser/profiles/profile_avatar_icon_util.h"
20 #include "chrome/browser/profiles/profile_manager.h"
21 #include "chrome/browser/signin/chrome_signin_helper.h"
22 #include "chrome/browser/ui/signin/profile_colors_util.h"
23 #include "chrome/common/chrome_constants.h"
24 #include "chrome/installer/util/google_update_settings.h"
25 #include "components/profile_metrics/browser_profile_type.h"
26 #include "components/profile_metrics/counts.h"
27 #include "components/signin/core/browser/signin_header_helper.h"
28 #include "content/public/browser/browser_thread.h"
29 
30 #if !defined(OS_ANDROID)
31 #include "chrome/browser/ui/browser_finder.h"
32 #endif
33 
34 namespace {
35 
36 #if !defined(OS_ANDROID)
37 constexpr base::TimeDelta kProfileActivityThreshold =
38     base::TimeDelta::FromDays(28);  // Should be integral number of weeks.
39 #endif
40 
41 enum class ProfileType {
42   ORIGINAL = 0,  // Refers to the original/default profile
43   SECONDARY,     // Refers to a user-created profile
44   kMaxValue = SECONDARY
45 };
46 
47 // Enum for getting net counts for adding and deleting users.
48 enum class ProfileNetUserCounts {
49   ADD_NEW_USER = 0,  // Total count of add new user
50   PROFILE_DELETED,   // User deleted a profile
51   kMaxValue = PROFILE_DELETED
52 };
53 
GetProfileType(const base::FilePath & profile_path)54 ProfileType GetProfileType(const base::FilePath& profile_path) {
55   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
56   ProfileType metric = ProfileType::SECONDARY;
57   ProfileManager* manager = g_browser_process->profile_manager();
58   base::FilePath user_data_dir;
59   // In unittests, we do not always have a profile_manager so check.
60   if (manager) {
61     user_data_dir = manager->user_data_dir();
62   }
63   if (profile_path == user_data_dir.AppendASCII(chrome::kInitialProfile)) {
64     metric = ProfileType::ORIGINAL;
65   }
66   return metric;
67 }
68 
GetProfileColorsUniqueness(ProfileAttributesStorage * storage)69 profile_metrics::ProfileColorsUniqueness GetProfileColorsUniqueness(
70     ProfileAttributesStorage* storage) {
71 #if defined(OS_ANDROID)
72   return profile_metrics::ProfileColorsUniqueness::kSingleProfile;
73 #else
74   std::vector<ProfileAttributesEntry*> entries =
75       storage->GetAllProfilesAttributes();
76   DCHECK(!entries.empty());
77   if (entries.size() == 1u)
78     return profile_metrics::ProfileColorsUniqueness::kSingleProfile;
79 
80   size_t default_colors_count = 0;
81   std::set<ProfileThemeColors> used_colors;
82   for (ProfileAttributesEntry* entry : entries) {
83     base::Optional<ProfileThemeColors> profile_colors =
84         entry->GetProfileThemeColorsIfSet();
85     if (!profile_colors) {
86       default_colors_count++;
87     } else if (!base::Contains(used_colors, *profile_colors)) {
88       used_colors.insert(*profile_colors);
89     } else {
90       return profile_metrics::ProfileColorsUniqueness::kRepeated;
91     }
92   }
93   return default_colors_count > 1u
94              ? profile_metrics::ProfileColorsUniqueness::
95                    kUniqueExceptForRepeatedDefault
96              : profile_metrics::ProfileColorsUniqueness::kUnique;
97 #endif
98 }
99 
100 }  // namespace
101 
102 // This enum is used for histograms. Do not change existing values. Append new
103 // values at the end.
104 enum ProfileAvatar {
105   AVATAR_GENERIC = 0,  // The names for avatar icons
106   AVATAR_GENERIC_AQUA = 1,
107   AVATAR_GENERIC_BLUE = 2,
108   AVATAR_GENERIC_GREEN = 3,
109   AVATAR_GENERIC_ORANGE = 4,
110   AVATAR_GENERIC_PURPLE = 5,
111   AVATAR_GENERIC_RED = 6,
112   AVATAR_GENERIC_YELLOW = 7,
113   AVATAR_SECRET_AGENT = 8,
114   AVATAR_SUPERHERO = 9,
115   AVATAR_VOLLEYBALL = 10,
116   AVATAR_BUSINESSMAN = 11,
117   AVATAR_NINJA = 12,
118   AVATAR_ALIEN = 13,
119   AVATAR_AWESOME = 14,
120   AVATAR_FLOWER = 15,
121   AVATAR_PIZZA = 16,
122   AVATAR_SOCCER = 17,
123   AVATAR_BURGER = 18,
124   AVATAR_CAT = 19,
125   AVATAR_CUPCAKE = 20,
126   AVATAR_DOG = 21,
127   AVATAR_HORSE = 22,
128   AVATAR_MARGARITA = 23,
129   AVATAR_NOTE = 24,
130   AVATAR_SUN_CLOUD = 25,
131   AVATAR_PLACEHOLDER = 26,
132   AVATAR_UNKNOWN = 27,
133   AVATAR_GAIA = 28,
134   // Modern avatars:
135   AVATAR_ORIGAMI_CAT = 29,
136   AVATAR_ORIGAMI_CORGI = 30,
137   AVATAR_ORIGAMI_DRAGON = 31,
138   AVATAR_ORIGAMI_ELEPHANT = 32,
139   AVATAR_ORIGAMI_FOX = 33,
140   AVATAR_ORIGAMI_MONKEY = 34,
141   AVATAR_ORIGAMI_PANDA = 35,
142   AVATAR_ORIGAMI_PENGUIN = 36,
143   AVATAR_ORIGAMI_PINKBUTTERFLY = 37,
144   AVATAR_ORIGAMI_RABBIT = 38,
145   AVATAR_ORIGAMI_UNICORN = 39,
146   AVATAR_ILLUSTRATION_BASKETBALL = 40,
147   AVATAR_ILLUSTRATION_BIKE = 41,
148   AVATAR_ILLUSTRATION_BIRD = 42,
149   AVATAR_ILLUSTRATION_CHEESE = 43,
150   AVATAR_ILLUSTRATION_FOOTBALL = 44,
151   AVATAR_ILLUSTRATION_RAMEN = 45,
152   AVATAR_ILLUSTRATION_SUNGLASSES = 46,
153   AVATAR_ILLUSTRATION_SUSHI = 47,
154   AVATAR_ILLUSTRATION_TAMAGOTCHI = 48,
155   AVATAR_ILLUSTRATION_VINYL = 49,
156   AVATAR_ABSTRACT_AVOCADO = 50,
157   AVATAR_ABSTRACT_CAPPUCCINO = 51,
158   AVATAR_ABSTRACT_ICECREAM = 52,
159   AVATAR_ABSTRACT_ICEWATER = 53,
160   AVATAR_ABSTRACT_MELON = 54,
161   AVATAR_ABSTRACT_ONIGIRI = 55,
162   AVATAR_ABSTRACT_PIZZA = 56,
163   AVATAR_ABSTRACT_SANDWICH = 57,
164   NUM_PROFILE_AVATAR_METRICS
165 };
166 
167 // static
IsProfileActive(const ProfileAttributesEntry * entry)168 bool ProfileMetrics::IsProfileActive(const ProfileAttributesEntry* entry) {
169 #if !defined(OS_ANDROID)
170   // TODO(mlerman): iOS and Android should set an ActiveTime in the
171   // ProfileAttributesStorage. (see ProfileManager::OnBrowserSetLastActive)
172   if (base::Time::Now() - entry->GetActiveTime() > kProfileActivityThreshold)
173     return false;
174 #endif
175   return true;
176 }
177 
178 // static
CountProfileInformation(ProfileAttributesStorage * storage,profile_metrics::Counts * counts)179 void ProfileMetrics::CountProfileInformation(ProfileAttributesStorage* storage,
180                                              profile_metrics::Counts* counts) {
181   size_t number_of_profiles = storage->GetNumberOfProfiles();
182   counts->total = number_of_profiles;
183 
184   // Ignore other metrics if we have no profiles.
185   if (!number_of_profiles)
186     return;
187 
188   std::vector<ProfileAttributesEntry*> entries =
189       storage->GetAllProfilesAttributes();
190   for (ProfileAttributesEntry* entry : entries) {
191     if (!IsProfileActive(entry)) {
192       counts->unused++;
193     } else {
194       counts->active++;
195       if (!entry->IsUsingDefaultName())
196         counts->named++;
197       if (entry->IsSupervised())
198         counts->supervised++;
199       if (entry->IsAuthenticated()) {
200         counts->signedin++;
201         if (entry->IsUsingGAIAPicture())
202           counts->gaia_icon++;
203         if (entry->IsAuthError())
204           counts->auth_errors++;
205       }
206     }
207   }
208   counts->colors_uniqueness = GetProfileColorsUniqueness(storage);
209 }
210 
GetBrowserProfileType(Profile * profile)211 profile_metrics::BrowserProfileType ProfileMetrics::GetBrowserProfileType(
212     Profile* profile) {
213   if (profile->IsSystemProfile())
214     return profile_metrics::BrowserProfileType::kSystem;
215   if (profile->IsGuestSession() || profile->IsEphemeralGuestProfile())
216     return profile_metrics::BrowserProfileType::kGuest;
217   // A regular profile can be in a guest session or a system profile. Hence it
218   // should be checked after them.
219   if (profile->IsRegularProfile())
220     return profile_metrics::BrowserProfileType::kRegular;
221 
222   if (profile->IsIncognitoProfile())
223     return profile_metrics::BrowserProfileType::kIncognito;
224 
225   if (profile->IsOffTheRecord() && !profile->IsPrimaryOTRProfile())
226     return profile_metrics::BrowserProfileType::kOtherOffTheRecordProfile;
227 
228   NOTREACHED();
229   return profile_metrics::BrowserProfileType::kMaxValue;
230 }
231 
LogNumberOfProfiles(ProfileAttributesStorage * storage)232 void ProfileMetrics::LogNumberOfProfiles(ProfileAttributesStorage* storage) {
233   profile_metrics::Counts counts;
234   CountProfileInformation(storage, &counts);
235   profile_metrics::LogProfileMetricsCounts(counts);
236 }
237 
LogProfileAddNewUser(ProfileAdd metric)238 void ProfileMetrics::LogProfileAddNewUser(ProfileAdd metric) {
239   base::UmaHistogramEnumeration("Profile.AddNewUser", metric);
240   base::UmaHistogramEnumeration("Profile.NetUserCount",
241                                 ProfileNetUserCounts::ADD_NEW_USER);
242 }
243 
LogProfileAvatarSelection(size_t icon_index)244 void ProfileMetrics::LogProfileAvatarSelection(size_t icon_index) {
245   ProfileAvatar icon_name = AVATAR_UNKNOWN;
246   switch (icon_index) {
247     case 0:
248       icon_name = AVATAR_GENERIC;
249       break;
250     case 1:
251       icon_name = AVATAR_GENERIC_AQUA;
252       break;
253     case 2:
254       icon_name = AVATAR_GENERIC_BLUE;
255       break;
256     case 3:
257       icon_name = AVATAR_GENERIC_GREEN;
258       break;
259     case 4:
260       icon_name = AVATAR_GENERIC_ORANGE;
261       break;
262     case 5:
263       icon_name = AVATAR_GENERIC_PURPLE;
264       break;
265     case 6:
266       icon_name = AVATAR_GENERIC_RED;
267       break;
268     case 7:
269       icon_name = AVATAR_GENERIC_YELLOW;
270       break;
271     case 8:
272       icon_name = AVATAR_SECRET_AGENT;
273       break;
274     case 9:
275       icon_name = AVATAR_SUPERHERO;
276       break;
277     case 10:
278       icon_name = AVATAR_VOLLEYBALL;
279       break;
280     case 11:
281       icon_name = AVATAR_BUSINESSMAN;
282       break;
283     case 12:
284       icon_name = AVATAR_NINJA;
285       break;
286     case 13:
287       icon_name = AVATAR_ALIEN;
288       break;
289     case 14:
290       icon_name = AVATAR_AWESOME;
291       break;
292     case 15:
293       icon_name = AVATAR_FLOWER;
294       break;
295     case 16:
296       icon_name = AVATAR_PIZZA;
297       break;
298     case 17:
299       icon_name = AVATAR_SOCCER;
300       break;
301     case 18:
302       icon_name = AVATAR_BURGER;
303       break;
304     case 19:
305       icon_name = AVATAR_CAT;
306       break;
307     case 20:
308       icon_name = AVATAR_CUPCAKE;
309       break;
310     case 21:
311       icon_name = AVATAR_DOG;
312       break;
313     case 22:
314       icon_name = AVATAR_HORSE;
315       break;
316     case 23:
317       icon_name = AVATAR_MARGARITA;
318       break;
319     case 24:
320       icon_name = AVATAR_NOTE;
321       break;
322     case 25:
323       icon_name = AVATAR_SUN_CLOUD;
324       break;
325     case 26:
326       icon_name = AVATAR_PLACEHOLDER;
327       break;
328     // Modern avatars:
329     case 27:
330       icon_name = AVATAR_ORIGAMI_CAT;
331       break;
332     case 28:
333       icon_name = AVATAR_ORIGAMI_CORGI;
334       break;
335     case 29:
336       icon_name = AVATAR_ORIGAMI_DRAGON;
337       break;
338     case 30:
339       icon_name = AVATAR_ORIGAMI_ELEPHANT;
340       break;
341     case 31:
342       icon_name = AVATAR_ORIGAMI_FOX;
343       break;
344     case 32:
345       icon_name = AVATAR_ORIGAMI_MONKEY;
346       break;
347     case 33:
348       icon_name = AVATAR_ORIGAMI_PANDA;
349       break;
350     case 34:
351       icon_name = AVATAR_ORIGAMI_PENGUIN;
352       break;
353     case 35:
354       icon_name = AVATAR_ORIGAMI_PINKBUTTERFLY;
355       break;
356     case 36:
357       icon_name = AVATAR_ORIGAMI_RABBIT;
358       break;
359     case 37:
360       icon_name = AVATAR_ORIGAMI_UNICORN;
361       break;
362     case 38:
363       icon_name = AVATAR_ILLUSTRATION_BASKETBALL;
364       break;
365     case 39:
366       icon_name = AVATAR_ILLUSTRATION_BIKE;
367       break;
368     case 40:
369       icon_name = AVATAR_ILLUSTRATION_BIRD;
370       break;
371     case 41:
372       icon_name = AVATAR_ILLUSTRATION_CHEESE;
373       break;
374     case 42:
375       icon_name = AVATAR_ILLUSTRATION_FOOTBALL;
376       break;
377     case 43:
378       icon_name = AVATAR_ILLUSTRATION_RAMEN;
379       break;
380     case 44:
381       icon_name = AVATAR_ILLUSTRATION_SUNGLASSES;
382       break;
383     case 45:
384       icon_name = AVATAR_ILLUSTRATION_SUSHI;
385       break;
386     case 46:
387       icon_name = AVATAR_ILLUSTRATION_TAMAGOTCHI;
388       break;
389     case 47:
390       icon_name = AVATAR_ILLUSTRATION_VINYL;
391       break;
392     case 48:
393       icon_name = AVATAR_ABSTRACT_AVOCADO;
394       break;
395     case 49:
396       icon_name = AVATAR_ABSTRACT_CAPPUCCINO;
397       break;
398     case 50:
399       icon_name = AVATAR_ABSTRACT_ICECREAM;
400       break;
401     case 51:
402       icon_name = AVATAR_ABSTRACT_ICEWATER;
403       break;
404     case 52:
405       icon_name = AVATAR_ABSTRACT_MELON;
406       break;
407     case 53:
408       icon_name = AVATAR_ABSTRACT_ONIGIRI;
409       break;
410     case 54:
411       icon_name = AVATAR_ABSTRACT_PIZZA;
412       break;
413     case 55:
414       icon_name = AVATAR_ABSTRACT_SANDWICH;
415       break;
416     case SIZE_MAX:
417       icon_name = AVATAR_GAIA;
418       break;
419     default:
420       NOTREACHED();
421   }
422   base::UmaHistogramEnumeration("Profile.Avatar", icon_name,
423                                 NUM_PROFILE_AVATAR_METRICS);
424 }
425 
LogProfileDeleteUser(ProfileDelete metric)426 void ProfileMetrics::LogProfileDeleteUser(ProfileDelete metric) {
427   DCHECK(metric < NUM_DELETE_PROFILE_METRICS);
428   base::UmaHistogramEnumeration("Profile.DeleteProfileAction", metric,
429                                 NUM_DELETE_PROFILE_METRICS);
430   if (metric != DELETE_PROFILE_USER_MANAGER_SHOW_WARNING &&
431       metric != DELETE_PROFILE_SETTINGS_SHOW_WARNING &&
432       metric != DELETE_PROFILE_ABORTED) {
433     // If a user was actually deleted, update the net user count.
434     base::UmaHistogramEnumeration("Profile.NetUserCount",
435                                   ProfileNetUserCounts::PROFILE_DELETED);
436   }
437 }
438 
LogProfileSwitchGaia(ProfileGaia metric)439 void ProfileMetrics::LogProfileSwitchGaia(ProfileGaia metric) {
440   if (metric == GAIA_OPT_IN)
441     LogProfileAvatarSelection(SIZE_MAX);
442   base::UmaHistogramEnumeration("Profile.SwitchGaiaPhotoSettings", metric,
443                                 NUM_PROFILE_GAIA_METRICS);
444 }
445 
LogProfileSyncInfo(ProfileSync metric)446 void ProfileMetrics::LogProfileSyncInfo(ProfileSync metric) {
447   DCHECK(metric < NUM_PROFILE_SYNC_METRICS);
448   base::UmaHistogramEnumeration("Profile.SyncCustomize", metric,
449                                 NUM_PROFILE_SYNC_METRICS);
450 }
451 
LogProfileDelete(bool profile_was_signed_in)452 void ProfileMetrics::LogProfileDelete(bool profile_was_signed_in) {
453   base::UmaHistogramBoolean("Profile.Delete", profile_was_signed_in);
454 }
455 
LogTimeToOpenUserManager(const base::TimeDelta & time_to_open)456 void ProfileMetrics::LogTimeToOpenUserManager(
457     const base::TimeDelta& time_to_open) {
458   base::UmaHistogramCustomTimes("Profile.TimeToOpenUserManagerUpTo1min",
459                                 time_to_open,
460                                 base::TimeDelta::FromMilliseconds(1),
461                                 base::TimeDelta::FromMinutes(1), 50);
462 }
463 
464 #if defined(OS_ANDROID)
LogProfileAndroidAccountManagementMenu(ProfileAndroidAccountManagementMenu metric,signin::GAIAServiceType gaia_service)465 void ProfileMetrics::LogProfileAndroidAccountManagementMenu(
466     ProfileAndroidAccountManagementMenu metric,
467     signin::GAIAServiceType gaia_service) {
468   // The first parameter to the histogram needs to be literal, because of the
469   // optimized implementation of |base::UmaHistogramEnumeration|. Do not attempt
470   // to refactor.
471   switch (gaia_service) {
472     case signin::GAIA_SERVICE_TYPE_NONE:
473       base::UmaHistogramEnumeration(
474           "Profile.AndroidAccountManagementMenu.NonGAIA", metric,
475           NUM_PROFILE_ANDROID_ACCOUNT_MANAGEMENT_MENU_METRICS);
476       break;
477     case signin::GAIA_SERVICE_TYPE_SIGNOUT:
478       base::UmaHistogramEnumeration(
479           "Profile.AndroidAccountManagementMenu.GAIASignout", metric,
480           NUM_PROFILE_ANDROID_ACCOUNT_MANAGEMENT_MENU_METRICS);
481       break;
482     case signin::GAIA_SERVICE_TYPE_INCOGNITO:
483       base::UmaHistogramEnumeration(
484           "Profile.AndroidAccountManagementMenu.GAIASignoutIncognito", metric,
485           NUM_PROFILE_ANDROID_ACCOUNT_MANAGEMENT_MENU_METRICS);
486       break;
487     case signin::GAIA_SERVICE_TYPE_ADDSESSION:
488       base::UmaHistogramEnumeration(
489           "Profile.AndroidAccountManagementMenu.GAIAAddSession", metric,
490           NUM_PROFILE_ANDROID_ACCOUNT_MANAGEMENT_MENU_METRICS);
491       break;
492     case signin::GAIA_SERVICE_TYPE_SIGNUP:
493       base::UmaHistogramEnumeration(
494           "Profile.AndroidAccountManagementMenu.GAIASignup", metric,
495           NUM_PROFILE_ANDROID_ACCOUNT_MANAGEMENT_MENU_METRICS);
496       break;
497     case signin::GAIA_SERVICE_TYPE_DEFAULT:
498       base::UmaHistogramEnumeration(
499           "Profile.AndroidAccountManagementMenu.GAIADefault", metric,
500           NUM_PROFILE_ANDROID_ACCOUNT_MANAGEMENT_MENU_METRICS);
501       break;
502   }
503 }
504 #endif  // defined(OS_ANDROID)
505 
LogProfileLaunch(Profile * profile)506 void ProfileMetrics::LogProfileLaunch(Profile* profile) {
507   if (profile->IsSupervised()) {
508     base::RecordAction(
509         base::UserMetricsAction("ManagedMode_NewManagedUserWindow"));
510   }
511 }
512 
LogProfileUpdate(const base::FilePath & profile_path)513 void ProfileMetrics::LogProfileUpdate(const base::FilePath& profile_path) {
514   base::UmaHistogramEnumeration("Profile.Update", GetProfileType(profile_path));
515 }
516