Upstream version 10.39.225.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / extensions / updater / extension_updater.cc
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