Home | History | Annotate | Download | only in login
      1 // Copyright (c) 2013 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/chromeos/login/user_image_manager_impl.h"
      6 
      7 #include "base/bind.h"
      8 #include "base/debug/trace_event.h"
      9 #include "base/file_util.h"
     10 #include "base/files/file_path.h"
     11 #include "base/logging.h"
     12 #include "base/metrics/histogram.h"
     13 #include "base/path_service.h"
     14 #include "base/prefs/pref_registry_simple.h"
     15 #include "base/prefs/pref_service.h"
     16 #include "base/rand_util.h"
     17 #include "base/threading/worker_pool.h"
     18 #include "base/time/time.h"
     19 #include "base/values.h"
     20 #include "chrome/browser/browser_process.h"
     21 #include "chrome/browser/chrome_notification_types.h"
     22 #include "chrome/browser/chromeos/login/default_user_images.h"
     23 #include "chrome/browser/chromeos/login/helper.h"
     24 #include "chrome/browser/chromeos/login/user_image.h"
     25 #include "chrome/browser/chromeos/login/user_manager.h"
     26 #include "chrome/browser/prefs/scoped_user_pref_update.h"
     27 #include "chrome/browser/profiles/profile_downloader.h"
     28 #include "chrome/browser/profiles/profile_manager.h"
     29 #include "chrome/common/chrome_paths.h"
     30 #include "content/public/browser/browser_thread.h"
     31 #include "content/public/browser/notification_service.h"
     32 #include "content/public/common/url_constants.h"
     33 #include "ui/gfx/image/image_skia.h"
     34 #include "ui/webui/web_ui_util.h"
     35 
     36 using content::BrowserThread;
     37 
     38 namespace chromeos {
     39 
     40 namespace {
     41 
     42 // A dictionary that maps usernames to old user image data with images stored in
     43 // PNG format. Deprecated.
     44 // TODO(ivankr): remove this const char after migration is gone.
     45 const char kUserImages[] = "UserImages";
     46 
     47 // A dictionary that maps usernames to user image data with images stored in
     48 // JPEG format.
     49 const char kUserImageProperties[] = "user_image_info";
     50 
     51 // Names of user image properties.
     52 const char kImagePathNodeName[] = "path";
     53 const char kImageIndexNodeName[] = "index";
     54 const char kImageURLNodeName[] = "url";
     55 
     56 // Delay betweeen user login and user image migration.
     57 const int kUserImageMigrationDelaySec = 50;
     58 
     59 // Delay betweeen user login and attempt to update user's profile data.
     60 const int kProfileDataDownloadDelaySec = 10;
     61 
     62 // Interval betweeen retries to update user's profile data.
     63 const int kProfileDataDownloadRetryIntervalSec = 300;
     64 
     65 // Delay betweeen subsequent profile refresh attempts (24 hrs).
     66 const int kProfileRefreshIntervalSec = 24 * 3600;
     67 
     68 const char kSafeImagePathExtension[] = ".jpg";
     69 
     70 // Enum for reporting histograms about profile picture download.
     71 enum ProfileDownloadResult {
     72   kDownloadSuccessChanged,
     73   kDownloadSuccess,
     74   kDownloadFailure,
     75   kDownloadDefault,
     76   kDownloadCached,
     77 
     78   // Must be the last, convenient count.
     79   kDownloadResultsCount
     80 };
     81 
     82 // Time histogram prefix for a cached profile image download.
     83 const char kProfileDownloadCachedTime[] =
     84     "UserImage.ProfileDownloadTime.Cached";
     85 // Time histogram prefix for the default profile image download.
     86 const char kProfileDownloadDefaultTime[] =
     87     "UserImage.ProfileDownloadTime.Default";
     88 // Time histogram prefix for a failed profile image download.
     89 const char kProfileDownloadFailureTime[] =
     90     "UserImage.ProfileDownloadTime.Failure";
     91 // Time histogram prefix for a successful profile image download.
     92 const char kProfileDownloadSuccessTime[] =
     93     "UserImage.ProfileDownloadTime.Success";
     94 // Time histogram suffix for a profile image download after login.
     95 const char kProfileDownloadReasonLoggedIn[] = "LoggedIn";
     96 // Time histogram suffix for a scheduled profile image download.
     97 const char kProfileDownloadReasonScheduled[] = "Scheduled";
     98 // Time histogram suffix for a profile image download retry.
     99 const char kProfileDownloadReasonRetry[] = "Retry";
    100 
    101 // Add a histogram showing the time it takes to download a profile image.
    102 // Separate histograms are reported for each download |reason| and |result|.
    103 void AddProfileImageTimeHistogram(ProfileDownloadResult result,
    104                                   const std::string& download_reason,
    105                                   const base::TimeDelta& time_delta) {
    106   std::string histogram_name;
    107   switch (result) {
    108     case kDownloadFailure:
    109       histogram_name = kProfileDownloadFailureTime;
    110       break;
    111     case kDownloadDefault:
    112       histogram_name = kProfileDownloadDefaultTime;
    113       break;
    114     case kDownloadSuccess:
    115       histogram_name = kProfileDownloadSuccessTime;
    116       break;
    117     case kDownloadCached:
    118       histogram_name = kProfileDownloadCachedTime;
    119       break;
    120     default:
    121       NOTREACHED();
    122   }
    123   if (!download_reason.empty()) {
    124     histogram_name += ".";
    125     histogram_name += download_reason;
    126   }
    127 
    128   static const base::TimeDelta min_time = base::TimeDelta::FromMilliseconds(1);
    129   static const base::TimeDelta max_time = base::TimeDelta::FromSeconds(50);
    130   const size_t bucket_count(50);
    131 
    132   base::HistogramBase* counter = base::Histogram::FactoryTimeGet(
    133       histogram_name, min_time, max_time, bucket_count,
    134       base::HistogramBase::kUmaTargetedHistogramFlag);
    135   counter->AddTime(time_delta);
    136 
    137   DVLOG(1) << "Profile image download time: " << time_delta.InSecondsF();
    138 }
    139 
    140 // Deletes image file.
    141 void DeleteImageFile(const std::string& image_path) {
    142   if (image_path.empty())
    143     return;
    144   base::FilePath fp(image_path);
    145   BrowserThread::PostTask(
    146       BrowserThread::FILE,
    147       FROM_HERE,
    148       base::Bind(base::IgnoreResult(&base::DeleteFile),
    149                  fp, /* recursive= */  false));
    150 }
    151 
    152 // Converts |image_index| to UMA histogram value.
    153 int ImageIndexToHistogramIndex(int image_index) {
    154   switch (image_index) {
    155     case User::kExternalImageIndex:
    156       // TODO(ivankr): Distinguish this from selected from file.
    157       return kHistogramImageFromCamera;
    158     case User::kProfileImageIndex:
    159       return kHistogramImageFromProfile;
    160     default:
    161       return image_index;
    162   }
    163 }
    164 
    165 }  // namespace
    166 
    167 // static
    168 int UserImageManagerImpl::user_image_migration_delay_sec =
    169     kUserImageMigrationDelaySec;
    170 
    171 // static
    172 void UserImageManager::RegisterPrefs(PrefRegistrySimple* registry) {
    173   registry->RegisterDictionaryPref(kUserImages);
    174   registry->RegisterDictionaryPref(kUserImageProperties);
    175 }
    176 
    177 UserImageManagerImpl::UserImageManagerImpl()
    178     : image_loader_(new UserImageLoader(ImageDecoder::ROBUST_JPEG_CODEC)),
    179       unsafe_image_loader_(new UserImageLoader(ImageDecoder::DEFAULT_CODEC)),
    180       last_image_set_async_(false),
    181       downloaded_profile_image_data_url_(content::kAboutBlankURL),
    182       downloading_profile_image_(false),
    183       migrate_current_user_on_load_(false) {
    184 }
    185 
    186 UserImageManagerImpl::~UserImageManagerImpl() {
    187 }
    188 
    189 void UserImageManagerImpl::LoadUserImages(const UserList& users) {
    190   PrefService* local_state = g_browser_process->local_state();
    191   const DictionaryValue* prefs_images_unsafe =
    192       local_state->GetDictionary(kUserImages);
    193   const DictionaryValue* prefs_images =
    194       local_state->GetDictionary(kUserImageProperties);
    195   if (!prefs_images && !prefs_images_unsafe)
    196     return;
    197 
    198   for (UserList::const_iterator it = users.begin(); it != users.end(); ++it) {
    199     User* user = *it;
    200     const base::DictionaryValue* image_properties = NULL;
    201     bool needs_migration = false;  // |true| if user has image in old format.
    202     bool safe_source = false;      // |true| if image loaded from safe source.
    203 
    204     if (prefs_images_unsafe) {
    205       needs_migration = prefs_images_unsafe->GetDictionaryWithoutPathExpansion(
    206           user->email(), &image_properties);
    207     }
    208     if (prefs_images) {
    209       safe_source = prefs_images->GetDictionaryWithoutPathExpansion(
    210           user->email(), &image_properties);
    211     }
    212 
    213     if (needs_migration)
    214       users_to_migrate_.insert(user->email());
    215 
    216     if (!image_properties) {
    217       SetInitialUserImage(user->email());
    218     } else {
    219       int image_index = User::kInvalidImageIndex;
    220       image_properties->GetInteger(kImageIndexNodeName, &image_index);
    221 
    222       if (image_index >= 0 && image_index < kDefaultImagesCount) {
    223         user->SetImage(UserImage(GetDefaultImage(image_index)),
    224                        image_index);
    225       } else if (image_index == User::kExternalImageIndex ||
    226                  image_index == User::kProfileImageIndex) {
    227         std::string image_path;
    228         image_properties->GetString(kImagePathNodeName, &image_path);
    229         // Path may be empty for profile images (meaning that the image
    230         // hasn't been downloaded for the first time yet, in which case a
    231         // download will be scheduled for |kProfileDataDownloadDelayMs|
    232         // after user logs in).
    233         DCHECK(!image_path.empty() || image_index == User::kProfileImageIndex);
    234         std::string image_url;
    235         image_properties->GetString(kImageURLNodeName, &image_url);
    236         GURL image_gurl(image_url);
    237         // Until image has been loaded, use the stub image (gray avatar).
    238         user->SetStubImage(image_index, true);
    239         user->SetImageURL(image_gurl);
    240         if (!image_path.empty()) {
    241           if (needs_migration) {
    242             // Non-JPG image will be migrated once user logs in.
    243             // Stub image will be used for now. Continue with other users.
    244             continue;
    245           }
    246           DCHECK(safe_source);
    247           if (!safe_source)
    248             continue;
    249 
    250           // Load user image asynchronously - at this point we are able to use
    251           // JPEG image loaded since image comes from safe pref source
    252           // i.e. converted to JPEG.
    253           image_loader_->Start(
    254               image_path, 0  /* no resize */,
    255               base::Bind(&UserImageManagerImpl::SetUserImage,
    256                          base::Unretained(this),
    257                          user->email(), image_index, image_gurl));
    258         }
    259       } else {
    260         NOTREACHED();
    261       }
    262     }
    263   }
    264 }
    265 
    266 void UserImageManagerImpl::UserLoggedIn(const std::string& email,
    267                                         bool user_is_new,
    268                                         bool user_is_local) {
    269   if (user_is_new) {
    270     if (!user_is_local)
    271       SetInitialUserImage(email);
    272   } else {
    273     User* user = UserManager::Get()->GetLoggedInUser();
    274 
    275     if (!user_is_local) {
    276       // If current user image is profile image, it needs to be refreshed.
    277       bool download_profile_image =
    278           user->image_index() == User::kProfileImageIndex;
    279       if (download_profile_image)
    280         InitDownloadedProfileImage();
    281 
    282       // Download user's profile data (full name and optionally image) to see if
    283       // it has changed.
    284       BrowserThread::PostDelayedTask(
    285           BrowserThread::UI,
    286           FROM_HERE,
    287           base::Bind(&UserImageManagerImpl::DownloadProfileData,
    288                      base::Unretained(this),
    289                      kProfileDownloadReasonLoggedIn,
    290                      download_profile_image),
    291           base::TimeDelta::FromSeconds(kProfileDataDownloadDelaySec));
    292     }
    293 
    294     UMA_HISTOGRAM_ENUMERATION("UserImage.LoggedIn",
    295                               ImageIndexToHistogramIndex(user->image_index()),
    296                               kHistogramImagesCount);
    297 
    298     if (users_to_migrate_.count(email)) {
    299       const DictionaryValue* prefs_images_unsafe =
    300           g_browser_process->local_state()->GetDictionary(kUserImages);
    301       const base::DictionaryValue* image_properties = NULL;
    302       if (prefs_images_unsafe->GetDictionaryWithoutPathExpansion(
    303               user->email(), &image_properties)) {
    304         std::string image_path;
    305         image_properties->GetString(kImagePathNodeName, &image_path);
    306         if (!image_path.empty()) {
    307           // User needs image format migration but
    308           // first we need to load and decode that image.
    309           LOG(INFO) << "Waiting for user image to load before migration";
    310           migrate_current_user_on_load_ = true;
    311               unsafe_image_loader_->Start(
    312                   image_path, 0  /* no resize */,
    313                   base::Bind(&UserImageManagerImpl::SetUserImage,
    314                              base::Unretained(this),
    315                              user->email(),
    316                              user->image_index(),
    317                              user->image_url()));
    318         } else {
    319           // Otherwise migrate user image properties right away.
    320           BrowserThread::PostDelayedTask(
    321               BrowserThread::UI,
    322               FROM_HERE,
    323               base::Bind(&UserImageManagerImpl::MigrateUserImage,
    324                          base::Unretained(this)),
    325               base::TimeDelta::FromSeconds(user_image_migration_delay_sec));
    326         }
    327       }
    328     }
    329   }
    330 
    331   if (!user_is_local) {
    332     // Set up a repeating timer for refreshing the profile data.
    333     profile_download_timer_.Start(
    334         FROM_HERE, base::TimeDelta::FromSeconds(kProfileRefreshIntervalSec),
    335         this, &UserImageManagerImpl::DownloadProfileDataScheduled);
    336   }
    337 }
    338 
    339 void UserImageManagerImpl::SaveUserDefaultImageIndex(
    340     const std::string& username,
    341     int image_index) {
    342   DCHECK(image_index >= 0 && image_index < kDefaultImagesCount);
    343   SetUserImage(username, image_index, GURL(),
    344                UserImage(GetDefaultImage(image_index)));
    345   SaveImageToLocalState(username, "", image_index, GURL(), false);
    346 }
    347 
    348 void UserImageManagerImpl::SaveUserImage(const std::string& username,
    349                                          const UserImage& user_image) {
    350   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    351   SaveUserImageInternal(username, User::kExternalImageIndex,
    352                         GURL(), user_image);
    353 }
    354 
    355 void UserImageManagerImpl::SaveUserImageFromFile(const std::string& username,
    356                                                  const base::FilePath& path) {
    357   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    358   // Always use unsafe image loader because we resize the image when saving
    359   // anyway.
    360   unsafe_image_loader_->Start(
    361       path.value(), login::kMaxUserImageSize,
    362       base::Bind(&UserImageManagerImpl::SaveUserImage,
    363                  base::Unretained(this), username));
    364 }
    365 
    366 void UserImageManagerImpl::SaveUserImageFromProfileImage(
    367     const std::string& username) {
    368   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    369   if (!downloaded_profile_image_.isNull()) {
    370     // Profile image has already been downloaded, so save it to file right now.
    371     DCHECK(profile_image_url_.is_valid());
    372     SaveUserImageInternal(
    373         username,
    374         User::kProfileImageIndex, profile_image_url_,
    375         UserImage::CreateAndEncode(downloaded_profile_image_));
    376   } else {
    377     // No profile image - use the stub image (gray avatar).
    378     SetUserImage(username, User::kProfileImageIndex, GURL(), UserImage());
    379     SaveImageToLocalState(username, "", User::kProfileImageIndex,
    380                           GURL(), false);
    381   }
    382 }
    383 
    384 void UserImageManagerImpl::DeleteUserImage(const std::string& username) {
    385   // Delete from the old dictionary, if present.
    386   DeleteOldUserImage(username);
    387 
    388   PrefService* prefs = g_browser_process->local_state();
    389   DictionaryPrefUpdate prefs_images_update(prefs, kUserImageProperties);
    390   const base::DictionaryValue* image_properties;
    391   if (prefs_images_update->GetDictionaryWithoutPathExpansion(
    392           username, &image_properties)) {
    393     std::string image_path;
    394     image_properties->GetString(kImageURLNodeName, &image_path);
    395     prefs_images_update->RemoveWithoutPathExpansion(username, NULL);
    396     DeleteImageFile(image_path);
    397   }
    398 }
    399 
    400 void UserImageManagerImpl::DownloadProfileImage(const std::string& reason) {
    401   DownloadProfileData(reason, true);
    402 }
    403 
    404 void UserImageManagerImpl::Shutdown() {
    405   profile_image_downloader_.reset();
    406 }
    407 
    408 const gfx::ImageSkia& UserImageManagerImpl::DownloadedProfileImage() const {
    409   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    410   return downloaded_profile_image_;
    411 }
    412 
    413 base::FilePath UserImageManagerImpl::GetImagePathForUser(
    414     const std::string& username) {
    415   std::string filename = username + kSafeImagePathExtension;
    416   base::FilePath user_data_dir;
    417   PathService::Get(chrome::DIR_USER_DATA, &user_data_dir);
    418   return user_data_dir.AppendASCII(filename);
    419 }
    420 
    421 void UserImageManagerImpl::SetInitialUserImage(const std::string& username) {
    422   // Choose a random default image.
    423   int image_id =
    424       base::RandInt(kFirstDefaultImageIndex, kDefaultImagesCount - 1);
    425   SaveUserDefaultImageIndex(username, image_id);
    426 }
    427 
    428 void UserImageManagerImpl::SetUserImage(const std::string& username,
    429                                         int image_index,
    430                                         const GURL& image_url,
    431                                         const UserImage& user_image) {
    432   User* user = const_cast<User*>(UserManager::Get()->FindUser(username));
    433   // User may have been removed by now.
    434   if (user) {
    435     bool image_changed = user->image_index() != User::kInvalidImageIndex;
    436     bool is_current_user = user == UserManager::Get()->GetLoggedInUser();
    437     if (!user_image.image().isNull())
    438       user->SetImage(user_image, image_index);
    439     else
    440       user->SetStubImage(image_index, false);
    441     user->SetImageURL(image_url);
    442     // For the logged-in user with a profile picture, initialize
    443     // |downloaded_profile_picture_|.
    444     if (is_current_user && image_index == User::kProfileImageIndex) {
    445       InitDownloadedProfileImage();
    446     }
    447     if (image_changed) {
    448       // Unless this is first-time setting with |SetInitialUserImage|,
    449       // send a notification about image change.
    450       content::NotificationService::current()->Notify(
    451           chrome::NOTIFICATION_LOGIN_USER_IMAGE_CHANGED,
    452           content::Source<UserImageManager>(this),
    453           content::Details<const User>(user));
    454     }
    455     if (is_current_user && migrate_current_user_on_load_)
    456       MigrateUserImage();
    457   }
    458 }
    459 
    460 void UserImageManagerImpl::SaveUserImageInternal(const std::string& username,
    461                                                  int image_index,
    462                                                  const GURL& image_url,
    463                                                  const UserImage& user_image) {
    464   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    465 
    466   SetUserImage(username, image_index, image_url, user_image);
    467 
    468   // Ignore if data stored or cached outside the user's cryptohome is to be
    469   // treated as ephemeral.
    470   if (UserManager::Get()->IsUserNonCryptohomeDataEphemeral(username))
    471     return;
    472 
    473   base::FilePath image_path = GetImagePathForUser(username);
    474   DVLOG(1) << "Saving user image to " << image_path.value();
    475 
    476   last_image_set_async_ = true;
    477 
    478   base::WorkerPool::PostTask(
    479       FROM_HERE,
    480       base::Bind(&UserImageManagerImpl::SaveImageToFile,
    481                  base::Unretained(this),
    482                  username, user_image, image_path, image_index, image_url),
    483       /* is_slow= */ false);
    484 }
    485 
    486 void UserImageManagerImpl::SaveImageToFile(const std::string& username,
    487                                            const UserImage& user_image,
    488                                            const base::FilePath& image_path,
    489                                            int image_index,
    490                                            const GURL& image_url) {
    491   if (!SaveBitmapToFile(user_image, image_path))
    492     return;
    493 
    494   BrowserThread::PostTask(
    495       BrowserThread::UI,
    496       FROM_HERE,
    497       base::Bind(&UserImageManagerImpl::SaveImageToLocalState,
    498                  base::Unretained(this),
    499                  username, image_path.value(), image_index, image_url, true));
    500 }
    501 
    502 void UserImageManagerImpl::SaveImageToLocalState(const std::string& username,
    503                                                  const std::string& image_path,
    504                                                  int image_index,
    505                                                  const GURL& image_url,
    506                                                  bool is_async) {
    507   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    508 
    509   // Ignore if data stored or cached outside the user's cryptohome is to be
    510   // treated as ephemeral.
    511   if (UserManager::Get()->IsUserNonCryptohomeDataEphemeral(username))
    512     return;
    513 
    514   // TODO(ivankr): use unique filenames for user images each time
    515   // a new image is set so that only the last image update is saved
    516   // to Local State and notified.
    517   if (is_async && !last_image_set_async_) {
    518     DVLOG(1) << "Ignoring saved image because it has changed";
    519     return;
    520   } else if (!is_async) {
    521     // Reset the async image save flag if called directly from the UI thread.
    522     last_image_set_async_ = false;
    523   }
    524 
    525   PrefService* local_state = g_browser_process->local_state();
    526   DictionaryPrefUpdate images_update(local_state, kUserImageProperties);
    527   base::DictionaryValue* image_properties = new base::DictionaryValue();
    528   image_properties->Set(kImagePathNodeName, new StringValue(image_path));
    529   image_properties->Set(kImageIndexNodeName,
    530                         new base::FundamentalValue(image_index));
    531   if (!image_url.is_empty()) {
    532     image_properties->Set(kImageURLNodeName,
    533                           new StringValue(image_url.spec()));
    534   } else {
    535     image_properties->Remove(kImageURLNodeName, NULL);
    536   }
    537   images_update->SetWithoutPathExpansion(username, image_properties);
    538   DVLOG(1) << "Saving path to user image in Local State.";
    539 
    540   if (users_to_migrate_.count(username)) {
    541     DeleteOldUserImage(username);
    542     users_to_migrate_.erase(username);
    543   }
    544 
    545   UserManager::Get()->NotifyLocalStateChanged();
    546 }
    547 
    548 bool UserImageManagerImpl::SaveBitmapToFile(const UserImage& user_image,
    549                                             const base::FilePath& image_path) {
    550   UserImage safe_image;
    551   const UserImage::RawImage* encoded_image = NULL;
    552   if (!user_image.is_safe_format()) {
    553     safe_image = UserImage::CreateAndEncode(user_image.image());
    554     encoded_image = &safe_image.raw_image();
    555     UMA_HISTOGRAM_MEMORY_KB("UserImage.RecodedJpegSize", encoded_image->size());
    556   } else if (user_image.has_raw_image()) {
    557     encoded_image = &user_image.raw_image();
    558   } else {
    559     NOTREACHED() << "Raw image missing.";
    560     return false;
    561   }
    562 
    563   if (file_util::WriteFile(image_path,
    564                            reinterpret_cast<const char*>(&(*encoded_image)[0]),
    565                            encoded_image->size()) == -1) {
    566     LOG(ERROR) << "Failed to save image to file.";
    567     return false;
    568   }
    569   return true;
    570 }
    571 
    572 void UserImageManagerImpl::InitDownloadedProfileImage() {
    573   const User* logged_in_user = UserManager::Get()->GetLoggedInUser();
    574   DCHECK_EQ(logged_in_user->image_index(), User::kProfileImageIndex);
    575   if (downloaded_profile_image_.isNull() && !logged_in_user->image_is_stub()) {
    576     VLOG(1) << "Profile image initialized";
    577     downloaded_profile_image_ = logged_in_user->image();
    578     downloaded_profile_image_data_url_ =
    579         webui::GetBitmapDataUrl(*downloaded_profile_image_.bitmap());
    580     profile_image_url_ = logged_in_user->image_url();
    581   }
    582 }
    583 
    584 void UserImageManagerImpl::DownloadProfileData(const std::string& reason,
    585                                                bool download_image) {
    586   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    587 
    588   // GAIA profiles exist for regular users only.
    589   if (!UserManager::Get()->IsLoggedInAsRegularUser())
    590     return;
    591 
    592   // Mark profile picture as needed.
    593   downloading_profile_image_ |= download_image;
    594 
    595   // Another download is already in progress
    596   if (profile_image_downloader_.get())
    597     return;
    598 
    599   profile_image_download_reason_ = reason;
    600   profile_image_load_start_time_ = base::Time::Now();
    601   profile_image_downloader_.reset(new ProfileDownloader(this));
    602   profile_image_downloader_->Start();
    603 }
    604 
    605 void UserImageManagerImpl::DownloadProfileDataScheduled() {
    606   const User* logged_in_user = UserManager::Get()->GetLoggedInUser();
    607   // If current user image is profile image, it needs to be refreshed.
    608   bool download_profile_image =
    609       logged_in_user->image_index() == User::kProfileImageIndex;
    610   DownloadProfileData(kProfileDownloadReasonScheduled, download_profile_image);
    611 }
    612 
    613 void UserImageManagerImpl::DownloadProfileDataRetry(bool download_image) {
    614   DownloadProfileData(kProfileDownloadReasonRetry, download_image);
    615 }
    616 
    617 // ProfileDownloaderDelegate override.
    618 bool UserImageManagerImpl::NeedsProfilePicture() const {
    619   return downloading_profile_image_;
    620 }
    621 
    622 // ProfileDownloaderDelegate override.
    623 int UserImageManagerImpl::GetDesiredImageSideLength() const {
    624   return GetCurrentUserImageSize();
    625 }
    626 
    627 // ProfileDownloaderDelegate override.
    628 std::string UserImageManagerImpl::GetCachedPictureURL() const {
    629   return profile_image_url_.spec();
    630 }
    631 
    632 Profile* UserImageManagerImpl::GetBrowserProfile() {
    633   return ProfileManager::GetDefaultProfile();
    634 }
    635 
    636 void UserImageManagerImpl::OnProfileDownloadSuccess(
    637     ProfileDownloader* downloader) {
    638   // Make sure that |ProfileDownloader| gets deleted after return.
    639   scoped_ptr<ProfileDownloader> profile_image_downloader(
    640       profile_image_downloader_.release());
    641   DCHECK_EQ(downloader, profile_image_downloader.get());
    642 
    643   UserManager* user_manager = UserManager::Get();
    644   const User* user = user_manager->GetLoggedInUser();
    645 
    646   if (!downloader->GetProfileFullName().empty()) {
    647     user_manager->SaveUserDisplayName(
    648         user->email(), downloader->GetProfileFullName());
    649   }
    650 
    651   bool requested_image = downloading_profile_image_;
    652   downloading_profile_image_ = false;
    653   if (!requested_image)
    654     return;
    655 
    656   ProfileDownloadResult result = kDownloadFailure;
    657   switch (downloader->GetProfilePictureStatus()) {
    658     case ProfileDownloader::PICTURE_SUCCESS:
    659       result = kDownloadSuccess;
    660       break;
    661     case ProfileDownloader::PICTURE_CACHED:
    662       result = kDownloadCached;
    663       break;
    664     case ProfileDownloader::PICTURE_DEFAULT:
    665       result = kDownloadDefault;
    666       break;
    667     default:
    668       NOTREACHED();
    669   }
    670 
    671   UMA_HISTOGRAM_ENUMERATION("UserImage.ProfileDownloadResult",
    672       result, kDownloadResultsCount);
    673 
    674   DCHECK(!profile_image_load_start_time_.is_null());
    675   base::TimeDelta delta = base::Time::Now() - profile_image_load_start_time_;
    676   AddProfileImageTimeHistogram(result, profile_image_download_reason_, delta);
    677 
    678   if (result == kDownloadDefault) {
    679     content::NotificationService::current()->Notify(
    680         chrome::NOTIFICATION_PROFILE_IMAGE_UPDATE_FAILED,
    681         content::Source<UserImageManager>(this),
    682         content::NotificationService::NoDetails());
    683   }
    684 
    685   // Nothing to do if picture is cached or the default avatar.
    686   if (result != kDownloadSuccess)
    687     return;
    688 
    689   // Check if this image is not the same as already downloaded.
    690   SkBitmap new_bitmap(downloader->GetProfilePicture());
    691   std::string new_image_data_url = webui::GetBitmapDataUrl(new_bitmap);
    692   if (!downloaded_profile_image_data_url_.empty() &&
    693       new_image_data_url == downloaded_profile_image_data_url_)
    694     return;
    695 
    696   downloaded_profile_image_data_url_ = new_image_data_url;
    697   downloaded_profile_image_ = gfx::ImageSkia::CreateFrom1xBitmap(
    698       downloader->GetProfilePicture());
    699   profile_image_url_ = GURL(downloader->GetProfilePictureURL());
    700 
    701   if (user->image_index() == User::kProfileImageIndex) {
    702     VLOG(1) << "Updating profile image for logged-in user";
    703     UMA_HISTOGRAM_ENUMERATION("UserImage.ProfileDownloadResult",
    704                               kDownloadSuccessChanged,
    705                               kDownloadResultsCount);
    706     // This will persist |downloaded_profile_image_| to file.
    707     SaveUserImageFromProfileImage(user->email());
    708   }
    709 
    710   content::NotificationService::current()->Notify(
    711       chrome::NOTIFICATION_PROFILE_IMAGE_UPDATED,
    712       content::Source<UserImageManager>(this),
    713       content::Details<const gfx::ImageSkia>(&downloaded_profile_image_));
    714 }
    715 
    716 void UserImageManagerImpl::OnProfileDownloadFailure(
    717     ProfileDownloader* downloader,
    718     ProfileDownloaderDelegate::FailureReason reason) {
    719   DCHECK_EQ(downloader, profile_image_downloader_.get());
    720   profile_image_downloader_.reset();
    721 
    722   UMA_HISTOGRAM_ENUMERATION("UserImage.ProfileDownloadResult",
    723       kDownloadFailure, kDownloadResultsCount);
    724 
    725   DCHECK(!profile_image_load_start_time_.is_null());
    726   base::TimeDelta delta = base::Time::Now() - profile_image_load_start_time_;
    727   AddProfileImageTimeHistogram(kDownloadFailure, profile_image_download_reason_,
    728                                delta);
    729 
    730   // Retry download after some time if a network error has occured.
    731   if (reason == ProfileDownloaderDelegate::NETWORK_ERROR) {
    732     BrowserThread::PostDelayedTask(
    733         BrowserThread::UI,
    734         FROM_HERE,
    735         base::Bind(&UserImageManagerImpl::DownloadProfileDataRetry,
    736                    base::Unretained(this),
    737                    downloading_profile_image_),
    738         base::TimeDelta::FromSeconds(kProfileDataDownloadRetryIntervalSec));
    739   }
    740 
    741   downloading_profile_image_ = false;
    742 
    743   content::NotificationService::current()->Notify(
    744       chrome::NOTIFICATION_PROFILE_IMAGE_UPDATE_FAILED,
    745       content::Source<UserImageManager>(this),
    746       content::NotificationService::NoDetails());
    747 }
    748 
    749 void UserImageManagerImpl::MigrateUserImage() {
    750   User* user = UserManager::Get()->GetLoggedInUser();
    751   if (user->image_is_loading()) {
    752     LOG(INFO) << "Waiting for user image to load before migration";
    753     migrate_current_user_on_load_ = true;
    754     return;
    755   }
    756   migrate_current_user_on_load_ = false;
    757   if (user->has_raw_image() && user->image_is_safe_format()) {
    758     // Nothing to migrate already, make sure we delete old image.
    759     DeleteOldUserImage(user->email());
    760     users_to_migrate_.erase(user->email());
    761     return;
    762   }
    763   if (user->HasDefaultImage()) {
    764     SaveUserDefaultImageIndex(user->email(), user->image_index());
    765   } else {
    766     SaveUserImageInternal(user->email(), user->image_index(),
    767                           user->image_url(), user->user_image());
    768   }
    769   UMA_HISTOGRAM_ENUMERATION("UserImage.Migration",
    770                             ImageIndexToHistogramIndex(user->image_index()),
    771                             kHistogramImagesCount);
    772 }
    773 
    774 void UserImageManagerImpl::DeleteOldUserImage(const std::string& username) {
    775   PrefService* prefs = g_browser_process->local_state();
    776   DictionaryPrefUpdate prefs_images_update(prefs, kUserImages);
    777   const base::DictionaryValue* image_properties;
    778   if (prefs_images_update->GetDictionaryWithoutPathExpansion(
    779           username, &image_properties)) {
    780     std::string image_path;
    781     image_properties->GetString(kImagePathNodeName, &image_path);
    782     prefs_images_update->RemoveWithoutPathExpansion(username, NULL);
    783     DeleteImageFile(image_path);
    784   }
    785 }
    786 
    787 }  // namespace chromeos
    788