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 "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/signin_header_helper.h"
15 #include "chrome/common/chrome_constants.h"
16 #include "chrome/installer/util/google_update_settings.h"
17 #include "content/public/browser/browser_thread.h"
18 #include "content/public/browser/user_metrics.h"
19
20 namespace {
21
22 const int kMaximumReportedProfileCount = 5;
23 const int kMaximumDaysOfDisuse = 4 * 7; // Should be integral number of weeks.
24
25 struct ProfileCounts {
26 size_t total;
27 size_t signedin;
28 size_t supervised;
29 size_t unused;
30 size_t gaia_icon;
31
ProfileCounts__anon735b6b3d0111::ProfileCounts32 ProfileCounts()
33 : total(0), signedin(0), supervised(0), unused(0), gaia_icon(0) {}
34 };
35
GetProfileType(const base::FilePath & profile_path)36 ProfileMetrics::ProfileType GetProfileType(
37 const base::FilePath& profile_path) {
38 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
39 ProfileMetrics::ProfileType metric = ProfileMetrics::SECONDARY;
40 ProfileManager* manager = g_browser_process->profile_manager();
41 base::FilePath user_data_dir;
42 // In unittests, we do not always have a profile_manager so check.
43 if (manager) {
44 user_data_dir = manager->user_data_dir();
45 }
46 if (profile_path == user_data_dir.AppendASCII(chrome::kInitialProfile)) {
47 metric = ProfileMetrics::ORIGINAL;
48 }
49 return metric;
50 }
51
UpdateReportedOSProfileStatistics(int active,int signedin)52 void UpdateReportedOSProfileStatistics(int active, int signedin) {
53 #if defined(OS_WIN)
54 GoogleUpdateSettings::UpdateProfileCounts(active, signedin);
55 #endif
56 }
57
CountProfileInformation(ProfileManager * manager,ProfileCounts * counts)58 bool CountProfileInformation(ProfileManager* manager, ProfileCounts* counts) {
59 const ProfileInfoCache& info_cache = manager->GetProfileInfoCache();
60 size_t number_of_profiles = info_cache.GetNumberOfProfiles();
61 counts->total = number_of_profiles;
62
63 // Ignore other metrics if we have no profiles, e.g. in Chrome Frame tests.
64 if (!number_of_profiles)
65 return false;
66
67 // Maximum age for "active" profile is 4 weeks.
68 base::Time oldest = base::Time::Now() -
69 base::TimeDelta::FromDays(kMaximumDaysOfDisuse);
70
71 for (size_t i = 0; i < number_of_profiles; ++i) {
72 if (info_cache.GetProfileActiveTimeAtIndex(i) < oldest) {
73 counts->unused++;
74 } else {
75 if (info_cache.ProfileIsSupervisedAtIndex(i))
76 counts->supervised++;
77 if (!info_cache.GetUserNameOfProfileAtIndex(i).empty()) {
78 counts->signedin++;
79 if (info_cache.IsUsingGAIAPictureOfProfileAtIndex(i))
80 counts->gaia_icon++;
81 }
82 }
83 }
84 return true;
85 }
86
LogLockedProfileInformation(ProfileManager * manager)87 void LogLockedProfileInformation(ProfileManager* manager) {
88 const ProfileInfoCache& info_cache = manager->GetProfileInfoCache();
89 size_t number_of_profiles = info_cache.GetNumberOfProfiles();
90
91 base::Time now = base::Time::Now();
92 const int kMinutesInProfileValidDuration =
93 base::TimeDelta::FromDays(28).InMinutes();
94 for (size_t i = 0; i < number_of_profiles; ++i) {
95 // Find when locked profiles were locked
96 if (info_cache.ProfileIsSigninRequiredAtIndex(i)) {
97 base::TimeDelta time_since_lock = now -
98 info_cache.GetProfileActiveTimeAtIndex(i);
99 // Specifying 100 buckets for the histogram to get a higher level of
100 // granularity in the reported data, given the large number of possible
101 // values (kMinutesInProfileValidDuration > 40,000).
102 UMA_HISTOGRAM_CUSTOM_COUNTS("Profile.LockedProfilesDuration",
103 time_since_lock.InMinutes(),
104 1,
105 kMinutesInProfileValidDuration,
106 100);
107 }
108 }
109 }
110
111 } // namespace
112
113 enum ProfileAvatar {
114 AVATAR_GENERIC = 0, // The names for avatar icons
115 AVATAR_GENERIC_AQUA,
116 AVATAR_GENERIC_BLUE,
117 AVATAR_GENERIC_GREEN,
118 AVATAR_GENERIC_ORANGE,
119 AVATAR_GENERIC_PURPLE,
120 AVATAR_GENERIC_RED,
121 AVATAR_GENERIC_YELLOW,
122 AVATAR_SECRET_AGENT,
123 AVATAR_SUPERHERO,
124 AVATAR_VOLLEYBALL, // 10
125 AVATAR_BUSINESSMAN,
126 AVATAR_NINJA,
127 AVATAR_ALIEN,
128 AVATAR_AWESOME,
129 AVATAR_FLOWER,
130 AVATAR_PIZZA,
131 AVATAR_SOCCER,
132 AVATAR_BURGER,
133 AVATAR_CAT,
134 AVATAR_CUPCAKE, // 20
135 AVATAR_DOG,
136 AVATAR_HORSE,
137 AVATAR_MARGARITA,
138 AVATAR_NOTE,
139 AVATAR_SUN_CLOUD,
140 AVATAR_PLACEHOLDER,
141 AVATAR_UNKNOWN, // 27
142 AVATAR_GAIA, // 28
143 NUM_PROFILE_AVATAR_METRICS
144 };
145
UpdateReportedProfilesStatistics(ProfileManager * manager)146 void ProfileMetrics::UpdateReportedProfilesStatistics(ProfileManager* manager) {
147 ProfileCounts counts;
148 if (CountProfileInformation(manager, &counts)) {
149 int limited_total = counts.total;
150 int limited_signedin = counts.signedin;
151 if (limited_total > kMaximumReportedProfileCount) {
152 limited_total = kMaximumReportedProfileCount + 1;
153 limited_signedin =
154 (int)((float)(counts.signedin * limited_total)
155 / counts.total + 0.5);
156 }
157 UpdateReportedOSProfileStatistics(limited_total, limited_signedin);
158 }
159 }
160
LogNumberOfProfiles(ProfileManager * manager)161 void ProfileMetrics::LogNumberOfProfiles(ProfileManager* manager) {
162 ProfileCounts counts;
163 bool success = CountProfileInformation(manager, &counts);
164 UMA_HISTOGRAM_COUNTS_100("Profile.NumberOfProfiles", counts.total);
165
166 // Ignore other metrics if we have no profiles, e.g. in Chrome Frame tests.
167 if (success) {
168 UMA_HISTOGRAM_COUNTS_100("Profile.NumberOfManagedProfiles",
169 counts.supervised);
170 UMA_HISTOGRAM_COUNTS_100("Profile.PercentageOfManagedProfiles",
171 100 * counts.supervised / counts.total);
172 UMA_HISTOGRAM_COUNTS_100("Profile.NumberOfSignedInProfiles",
173 counts.signedin);
174 UMA_HISTOGRAM_COUNTS_100("Profile.NumberOfUnusedProfiles",
175 counts.unused);
176 UMA_HISTOGRAM_COUNTS_100("Profile.NumberOfSignedInProfilesWithGAIAIcons",
177 counts.gaia_icon);
178
179 LogLockedProfileInformation(manager);
180 UpdateReportedOSProfileStatistics(counts.total, counts.signedin);
181 }
182 }
183
LogProfileAddNewUser(ProfileAdd metric)184 void ProfileMetrics::LogProfileAddNewUser(ProfileAdd metric) {
185 DCHECK(metric < NUM_PROFILE_ADD_METRICS);
186 UMA_HISTOGRAM_ENUMERATION("Profile.AddNewUser", metric,
187 NUM_PROFILE_ADD_METRICS);
188 UMA_HISTOGRAM_ENUMERATION("Profile.NetUserCount", ADD_NEW_USER,
189 NUM_PROFILE_NET_METRICS);
190 }
191
LogProfileAvatarSelection(size_t icon_index)192 void ProfileMetrics::LogProfileAvatarSelection(size_t icon_index) {
193 DCHECK(icon_index < NUM_PROFILE_AVATAR_METRICS);
194 ProfileAvatar icon_name = AVATAR_UNKNOWN;
195 switch (icon_index) {
196 case 0:
197 icon_name = AVATAR_GENERIC;
198 break;
199 case 1:
200 icon_name = AVATAR_GENERIC_AQUA;
201 break;
202 case 2:
203 icon_name = AVATAR_GENERIC_BLUE;
204 break;
205 case 3:
206 icon_name = AVATAR_GENERIC_GREEN;
207 break;
208 case 4:
209 icon_name = AVATAR_GENERIC_ORANGE;
210 break;
211 case 5:
212 icon_name = AVATAR_GENERIC_PURPLE;
213 break;
214 case 6:
215 icon_name = AVATAR_GENERIC_RED;
216 break;
217 case 7:
218 icon_name = AVATAR_GENERIC_YELLOW;
219 break;
220 case 8:
221 icon_name = AVATAR_SECRET_AGENT;
222 break;
223 case 9:
224 icon_name = AVATAR_SUPERHERO;
225 break;
226 case 10:
227 icon_name = AVATAR_VOLLEYBALL;
228 break;
229 case 11:
230 icon_name = AVATAR_BUSINESSMAN;
231 break;
232 case 12:
233 icon_name = AVATAR_NINJA;
234 break;
235 case 13:
236 icon_name = AVATAR_ALIEN;
237 break;
238 case 14:
239 icon_name = AVATAR_AWESOME;
240 break;
241 case 15:
242 icon_name = AVATAR_FLOWER;
243 break;
244 case 16:
245 icon_name = AVATAR_PIZZA;
246 break;
247 case 17:
248 icon_name = AVATAR_SOCCER;
249 break;
250 case 18:
251 icon_name = AVATAR_BURGER;
252 break;
253 case 19:
254 icon_name = AVATAR_CAT;
255 break;
256 case 20:
257 icon_name = AVATAR_CUPCAKE;
258 break;
259 case 21:
260 icon_name = AVATAR_DOG;
261 break;
262 case 22:
263 icon_name = AVATAR_HORSE;
264 break;
265 case 23:
266 icon_name = AVATAR_MARGARITA;
267 break;
268 case 24:
269 icon_name = AVATAR_NOTE;
270 break;
271 case 25:
272 icon_name = AVATAR_SUN_CLOUD;
273 break;
274 case 26:
275 icon_name = AVATAR_PLACEHOLDER;
276 break;
277 case 28:
278 icon_name = AVATAR_GAIA;
279 break;
280 default: // We should never actually get here.
281 NOTREACHED();
282 break;
283 }
284 UMA_HISTOGRAM_ENUMERATION("Profile.Avatar", icon_name,
285 NUM_PROFILE_AVATAR_METRICS);
286 }
287
LogProfileDeleteUser(ProfileNetUserCounts metric)288 void ProfileMetrics::LogProfileDeleteUser(ProfileNetUserCounts metric) {
289 DCHECK(metric < NUM_PROFILE_NET_METRICS);
290 UMA_HISTOGRAM_ENUMERATION("Profile.NetUserCount", metric,
291 NUM_PROFILE_NET_METRICS);
292 }
293
LogProfileOpenMethod(ProfileOpen metric)294 void ProfileMetrics::LogProfileOpenMethod(ProfileOpen metric) {
295 DCHECK(metric < NUM_PROFILE_OPEN_METRICS);
296 UMA_HISTOGRAM_ENUMERATION("Profile.OpenMethod", metric,
297 NUM_PROFILE_OPEN_METRICS);
298 }
299
LogProfileSwitchGaia(ProfileGaia metric)300 void ProfileMetrics::LogProfileSwitchGaia(ProfileGaia metric) {
301 if (metric == GAIA_OPT_IN)
302 LogProfileAvatarSelection(AVATAR_GAIA);
303 UMA_HISTOGRAM_ENUMERATION("Profile.SwitchGaiaPhotoSettings",
304 metric,
305 NUM_PROFILE_GAIA_METRICS);
306 }
307
LogProfileSwitchUser(ProfileOpen metric)308 void ProfileMetrics::LogProfileSwitchUser(ProfileOpen metric) {
309 DCHECK(metric < NUM_PROFILE_OPEN_METRICS);
310 UMA_HISTOGRAM_ENUMERATION("Profile.OpenMethod", metric,
311 NUM_PROFILE_OPEN_METRICS);
312 }
313
LogProfileSyncInfo(ProfileSync metric)314 void ProfileMetrics::LogProfileSyncInfo(ProfileSync metric) {
315 DCHECK(metric < NUM_PROFILE_SYNC_METRICS);
316 UMA_HISTOGRAM_ENUMERATION("Profile.SyncCustomize", metric,
317 NUM_PROFILE_SYNC_METRICS);
318 }
319
LogProfileAuthResult(ProfileAuth metric)320 void ProfileMetrics::LogProfileAuthResult(ProfileAuth metric) {
321 UMA_HISTOGRAM_ENUMERATION("Profile.AuthResult", metric,
322 NUM_PROFILE_AUTH_METRICS);
323 }
324
LogProfileUpgradeEnrollment(ProfileUpgradeEnrollment metric)325 void ProfileMetrics::LogProfileUpgradeEnrollment(
326 ProfileUpgradeEnrollment metric) {
327 UMA_HISTOGRAM_ENUMERATION("Profile.UpgradeEnrollment", metric,
328 NUM_PROFILE_ENROLLMENT_METRICS);
329 }
330
LogProfileDesktopMenu(ProfileDesktopMenu metric,signin::GAIAServiceType gaia_service)331 void ProfileMetrics::LogProfileDesktopMenu(
332 ProfileDesktopMenu metric,
333 signin::GAIAServiceType gaia_service) {
334 // The first parameter to the histogram needs to be literal, because of the
335 // optimized implementation of |UMA_HISTOGRAM_ENUMERATION|. Do not attempt
336 // to refactor.
337 switch (gaia_service) {
338 case signin::GAIA_SERVICE_TYPE_NONE:
339 UMA_HISTOGRAM_ENUMERATION("Profile.DesktopMenu.NonGAIA", metric,
340 NUM_PROFILE_DESKTOP_MENU_METRICS);
341 break;
342 case signin::GAIA_SERVICE_TYPE_SIGNOUT:
343 UMA_HISTOGRAM_ENUMERATION("Profile.DesktopMenu.GAIASignout", metric,
344 NUM_PROFILE_DESKTOP_MENU_METRICS);
345 break;
346 case signin::GAIA_SERVICE_TYPE_INCOGNITO:
347 UMA_HISTOGRAM_ENUMERATION("Profile.DesktopMenu.GAIAIncognito",
348 metric, NUM_PROFILE_DESKTOP_MENU_METRICS);
349 break;
350 case signin::GAIA_SERVICE_TYPE_ADDSESSION:
351 UMA_HISTOGRAM_ENUMERATION("Profile.DesktopMenu.GAIAAddSession", metric,
352 NUM_PROFILE_DESKTOP_MENU_METRICS);
353 break;
354 case signin::GAIA_SERVICE_TYPE_REAUTH:
355 UMA_HISTOGRAM_ENUMERATION("Profile.DesktopMenu.GAIAReAuth", metric,
356 NUM_PROFILE_DESKTOP_MENU_METRICS);
357 break;
358 case signin::GAIA_SERVICE_TYPE_DEFAULT:
359 UMA_HISTOGRAM_ENUMERATION("Profile.DesktopMenu.GAIADefault", metric,
360 NUM_PROFILE_DESKTOP_MENU_METRICS);
361 break;
362 }
363 }
364
LogProfileDelete(bool profile_was_signed_in)365 void ProfileMetrics::LogProfileDelete(bool profile_was_signed_in) {
366 UMA_HISTOGRAM_BOOLEAN("Profile.Delete", profile_was_signed_in);
367 }
368
369 #if defined(OS_ANDROID)
LogProfileAndroidAccountManagementMenu(ProfileAndroidAccountManagementMenu metric,signin::GAIAServiceType gaia_service)370 void ProfileMetrics::LogProfileAndroidAccountManagementMenu(
371 ProfileAndroidAccountManagementMenu metric,
372 signin::GAIAServiceType gaia_service) {
373 // The first parameter to the histogram needs to be literal, because of the
374 // optimized implementation of |UMA_HISTOGRAM_ENUMERATION|. Do not attempt
375 // to refactor.
376 switch (gaia_service) {
377 case signin::GAIA_SERVICE_TYPE_NONE:
378 UMA_HISTOGRAM_ENUMERATION(
379 "Profile.AndroidAccountManagementMenu.NonGAIA",
380 metric,
381 NUM_PROFILE_ANDROID_ACCOUNT_MANAGEMENT_MENU_METRICS);
382 break;
383 case signin::GAIA_SERVICE_TYPE_SIGNOUT:
384 UMA_HISTOGRAM_ENUMERATION(
385 "Profile.AndroidAccountManagementMenu.GAIASignout",
386 metric,
387 NUM_PROFILE_ANDROID_ACCOUNT_MANAGEMENT_MENU_METRICS);
388 break;
389 case signin::GAIA_SERVICE_TYPE_INCOGNITO:
390 UMA_HISTOGRAM_ENUMERATION(
391 "Profile.AndroidAccountManagementMenu.GAIASignoutIncognito",
392 metric,
393 NUM_PROFILE_ANDROID_ACCOUNT_MANAGEMENT_MENU_METRICS);
394 break;
395 case signin::GAIA_SERVICE_TYPE_ADDSESSION:
396 UMA_HISTOGRAM_ENUMERATION(
397 "Profile.AndroidAccountManagementMenu.GAIAAddSession",
398 metric,
399 NUM_PROFILE_ANDROID_ACCOUNT_MANAGEMENT_MENU_METRICS);
400 break;
401 case signin::GAIA_SERVICE_TYPE_REAUTH:
402 UMA_HISTOGRAM_ENUMERATION(
403 "Profile.AndroidAccountManagementMenu.GAIAReAuth",
404 metric,
405 NUM_PROFILE_ANDROID_ACCOUNT_MANAGEMENT_MENU_METRICS);
406 break;
407 case signin::GAIA_SERVICE_TYPE_DEFAULT:
408 UMA_HISTOGRAM_ENUMERATION(
409 "Profile.AndroidAccountManagementMenu.GAIADefault",
410 metric,
411 NUM_PROFILE_ANDROID_ACCOUNT_MANAGEMENT_MENU_METRICS);
412 break;
413 }
414 }
415 #endif // defined(OS_ANDROID)
416
LogProfileLaunch(Profile * profile)417 void ProfileMetrics::LogProfileLaunch(Profile* profile) {
418 base::FilePath profile_path = profile->GetPath();
419 UMA_HISTOGRAM_ENUMERATION("Profile.LaunchBrowser",
420 GetProfileType(profile_path),
421 NUM_PROFILE_TYPE_METRICS);
422
423 if (profile->IsSupervised()) {
424 content::RecordAction(
425 base::UserMetricsAction("ManagedMode_NewManagedUserWindow"));
426 }
427 }
428
LogProfileSyncSignIn(const base::FilePath & profile_path)429 void ProfileMetrics::LogProfileSyncSignIn(const base::FilePath& profile_path) {
430 UMA_HISTOGRAM_ENUMERATION("Profile.SyncSignIn",
431 GetProfileType(profile_path),
432 NUM_PROFILE_TYPE_METRICS);
433 }
434
LogProfileUpdate(const base::FilePath & profile_path)435 void ProfileMetrics::LogProfileUpdate(const base::FilePath& profile_path) {
436 UMA_HISTOGRAM_ENUMERATION("Profile.Update",
437 GetProfileType(profile_path),
438 NUM_PROFILE_TYPE_METRICS);
439 }
440