Disable view source for Developer Tools.
[chromium-blink-merge.git] / chrome / browser / extensions / updater / extension_updater.cc
blob7813887803b1cd66c78a3c461534a9c95a97707f
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/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/updater/extension_downloader.h"
24 #include "chrome/browser/profiles/profile.h"
25 #include "chrome/common/pref_names.h"
26 #include "content/public/browser/browser_thread.h"
27 #include "content/public/browser/notification_details.h"
28 #include "content/public/browser/notification_service.h"
29 #include "content/public/browser/notification_source.h"
30 #include "crypto/sha2.h"
31 #include "extensions/browser/pending_extension_manager.h"
32 #include "extensions/browser/pref_names.h"
33 #include "extensions/common/constants.h"
34 #include "extensions/common/extension.h"
35 #include "extensions/common/extension_set.h"
36 #include "extensions/common/manifest.h"
38 using base::RandDouble;
39 using base::RandInt;
40 using base::Time;
41 using base::TimeDelta;
42 using content::BrowserThread;
44 typedef extensions::ExtensionDownloaderDelegate::Error Error;
45 typedef extensions::ExtensionDownloaderDelegate::PingResult PingResult;
47 namespace {
49 // Wait at least 5 minutes after browser startup before we do any checks. If you
50 // change this value, make sure to update comments where it is used.
51 const int kStartupWaitSeconds = 60 * 5;
53 // For sanity checking on update frequency - enforced in release mode only.
54 #ifdef NDEBUG
55 const int kMinUpdateFrequencySeconds = 30;
56 #endif
57 const int kMaxUpdateFrequencySeconds = 60 * 60 * 24 * 7; // 7 days
59 // Require at least 5 seconds between consecutive non-succesful extension update
60 // checks.
61 const int kMinUpdateThrottleTime = 5;
63 // When we've computed a days value, we want to make sure we don't send a
64 // negative value (due to the system clock being set backwards, etc.), since -1
65 // is a special sentinel value that means "never pinged", and other negative
66 // values don't make sense.
67 int SanitizeDays(int days) {
68 if (days < 0)
69 return 0;
70 return days;
73 // Calculates the value to use for the ping days parameter.
74 int CalculatePingDays(const Time& last_ping_day) {
75 int days = extensions::ManifestFetchData::kNeverPinged;
76 if (!last_ping_day.is_null()) {
77 days = SanitizeDays((Time::Now() - last_ping_day).InDays());
79 return days;
82 int CalculateActivePingDays(const Time& last_active_ping_day,
83 bool hasActiveBit) {
84 if (!hasActiveBit)
85 return 0;
86 if (last_active_ping_day.is_null())
87 return extensions::ManifestFetchData::kNeverPinged;
88 return SanitizeDays((Time::Now() - last_active_ping_day).InDays());
91 } // namespace
93 namespace extensions {
95 ExtensionUpdater::CheckParams::CheckParams()
96 : install_immediately(false) {}
98 ExtensionUpdater::CheckParams::~CheckParams() {}
100 ExtensionUpdater::FetchedCRXFile::FetchedCRXFile(
101 const std::string& i,
102 const base::FilePath& p,
103 const GURL& u,
104 const std::set<int>& request_ids)
105 : extension_id(i),
106 path(p),
107 download_url(u),
108 request_ids(request_ids) {}
110 ExtensionUpdater::FetchedCRXFile::FetchedCRXFile() : path(), download_url() {}
112 ExtensionUpdater::FetchedCRXFile::~FetchedCRXFile() {}
114 ExtensionUpdater::InProgressCheck::InProgressCheck()
115 : install_immediately(false) {}
117 ExtensionUpdater::InProgressCheck::~InProgressCheck() {}
119 struct ExtensionUpdater::ThrottleInfo {
120 ThrottleInfo()
121 : in_progress(true),
122 throttle_delay(kMinUpdateThrottleTime),
123 check_start(Time::Now()) {}
125 bool in_progress;
126 int throttle_delay;
127 Time check_start;
130 ExtensionUpdater::ExtensionUpdater(ExtensionServiceInterface* service,
131 ExtensionPrefs* extension_prefs,
132 PrefService* prefs,
133 Profile* profile,
134 int frequency_seconds)
135 : alive_(false),
136 weak_ptr_factory_(this),
137 service_(service), frequency_seconds_(frequency_seconds),
138 will_check_soon_(false), extension_prefs_(extension_prefs),
139 prefs_(prefs), profile_(profile),
140 next_request_id_(0),
141 crx_install_is_running_(false) {
142 DCHECK_GE(frequency_seconds_, 5);
143 DCHECK_LE(frequency_seconds_, kMaxUpdateFrequencySeconds);
144 #ifdef NDEBUG
145 // In Release mode we enforce that update checks don't happen too often.
146 frequency_seconds_ = std::max(frequency_seconds_, kMinUpdateFrequencySeconds);
147 #endif
148 frequency_seconds_ = std::min(frequency_seconds_, kMaxUpdateFrequencySeconds);
150 registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_INSTALLED,
151 content::NotificationService::AllBrowserContextsAndSources());
154 ExtensionUpdater::~ExtensionUpdater() {
155 Stop();
158 // The overall goal here is to balance keeping clients up to date while
159 // avoiding a thundering herd against update servers.
160 TimeDelta ExtensionUpdater::DetermineFirstCheckDelay() {
161 DCHECK(alive_);
162 // If someone's testing with a quick frequency, just allow it.
163 if (frequency_seconds_ < kStartupWaitSeconds)
164 return TimeDelta::FromSeconds(frequency_seconds_);
166 // If we've never scheduled a check before, start at frequency_seconds_.
167 if (!prefs_->HasPrefPath(pref_names::kNextUpdateCheck))
168 return TimeDelta::FromSeconds(frequency_seconds_);
170 // If it's been a long time since our last actual check, we want to do one
171 // relatively soon.
172 Time now = Time::Now();
173 Time last = Time::FromInternalValue(prefs_->GetInt64(
174 pref_names::kLastUpdateCheck));
175 int days = (now - last).InDays();
176 if (days >= 30) {
177 // Wait 5-10 minutes.
178 return TimeDelta::FromSeconds(RandInt(kStartupWaitSeconds,
179 kStartupWaitSeconds * 2));
180 } else if (days >= 14) {
181 // Wait 10-20 minutes.
182 return TimeDelta::FromSeconds(RandInt(kStartupWaitSeconds * 2,
183 kStartupWaitSeconds * 4));
184 } else if (days >= 3) {
185 // Wait 20-40 minutes.
186 return TimeDelta::FromSeconds(RandInt(kStartupWaitSeconds * 4,
187 kStartupWaitSeconds * 8));
190 // Read the persisted next check time, and use that if it isn't too soon.
191 // Otherwise pick something random.
192 Time saved_next = Time::FromInternalValue(prefs_->GetInt64(
193 pref_names::kNextUpdateCheck));
194 Time earliest = now + TimeDelta::FromSeconds(kStartupWaitSeconds);
195 if (saved_next >= earliest) {
196 return saved_next - now;
197 } else {
198 return TimeDelta::FromSeconds(RandInt(kStartupWaitSeconds,
199 frequency_seconds_));
203 void ExtensionUpdater::Start() {
204 DCHECK(!alive_);
205 // If these are NULL, then that means we've been called after Stop()
206 // has been called.
207 DCHECK(service_);
208 DCHECK(extension_prefs_);
209 DCHECK(prefs_);
210 DCHECK(profile_);
211 DCHECK(!weak_ptr_factory_.HasWeakPtrs());
212 alive_ = true;
213 // Make sure our prefs are registered, then schedule the first check.
214 ScheduleNextCheck(DetermineFirstCheckDelay());
217 void ExtensionUpdater::Stop() {
218 weak_ptr_factory_.InvalidateWeakPtrs();
219 alive_ = false;
220 service_ = NULL;
221 extension_prefs_ = NULL;
222 prefs_ = NULL;
223 profile_ = NULL;
224 timer_.Stop();
225 will_check_soon_ = false;
226 downloader_.reset();
229 void ExtensionUpdater::ScheduleNextCheck(const TimeDelta& target_delay) {
230 DCHECK(alive_);
231 DCHECK(!timer_.IsRunning());
232 DCHECK(target_delay >= TimeDelta::FromSeconds(1));
234 // Add +/- 10% random jitter.
235 double delay_ms = target_delay.InMillisecondsF();
236 double jitter_factor = (RandDouble() * .2) - 0.1;
237 delay_ms += delay_ms * jitter_factor;
238 TimeDelta actual_delay = TimeDelta::FromMilliseconds(
239 static_cast<int64>(delay_ms));
241 // Save the time of next check.
242 Time next = Time::Now() + actual_delay;
243 prefs_->SetInt64(pref_names::kNextUpdateCheck, next.ToInternalValue());
245 timer_.Start(FROM_HERE, actual_delay, this, &ExtensionUpdater::TimerFired);
248 void ExtensionUpdater::TimerFired() {
249 DCHECK(alive_);
250 CheckNow(default_params_);
252 // If the user has overridden the update frequency, don't bother reporting
253 // this.
254 if (frequency_seconds_ == extensions::kDefaultUpdateFrequencySeconds) {
255 Time last = Time::FromInternalValue(prefs_->GetInt64(
256 pref_names::kLastUpdateCheck));
257 if (last.ToInternalValue() != 0) {
258 // Use counts rather than time so we can use minutes rather than millis.
259 UMA_HISTOGRAM_CUSTOM_COUNTS("Extensions.UpdateCheckGap",
260 (Time::Now() - last).InMinutes(),
261 TimeDelta::FromSeconds(kStartupWaitSeconds).InMinutes(),
262 TimeDelta::FromDays(40).InMinutes(),
263 50); // 50 buckets seems to be the default.
267 // Save the last check time, and schedule the next check.
268 int64 now = Time::Now().ToInternalValue();
269 prefs_->SetInt64(pref_names::kLastUpdateCheck, now);
270 ScheduleNextCheck(TimeDelta::FromSeconds(frequency_seconds_));
273 void ExtensionUpdater::CheckSoon() {
274 DCHECK(alive_);
275 if (will_check_soon_)
276 return;
277 if (BrowserThread::PostTask(
278 BrowserThread::UI, FROM_HERE,
279 base::Bind(&ExtensionUpdater::DoCheckSoon,
280 weak_ptr_factory_.GetWeakPtr()))) {
281 will_check_soon_ = true;
282 } else {
283 NOTREACHED();
287 bool ExtensionUpdater::WillCheckSoon() const {
288 return will_check_soon_;
291 void ExtensionUpdater::DoCheckSoon() {
292 DCHECK(will_check_soon_);
293 CheckNow(default_params_);
294 will_check_soon_ = false;
297 void ExtensionUpdater::AddToDownloader(
298 const ExtensionSet* extensions,
299 const std::list<std::string>& pending_ids,
300 int request_id) {
301 InProgressCheck& request = requests_in_progress_[request_id];
302 for (ExtensionSet::const_iterator extension_iter = extensions->begin();
303 extension_iter != extensions->end(); ++extension_iter) {
304 const Extension& extension = *extension_iter->get();
305 if (!Manifest::IsAutoUpdateableLocation(extension.location())) {
306 VLOG(2) << "Extension " << extension.id() << " is not auto updateable";
307 continue;
309 // An extension might be overwritten by policy, and have its update url
310 // changed. Make sure existing extensions aren't fetched again, if a
311 // pending fetch for an extension with the same id already exists.
312 std::list<std::string>::const_iterator pending_id_iter = std::find(
313 pending_ids.begin(), pending_ids.end(), extension.id());
314 if (pending_id_iter == pending_ids.end()) {
315 if (downloader_->AddExtension(extension, request_id))
316 request.in_progress_ids_.push_back(extension.id());
321 void ExtensionUpdater::CheckNow(const CheckParams& params) {
322 int request_id = next_request_id_++;
324 VLOG(2) << "Starting update check " << request_id;
325 if (params.ids.empty())
326 NotifyStarted();
328 DCHECK(alive_);
330 InProgressCheck& request = requests_in_progress_[request_id];
331 request.callback = params.callback;
332 request.install_immediately = params.install_immediately;
334 if (!downloader_.get()) {
335 downloader_.reset(
336 new ExtensionDownloader(this, profile_->GetRequestContext()));
339 // Add fetch records for extensions that should be fetched by an update URL.
340 // These extensions are not yet installed. They come from group policy
341 // and external install sources.
342 const PendingExtensionManager* pending_extension_manager =
343 service_->pending_extension_manager();
345 std::list<std::string> pending_ids;
347 if (params.ids.empty()) {
348 // If no extension ids are specified, check for updates for all extensions.
349 pending_extension_manager->GetPendingIdsForUpdateCheck(&pending_ids);
351 std::list<std::string>::const_iterator iter;
352 for (iter = pending_ids.begin(); iter != pending_ids.end(); ++iter) {
353 const PendingExtensionInfo* info = pending_extension_manager->GetById(
354 *iter);
355 if (!Manifest::IsAutoUpdateableLocation(info->install_source())) {
356 VLOG(2) << "Extension " << *iter << " is not auto updateable";
357 continue;
359 if (downloader_->AddPendingExtension(*iter, info->update_url(),
360 request_id))
361 request.in_progress_ids_.push_back(*iter);
364 AddToDownloader(service_->extensions(), pending_ids, request_id);
365 AddToDownloader(service_->disabled_extensions(), pending_ids, request_id);
366 } else {
367 for (std::list<std::string>::const_iterator it = params.ids.begin();
368 it != params.ids.end(); ++it) {
369 const Extension* extension = service_->GetExtensionById(*it, true);
370 DCHECK(extension);
371 if (downloader_->AddExtension(*extension, request_id))
372 request.in_progress_ids_.push_back(extension->id());
376 // StartAllPending() might call OnExtensionDownloadFailed/Finished before
377 // it returns, which would cause NotifyIfFinished to incorrectly try to
378 // send out a notification. So check before we call StartAllPending if any
379 // extensions are going to be updated, and use that to figure out if
380 // NotifyIfFinished should be called.
381 bool noChecks = request.in_progress_ids_.empty();
383 // StartAllPending() will call OnExtensionDownloadFailed or
384 // OnExtensionDownloadFinished for each extension that was checked.
385 downloader_->StartAllPending();
388 if (noChecks)
389 NotifyIfFinished(request_id);
392 bool ExtensionUpdater::CheckExtensionSoon(const std::string& extension_id,
393 const FinishedCallback& callback) {
394 bool have_throttle_info = ContainsKey(throttle_info_, extension_id);
395 ThrottleInfo& info = throttle_info_[extension_id];
396 if (have_throttle_info) {
397 // We already had a ThrottleInfo object for this extension, check if the
398 // update check request should be allowed.
400 // If another check is in progress, don't start a new check.
401 if (info.in_progress)
402 return false;
404 Time now = Time::Now();
405 Time last = info.check_start;
406 // If somehow time moved back, we don't want to infinitely keep throttling.
407 if (now < last) {
408 last = now;
409 info.check_start = now;
411 Time earliest = last + TimeDelta::FromSeconds(info.throttle_delay);
412 // If check is too soon, throttle.
413 if (now < earliest)
414 return false;
416 // TODO(mek): Somehow increase time between allowing checks when checks
417 // are repeatedly throttled and don't result in updates being installed.
419 // It's okay to start a check, update values.
420 info.check_start = now;
421 info.in_progress = true;
424 CheckParams params;
425 params.ids.push_back(extension_id);
426 params.callback = base::Bind(&ExtensionUpdater::ExtensionCheckFinished,
427 weak_ptr_factory_.GetWeakPtr(),
428 extension_id, callback);
429 CheckNow(params);
430 return true;
433 void ExtensionUpdater::ExtensionCheckFinished(
434 const std::string& extension_id,
435 const FinishedCallback& callback) {
436 std::map<std::string, ThrottleInfo>::iterator it =
437 throttle_info_.find(extension_id);
438 if (it != throttle_info_.end()) {
439 it->second.in_progress = false;
441 callback.Run();
444 void ExtensionUpdater::OnExtensionDownloadFailed(
445 const std::string& id,
446 Error error,
447 const PingResult& ping,
448 const std::set<int>& request_ids) {
449 DCHECK(alive_);
450 UpdatePingData(id, ping);
451 bool install_immediately = false;
452 for (std::set<int>::const_iterator it = request_ids.begin();
453 it != request_ids.end(); ++it) {
454 InProgressCheck& request = requests_in_progress_[*it];
455 install_immediately |= request.install_immediately;
456 request.in_progress_ids_.remove(id);
457 NotifyIfFinished(*it);
460 // This method is called if no updates were found. However a previous update
461 // check might have queued an update for this extension already. If a
462 // current update check has |install_immediately| set the previously
463 // queued update should be installed now.
464 if (install_immediately && service_->GetPendingExtensionUpdate(id))
465 service_->FinishDelayedInstallation(id);
468 void ExtensionUpdater::OnExtensionDownloadFinished(
469 const std::string& id,
470 const base::FilePath& path,
471 const GURL& download_url,
472 const std::string& version,
473 const PingResult& ping,
474 const std::set<int>& request_ids) {
475 DCHECK(alive_);
476 UpdatePingData(id, ping);
478 VLOG(2) << download_url << " written to " << path.value();
480 FetchedCRXFile fetched(id, path, download_url, request_ids);
481 fetched_crx_files_.push(fetched);
483 // MaybeInstallCRXFile() removes extensions from |in_progress_ids_| after
484 // starting the crx installer.
485 MaybeInstallCRXFile();
488 bool ExtensionUpdater::GetPingDataForExtension(
489 const std::string& id,
490 ManifestFetchData::PingData* ping_data) {
491 DCHECK(alive_);
492 ping_data->rollcall_days = CalculatePingDays(
493 extension_prefs_->LastPingDay(id));
494 ping_data->is_enabled = service_->IsExtensionEnabled(id);
495 ping_data->active_days =
496 CalculateActivePingDays(extension_prefs_->LastActivePingDay(id),
497 extension_prefs_->GetActiveBit(id));
498 return true;
501 std::string ExtensionUpdater::GetUpdateUrlData(const std::string& id) {
502 DCHECK(alive_);
503 return extension::GetUpdateURLData(extension_prefs_, id);
506 bool ExtensionUpdater::IsExtensionPending(const std::string& id) {
507 DCHECK(alive_);
508 return service_->pending_extension_manager()->IsIdPending(id);
511 bool ExtensionUpdater::GetExtensionExistingVersion(const std::string& id,
512 std::string* version) {
513 DCHECK(alive_);
514 const Extension* extension = service_->GetExtensionById(id, true);
515 if (!extension)
516 return false;
517 const Extension* update = service_->GetPendingExtensionUpdate(id);
518 if (update)
519 *version = update->VersionString();
520 else
521 *version = extension->VersionString();
522 return true;
525 void ExtensionUpdater::UpdatePingData(const std::string& id,
526 const PingResult& ping_result) {
527 DCHECK(alive_);
528 if (ping_result.did_ping)
529 extension_prefs_->SetLastPingDay(id, ping_result.day_start);
530 if (extension_prefs_->GetActiveBit(id)) {
531 extension_prefs_->SetActiveBit(id, false);
532 extension_prefs_->SetLastActivePingDay(id, ping_result.day_start);
536 void ExtensionUpdater::MaybeInstallCRXFile() {
537 if (crx_install_is_running_ || fetched_crx_files_.empty())
538 return;
540 std::set<int> request_ids;
542 while (!fetched_crx_files_.empty() && !crx_install_is_running_) {
543 const FetchedCRXFile& crx_file = fetched_crx_files_.top();
545 VLOG(2) << "updating " << crx_file.extension_id
546 << " with " << crx_file.path.value();
548 // The ExtensionService is now responsible for cleaning up the temp file
549 // at |crx_file.path|.
550 CrxInstaller* installer = NULL;
551 if (service_->UpdateExtension(crx_file.extension_id,
552 crx_file.path,
553 crx_file.download_url,
554 &installer)) {
555 crx_install_is_running_ = true;
556 current_crx_file_ = crx_file;
558 for (std::set<int>::const_iterator it = crx_file.request_ids.begin();
559 it != crx_file.request_ids.end(); ++it) {
560 InProgressCheck& request = requests_in_progress_[*it];
561 if (request.install_immediately) {
562 installer->set_install_wait_for_idle(false);
563 break;
567 // Source parameter ensures that we only see the completion event for the
568 // the installer we started.
569 registrar_.Add(this,
570 chrome::NOTIFICATION_CRX_INSTALLER_DONE,
571 content::Source<CrxInstaller>(installer));
572 } else {
573 for (std::set<int>::const_iterator it = crx_file.request_ids.begin();
574 it != crx_file.request_ids.end(); ++it) {
575 InProgressCheck& request = requests_in_progress_[*it];
576 request.in_progress_ids_.remove(crx_file.extension_id);
578 request_ids.insert(crx_file.request_ids.begin(),
579 crx_file.request_ids.end());
581 fetched_crx_files_.pop();
584 for (std::set<int>::const_iterator it = request_ids.begin();
585 it != request_ids.end(); ++it) {
586 NotifyIfFinished(*it);
590 void ExtensionUpdater::Observe(int type,
591 const content::NotificationSource& source,
592 const content::NotificationDetails& details) {
593 switch (type) {
594 case chrome::NOTIFICATION_CRX_INSTALLER_DONE: {
595 // No need to listen for CRX_INSTALLER_DONE anymore.
596 registrar_.Remove(this,
597 chrome::NOTIFICATION_CRX_INSTALLER_DONE,
598 source);
599 crx_install_is_running_ = false;
601 const FetchedCRXFile& crx_file = current_crx_file_;
602 for (std::set<int>::const_iterator it = crx_file.request_ids.begin();
603 it != crx_file.request_ids.end(); ++it) {
604 InProgressCheck& request = requests_in_progress_[*it];
605 request.in_progress_ids_.remove(crx_file.extension_id);
606 NotifyIfFinished(*it);
609 // If any files are available to update, start one.
610 MaybeInstallCRXFile();
611 break;
613 case chrome::NOTIFICATION_EXTENSION_INSTALLED: {
614 const Extension* extension =
615 content::Details<const InstalledExtensionInfo>(details)->extension;
616 if (extension)
617 throttle_info_.erase(extension->id());
618 break;
620 default:
621 NOTREACHED();
625 void ExtensionUpdater::NotifyStarted() {
626 content::NotificationService::current()->Notify(
627 chrome::NOTIFICATION_EXTENSION_UPDATING_STARTED,
628 content::Source<Profile>(profile_),
629 content::NotificationService::NoDetails());
632 void ExtensionUpdater::NotifyIfFinished(int request_id) {
633 DCHECK(ContainsKey(requests_in_progress_, request_id));
634 const InProgressCheck& request = requests_in_progress_[request_id];
635 if (request.in_progress_ids_.empty()) {
636 VLOG(2) << "Finished update check " << request_id;
637 if (!request.callback.is_null())
638 request.callback.Run();
639 requests_in_progress_.erase(request_id);
643 } // namespace extensions