Home | History | Annotate | Download | only in avatar
      1 // Copyright 2014 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/users/avatar/user_image_manager_impl.h"
      6 
      7 #include "base/bind.h"
      8 #include "base/debug/trace_event.h"
      9 #include "base/files/file_path.h"
     10 #include "base/files/file_util.h"
     11 #include "base/logging.h"
     12 #include "base/message_loop/message_loop_proxy.h"
     13 #include "base/metrics/histogram.h"
     14 #include "base/path_service.h"
     15 #include "base/prefs/pref_registry_simple.h"
     16 #include "base/prefs/pref_service.h"
     17 #include "base/prefs/scoped_user_pref_update.h"
     18 #include "base/rand_util.h"
     19 #include "base/sequenced_task_runner.h"
     20 #include "base/task_runner_util.h"
     21 #include "base/threading/sequenced_worker_pool.h"
     22 #include "base/time/time.h"
     23 #include "base/values.h"
     24 #include "chrome/browser/browser_process.h"
     25 #include "chrome/browser/chrome_notification_types.h"
     26 #include "chrome/browser/chromeos/login/helper.h"
     27 #include "chrome/browser/chromeos/login/users/avatar/user_image_sync_observer.h"
     28 #include "chrome/browser/chromeos/profiles/profile_helper.h"
     29 #include "chrome/browser/profiles/profile_downloader.h"
     30 #include "chrome/browser/profiles/profile_manager.h"
     31 #include "chrome/common/chrome_paths.h"
     32 #include "chrome/grit/theme_resources.h"
     33 #include "components/user_manager/user_image/default_user_images.h"
     34 #include "components/user_manager/user_image/user_image.h"
     35 #include "components/user_manager/user_manager.h"
     36 #include "components/user_manager/user_type.h"
     37 #include "content/public/browser/browser_thread.h"
     38 #include "content/public/browser/notification_service.h"
     39 #include "policy/policy_constants.h"
     40 #include "ui/base/resource/resource_bundle.h"
     41 #include "ui/gfx/image/image_skia.h"
     42 
     43 namespace chromeos {
     44 
     45 namespace {
     46 
     47 // A dictionary that maps user_ids to old user image data with images stored in
     48 // PNG format. Deprecated.
     49 // TODO(ivankr): remove this const char after migration is gone.
     50 const char kUserImages[] = "UserImages";
     51 
     52 // A dictionary that maps user_ids to user image data with images stored in
     53 // JPEG format.
     54 const char kUserImageProperties[] = "user_image_info";
     55 
     56 // Names of user image properties.
     57 const char kImagePathNodeName[] = "path";
     58 const char kImageIndexNodeName[] = "index";
     59 const char kImageURLNodeName[] = "url";
     60 
     61 // Delay betweeen user login and attempt to update user's profile data.
     62 const int kProfileDataDownloadDelaySec = 10;
     63 
     64 // Interval betweeen retries to update user's profile data.
     65 const int kProfileDataDownloadRetryIntervalSec = 300;
     66 
     67 // Delay betweeen subsequent profile refresh attempts (24 hrs).
     68 const int kProfileRefreshIntervalSec = 24 * 3600;
     69 
     70 const char kSafeImagePathExtension[] = ".jpg";
     71 
     72 // Enum for reporting histograms about profile picture download.
     73 enum ProfileDownloadResult {
     74   kDownloadSuccessChanged,
     75   kDownloadSuccess,
     76   kDownloadFailure,
     77   kDownloadDefault,
     78   kDownloadCached,
     79 
     80   // Must be the last, convenient count.
     81   kDownloadResultsCount
     82 };
     83 
     84 // Time histogram prefix for a cached profile image download.
     85 const char kProfileDownloadCachedTime[] =
     86     "UserImage.ProfileDownloadTime.Cached";
     87 // Time histogram prefix for the default profile image download.
     88 const char kProfileDownloadDefaultTime[] =
     89     "UserImage.ProfileDownloadTime.Default";
     90 // Time histogram prefix for a failed profile image download.
     91 const char kProfileDownloadFailureTime[] =
     92     "UserImage.ProfileDownloadTime.Failure";
     93 // Time histogram prefix for a successful profile image download.
     94 const char kProfileDownloadSuccessTime[] =
     95     "UserImage.ProfileDownloadTime.Success";
     96 // Time histogram suffix for a profile image download after login.
     97 const char kProfileDownloadReasonLoggedIn[] = "LoggedIn";
     98 // Time histogram suffix for a profile image download when the user chooses the
     99 // profile image but it has not been downloaded yet.
    100 const char kProfileDownloadReasonProfileImageChosen[] = "ProfileImageChosen";
    101 // Time histogram suffix for a scheduled profile image download.
    102 const char kProfileDownloadReasonScheduled[] = "Scheduled";
    103 // Time histogram suffix for a profile image download retry.
    104 const char kProfileDownloadReasonRetry[] = "Retry";
    105 
    106 static bool g_ignore_profile_data_download_delay_ = false;
    107 
    108 // Add a histogram showing the time it takes to download profile image.
    109 // Separate histograms are reported for each download |reason| and |result|.
    110 void AddProfileImageTimeHistogram(ProfileDownloadResult result,
    111                                   const std::string& download_reason,
    112                                   const base::TimeDelta& time_delta) {
    113   std::string histogram_name;
    114   switch (result) {
    115     case kDownloadFailure:
    116       histogram_name = kProfileDownloadFailureTime;
    117       break;
    118     case kDownloadDefault:
    119       histogram_name = kProfileDownloadDefaultTime;
    120       break;
    121     case kDownloadSuccess:
    122       histogram_name = kProfileDownloadSuccessTime;
    123       break;
    124     case kDownloadCached:
    125       histogram_name = kProfileDownloadCachedTime;
    126       break;
    127     default:
    128       NOTREACHED();
    129   }
    130   if (!download_reason.empty()) {
    131     histogram_name += ".";
    132     histogram_name += download_reason;
    133   }
    134 
    135   static const base::TimeDelta min_time = base::TimeDelta::FromMilliseconds(1);
    136   static const base::TimeDelta max_time = base::TimeDelta::FromSeconds(50);
    137   const size_t bucket_count(50);
    138 
    139   base::HistogramBase* counter = base::Histogram::FactoryTimeGet(
    140       histogram_name, min_time, max_time, bucket_count,
    141       base::HistogramBase::kUmaTargetedHistogramFlag);
    142   counter->AddTime(time_delta);
    143 
    144   DVLOG(1) << "Profile image download time: " << time_delta.InSecondsF();
    145 }
    146 
    147 // Converts |image_index| to UMA histogram value.
    148 int ImageIndexToHistogramIndex(int image_index) {
    149   switch (image_index) {
    150     case user_manager::User::USER_IMAGE_EXTERNAL:
    151       // TODO(ivankr): Distinguish this from selected from file.
    152       return user_manager::kHistogramImageFromCamera;
    153     case user_manager::User::USER_IMAGE_PROFILE:
    154       return user_manager::kHistogramImageFromProfile;
    155     default:
    156       return image_index;
    157   }
    158 }
    159 
    160 bool SaveImage(const user_manager::UserImage& user_image,
    161                const base::FilePath& image_path) {
    162   user_manager::UserImage safe_image;
    163   const user_manager::UserImage::RawImage* encoded_image = NULL;
    164   if (!user_image.is_safe_format()) {
    165     safe_image = user_manager::UserImage::CreateAndEncode(user_image.image());
    166     encoded_image = &safe_image.raw_image();
    167     UMA_HISTOGRAM_MEMORY_KB("UserImage.RecodedJpegSize", encoded_image->size());
    168   } else if (user_image.has_raw_image()) {
    169     encoded_image = &user_image.raw_image();
    170   } else {
    171     NOTREACHED() << "Raw image missing.";
    172     return false;
    173   }
    174 
    175   if (!encoded_image->size() ||
    176       base::WriteFile(image_path,
    177                       reinterpret_cast<const char*>(&(*encoded_image)[0]),
    178                       encoded_image->size()) == -1) {
    179     LOG(ERROR) << "Failed to save image to file.";
    180     return false;
    181   }
    182 
    183   return true;
    184 }
    185 
    186 }  // namespace
    187 
    188 // static
    189 void UserImageManager::RegisterPrefs(PrefRegistrySimple* registry) {
    190   registry->RegisterDictionaryPref(kUserImages);
    191   registry->RegisterDictionaryPref(kUserImageProperties);
    192 }
    193 
    194 // Every image load or update is encapsulated by a Job. The Job is allowed to
    195 // perform tasks on background threads or in helper processes but:
    196 // * Changes to User objects and local state as well as any calls to the
    197 //   |parent_| must be performed on the thread that the Job is created on only.
    198 // * File writes and deletions must be performed via the |parent_|'s
    199 //   |background_task_runner_| only.
    200 //
    201 // Only one of the Load*() and Set*() methods may be called per Job.
    202 class UserImageManagerImpl::Job {
    203  public:
    204   // The |Job| will update the user object corresponding to |parent|.
    205   explicit Job(UserImageManagerImpl* parent);
    206   ~Job();
    207 
    208   // Loads the image at |image_path| or one of the default images,
    209   // depending on |image_index|, and updates the user object with the
    210   // new image.
    211   void LoadImage(base::FilePath image_path,
    212                  const int image_index,
    213                  const GURL& image_url);
    214 
    215   // Sets the user image in local state to the default image indicated
    216   // by |default_image_index|. Also updates the user object with the
    217   // new image.
    218   void SetToDefaultImage(int default_image_index);
    219 
    220   // Saves the |user_image| to disk and sets the user image in local
    221   // state to that image. Also updates the user with the new image.
    222   void SetToImage(int image_index, const user_manager::UserImage& user_image);
    223 
    224   // Decodes the JPEG image |data|, crops and resizes the image, saves
    225   // it to disk and sets the user image in local state to that image.
    226   // Also updates the user object with the new image.
    227   void SetToImageData(scoped_ptr<std::string> data);
    228 
    229   // Loads the image at |path|, transcodes it to JPEG format, saves
    230   // the image to disk and sets the user image in local state to that
    231   // image.  If |resize| is true, the image is cropped and resized
    232   // before transcoding.  Also updates the user object with the new
    233   // image.
    234   void SetToPath(const base::FilePath& path,
    235                  int image_index,
    236                  const GURL& image_url,
    237                  bool resize);
    238 
    239  private:
    240   // Called back after an image has been loaded from disk.
    241   void OnLoadImageDone(bool save, const user_manager::UserImage& user_image);
    242 
    243   // Updates the user object with |user_image_|.
    244   void UpdateUser();
    245 
    246   // Saves |user_image_| to disk in JPEG format. Local state will be updated
    247   // when a callback indicates that the image has been saved.
    248   void SaveImageAndUpdateLocalState();
    249 
    250   // Called back after the |user_image_| has been saved to
    251   // disk. Updates the user image information in local state. The
    252   // information is only updated if |success| is true (indicating that
    253   // the image was saved successfully) or the user image is the
    254   // profile image (indicating that even if the image could not be
    255   // saved because it is not available right now, it will be
    256   // downloaded eventually).
    257   void OnSaveImageDone(bool success);
    258 
    259   // Updates the user image in local state, setting it to one of the
    260   // default images or the saved |user_image_|, depending on
    261   // |image_index_|.
    262   void UpdateLocalState();
    263 
    264   // Notifies the |parent_| that the Job is done.
    265   void NotifyJobDone();
    266 
    267   const std::string& user_id() const { return parent_->user_id(); }
    268 
    269   UserImageManagerImpl* parent_;
    270 
    271   // Whether one of the Load*() or Set*() methods has been run already.
    272   bool run_;
    273 
    274   int image_index_;
    275   GURL image_url_;
    276   base::FilePath image_path_;
    277 
    278   user_manager::UserImage user_image_;
    279 
    280   base::WeakPtrFactory<Job> weak_factory_;
    281 
    282   DISALLOW_COPY_AND_ASSIGN(Job);
    283 };
    284 
    285 UserImageManagerImpl::Job::Job(UserImageManagerImpl* parent)
    286     : parent_(parent),
    287       run_(false),
    288       weak_factory_(this) {
    289 }
    290 
    291 UserImageManagerImpl::Job::~Job() {
    292 }
    293 
    294 void UserImageManagerImpl::Job::LoadImage(base::FilePath image_path,
    295                                           const int image_index,
    296                                           const GURL& image_url) {
    297   DCHECK(!run_);
    298   run_ = true;
    299 
    300   image_index_ = image_index;
    301   image_url_ = image_url;
    302   image_path_ = image_path;
    303 
    304   if (image_index_ >= 0 && image_index_ < user_manager::kDefaultImagesCount) {
    305     // Load one of the default images. This happens synchronously.
    306     user_image_ =
    307         user_manager::UserImage(user_manager::GetDefaultImage(image_index_));
    308     UpdateUser();
    309     NotifyJobDone();
    310   } else if (image_index_ == user_manager::User::USER_IMAGE_EXTERNAL ||
    311              image_index_ == user_manager::User::USER_IMAGE_PROFILE) {
    312     // Load the user image from a file referenced by |image_path|. This happens
    313     // asynchronously. The JPEG image loader can be used here because
    314     // LoadImage() is called only for users whose user image has previously
    315     // been set by one of the Set*() methods, which transcode to JPEG format.
    316     DCHECK(!image_path_.empty());
    317     parent_->image_loader_->Start(image_path_.value(),
    318                                   0,
    319                                   base::Bind(&Job::OnLoadImageDone,
    320                                              weak_factory_.GetWeakPtr(),
    321                                              false));
    322   } else {
    323     NOTREACHED();
    324     NotifyJobDone();
    325   }
    326 }
    327 
    328 void UserImageManagerImpl::Job::SetToDefaultImage(int default_image_index) {
    329   DCHECK(!run_);
    330   run_ = true;
    331 
    332   DCHECK_LE(0, default_image_index);
    333   DCHECK_GT(user_manager::kDefaultImagesCount, default_image_index);
    334 
    335   image_index_ = default_image_index;
    336   user_image_ =
    337       user_manager::UserImage(user_manager::GetDefaultImage(image_index_));
    338 
    339   UpdateUser();
    340   UpdateLocalState();
    341   NotifyJobDone();
    342 }
    343 
    344 void UserImageManagerImpl::Job::SetToImage(
    345     int image_index,
    346     const user_manager::UserImage& user_image) {
    347   DCHECK(!run_);
    348   run_ = true;
    349 
    350   DCHECK(image_index == user_manager::User::USER_IMAGE_EXTERNAL ||
    351          image_index == user_manager::User::USER_IMAGE_PROFILE);
    352 
    353   image_index_ = image_index;
    354   user_image_ = user_image;
    355 
    356   UpdateUser();
    357   SaveImageAndUpdateLocalState();
    358 }
    359 
    360 void UserImageManagerImpl::Job::SetToImageData(scoped_ptr<std::string> data) {
    361   DCHECK(!run_);
    362   run_ = true;
    363 
    364   image_index_ = user_manager::User::USER_IMAGE_EXTERNAL;
    365 
    366   // This method uses the image_loader_, not the unsafe_image_loader_:
    367   // * This is necessary because the method is used to update the user image
    368   //   whenever the policy for a user is set. In the case of device-local
    369   //   accounts, policy may change at any time, even if the user is not
    370   //   currently logged in (and thus, the unsafe_image_loader_ may not be used).
    371   // * This is possible because only JPEG |data| is accepted. No support for
    372   //   other image file formats is needed.
    373   // * This is safe because the image_loader_ employs a hardened JPEG decoder
    374   //   that protects against malicious invalid image data being used to attack
    375   //   the login screen or another user session currently in progress.
    376   parent_->image_loader_->Start(data.Pass(),
    377                                 login::kMaxUserImageSize,
    378                                 base::Bind(&Job::OnLoadImageDone,
    379                                            weak_factory_.GetWeakPtr(),
    380                                            true));
    381 }
    382 
    383 void UserImageManagerImpl::Job::SetToPath(const base::FilePath& path,
    384                                           int image_index,
    385                                           const GURL& image_url,
    386                                           bool resize) {
    387   DCHECK(!run_);
    388   run_ = true;
    389 
    390   image_index_ = image_index;
    391   image_url_ = image_url;
    392 
    393   DCHECK(!path.empty());
    394   parent_->unsafe_image_loader_->Start(path.value(),
    395                                        resize ? login::kMaxUserImageSize : 0,
    396                                        base::Bind(&Job::OnLoadImageDone,
    397                                                   weak_factory_.GetWeakPtr(),
    398                                                   true));
    399 }
    400 
    401 void UserImageManagerImpl::Job::OnLoadImageDone(
    402     bool save,
    403     const user_manager::UserImage& user_image) {
    404   user_image_ = user_image;
    405   UpdateUser();
    406   if (save)
    407     SaveImageAndUpdateLocalState();
    408   else
    409     NotifyJobDone();
    410 }
    411 
    412 void UserImageManagerImpl::Job::UpdateUser() {
    413   user_manager::User* user =
    414       parent_->user_manager_->FindUserAndModify(user_id());
    415   if (!user)
    416     return;
    417 
    418   if (!user_image_.image().isNull()) {
    419     user->SetImage(user_image_, image_index_);
    420   } else {
    421     user->SetStubImage(
    422         user_manager::UserImage(
    423             *ResourceBundle::GetSharedInstance().GetImageSkiaNamed(
    424                 IDR_PROFILE_PICTURE_LOADING)),
    425         image_index_,
    426         false);
    427   }
    428   user->SetImageURL(image_url_);
    429 
    430   parent_->OnJobChangedUserImage();
    431 }
    432 
    433 void UserImageManagerImpl::Job::SaveImageAndUpdateLocalState() {
    434   base::FilePath user_data_dir;
    435   PathService::Get(chrome::DIR_USER_DATA, &user_data_dir);
    436   image_path_ = user_data_dir.Append(user_id() + kSafeImagePathExtension);
    437 
    438   base::PostTaskAndReplyWithResult(
    439       parent_->background_task_runner_.get(),
    440       FROM_HERE,
    441       base::Bind(&SaveImage, user_image_, image_path_),
    442       base::Bind(&Job::OnSaveImageDone, weak_factory_.GetWeakPtr()));
    443 }
    444 
    445 void UserImageManagerImpl::Job::OnSaveImageDone(bool success) {
    446   if (success || image_index_ == user_manager::User::USER_IMAGE_PROFILE)
    447     UpdateLocalState();
    448   NotifyJobDone();
    449 }
    450 
    451 void UserImageManagerImpl::Job::UpdateLocalState() {
    452   // Ignore if data stored or cached outside the user's cryptohome is to be
    453   // treated as ephemeral.
    454   if (parent_->user_manager_->IsUserNonCryptohomeDataEphemeral(user_id()))
    455     return;
    456 
    457   scoped_ptr<base::DictionaryValue> entry(new base::DictionaryValue);
    458   entry->Set(kImagePathNodeName, new base::StringValue(image_path_.value()));
    459   entry->Set(kImageIndexNodeName, new base::FundamentalValue(image_index_));
    460   if (!image_url_.is_empty())
    461     entry->Set(kImageURLNodeName, new base::StringValue(image_url_.spec()));
    462   DictionaryPrefUpdate update(g_browser_process->local_state(),
    463                               kUserImageProperties);
    464   update->SetWithoutPathExpansion(user_id(), entry.release());
    465 
    466   parent_->user_manager_->NotifyLocalStateChanged();
    467 }
    468 
    469 void UserImageManagerImpl::Job::NotifyJobDone() {
    470   parent_->OnJobDone();
    471 }
    472 
    473 UserImageManagerImpl::UserImageManagerImpl(
    474     const std::string& user_id,
    475     user_manager::UserManager* user_manager)
    476     : UserImageManager(user_id),
    477       user_manager_(user_manager),
    478       downloading_profile_image_(false),
    479       profile_image_requested_(false),
    480       has_managed_image_(false),
    481       user_needs_migration_(false),
    482       weak_factory_(this) {
    483   base::SequencedWorkerPool* blocking_pool =
    484       content::BrowserThread::GetBlockingPool();
    485   background_task_runner_ =
    486       blocking_pool->GetSequencedTaskRunnerWithShutdownBehavior(
    487           blocking_pool->GetSequenceToken(),
    488           base::SequencedWorkerPool::CONTINUE_ON_SHUTDOWN);
    489   image_loader_ = new UserImageLoader(ImageDecoder::ROBUST_JPEG_CODEC,
    490                                       background_task_runner_);
    491   unsafe_image_loader_ = new UserImageLoader(ImageDecoder::DEFAULT_CODEC,
    492                                              background_task_runner_);
    493 }
    494 
    495 UserImageManagerImpl::~UserImageManagerImpl() {}
    496 
    497 void UserImageManagerImpl::LoadUserImage() {
    498   PrefService* local_state = g_browser_process->local_state();
    499   const base::DictionaryValue* prefs_images_unsafe =
    500       local_state->GetDictionary(kUserImages);
    501   const base::DictionaryValue* prefs_images =
    502       local_state->GetDictionary(kUserImageProperties);
    503   if (!prefs_images && !prefs_images_unsafe)
    504     return;
    505   user_manager::User* user = GetUserAndModify();
    506   bool needs_migration = false;
    507 
    508   // If entries are found in both |prefs_images_unsafe| and |prefs_images|,
    509   // |prefs_images| is honored for now but |prefs_images_unsafe| will be
    510   // migrated, overwriting the |prefs_images| entry, when the user logs in.
    511   const base::DictionaryValue* image_properties = NULL;
    512   if (prefs_images_unsafe) {
    513     needs_migration = prefs_images_unsafe->GetDictionaryWithoutPathExpansion(
    514         user_id(), &image_properties);
    515     if (needs_migration)
    516       user_needs_migration_ = true;
    517   }
    518   if (prefs_images) {
    519     prefs_images->GetDictionaryWithoutPathExpansion(user_id(),
    520                                                     &image_properties);
    521   }
    522 
    523   // If the user image for |user_id| is managed by policy and the policy-set
    524   // image is being loaded and persisted right now, let that job continue. It
    525   // will update the user image when done.
    526   if (IsUserImageManaged() && job_.get())
    527     return;
    528 
    529   if (!image_properties) {
    530     SetInitialUserImage();
    531     return;
    532   }
    533 
    534   int image_index = user_manager::User::USER_IMAGE_INVALID;
    535   image_properties->GetInteger(kImageIndexNodeName, &image_index);
    536   if (image_index >= 0 && image_index < user_manager::kDefaultImagesCount) {
    537     user->SetImage(
    538         user_manager::UserImage(user_manager::GetDefaultImage(image_index)),
    539         image_index);
    540     return;
    541   }
    542 
    543   if (image_index != user_manager::User::USER_IMAGE_EXTERNAL &&
    544       image_index != user_manager::User::USER_IMAGE_PROFILE) {
    545     NOTREACHED();
    546     return;
    547   }
    548 
    549   std::string image_url_string;
    550   image_properties->GetString(kImageURLNodeName, &image_url_string);
    551   GURL image_url(image_url_string);
    552   std::string image_path;
    553   image_properties->GetString(kImagePathNodeName, &image_path);
    554 
    555   user->SetImageURL(image_url);
    556   user->SetStubImage(user_manager::UserImage(
    557                          *ResourceBundle::GetSharedInstance().GetImageSkiaNamed(
    558                              IDR_PROFILE_PICTURE_LOADING)),
    559                      image_index,
    560                      true);
    561   DCHECK(!image_path.empty() ||
    562          image_index == user_manager::User::USER_IMAGE_PROFILE);
    563   if (image_path.empty() || needs_migration) {
    564     // Return if either of the following is true:
    565     // * The profile image is to be used but has not been downloaded yet. The
    566     //   profile image will be downloaded after login.
    567     // * The image needs migration. Migration will be performed after login.
    568     return;
    569   }
    570 
    571   job_.reset(new Job(this));
    572   job_->LoadImage(base::FilePath(image_path), image_index, image_url);
    573 }
    574 
    575 void UserImageManagerImpl::UserLoggedIn(bool user_is_new,
    576                                         bool user_is_local) {
    577   const user_manager::User* user = GetUser();
    578   if (user_is_new) {
    579     if (!user_is_local)
    580       SetInitialUserImage();
    581   } else {
    582     UMA_HISTOGRAM_ENUMERATION("UserImage.LoggedIn",
    583                               ImageIndexToHistogramIndex(user->image_index()),
    584                               user_manager::kHistogramImagesCount);
    585 
    586     if (!IsUserImageManaged() && user_needs_migration_) {
    587       const base::DictionaryValue* prefs_images_unsafe =
    588           g_browser_process->local_state()->GetDictionary(kUserImages);
    589       const base::DictionaryValue* image_properties = NULL;
    590       if (prefs_images_unsafe->GetDictionaryWithoutPathExpansion(
    591               user_id(), &image_properties)) {
    592         std::string image_path;
    593         image_properties->GetString(kImagePathNodeName, &image_path);
    594         job_.reset(new Job(this));
    595         if (!image_path.empty()) {
    596           VLOG(0) << "Loading old user image, then migrating it.";
    597           job_->SetToPath(base::FilePath(image_path),
    598                           user->image_index(),
    599                           user->image_url(),
    600                           false);
    601         } else {
    602           job_->SetToDefaultImage(user->image_index());
    603         }
    604       }
    605     }
    606   }
    607 
    608   // Reset the downloaded profile image as a new user logged in.
    609   downloaded_profile_image_ = gfx::ImageSkia();
    610   profile_image_url_ = GURL();
    611   profile_image_requested_ = false;
    612 
    613   if (IsUserLoggedInAndRegular()) {
    614     TryToInitDownloadedProfileImage();
    615 
    616     // Schedule an initial download of the profile data (full name and
    617     // optionally image).
    618     profile_download_one_shot_timer_.Start(
    619         FROM_HERE,
    620         g_ignore_profile_data_download_delay_ ?
    621             base::TimeDelta() :
    622             base::TimeDelta::FromSeconds(kProfileDataDownloadDelaySec),
    623         base::Bind(&UserImageManagerImpl::DownloadProfileData,
    624                    base::Unretained(this),
    625                    kProfileDownloadReasonLoggedIn));
    626     // Schedule periodic refreshes of the profile data.
    627     profile_download_periodic_timer_.Start(
    628         FROM_HERE,
    629         base::TimeDelta::FromSeconds(kProfileRefreshIntervalSec),
    630         base::Bind(&UserImageManagerImpl::DownloadProfileData,
    631                    base::Unretained(this),
    632                    kProfileDownloadReasonScheduled));
    633   } else {
    634     profile_download_one_shot_timer_.Stop();
    635     profile_download_periodic_timer_.Stop();
    636   }
    637 
    638   user_image_sync_observer_.reset();
    639   TryToCreateImageSyncObserver();
    640 }
    641 
    642 void UserImageManagerImpl::SaveUserDefaultImageIndex(int default_image_index) {
    643   if (IsUserImageManaged())
    644     return;
    645   job_.reset(new Job(this));
    646   job_->SetToDefaultImage(default_image_index);
    647 }
    648 
    649 void UserImageManagerImpl::SaveUserImage(
    650     const user_manager::UserImage& user_image) {
    651   if (IsUserImageManaged())
    652     return;
    653   job_.reset(new Job(this));
    654   job_->SetToImage(user_manager::User::USER_IMAGE_EXTERNAL, user_image);
    655 }
    656 
    657 void UserImageManagerImpl::SaveUserImageFromFile(const base::FilePath& path) {
    658   if (IsUserImageManaged())
    659     return;
    660   job_.reset(new Job(this));
    661   job_->SetToPath(path, user_manager::User::USER_IMAGE_EXTERNAL, GURL(), true);
    662 }
    663 
    664 void UserImageManagerImpl::SaveUserImageFromProfileImage() {
    665   if (IsUserImageManaged())
    666     return;
    667   // Use the profile image if it has been downloaded already. Otherwise, use a
    668   // stub image (gray avatar).
    669   job_.reset(new Job(this));
    670   job_->SetToImage(user_manager::User::USER_IMAGE_PROFILE,
    671                    downloaded_profile_image_.isNull()
    672                        ? user_manager::UserImage()
    673                        : user_manager::UserImage::CreateAndEncode(
    674                              downloaded_profile_image_));
    675   // If no profile image has been downloaded yet, ensure that a download is
    676   // started.
    677   if (downloaded_profile_image_.isNull())
    678     DownloadProfileData(kProfileDownloadReasonProfileImageChosen);
    679 }
    680 
    681 void UserImageManagerImpl::DeleteUserImage() {
    682   job_.reset();
    683   DeleteUserImageAndLocalStateEntry(kUserImages);
    684   DeleteUserImageAndLocalStateEntry(kUserImageProperties);
    685 }
    686 
    687 void UserImageManagerImpl::DownloadProfileImage(const std::string& reason) {
    688   profile_image_requested_ = true;
    689   DownloadProfileData(reason);
    690 }
    691 
    692 const gfx::ImageSkia& UserImageManagerImpl::DownloadedProfileImage() const {
    693   return downloaded_profile_image_;
    694 }
    695 
    696 UserImageSyncObserver* UserImageManagerImpl::GetSyncObserver() const {
    697   return user_image_sync_observer_.get();
    698 }
    699 
    700 void UserImageManagerImpl::Shutdown() {
    701   profile_downloader_.reset();
    702   user_image_sync_observer_.reset();
    703 }
    704 
    705 void UserImageManagerImpl::OnExternalDataSet(const std::string& policy) {
    706   DCHECK_EQ(policy::key::kUserAvatarImage, policy);
    707   if (IsUserImageManaged())
    708     return;
    709 
    710   has_managed_image_ = true;
    711   job_.reset();
    712 
    713   const user_manager::User* user = GetUser();
    714   // If the user image for the currently logged-in user became managed, stop the
    715   // sync observer so that the policy-set image does not get synced out.
    716   if (user && user->is_logged_in())
    717     user_image_sync_observer_.reset();
    718 }
    719 
    720 void UserImageManagerImpl::OnExternalDataCleared(const std::string& policy) {
    721   DCHECK_EQ(policy::key::kUserAvatarImage, policy);
    722   has_managed_image_ = false;
    723   SetInitialUserImage();
    724   TryToCreateImageSyncObserver();
    725 }
    726 
    727 void UserImageManagerImpl::OnExternalDataFetched(const std::string& policy,
    728                                                  scoped_ptr<std::string> data) {
    729   DCHECK_EQ(policy::key::kUserAvatarImage, policy);
    730   DCHECK(IsUserImageManaged());
    731   if (data) {
    732     job_.reset(new Job(this));
    733     job_->SetToImageData(data.Pass());
    734   }
    735 }
    736 
    737 // static
    738 void UserImageManagerImpl::IgnoreProfileDataDownloadDelayForTesting() {
    739   g_ignore_profile_data_download_delay_ = true;
    740 }
    741 
    742 bool UserImageManagerImpl::NeedsProfilePicture() const {
    743   return downloading_profile_image_;
    744 }
    745 
    746 int UserImageManagerImpl::GetDesiredImageSideLength() const {
    747   return GetCurrentUserImageSize();
    748 }
    749 
    750 Profile* UserImageManagerImpl::GetBrowserProfile() {
    751   return ProfileHelper::Get()->GetProfileByUserUnsafe(GetUser());
    752 }
    753 
    754 std::string UserImageManagerImpl::GetCachedPictureURL() const {
    755   return profile_image_url_.spec();
    756 }
    757 
    758 void UserImageManagerImpl::OnProfileDownloadSuccess(
    759     ProfileDownloader* downloader) {
    760   // Ensure that the |profile_downloader_| is deleted when this method returns.
    761   scoped_ptr<ProfileDownloader> profile_downloader(
    762       profile_downloader_.release());
    763   DCHECK_EQ(downloader, profile_downloader.get());
    764 
    765   user_manager_->UpdateUserAccountData(
    766       user_id(),
    767       user_manager::UserManager::UserAccountData(
    768           downloader->GetProfileFullName(),
    769           downloader->GetProfileGivenName(),
    770           downloader->GetProfileLocale()));
    771   if (!downloading_profile_image_)
    772     return;
    773 
    774   ProfileDownloadResult result = kDownloadFailure;
    775   switch (downloader->GetProfilePictureStatus()) {
    776     case ProfileDownloader::PICTURE_SUCCESS:
    777       result = kDownloadSuccess;
    778       break;
    779     case ProfileDownloader::PICTURE_CACHED:
    780       result = kDownloadCached;
    781       break;
    782     case ProfileDownloader::PICTURE_DEFAULT:
    783       result = kDownloadDefault;
    784       break;
    785     default:
    786       NOTREACHED();
    787   }
    788 
    789   UMA_HISTOGRAM_ENUMERATION("UserImage.ProfileDownloadResult",
    790                             result,
    791                             kDownloadResultsCount);
    792   DCHECK(!profile_image_load_start_time_.is_null());
    793   AddProfileImageTimeHistogram(
    794       result,
    795       profile_image_download_reason_,
    796       base::TimeTicks::Now() - profile_image_load_start_time_);
    797 
    798   // Ignore the image if it is no longer needed.
    799   if (!NeedProfileImage())
    800     return;
    801 
    802   if (result == kDownloadDefault) {
    803     content::NotificationService::current()->Notify(
    804         chrome::NOTIFICATION_PROFILE_IMAGE_UPDATE_FAILED,
    805         content::Source<UserImageManager>(this),
    806         content::NotificationService::NoDetails());
    807   } else {
    808     profile_image_requested_ = false;
    809   }
    810 
    811   // Nothing to do if the picture is cached or is the default avatar.
    812   if (result != kDownloadSuccess)
    813     return;
    814 
    815   downloaded_profile_image_ = gfx::ImageSkia::CreateFrom1xBitmap(
    816       downloader->GetProfilePicture());
    817   profile_image_url_ = GURL(downloader->GetProfilePictureURL());
    818 
    819   const user_manager::User* user = GetUser();
    820   if (user->image_index() == user_manager::User::USER_IMAGE_PROFILE) {
    821     VLOG(1) << "Updating profile image for logged-in user.";
    822     UMA_HISTOGRAM_ENUMERATION("UserImage.ProfileDownloadResult",
    823                               kDownloadSuccessChanged,
    824                               kDownloadResultsCount);
    825     // This will persist |downloaded_profile_image_| to disk.
    826     SaveUserImageFromProfileImage();
    827   }
    828 
    829   content::NotificationService::current()->Notify(
    830       chrome::NOTIFICATION_PROFILE_IMAGE_UPDATED,
    831       content::Source<UserImageManager>(this),
    832       content::Details<const gfx::ImageSkia>(&downloaded_profile_image_));
    833 }
    834 
    835 void UserImageManagerImpl::OnProfileDownloadFailure(
    836     ProfileDownloader* downloader,
    837     ProfileDownloaderDelegate::FailureReason reason) {
    838   DCHECK_EQ(downloader, profile_downloader_.get());
    839   profile_downloader_.reset();
    840 
    841   if (downloading_profile_image_) {
    842     UMA_HISTOGRAM_ENUMERATION("UserImage.ProfileDownloadResult",
    843                               kDownloadFailure,
    844                               kDownloadResultsCount);
    845     DCHECK(!profile_image_load_start_time_.is_null());
    846     AddProfileImageTimeHistogram(
    847         kDownloadFailure,
    848         profile_image_download_reason_,
    849         base::TimeTicks::Now() - profile_image_load_start_time_);
    850   }
    851 
    852   if (reason == ProfileDownloaderDelegate::NETWORK_ERROR) {
    853     // Retry download after a delay if a network error occurred.
    854     profile_download_one_shot_timer_.Start(
    855         FROM_HERE,
    856         base::TimeDelta::FromSeconds(kProfileDataDownloadRetryIntervalSec),
    857         base::Bind(&UserImageManagerImpl::DownloadProfileData,
    858                    base::Unretained(this),
    859                    kProfileDownloadReasonRetry));
    860   }
    861 
    862   content::NotificationService::current()->Notify(
    863       chrome::NOTIFICATION_PROFILE_IMAGE_UPDATE_FAILED,
    864       content::Source<UserImageManager>(this),
    865       content::NotificationService::NoDetails());
    866 }
    867 
    868 bool UserImageManagerImpl::IsUserImageManaged() const {
    869   return has_managed_image_;
    870 }
    871 
    872 void UserImageManagerImpl::SetInitialUserImage() {
    873   // Choose a random default image.
    874   SaveUserDefaultImageIndex(
    875       base::RandInt(user_manager::kFirstDefaultImageIndex,
    876                     user_manager::kDefaultImagesCount - 1));
    877 }
    878 
    879 void UserImageManagerImpl::TryToInitDownloadedProfileImage() {
    880   const user_manager::User* user = GetUser();
    881   if (user->image_index() == user_manager::User::USER_IMAGE_PROFILE &&
    882       downloaded_profile_image_.isNull() && !user->image_is_stub()) {
    883     // Initialize the |downloaded_profile_image_| for the currently logged-in
    884     // user if it has not been initialized already, the user image is the
    885     // profile image and the user image has been loaded successfully.
    886     VLOG(1) << "Profile image initialized from disk.";
    887     downloaded_profile_image_ = user->GetImage();
    888     profile_image_url_ = user->image_url();
    889   }
    890 }
    891 
    892 bool UserImageManagerImpl::NeedProfileImage() const {
    893   const user_manager::User* user = GetUser();
    894   return IsUserLoggedInAndRegular() &&
    895          (user->image_index() == user_manager::User::USER_IMAGE_PROFILE ||
    896           profile_image_requested_);
    897 }
    898 
    899 void UserImageManagerImpl::DownloadProfileData(const std::string& reason) {
    900   // GAIA profiles exist for regular users only.
    901   if (!IsUserLoggedInAndRegular())
    902     return;
    903 
    904   // If a download is already in progress, allow it to continue, with one
    905   // exception: If the current download does not include the profile image but
    906   // the image has since become necessary, start a new download that includes
    907   // the profile image.
    908   if (profile_downloader_ &&
    909       (downloading_profile_image_ || !NeedProfileImage())) {
    910     return;
    911   }
    912 
    913   downloading_profile_image_ = NeedProfileImage();
    914   profile_image_download_reason_ = reason;
    915   profile_image_load_start_time_ = base::TimeTicks::Now();
    916   profile_downloader_.reset(new ProfileDownloader(this));
    917   profile_downloader_->Start();
    918 }
    919 
    920 void UserImageManagerImpl::DeleteUserImageAndLocalStateEntry(
    921     const char* prefs_dict_root) {
    922   DictionaryPrefUpdate update(g_browser_process->local_state(),
    923                               prefs_dict_root);
    924   const base::DictionaryValue* image_properties;
    925   if (!update->GetDictionaryWithoutPathExpansion(user_id(), &image_properties))
    926     return;
    927 
    928   std::string image_path;
    929   image_properties->GetString(kImagePathNodeName, &image_path);
    930   if (!image_path.empty()) {
    931     background_task_runner_->PostTask(
    932         FROM_HERE,
    933         base::Bind(base::IgnoreResult(&base::DeleteFile),
    934                    base::FilePath(image_path),
    935                    false));
    936   }
    937   update->RemoveWithoutPathExpansion(user_id(), NULL);
    938 }
    939 
    940 void UserImageManagerImpl::OnJobChangedUserImage() {
    941   if (GetUser()->is_logged_in())
    942     TryToInitDownloadedProfileImage();
    943 
    944   content::NotificationService::current()->Notify(
    945       chrome::NOTIFICATION_LOGIN_USER_IMAGE_CHANGED,
    946       content::Source<UserImageManagerImpl>(this),
    947       content::Details<const user_manager::User>(GetUser()));
    948 }
    949 
    950 void UserImageManagerImpl::OnJobDone() {
    951   if (job_.get())
    952     base::MessageLoopProxy::current()->DeleteSoon(FROM_HERE, job_.release());
    953   else
    954     NOTREACHED();
    955 
    956   if (!user_needs_migration_)
    957     return;
    958   // Migration completed for |user_id|.
    959   user_needs_migration_ = false;
    960 
    961   const base::DictionaryValue* prefs_images_unsafe =
    962       g_browser_process->local_state()->GetDictionary(kUserImages);
    963   const base::DictionaryValue* image_properties = NULL;
    964   if (!prefs_images_unsafe->GetDictionaryWithoutPathExpansion(
    965           user_id(), &image_properties)) {
    966     NOTREACHED();
    967     return;
    968   }
    969 
    970   int image_index = user_manager::User::USER_IMAGE_INVALID;
    971   image_properties->GetInteger(kImageIndexNodeName, &image_index);
    972   UMA_HISTOGRAM_ENUMERATION("UserImage.Migration",
    973                             ImageIndexToHistogramIndex(image_index),
    974                             user_manager::kHistogramImagesCount);
    975 
    976   std::string image_path;
    977   image_properties->GetString(kImagePathNodeName, &image_path);
    978   if (!image_path.empty()) {
    979     // If an old image exists, delete it and remove |user_id| from the old prefs
    980     // dictionary only after the deletion has completed. This ensures that no
    981     // orphaned image is left behind if the browser crashes before the deletion
    982     // has been performed: In that case, local state will be unchanged and the
    983     // migration will be run again on the user's next login.
    984     background_task_runner_->PostTaskAndReply(
    985         FROM_HERE,
    986         base::Bind(base::IgnoreResult(&base::DeleteFile),
    987                    base::FilePath(image_path),
    988                    false),
    989         base::Bind(&UserImageManagerImpl::UpdateLocalStateAfterMigration,
    990                    weak_factory_.GetWeakPtr()));
    991   } else {
    992     // If no old image exists, remove |user_id| from the old prefs dictionary.
    993     UpdateLocalStateAfterMigration();
    994   }
    995 }
    996 
    997 void UserImageManagerImpl::UpdateLocalStateAfterMigration() {
    998   DictionaryPrefUpdate update(g_browser_process->local_state(),
    999                               kUserImages);
   1000   update->RemoveWithoutPathExpansion(user_id(), NULL);
   1001 }
   1002 
   1003 void UserImageManagerImpl::TryToCreateImageSyncObserver() {
   1004   const user_manager::User* user = GetUser();
   1005   // If the currently logged-in user's user image is managed, the sync observer
   1006   // must not be started so that the policy-set image does not get synced out.
   1007   if (!user_image_sync_observer_ &&
   1008       user && user->CanSyncImage() &&
   1009       !IsUserImageManaged()) {
   1010     user_image_sync_observer_.reset(new UserImageSyncObserver(user));
   1011   }
   1012 }
   1013 
   1014 const user_manager::User* UserImageManagerImpl::GetUser() const {
   1015   return user_manager_->FindUser(user_id());
   1016 }
   1017 
   1018 user_manager::User* UserImageManagerImpl::GetUserAndModify() const {
   1019   return user_manager_->FindUserAndModify(user_id());
   1020 }
   1021 
   1022 bool UserImageManagerImpl::IsUserLoggedInAndRegular() const {
   1023   const user_manager::User* user = GetUser();
   1024   if (!user)
   1025     return false;
   1026   return user->is_logged_in() &&
   1027          user->GetType() == user_manager::USER_TYPE_REGULAR;
   1028 }
   1029 
   1030 }  // namespace chromeos
   1031