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