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
41using base::RandDouble;
42using base::RandInt;
43using base::Time;
44using base::TimeDelta;
45using content::BrowserThread;
46using extensions::Extension;
47using extensions::ExtensionSet;
48using omaha_query_params::OmahaQueryParams;
49
50typedef extensions::ExtensionDownloaderDelegate::Error Error;
51typedef extensions::ExtensionDownloaderDelegate::PingResult PingResult;
52
53namespace {
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.
57const int kStartupWaitSeconds = 60 * 5;
58
59// For sanity checking on update frequency - enforced in release mode only.
60#if defined(NDEBUG)
61const int kMinUpdateFrequencySeconds = 30;
62#endif
63const int kMaxUpdateFrequencySeconds = 60 * 60 * 24 * 7;  // 7 days
64
65// Require at least 5 seconds between consecutive non-succesful extension update
66// checks.
67const int kMinUpdateThrottleTime = 5;
68
69// The installsource query parameter to use when forcing updates due to NaCl
70// arch mismatch.
71const 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.
77int 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.
84int 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
92int 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
101void 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
107void 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
159void 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
165void 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
184namespace extensions {
185
186ExtensionUpdater::CheckParams::CheckParams()
187    : install_immediately(false) {}
188
189ExtensionUpdater::CheckParams::~CheckParams() {}
190
191ExtensionUpdater::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
201ExtensionUpdater::FetchedCRXFile::FetchedCRXFile()
202    : path(), file_ownership_passed(true) {}
203
204ExtensionUpdater::FetchedCRXFile::~FetchedCRXFile() {}
205
206ExtensionUpdater::InProgressCheck::InProgressCheck()
207    : install_immediately(false) {}
208
209ExtensionUpdater::InProgressCheck::~InProgressCheck() {}
210
211struct 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
222ExtensionUpdater::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
254ExtensionUpdater::~ExtensionUpdater() {
255  Stop();
256}
257
258void 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.
266TimeDelta 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
310void 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
324void 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
336void 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
355void 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
380void 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
394bool ExtensionUpdater::WillCheckSoon() const {
395  return will_check_soon_;
396}
397
398void ExtensionUpdater::DoCheckSoon() {
399  DCHECK(will_check_soon_);
400  CheckNow(default_params_);
401  will_check_soon_ = false;
402}
403
404void 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
428void ExtensionUpdater::CheckNow(const CheckParams& params) {
429  DetermineForcedUpdates(
430      profile_,
431      base::Bind(&ExtensionUpdater::OnForcedUpdatesDetermined,
432                 weak_ptr_factory_.GetWeakPtr(),
433                 params));
434}
435
436void 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
508bool 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
549void 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
560void 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
584void 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
605bool 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
618std::string ExtensionUpdater::GetUpdateUrlData(const std::string& id) {
619  DCHECK(alive_);
620  return extension::GetUpdateURLData(extension_prefs_, id);
621}
622
623bool ExtensionUpdater::IsExtensionPending(const std::string& id) {
624  DCHECK(alive_);
625  return service_->pending_extension_manager()->IsIdPending(id);
626}
627
628bool 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
642bool 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
654void 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
665void 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
719void 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
739void 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
748void ExtensionUpdater::NotifyStarted() {
749  content::NotificationService::current()->Notify(
750      extensions::NOTIFICATION_EXTENSION_UPDATING_STARTED,
751      content::Source<Profile>(profile_),
752      content::NotificationService::NoDetails());
753}
754
755void 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