Rename GetIconID to GetIconId
[chromium-blink-merge.git] / chrome / browser / extensions / updater / extension_updater.cc
blob9343753d58a00d338d6a6152c4b33379157ad0c3
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.
5 #include "chrome/browser/extensions/updater/extension_updater.h"
7 #include <algorithm>
8 #include <set>
9 #include <vector>
11 #include "base/bind.h"
12 #include "base/files/file_util.h"
13 #include "base/logging.h"
14 #include "base/metrics/histogram.h"
15 #include "base/prefs/pref_service.h"
16 #include "base/rand_util.h"
17 #include "base/stl_util.h"
18 #include "base/strings/string_number_conversions.h"
19 #include "base/strings/string_split.h"
20 #include "chrome/browser/chrome_notification_types.h"
21 #include "chrome/browser/extensions/api/module/module.h"
22 #include "chrome/browser/extensions/crx_installer.h"
23 #include "chrome/browser/extensions/extension_service.h"
24 #include "chrome/browser/extensions/pending_extension_manager.h"
25 #include "chrome/browser/profiles/profile.h"
26 #include "components/update_client/update_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"
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 update_client::UpdateQueryParams;
50 typedef extensions::ExtensionDownloaderDelegate::Error Error;
51 typedef extensions::ExtensionDownloaderDelegate::PingResult PingResult;
53 namespace {
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;
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
65 // Require at least 5 seconds between consecutive non-succesful extension update
66 // checks.
67 const int kMinUpdateThrottleTime = 5;
69 // The installsource query parameter to use when forcing updates due to NaCl
70 // arch mismatch.
71 const char kWrongMultiCrxInstallSource[] = "wrong_multi_crx";
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;
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());
89 return days;
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());
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());
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 == UpdateQueryParams::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;
147 if (force)
148 forced_updates->insert(extension->id());
151 BrowserThread::PostTask(
152 BrowserThread::UI,
153 FROM_HERE,
154 base::Bind(&RespondWithForcedUpdates,
155 callback,
156 base::Passed(&forced_updates)));
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));
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));
182 } // namespace
184 namespace extensions {
186 ExtensionUpdater::CheckParams::CheckParams()
187 : install_immediately(false) {}
189 ExtensionUpdater::CheckParams::~CheckParams() {}
191 ExtensionUpdater::FetchedCRXFile::FetchedCRXFile(
192 const CRXFileInfo& file,
193 bool file_ownership_passed,
194 const std::set<int>& request_ids,
195 const InstallCallback& callback)
196 : info(file),
197 file_ownership_passed(file_ownership_passed),
198 request_ids(request_ids),
199 callback(callback) {
202 ExtensionUpdater::FetchedCRXFile::FetchedCRXFile()
203 : file_ownership_passed(true) {
206 ExtensionUpdater::FetchedCRXFile::~FetchedCRXFile() {}
208 ExtensionUpdater::InProgressCheck::InProgressCheck()
209 : install_immediately(false) {}
211 ExtensionUpdater::InProgressCheck::~InProgressCheck() {}
213 struct ExtensionUpdater::ThrottleInfo {
214 ThrottleInfo()
215 : in_progress(true),
216 throttle_delay(kMinUpdateThrottleTime),
217 check_start(Time::Now()) {}
219 bool in_progress;
220 int throttle_delay;
221 Time check_start;
224 ExtensionUpdater::ExtensionUpdater(
225 ExtensionServiceInterface* service,
226 ExtensionPrefs* extension_prefs,
227 PrefService* prefs,
228 Profile* profile,
229 int frequency_seconds,
230 ExtensionCache* cache,
231 const ExtensionDownloader::Factory& downloader_factory)
232 : alive_(false),
233 service_(service),
234 downloader_factory_(downloader_factory),
235 frequency_seconds_(frequency_seconds),
236 will_check_soon_(false),
237 extension_prefs_(extension_prefs),
238 prefs_(prefs),
239 profile_(profile),
240 next_request_id_(0),
241 extension_registry_observer_(this),
242 crx_install_is_running_(false),
243 extension_cache_(cache),
244 weak_ptr_factory_(this) {
245 DCHECK_GE(frequency_seconds_, 5);
246 DCHECK_LE(frequency_seconds_, kMaxUpdateFrequencySeconds);
247 #if defined(NDEBUG)
248 // In Release mode we enforce that update checks don't happen too often.
249 frequency_seconds_ = std::max(frequency_seconds_, kMinUpdateFrequencySeconds);
250 #endif
251 frequency_seconds_ = std::min(frequency_seconds_, kMaxUpdateFrequencySeconds);
253 extension_registry_observer_.Add(ExtensionRegistry::Get(profile));
256 ExtensionUpdater::~ExtensionUpdater() {
257 Stop();
260 void ExtensionUpdater::EnsureDownloaderCreated() {
261 if (!downloader_.get()) {
262 downloader_ = downloader_factory_.Run(this);
266 // The overall goal here is to balance keeping clients up to date while
267 // avoiding a thundering herd against update servers.
268 TimeDelta ExtensionUpdater::DetermineFirstCheckDelay() {
269 DCHECK(alive_);
270 // If someone's testing with a quick frequency, just allow it.
271 if (frequency_seconds_ < kStartupWaitSeconds)
272 return TimeDelta::FromSeconds(frequency_seconds_);
274 // If we've never scheduled a check before, start at frequency_seconds_.
275 if (!prefs_->HasPrefPath(pref_names::kNextUpdateCheck))
276 return TimeDelta::FromSeconds(frequency_seconds_);
278 // If it's been a long time since our last actual check, we want to do one
279 // relatively soon.
280 Time now = Time::Now();
281 Time last = Time::FromInternalValue(prefs_->GetInt64(
282 pref_names::kLastUpdateCheck));
283 int days = (now - last).InDays();
284 if (days >= 30) {
285 // Wait 5-10 minutes.
286 return TimeDelta::FromSeconds(RandInt(kStartupWaitSeconds,
287 kStartupWaitSeconds * 2));
288 } else if (days >= 14) {
289 // Wait 10-20 minutes.
290 return TimeDelta::FromSeconds(RandInt(kStartupWaitSeconds * 2,
291 kStartupWaitSeconds * 4));
292 } else if (days >= 3) {
293 // Wait 20-40 minutes.
294 return TimeDelta::FromSeconds(RandInt(kStartupWaitSeconds * 4,
295 kStartupWaitSeconds * 8));
298 // Read the persisted next check time, and use that if it isn't too soon
299 // or too late. Otherwise pick something random.
300 Time saved_next = Time::FromInternalValue(prefs_->GetInt64(
301 pref_names::kNextUpdateCheck));
302 Time earliest = now + TimeDelta::FromSeconds(kStartupWaitSeconds);
303 Time latest = now + TimeDelta::FromSeconds(frequency_seconds_);
304 if (saved_next >= earliest && saved_next <= latest) {
305 return saved_next - now;
306 } else {
307 return TimeDelta::FromSeconds(RandInt(kStartupWaitSeconds,
308 frequency_seconds_));
312 void ExtensionUpdater::Start() {
313 DCHECK(!alive_);
314 // If these are NULL, then that means we've been called after Stop()
315 // has been called.
316 DCHECK(service_);
317 DCHECK(extension_prefs_);
318 DCHECK(prefs_);
319 DCHECK(profile_);
320 DCHECK(!weak_ptr_factory_.HasWeakPtrs());
321 alive_ = true;
322 // Make sure our prefs are registered, then schedule the first check.
323 ScheduleNextCheck(DetermineFirstCheckDelay());
326 void ExtensionUpdater::Stop() {
327 weak_ptr_factory_.InvalidateWeakPtrs();
328 alive_ = false;
329 service_ = NULL;
330 extension_prefs_ = NULL;
331 prefs_ = NULL;
332 profile_ = NULL;
333 timer_.Stop();
334 will_check_soon_ = false;
335 downloader_.reset();
338 void ExtensionUpdater::ScheduleNextCheck(const TimeDelta& target_delay) {
339 DCHECK(alive_);
340 DCHECK(!timer_.IsRunning());
341 DCHECK(target_delay >= TimeDelta::FromSeconds(1));
343 // Add +/- 10% random jitter.
344 double delay_ms = target_delay.InMillisecondsF();
345 double jitter_factor = (RandDouble() * .2) - 0.1;
346 delay_ms += delay_ms * jitter_factor;
347 TimeDelta actual_delay = TimeDelta::FromMilliseconds(
348 static_cast<int64>(delay_ms));
350 // Save the time of next check.
351 Time next = Time::Now() + actual_delay;
352 prefs_->SetInt64(pref_names::kNextUpdateCheck, next.ToInternalValue());
354 timer_.Start(FROM_HERE, actual_delay, this, &ExtensionUpdater::TimerFired);
357 void ExtensionUpdater::TimerFired() {
358 DCHECK(alive_);
359 CheckNow(default_params_);
361 // If the user has overridden the update frequency, don't bother reporting
362 // this.
363 if (frequency_seconds_ == extensions::kDefaultUpdateFrequencySeconds) {
364 Time last = Time::FromInternalValue(prefs_->GetInt64(
365 pref_names::kLastUpdateCheck));
366 if (last.ToInternalValue() != 0) {
367 // Use counts rather than time so we can use minutes rather than millis.
368 UMA_HISTOGRAM_CUSTOM_COUNTS("Extensions.UpdateCheckGap",
369 (Time::Now() - last).InMinutes(),
370 TimeDelta::FromSeconds(kStartupWaitSeconds).InMinutes(),
371 TimeDelta::FromDays(40).InMinutes(),
372 50); // 50 buckets seems to be the default.
376 // Save the last check time, and schedule the next check.
377 int64 now = Time::Now().ToInternalValue();
378 prefs_->SetInt64(pref_names::kLastUpdateCheck, now);
379 ScheduleNextCheck(TimeDelta::FromSeconds(frequency_seconds_));
382 void ExtensionUpdater::CheckSoon() {
383 DCHECK(alive_);
384 if (will_check_soon_)
385 return;
386 if (BrowserThread::PostTask(
387 BrowserThread::UI, FROM_HERE,
388 base::Bind(&ExtensionUpdater::DoCheckSoon,
389 weak_ptr_factory_.GetWeakPtr()))) {
390 will_check_soon_ = true;
391 } else {
392 NOTREACHED();
396 bool ExtensionUpdater::WillCheckSoon() const {
397 return will_check_soon_;
400 void ExtensionUpdater::SetExtensionCacheForTesting(
401 ExtensionCache* extension_cache) {
402 extension_cache_ = extension_cache;
405 void ExtensionUpdater::StopTimerForTesting() {
406 timer_.Stop();
409 void ExtensionUpdater::DoCheckSoon() {
410 DCHECK(will_check_soon_);
411 CheckNow(default_params_);
412 will_check_soon_ = false;
415 void ExtensionUpdater::AddToDownloader(
416 const ExtensionSet* extensions,
417 const std::list<std::string>& pending_ids,
418 int request_id) {
419 InProgressCheck& request = requests_in_progress_[request_id];
420 for (ExtensionSet::const_iterator extension_iter = extensions->begin();
421 extension_iter != extensions->end(); ++extension_iter) {
422 const Extension& extension = *extension_iter->get();
423 if (!Manifest::IsAutoUpdateableLocation(extension.location())) {
424 VLOG(2) << "Extension " << extension.id() << " is not auto updateable";
425 continue;
427 // An extension might be overwritten by policy, and have its update url
428 // changed. Make sure existing extensions aren't fetched again, if a
429 // pending fetch for an extension with the same id already exists.
430 std::list<std::string>::const_iterator pending_id_iter = std::find(
431 pending_ids.begin(), pending_ids.end(), extension.id());
432 if (pending_id_iter == pending_ids.end()) {
433 if (downloader_->AddExtension(extension, request_id))
434 request.in_progress_ids_.push_back(extension.id());
439 void ExtensionUpdater::CheckNow(const CheckParams& params) {
440 DetermineForcedUpdates(
441 profile_,
442 base::Bind(&ExtensionUpdater::OnForcedUpdatesDetermined,
443 weak_ptr_factory_.GetWeakPtr(),
444 params));
447 void ExtensionUpdater::OnForcedUpdatesDetermined(
448 const CheckParams& params,
449 const std::set<std::string>& forced_updates) {
450 int request_id = next_request_id_++;
452 VLOG(2) << "Starting update check " << request_id;
453 if (params.ids.empty())
454 NotifyStarted();
456 DCHECK(alive_);
458 InProgressCheck& request = requests_in_progress_[request_id];
459 request.callback = params.callback;
460 request.install_immediately = params.install_immediately;
462 EnsureDownloaderCreated();
464 forced_updates_ = forced_updates;
466 // Add fetch records for extensions that should be fetched by an update URL.
467 // These extensions are not yet installed. They come from group policy
468 // and external install sources.
469 const PendingExtensionManager* pending_extension_manager =
470 service_->pending_extension_manager();
472 std::list<std::string> pending_ids;
474 if (params.ids.empty()) {
475 // If no extension ids are specified, check for updates for all extensions.
476 pending_extension_manager->GetPendingIdsForUpdateCheck(&pending_ids);
478 std::list<std::string>::const_iterator iter;
479 for (iter = pending_ids.begin(); iter != pending_ids.end(); ++iter) {
480 const PendingExtensionInfo* info = pending_extension_manager->GetById(
481 *iter);
482 if (!Manifest::IsAutoUpdateableLocation(info->install_source())) {
483 VLOG(2) << "Extension " << *iter << " is not auto updateable";
484 continue;
486 if (downloader_->AddPendingExtension(*iter, info->update_url(),
487 request_id))
488 request.in_progress_ids_.push_back(*iter);
491 ExtensionRegistry* registry = ExtensionRegistry::Get(profile_);
492 AddToDownloader(&registry->enabled_extensions(), pending_ids, request_id);
493 AddToDownloader(&registry->disabled_extensions(), pending_ids, request_id);
494 } else {
495 for (std::list<std::string>::const_iterator it = params.ids.begin();
496 it != params.ids.end(); ++it) {
497 const Extension* extension = service_->GetExtensionById(*it, true);
498 DCHECK(extension);
499 if (downloader_->AddExtension(*extension, request_id))
500 request.in_progress_ids_.push_back(extension->id());
504 // StartAllPending() might call OnExtensionDownloadFailed/Finished before
505 // it returns, which would cause NotifyIfFinished to incorrectly try to
506 // send out a notification. So check before we call StartAllPending if any
507 // extensions are going to be updated, and use that to figure out if
508 // NotifyIfFinished should be called.
509 bool noChecks = request.in_progress_ids_.empty();
511 // StartAllPending() will call OnExtensionDownloadFailed or
512 // OnExtensionDownloadFinished for each extension that was checked.
513 downloader_->StartAllPending(extension_cache_);
515 if (noChecks)
516 NotifyIfFinished(request_id);
519 bool ExtensionUpdater::CheckExtensionSoon(const std::string& extension_id,
520 const FinishedCallback& callback) {
521 bool have_throttle_info = ContainsKey(throttle_info_, extension_id);
522 ThrottleInfo& info = throttle_info_[extension_id];
523 if (have_throttle_info) {
524 // We already had a ThrottleInfo object for this extension, check if the
525 // update check request should be allowed.
527 // If another check is in progress, don't start a new check.
528 if (info.in_progress)
529 return false;
531 Time now = Time::Now();
532 Time last = info.check_start;
533 // If somehow time moved back, we don't want to infinitely keep throttling.
534 if (now < last) {
535 last = now;
536 info.check_start = now;
538 Time earliest = last + TimeDelta::FromSeconds(info.throttle_delay);
539 // If check is too soon, throttle.
540 if (now < earliest)
541 return false;
543 // TODO(mek): Somehow increase time between allowing checks when checks
544 // are repeatedly throttled and don't result in updates being installed.
546 // It's okay to start a check, update values.
547 info.check_start = now;
548 info.in_progress = true;
551 CheckParams params;
552 params.ids.push_back(extension_id);
553 params.callback = base::Bind(&ExtensionUpdater::ExtensionCheckFinished,
554 weak_ptr_factory_.GetWeakPtr(),
555 extension_id, callback);
556 CheckNow(params);
557 return true;
560 void ExtensionUpdater::ExtensionCheckFinished(
561 const std::string& extension_id,
562 const FinishedCallback& callback) {
563 std::map<std::string, ThrottleInfo>::iterator it =
564 throttle_info_.find(extension_id);
565 if (it != throttle_info_.end()) {
566 it->second.in_progress = false;
568 callback.Run();
571 void ExtensionUpdater::OnExtensionDownloadFailed(
572 const std::string& id,
573 Error error,
574 const PingResult& ping,
575 const std::set<int>& request_ids) {
576 DCHECK(alive_);
577 UpdatePingData(id, ping);
578 bool install_immediately = false;
579 for (std::set<int>::const_iterator it = request_ids.begin();
580 it != request_ids.end(); ++it) {
581 InProgressCheck& request = requests_in_progress_[*it];
582 install_immediately |= request.install_immediately;
583 request.in_progress_ids_.remove(id);
584 NotifyIfFinished(*it);
587 // This method is called if no updates were found. However a previous update
588 // check might have queued an update for this extension already. If a
589 // current update check has |install_immediately| set the previously
590 // queued update should be installed now.
591 if (install_immediately && service_->GetPendingExtensionUpdate(id))
592 service_->FinishDelayedInstallation(id);
595 void ExtensionUpdater::OnExtensionDownloadFinished(
596 const CRXFileInfo& file,
597 bool file_ownership_passed,
598 const GURL& download_url,
599 const std::string& version,
600 const PingResult& ping,
601 const std::set<int>& request_ids,
602 const InstallCallback& callback) {
603 DCHECK(alive_);
604 UpdatePingData(file.extension_id, ping);
606 VLOG(2) << download_url << " written to " << file.path.value();
608 FetchedCRXFile fetched(file, file_ownership_passed, request_ids, callback);
609 fetched_crx_files_.push(fetched);
611 // MaybeInstallCRXFile() removes extensions from |in_progress_ids_| after
612 // starting the crx installer.
613 MaybeInstallCRXFile();
616 bool ExtensionUpdater::GetPingDataForExtension(
617 const std::string& id,
618 ManifestFetchData::PingData* ping_data) {
619 DCHECK(alive_);
620 ping_data->rollcall_days = CalculatePingDays(
621 extension_prefs_->LastPingDay(id));
622 ping_data->is_enabled = service_->IsExtensionEnabled(id);
623 if (!ping_data->is_enabled)
624 ping_data->disable_reasons = extension_prefs_->GetDisableReasons(id);
625 ping_data->active_days =
626 CalculateActivePingDays(extension_prefs_->LastActivePingDay(id),
627 extension_prefs_->GetActiveBit(id));
628 return true;
631 std::string ExtensionUpdater::GetUpdateUrlData(const std::string& id) {
632 DCHECK(alive_);
633 return extension::GetUpdateURLData(extension_prefs_, id);
636 bool ExtensionUpdater::IsExtensionPending(const std::string& id) {
637 DCHECK(alive_);
638 return service_->pending_extension_manager()->IsIdPending(id);
641 bool ExtensionUpdater::GetExtensionExistingVersion(const std::string& id,
642 std::string* version) {
643 DCHECK(alive_);
644 const Extension* extension = service_->GetExtensionById(id, true);
645 if (!extension)
646 return false;
647 const Extension* update = service_->GetPendingExtensionUpdate(id);
648 if (update)
649 *version = update->VersionString();
650 else
651 *version = extension->VersionString();
652 return true;
655 bool ExtensionUpdater::ShouldForceUpdate(
656 const std::string& extension_id,
657 std::string* source) {
658 bool force = forced_updates_.find(extension_id) != forced_updates_.end();
659 // Currently the only reason to force is a NaCl arch mismatch with the
660 // installed extension contents.
661 if (force) {
662 *source = kWrongMultiCrxInstallSource;
664 return force;
667 void ExtensionUpdater::UpdatePingData(const std::string& id,
668 const PingResult& ping_result) {
669 DCHECK(alive_);
670 if (ping_result.did_ping)
671 extension_prefs_->SetLastPingDay(id, ping_result.day_start);
672 if (extension_prefs_->GetActiveBit(id)) {
673 extension_prefs_->SetActiveBit(id, false);
674 extension_prefs_->SetLastActivePingDay(id, ping_result.day_start);
678 void ExtensionUpdater::MaybeInstallCRXFile() {
679 if (crx_install_is_running_ || fetched_crx_files_.empty())
680 return;
682 std::set<int> request_ids;
684 while (!fetched_crx_files_.empty() && !crx_install_is_running_) {
685 const FetchedCRXFile& crx_file = fetched_crx_files_.top();
687 VLOG(2) << "updating " << crx_file.info.extension_id
688 << " with " << crx_file.info.path.value();
690 // The ExtensionService is now responsible for cleaning up the temp file
691 // at |crx_file.info.path|.
692 CrxInstaller* installer = NULL;
693 if (service_->UpdateExtension(crx_file.info,
694 crx_file.file_ownership_passed,
695 &installer)) {
696 crx_install_is_running_ = true;
697 current_crx_file_ = crx_file;
699 for (std::set<int>::const_iterator it = crx_file.request_ids.begin();
700 it != crx_file.request_ids.end(); ++it) {
701 InProgressCheck& request = requests_in_progress_[*it];
702 if (request.install_immediately) {
703 installer->set_install_immediately(true);
704 break;
708 // Source parameter ensures that we only see the completion event for the
709 // the installer we started.
710 registrar_.Add(this,
711 extensions::NOTIFICATION_CRX_INSTALLER_DONE,
712 content::Source<CrxInstaller>(installer));
713 } else {
714 for (std::set<int>::const_iterator it = crx_file.request_ids.begin();
715 it != crx_file.request_ids.end(); ++it) {
716 InProgressCheck& request = requests_in_progress_[*it];
717 request.in_progress_ids_.remove(crx_file.info.extension_id);
719 request_ids.insert(crx_file.request_ids.begin(),
720 crx_file.request_ids.end());
722 fetched_crx_files_.pop();
725 for (std::set<int>::const_iterator it = request_ids.begin();
726 it != request_ids.end(); ++it) {
727 NotifyIfFinished(*it);
731 void ExtensionUpdater::Observe(int type,
732 const content::NotificationSource& source,
733 const content::NotificationDetails& details) {
734 DCHECK_EQ(type, extensions::NOTIFICATION_CRX_INSTALLER_DONE);
736 registrar_.Remove(this, extensions::NOTIFICATION_CRX_INSTALLER_DONE, source);
737 crx_install_is_running_ = false;
739 // If installing this file didn't succeed, we may need to re-download it.
740 const Extension* extension = content::Details<const Extension>(details).ptr();
741 extensions::CrxInstaller* installer =
742 content::Source<extensions::CrxInstaller>(source).ptr();
743 const FetchedCRXFile& crx_file = current_crx_file_;
744 if (!extension && installer->hash_check_failed() &&
745 !crx_file.callback.is_null()) {
746 // If extension downloader asked us to notify it about failed installations,
747 // it will resume a pending download from the manifest data it has already
748 // fetched and call us again with the same request_id's (with either
749 // OnExtensionDownloadFailed or OnExtensionDownloadFinished). For that
750 // reason we don't notify finished requests yet.
751 crx_file.callback.Run(true);
752 } else {
753 for (std::set<int>::const_iterator it = crx_file.request_ids.begin();
754 it != crx_file.request_ids.end(); ++it) {
755 InProgressCheck& request = requests_in_progress_[*it];
756 request.in_progress_ids_.remove(crx_file.info.extension_id);
757 NotifyIfFinished(*it);
759 if (!crx_file.callback.is_null()) {
760 crx_file.callback.Run(false);
764 // If any files are available to update, start one.
765 MaybeInstallCRXFile();
768 void ExtensionUpdater::OnExtensionWillBeInstalled(
769 content::BrowserContext* browser_context,
770 const Extension* extension,
771 bool is_update,
772 bool from_ephemeral,
773 const std::string& old_name) {
774 throttle_info_.erase(extension->id());
777 void ExtensionUpdater::NotifyStarted() {
778 content::NotificationService::current()->Notify(
779 extensions::NOTIFICATION_EXTENSION_UPDATING_STARTED,
780 content::Source<Profile>(profile_),
781 content::NotificationService::NoDetails());
784 void ExtensionUpdater::NotifyIfFinished(int request_id) {
785 DCHECK(ContainsKey(requests_in_progress_, request_id));
786 const InProgressCheck& request = requests_in_progress_[request_id];
787 if (request.in_progress_ids_.empty()) {
788 VLOG(2) << "Finished update check " << request_id;
789 if (!request.callback.is_null())
790 request.callback.Run();
791 requests_in_progress_.erase(request_id);
795 } // namespace extensions