Home | History | Annotate | Download | only in updater
      1 // Copyright (c) 2012 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/extensions/updater/extension_updater.h"
      6 
      7 #include <algorithm>
      8 #include <set>
      9 
     10 #include "base/bind.h"
     11 #include "base/files/file_util.h"
     12 #include "base/logging.h"
     13 #include "base/metrics/histogram.h"
     14 #include "base/prefs/pref_service.h"
     15 #include "base/rand_util.h"
     16 #include "base/stl_util.h"
     17 #include "base/strings/string_number_conversions.h"
     18 #include "base/strings/string_split.h"
     19 #include "chrome/browser/chrome_notification_types.h"
     20 #include "chrome/browser/extensions/api/module/module.h"
     21 #include "chrome/browser/extensions/crx_installer.h"
     22 #include "chrome/browser/extensions/extension_service.h"
     23 #include "chrome/browser/extensions/pending_extension_manager.h"
     24 #include "chrome/browser/profiles/profile.h"
     25 #include "chrome/common/pref_names.h"
     26 #include "components/omaha_query_params/omaha_query_params.h"
     27 #include "content/public/browser/browser_thread.h"
     28 #include "content/public/browser/notification_details.h"
     29 #include "content/public/browser/notification_service.h"
     30 #include "content/public/browser/notification_source.h"
     31 #include "crypto/sha2.h"
     32 #include "extensions/browser/extension_prefs.h"
     33 #include "extensions/browser/extension_registry.h"
     34 #include "extensions/browser/pref_names.h"
     35 #include "extensions/common/constants.h"
     36 #include "extensions/common/extension.h"
     37 #include "extensions/common/extension_set.h"
     38 #include "extensions/common/manifest.h"
     39 #include "extensions/common/manifest_constants.h"
     40 
     41 using base::RandDouble;
     42 using base::RandInt;
     43 using base::Time;
     44 using base::TimeDelta;
     45 using content::BrowserThread;
     46 using extensions::Extension;
     47 using extensions::ExtensionSet;
     48 using omaha_query_params::OmahaQueryParams;
     49 
     50 typedef extensions::ExtensionDownloaderDelegate::Error Error;
     51 typedef extensions::ExtensionDownloaderDelegate::PingResult PingResult;
     52 
     53 namespace {
     54 
     55 // Wait at least 5 minutes after browser startup before we do any checks. If you
     56 // change this value, make sure to update comments where it is used.
     57 const int kStartupWaitSeconds = 60 * 5;
     58 
     59 // For sanity checking on update frequency - enforced in release mode only.
     60 #if defined(NDEBUG)
     61 const int kMinUpdateFrequencySeconds = 30;
     62 #endif
     63 const int kMaxUpdateFrequencySeconds = 60 * 60 * 24 * 7;  // 7 days
     64 
     65 // Require at least 5 seconds between consecutive non-succesful extension update
     66 // checks.
     67 const int kMinUpdateThrottleTime = 5;
     68 
     69 // The installsource query parameter to use when forcing updates due to NaCl
     70 // arch mismatch.
     71 const char kWrongMultiCrxInstallSource[] = "wrong_multi_crx";
     72 
     73 // When we've computed a days value, we want to make sure we don't send a
     74 // negative value (due to the system clock being set backwards, etc.), since -1
     75 // is a special sentinel value that means "never pinged", and other negative
     76 // values don't make sense.
     77 int SanitizeDays(int days) {
     78   if (days < 0)
     79     return 0;
     80   return days;
     81 }
     82 
     83 // Calculates the value to use for the ping days parameter.
     84 int CalculatePingDays(const Time& last_ping_day) {
     85   int days = extensions::ManifestFetchData::kNeverPinged;
     86   if (!last_ping_day.is_null()) {
     87     days = SanitizeDays((Time::Now() - last_ping_day).InDays());
     88   }
     89   return days;
     90 }
     91 
     92 int CalculateActivePingDays(const Time& last_active_ping_day,
     93                             bool hasActiveBit) {
     94   if (!hasActiveBit)
     95     return 0;
     96   if (last_active_ping_day.is_null())
     97     return extensions::ManifestFetchData::kNeverPinged;
     98   return SanitizeDays((Time::Now() - last_active_ping_day).InDays());
     99 }
    100 
    101 void RespondWithForcedUpdates(
    102     const base::Callback<void(const std::set<std::string>&)>& callback,
    103     scoped_ptr<std::set<std::string> > forced_updates) {
    104   callback.Run(*forced_updates.get());
    105 }
    106 
    107 void DetermineForcedUpdatesOnBlockingPool(
    108     scoped_ptr<std::vector<scoped_refptr<const Extension> > > extensions,
    109     const base::Callback<void(const std::set<std::string>&)>& callback) {
    110   scoped_ptr<std::set<std::string> > forced_updates(
    111       new std::set<std::string>());
    112   DCHECK(!BrowserThread::CurrentlyOn(BrowserThread::UI));
    113   for (std::vector<scoped_refptr<const Extension> >::const_iterator iter =
    114           extensions->begin();
    115        iter != extensions->end();
    116        ++iter) {
    117     scoped_refptr<const Extension> extension = *iter;
    118     base::FilePath platform_specific_path = extension->path().Append(
    119         extensions::kPlatformSpecificFolder);
    120     if (base::PathExists(platform_specific_path)) {
    121       bool force = true;
    122       const base::ListValue* platforms;
    123       if (extension->manifest()->GetList(extensions::manifest_keys::kPlatforms,
    124                                          &platforms)) {
    125         for (size_t i = 0; i < platforms->GetSize(); ++i) {
    126           const base::DictionaryValue* p;
    127           if (platforms->GetDictionary(i, &p)) {
    128             std::string nacl_arch;
    129             if (p->GetString(extensions::manifest_keys::kNaClArch,
    130                              &nacl_arch) &&
    131                 nacl_arch == OmahaQueryParams::GetNaclArch()) {
    132               std::string subpath;
    133               if (p->GetString(extensions::manifest_keys::kSubPackagePath,
    134                                &subpath)) {
    135                 // _platform_specific is part of the sub_package_path entry.
    136                 base::FilePath platform_specific_subpath =
    137                     extension->path().AppendASCII(subpath);
    138                 if (base::PathExists(platform_specific_subpath)) {
    139                   force = false;
    140                 }
    141               }
    142             }
    143           }
    144         }
    145       }
    146 
    147       if (force)
    148         forced_updates->insert(extension->id());
    149    }
    150   }
    151   BrowserThread::PostTask(
    152       BrowserThread::UI,
    153       FROM_HERE,
    154       base::Bind(&RespondWithForcedUpdates,
    155                  callback,
    156                  base::Passed(&forced_updates)));
    157 }
    158 
    159 void CollectExtensionsFromSet(
    160     const ExtensionSet& extensions,
    161     std::vector<scoped_refptr<const Extension> >* paths) {
    162   std::copy(extensions.begin(), extensions.end(), std::back_inserter(*paths));
    163 }
    164 
    165 void DetermineForcedUpdates(
    166     content::BrowserContext* browser_context,
    167     const base::Callback<void(const std::set<std::string>&)>& callback) {
    168   scoped_ptr<std::vector<scoped_refptr<const Extension> > > extensions(
    169       new std::vector<scoped_refptr<const Extension> >());
    170   const extensions::ExtensionRegistry* registry =
    171       extensions::ExtensionRegistry::Get(browser_context);
    172   scoped_ptr<ExtensionSet> installed_extensions =
    173       registry->GenerateInstalledExtensionsSet();
    174   CollectExtensionsFromSet(*installed_extensions.get(), extensions.get());
    175   BrowserThread::PostBlockingPoolTask(
    176       FROM_HERE,
    177       base::Bind(&DetermineForcedUpdatesOnBlockingPool,
    178                  base::Passed(&extensions),
    179                  callback));
    180 }
    181 
    182 }  // namespace
    183 
    184 namespace extensions {
    185 
    186 ExtensionUpdater::CheckParams::CheckParams()
    187     : install_immediately(false) {}
    188 
    189 ExtensionUpdater::CheckParams::~CheckParams() {}
    190 
    191 ExtensionUpdater::FetchedCRXFile::FetchedCRXFile(
    192     const std::string& i,
    193     const base::FilePath& p,
    194     bool file_ownership_passed,
    195     const std::set<int>& request_ids)
    196     : extension_id(i),
    197       path(p),
    198       file_ownership_passed(file_ownership_passed),
    199       request_ids(request_ids) {}
    200 
    201 ExtensionUpdater::FetchedCRXFile::FetchedCRXFile()
    202     : path(), file_ownership_passed(true) {}
    203 
    204 ExtensionUpdater::FetchedCRXFile::~FetchedCRXFile() {}
    205 
    206 ExtensionUpdater::InProgressCheck::InProgressCheck()
    207     : install_immediately(false) {}
    208 
    209 ExtensionUpdater::InProgressCheck::~InProgressCheck() {}
    210 
    211 struct ExtensionUpdater::ThrottleInfo {
    212   ThrottleInfo()
    213       : in_progress(true),
    214         throttle_delay(kMinUpdateThrottleTime),
    215         check_start(Time::Now()) {}
    216 
    217   bool in_progress;
    218   int throttle_delay;
    219   Time check_start;
    220 };
    221 
    222 ExtensionUpdater::ExtensionUpdater(
    223     ExtensionServiceInterface* service,
    224     ExtensionPrefs* extension_prefs,
    225     PrefService* prefs,
    226     Profile* profile,
    227     int frequency_seconds,
    228     ExtensionCache* cache,
    229     const ExtensionDownloader::Factory& downloader_factory)
    230     : alive_(false),
    231       service_(service),
    232       downloader_factory_(downloader_factory),
    233       frequency_seconds_(frequency_seconds),
    234       will_check_soon_(false),
    235       extension_prefs_(extension_prefs),
    236       prefs_(prefs),
    237       profile_(profile),
    238       next_request_id_(0),
    239       extension_registry_observer_(this),
    240       crx_install_is_running_(false),
    241       extension_cache_(cache),
    242       weak_ptr_factory_(this) {
    243   DCHECK_GE(frequency_seconds_, 5);
    244   DCHECK_LE(frequency_seconds_, kMaxUpdateFrequencySeconds);
    245 #if defined(NDEBUG)
    246   // In Release mode we enforce that update checks don't happen too often.
    247   frequency_seconds_ = std::max(frequency_seconds_, kMinUpdateFrequencySeconds);
    248 #endif
    249   frequency_seconds_ = std::min(frequency_seconds_, kMaxUpdateFrequencySeconds);
    250 
    251   extension_registry_observer_.Add(ExtensionRegistry::Get(profile));
    252 }
    253 
    254 ExtensionUpdater::~ExtensionUpdater() {
    255   Stop();
    256 }
    257 
    258 void ExtensionUpdater::EnsureDownloaderCreated() {
    259   if (!downloader_.get()) {
    260     downloader_ = downloader_factory_.Run(this);
    261   }
    262 }
    263 
    264 // The overall goal here is to balance keeping clients up to date while
    265 // avoiding a thundering herd against update servers.
    266 TimeDelta ExtensionUpdater::DetermineFirstCheckDelay() {
    267   DCHECK(alive_);
    268   // If someone's testing with a quick frequency, just allow it.
    269   if (frequency_seconds_ < kStartupWaitSeconds)
    270     return TimeDelta::FromSeconds(frequency_seconds_);
    271 
    272   // If we've never scheduled a check before, start at frequency_seconds_.
    273   if (!prefs_->HasPrefPath(pref_names::kNextUpdateCheck))
    274     return TimeDelta::FromSeconds(frequency_seconds_);
    275 
    276   // If it's been a long time since our last actual check, we want to do one
    277   // relatively soon.
    278   Time now = Time::Now();
    279   Time last = Time::FromInternalValue(prefs_->GetInt64(
    280       pref_names::kLastUpdateCheck));
    281   int days = (now - last).InDays();
    282   if (days >= 30) {
    283     // Wait 5-10 minutes.
    284     return TimeDelta::FromSeconds(RandInt(kStartupWaitSeconds,
    285                                           kStartupWaitSeconds * 2));
    286   } else if (days >= 14) {
    287     // Wait 10-20 minutes.
    288     return TimeDelta::FromSeconds(RandInt(kStartupWaitSeconds * 2,
    289                                           kStartupWaitSeconds * 4));
    290   } else if (days >= 3) {
    291     // Wait 20-40 minutes.
    292     return TimeDelta::FromSeconds(RandInt(kStartupWaitSeconds * 4,
    293                                           kStartupWaitSeconds * 8));
    294   }
    295 
    296   // Read the persisted next check time, and use that if it isn't too soon
    297   // or too late. Otherwise pick something random.
    298   Time saved_next = Time::FromInternalValue(prefs_->GetInt64(
    299       pref_names::kNextUpdateCheck));
    300   Time earliest = now + TimeDelta::FromSeconds(kStartupWaitSeconds);
    301   Time latest = now + TimeDelta::FromSeconds(frequency_seconds_);
    302   if (saved_next >= earliest && saved_next <= latest) {
    303     return saved_next - now;
    304   } else {
    305     return TimeDelta::FromSeconds(RandInt(kStartupWaitSeconds,
    306                                           frequency_seconds_));
    307   }
    308 }
    309 
    310 void ExtensionUpdater::Start() {
    311   DCHECK(!alive_);
    312   // If these are NULL, then that means we've been called after Stop()
    313   // has been called.
    314   DCHECK(service_);
    315   DCHECK(extension_prefs_);
    316   DCHECK(prefs_);
    317   DCHECK(profile_);
    318   DCHECK(!weak_ptr_factory_.HasWeakPtrs());
    319   alive_ = true;
    320   // Make sure our prefs are registered, then schedule the first check.
    321   ScheduleNextCheck(DetermineFirstCheckDelay());
    322 }
    323 
    324 void ExtensionUpdater::Stop() {
    325   weak_ptr_factory_.InvalidateWeakPtrs();
    326   alive_ = false;
    327   service_ = NULL;
    328   extension_prefs_ = NULL;
    329   prefs_ = NULL;
    330   profile_ = NULL;
    331   timer_.Stop();
    332   will_check_soon_ = false;
    333   downloader_.reset();
    334 }
    335 
    336 void ExtensionUpdater::ScheduleNextCheck(const TimeDelta& target_delay) {
    337   DCHECK(alive_);
    338   DCHECK(!timer_.IsRunning());
    339   DCHECK(target_delay >= TimeDelta::FromSeconds(1));
    340 
    341   // Add +/- 10% random jitter.
    342   double delay_ms = target_delay.InMillisecondsF();
    343   double jitter_factor = (RandDouble() * .2) - 0.1;
    344   delay_ms += delay_ms * jitter_factor;
    345   TimeDelta actual_delay = TimeDelta::FromMilliseconds(
    346       static_cast<int64>(delay_ms));
    347 
    348   // Save the time of next check.
    349   Time next = Time::Now() + actual_delay;
    350   prefs_->SetInt64(pref_names::kNextUpdateCheck, next.ToInternalValue());
    351 
    352   timer_.Start(FROM_HERE, actual_delay, this, &ExtensionUpdater::TimerFired);
    353 }
    354 
    355 void ExtensionUpdater::TimerFired() {
    356   DCHECK(alive_);
    357   CheckNow(default_params_);
    358 
    359   // If the user has overridden the update frequency, don't bother reporting
    360   // this.
    361   if (frequency_seconds_ == extensions::kDefaultUpdateFrequencySeconds) {
    362     Time last = Time::FromInternalValue(prefs_->GetInt64(
    363         pref_names::kLastUpdateCheck));
    364     if (last.ToInternalValue() != 0) {
    365       // Use counts rather than time so we can use minutes rather than millis.
    366       UMA_HISTOGRAM_CUSTOM_COUNTS("Extensions.UpdateCheckGap",
    367           (Time::Now() - last).InMinutes(),
    368           TimeDelta::FromSeconds(kStartupWaitSeconds).InMinutes(),
    369           TimeDelta::FromDays(40).InMinutes(),
    370           50);  // 50 buckets seems to be the default.
    371     }
    372   }
    373 
    374   // Save the last check time, and schedule the next check.
    375   int64 now = Time::Now().ToInternalValue();
    376   prefs_->SetInt64(pref_names::kLastUpdateCheck, now);
    377   ScheduleNextCheck(TimeDelta::FromSeconds(frequency_seconds_));
    378 }
    379 
    380 void ExtensionUpdater::CheckSoon() {
    381   DCHECK(alive_);
    382   if (will_check_soon_)
    383     return;
    384   if (BrowserThread::PostTask(
    385           BrowserThread::UI, FROM_HERE,
    386           base::Bind(&ExtensionUpdater::DoCheckSoon,
    387                      weak_ptr_factory_.GetWeakPtr()))) {
    388     will_check_soon_ = true;
    389   } else {
    390     NOTREACHED();
    391   }
    392 }
    393 
    394 bool ExtensionUpdater::WillCheckSoon() const {
    395   return will_check_soon_;
    396 }
    397 
    398 void ExtensionUpdater::DoCheckSoon() {
    399   DCHECK(will_check_soon_);
    400   CheckNow(default_params_);
    401   will_check_soon_ = false;
    402 }
    403 
    404 void ExtensionUpdater::AddToDownloader(
    405     const ExtensionSet* extensions,
    406     const std::list<std::string>& pending_ids,
    407     int request_id) {
    408   InProgressCheck& request = requests_in_progress_[request_id];
    409   for (ExtensionSet::const_iterator extension_iter = extensions->begin();
    410        extension_iter != extensions->end(); ++extension_iter) {
    411     const Extension& extension = *extension_iter->get();
    412     if (!Manifest::IsAutoUpdateableLocation(extension.location())) {
    413       VLOG(2) << "Extension " << extension.id() << " is not auto updateable";
    414       continue;
    415     }
    416     // An extension might be overwritten by policy, and have its update url
    417     // changed. Make sure existing extensions aren't fetched again, if a
    418     // pending fetch for an extension with the same id already exists.
    419     std::list<std::string>::const_iterator pending_id_iter = std::find(
    420         pending_ids.begin(), pending_ids.end(), extension.id());
    421     if (pending_id_iter == pending_ids.end()) {
    422       if (downloader_->AddExtension(extension, request_id))
    423         request.in_progress_ids_.push_back(extension.id());
    424     }
    425   }
    426 }
    427 
    428 void ExtensionUpdater::CheckNow(const CheckParams& params) {
    429   DetermineForcedUpdates(
    430       profile_,
    431       base::Bind(&ExtensionUpdater::OnForcedUpdatesDetermined,
    432                  weak_ptr_factory_.GetWeakPtr(),
    433                  params));
    434 }
    435 
    436 void ExtensionUpdater::OnForcedUpdatesDetermined(
    437     const CheckParams& params,
    438     const std::set<std::string>& forced_updates) {
    439   int request_id = next_request_id_++;
    440 
    441   VLOG(2) << "Starting update check " << request_id;
    442   if (params.ids.empty())
    443     NotifyStarted();
    444 
    445   DCHECK(alive_);
    446 
    447   InProgressCheck& request = requests_in_progress_[request_id];
    448   request.callback = params.callback;
    449   request.install_immediately = params.install_immediately;
    450 
    451   EnsureDownloaderCreated();
    452 
    453   forced_updates_ = forced_updates;
    454 
    455   // Add fetch records for extensions that should be fetched by an update URL.
    456   // These extensions are not yet installed. They come from group policy
    457   // and external install sources.
    458   const PendingExtensionManager* pending_extension_manager =
    459       service_->pending_extension_manager();
    460 
    461   std::list<std::string> pending_ids;
    462 
    463   if (params.ids.empty()) {
    464     // If no extension ids are specified, check for updates for all extensions.
    465     pending_extension_manager->GetPendingIdsForUpdateCheck(&pending_ids);
    466 
    467     std::list<std::string>::const_iterator iter;
    468     for (iter = pending_ids.begin(); iter != pending_ids.end(); ++iter) {
    469       const PendingExtensionInfo* info = pending_extension_manager->GetById(
    470           *iter);
    471       if (!Manifest::IsAutoUpdateableLocation(info->install_source())) {
    472         VLOG(2) << "Extension " << *iter << " is not auto updateable";
    473         continue;
    474       }
    475       if (downloader_->AddPendingExtension(*iter, info->update_url(),
    476                                            request_id))
    477         request.in_progress_ids_.push_back(*iter);
    478     }
    479 
    480     ExtensionRegistry* registry = ExtensionRegistry::Get(profile_);
    481     AddToDownloader(&registry->enabled_extensions(), pending_ids, request_id);
    482     AddToDownloader(&registry->disabled_extensions(), pending_ids, request_id);
    483   } else {
    484     for (std::list<std::string>::const_iterator it = params.ids.begin();
    485          it != params.ids.end(); ++it) {
    486       const Extension* extension = service_->GetExtensionById(*it, true);
    487       DCHECK(extension);
    488       if (downloader_->AddExtension(*extension, request_id))
    489         request.in_progress_ids_.push_back(extension->id());
    490     }
    491   }
    492 
    493   // StartAllPending() might call OnExtensionDownloadFailed/Finished before
    494   // it returns, which would cause NotifyIfFinished to incorrectly try to
    495   // send out a notification. So check before we call StartAllPending if any
    496   // extensions are going to be updated, and use that to figure out if
    497   // NotifyIfFinished should be called.
    498   bool noChecks = request.in_progress_ids_.empty();
    499 
    500   // StartAllPending() will call OnExtensionDownloadFailed or
    501   // OnExtensionDownloadFinished for each extension that was checked.
    502   downloader_->StartAllPending(extension_cache_);
    503 
    504   if (noChecks)
    505     NotifyIfFinished(request_id);
    506 }
    507 
    508 bool ExtensionUpdater::CheckExtensionSoon(const std::string& extension_id,
    509                                           const FinishedCallback& callback) {
    510   bool have_throttle_info = ContainsKey(throttle_info_, extension_id);
    511   ThrottleInfo& info = throttle_info_[extension_id];
    512   if (have_throttle_info) {
    513     // We already had a ThrottleInfo object for this extension, check if the
    514     // update check request should be allowed.
    515 
    516     // If another check is in progress, don't start a new check.
    517     if (info.in_progress)
    518       return false;
    519 
    520     Time now = Time::Now();
    521     Time last = info.check_start;
    522     // If somehow time moved back, we don't want to infinitely keep throttling.
    523     if (now < last) {
    524       last = now;
    525       info.check_start = now;
    526     }
    527     Time earliest = last + TimeDelta::FromSeconds(info.throttle_delay);
    528     // If check is too soon, throttle.
    529     if (now < earliest)
    530       return false;
    531 
    532     // TODO(mek): Somehow increase time between allowing checks when checks
    533     // are repeatedly throttled and don't result in updates being installed.
    534 
    535     // It's okay to start a check, update values.
    536     info.check_start = now;
    537     info.in_progress = true;
    538   }
    539 
    540   CheckParams params;
    541   params.ids.push_back(extension_id);
    542   params.callback = base::Bind(&ExtensionUpdater::ExtensionCheckFinished,
    543                                weak_ptr_factory_.GetWeakPtr(),
    544                                extension_id, callback);
    545   CheckNow(params);
    546   return true;
    547 }
    548 
    549 void ExtensionUpdater::ExtensionCheckFinished(
    550     const std::string& extension_id,
    551     const FinishedCallback& callback) {
    552   std::map<std::string, ThrottleInfo>::iterator it =
    553       throttle_info_.find(extension_id);
    554   if (it != throttle_info_.end()) {
    555     it->second.in_progress = false;
    556   }
    557   callback.Run();
    558 }
    559 
    560 void ExtensionUpdater::OnExtensionDownloadFailed(
    561     const std::string& id,
    562     Error error,
    563     const PingResult& ping,
    564     const std::set<int>& request_ids) {
    565   DCHECK(alive_);
    566   UpdatePingData(id, ping);
    567   bool install_immediately = false;
    568   for (std::set<int>::const_iterator it = request_ids.begin();
    569        it != request_ids.end(); ++it) {
    570     InProgressCheck& request = requests_in_progress_[*it];
    571     install_immediately |= request.install_immediately;
    572     request.in_progress_ids_.remove(id);
    573     NotifyIfFinished(*it);
    574   }
    575 
    576   // This method is called if no updates were found. However a previous update
    577   // check might have queued an update for this extension already. If a
    578   // current update check has |install_immediately| set the previously
    579   // queued update should be installed now.
    580   if (install_immediately && service_->GetPendingExtensionUpdate(id))
    581     service_->FinishDelayedInstallation(id);
    582 }
    583 
    584 void ExtensionUpdater::OnExtensionDownloadFinished(
    585     const std::string& id,
    586     const base::FilePath& path,
    587     bool file_ownership_passed,
    588     const GURL& download_url,
    589     const std::string& version,
    590     const PingResult& ping,
    591     const std::set<int>& request_ids) {
    592   DCHECK(alive_);
    593   UpdatePingData(id, ping);
    594 
    595   VLOG(2) << download_url << " written to " << path.value();
    596 
    597   FetchedCRXFile fetched(id, path, file_ownership_passed, request_ids);
    598   fetched_crx_files_.push(fetched);
    599 
    600   // MaybeInstallCRXFile() removes extensions from |in_progress_ids_| after
    601   // starting the crx installer.
    602   MaybeInstallCRXFile();
    603 }
    604 
    605 bool ExtensionUpdater::GetPingDataForExtension(
    606     const std::string& id,
    607     ManifestFetchData::PingData* ping_data) {
    608   DCHECK(alive_);
    609   ping_data->rollcall_days = CalculatePingDays(
    610       extension_prefs_->LastPingDay(id));
    611   ping_data->is_enabled = service_->IsExtensionEnabled(id);
    612   ping_data->active_days =
    613       CalculateActivePingDays(extension_prefs_->LastActivePingDay(id),
    614                               extension_prefs_->GetActiveBit(id));
    615   return true;
    616 }
    617 
    618 std::string ExtensionUpdater::GetUpdateUrlData(const std::string& id) {
    619   DCHECK(alive_);
    620   return extension::GetUpdateURLData(extension_prefs_, id);
    621 }
    622 
    623 bool ExtensionUpdater::IsExtensionPending(const std::string& id) {
    624   DCHECK(alive_);
    625   return service_->pending_extension_manager()->IsIdPending(id);
    626 }
    627 
    628 bool ExtensionUpdater::GetExtensionExistingVersion(const std::string& id,
    629                                                    std::string* version) {
    630   DCHECK(alive_);
    631   const Extension* extension = service_->GetExtensionById(id, true);
    632   if (!extension)
    633     return false;
    634   const Extension* update = service_->GetPendingExtensionUpdate(id);
    635   if (update)
    636     *version = update->VersionString();
    637   else
    638     *version = extension->VersionString();
    639   return true;
    640 }
    641 
    642 bool ExtensionUpdater::ShouldForceUpdate(
    643     const std::string& extension_id,
    644     std::string* source) {
    645   bool force = forced_updates_.find(extension_id) != forced_updates_.end();
    646   // Currently the only reason to force is a NaCl arch mismatch with the
    647   // installed extension contents.
    648   if (force) {
    649     *source = kWrongMultiCrxInstallSource;
    650   }
    651   return force;
    652 }
    653 
    654 void ExtensionUpdater::UpdatePingData(const std::string& id,
    655                                       const PingResult& ping_result) {
    656   DCHECK(alive_);
    657   if (ping_result.did_ping)
    658     extension_prefs_->SetLastPingDay(id, ping_result.day_start);
    659   if (extension_prefs_->GetActiveBit(id)) {
    660     extension_prefs_->SetActiveBit(id, false);
    661     extension_prefs_->SetLastActivePingDay(id, ping_result.day_start);
    662   }
    663 }
    664 
    665 void ExtensionUpdater::MaybeInstallCRXFile() {
    666   if (crx_install_is_running_ || fetched_crx_files_.empty())
    667     return;
    668 
    669   std::set<int> request_ids;
    670 
    671   while (!fetched_crx_files_.empty() && !crx_install_is_running_) {
    672     const FetchedCRXFile& crx_file = fetched_crx_files_.top();
    673 
    674     VLOG(2) << "updating " << crx_file.extension_id
    675             << " with " << crx_file.path.value();
    676 
    677     // The ExtensionService is now responsible for cleaning up the temp file
    678     // at |crx_file.path|.
    679     CrxInstaller* installer = NULL;
    680     if (service_->UpdateExtension(crx_file.extension_id,
    681                                   crx_file.path,
    682                                   crx_file.file_ownership_passed,
    683                                   &installer)) {
    684       crx_install_is_running_ = true;
    685       current_crx_file_ = crx_file;
    686 
    687       for (std::set<int>::const_iterator it = crx_file.request_ids.begin();
    688           it != crx_file.request_ids.end(); ++it) {
    689         InProgressCheck& request = requests_in_progress_[*it];
    690         if (request.install_immediately) {
    691           installer->set_install_immediately(true);
    692           break;
    693         }
    694       }
    695 
    696       // Source parameter ensures that we only see the completion event for the
    697       // the installer we started.
    698       registrar_.Add(this,
    699                      extensions::NOTIFICATION_CRX_INSTALLER_DONE,
    700                      content::Source<CrxInstaller>(installer));
    701     } else {
    702       for (std::set<int>::const_iterator it = crx_file.request_ids.begin();
    703            it != crx_file.request_ids.end(); ++it) {
    704         InProgressCheck& request = requests_in_progress_[*it];
    705         request.in_progress_ids_.remove(crx_file.extension_id);
    706       }
    707       request_ids.insert(crx_file.request_ids.begin(),
    708                          crx_file.request_ids.end());
    709     }
    710     fetched_crx_files_.pop();
    711   }
    712 
    713   for (std::set<int>::const_iterator it = request_ids.begin();
    714        it != request_ids.end(); ++it) {
    715     NotifyIfFinished(*it);
    716   }
    717 }
    718 
    719 void ExtensionUpdater::Observe(int type,
    720                                const content::NotificationSource& source,
    721                                const content::NotificationDetails& details) {
    722   DCHECK_EQ(type, extensions::NOTIFICATION_CRX_INSTALLER_DONE);
    723 
    724   registrar_.Remove(this, extensions::NOTIFICATION_CRX_INSTALLER_DONE, source);
    725   crx_install_is_running_ = false;
    726 
    727   const FetchedCRXFile& crx_file = current_crx_file_;
    728   for (std::set<int>::const_iterator it = crx_file.request_ids.begin();
    729       it != crx_file.request_ids.end(); ++it) {
    730     InProgressCheck& request = requests_in_progress_[*it];
    731     request.in_progress_ids_.remove(crx_file.extension_id);
    732     NotifyIfFinished(*it);
    733   }
    734 
    735   // If any files are available to update, start one.
    736   MaybeInstallCRXFile();
    737 }
    738 
    739 void ExtensionUpdater::OnExtensionWillBeInstalled(
    740     content::BrowserContext* browser_context,
    741     const Extension* extension,
    742     bool is_update,
    743     bool from_ephemeral,
    744     const std::string& old_name) {
    745   throttle_info_.erase(extension->id());
    746 }
    747 
    748 void ExtensionUpdater::NotifyStarted() {
    749   content::NotificationService::current()->Notify(
    750       extensions::NOTIFICATION_EXTENSION_UPDATING_STARTED,
    751       content::Source<Profile>(profile_),
    752       content::NotificationService::NoDetails());
    753 }
    754 
    755 void ExtensionUpdater::NotifyIfFinished(int request_id) {
    756   DCHECK(ContainsKey(requests_in_progress_, request_id));
    757   const InProgressCheck& request = requests_in_progress_[request_id];
    758   if (request.in_progress_ids_.empty()) {
    759     VLOG(2) << "Finished update check " << request_id;
    760     if (!request.callback.is_null())
    761       request.callback.Run();
    762     requests_in_progress_.erase(request_id);
    763   }
    764 }
    765 
    766 }  // namespace extensions
    767