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 struct ProfileCounts {
     26   size_t total;
     27   size_t signedin;
     28   size_t supervised;
     29   size_t unused;
     30   size_t gaia_icon;
     31 
     32   ProfileCounts()
     33       : total(0), signedin(0), supervised(0), unused(0), gaia_icon(0) {}
     34 };
     35 
     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 
     52 void UpdateReportedOSProfileStatistics(int active, int signedin) {
     53 #if defined(OS_WIN)
     54   GoogleUpdateSettings::UpdateProfileCounts(active, signedin);
     55 #endif
     56 }
     57 
     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 
     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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    320 void ProfileMetrics::LogProfileAuthResult(ProfileAuth metric) {
    321   UMA_HISTOGRAM_ENUMERATION("Profile.AuthResult", metric,
    322                             NUM_PROFILE_AUTH_METRICS);
    323 }
    324 
    325 void ProfileMetrics::LogProfileUpgradeEnrollment(
    326     ProfileUpgradeEnrollment metric) {
    327   UMA_HISTOGRAM_ENUMERATION("Profile.UpgradeEnrollment", metric,
    328                             NUM_PROFILE_ENROLLMENT_METRICS);
    329 }
    330 
    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 
    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)
    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 
    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 
    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 
    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