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