NaCl: Update revision in DEPS, r12770 -> r12773
[chromium-blink-merge.git] / chrome / browser / extensions / updater / extension_updater.cc
blob6e260767fbda2707ce28ea78e60fc212d5e883a6
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/extension_registry.h"
32 #include "extensions/browser/pending_extension_manager.h"
33 #include "extensions/browser/pref_names.h"
34 #include "extensions/common/constants.h"
35 #include "extensions/common/extension.h"
36 #include "extensions/common/extension_set.h"
37 #include "extensions/common/manifest.h"
39 using base::RandDouble;
40 using base::RandInt;
41 using base::Time;
42 using base::TimeDelta;
43 using content::BrowserThread;
45 typedef extensions::ExtensionDownloaderDelegate::Error Error;
46 typedef extensions::ExtensionDownloaderDelegate::PingResult PingResult;
48 namespace {
50 // Wait at least 5 minutes after browser startup before we do any checks. If you
51 // change this value, make sure to update comments where it is used.
52 const int kStartupWaitSeconds = 60 * 5;
54 // For sanity checking on update frequency - enforced in release mode only.
55 #ifdef NDEBUG
56 const int kMinUpdateFrequencySeconds = 30;
57 #endif
58 const int kMaxUpdateFrequencySeconds = 60 * 60 * 24 * 7; // 7 days
60 // Require at least 5 seconds between consecutive non-succesful extension update
61 // checks.
62 const int kMinUpdateThrottleTime = 5;
64 // When we've computed a days value, we want to make sure we don't send a
65 // negative value (due to the system clock being set backwards, etc.), since -1
66 // is a special sentinel value that means "never pinged", and other negative
67 // values don't make sense.
68 int SanitizeDays(int days) {
69 if (days < 0)
70 return 0;
71 return days;
74 // Calculates the value to use for the ping days parameter.
75 int CalculatePingDays(const Time& last_ping_day) {
76 int days = extensions::ManifestFetchData::kNeverPinged;
77 if (!last_ping_day.is_null()) {
78 days = SanitizeDays((Time::Now() - last_ping_day).InDays());
80 return days;
83 int CalculateActivePingDays(const Time& last_active_ping_day,
84 bool hasActiveBit) {
85 if (!hasActiveBit)
86 return 0;
87 if (last_active_ping_day.is_null())
88 return extensions::ManifestFetchData::kNeverPinged;
89 return SanitizeDays((Time::Now() - last_active_ping_day).InDays());
92 } // namespace
94 namespace extensions {
96 ExtensionUpdater::CheckParams::CheckParams()
97 : install_immediately(false) {}
99 ExtensionUpdater::CheckParams::~CheckParams() {}
101 ExtensionUpdater::FetchedCRXFile::FetchedCRXFile(
102 const std::string& i,
103 const base::FilePath& p,
104 bool file_ownership_passed,
105 const GURL& u,
106 const std::set<int>& request_ids)
107 : extension_id(i),
108 path(p),
109 file_ownership_passed(file_ownership_passed),
110 download_url(u),
111 request_ids(request_ids) {}
113 ExtensionUpdater::FetchedCRXFile::FetchedCRXFile()
114 : path(), file_ownership_passed(true), download_url() {}
116 ExtensionUpdater::FetchedCRXFile::~FetchedCRXFile() {}
118 ExtensionUpdater::InProgressCheck::InProgressCheck()
119 : install_immediately(false) {}
121 ExtensionUpdater::InProgressCheck::~InProgressCheck() {}
123 struct ExtensionUpdater::ThrottleInfo {
124 ThrottleInfo()
125 : in_progress(true),
126 throttle_delay(kMinUpdateThrottleTime),
127 check_start(Time::Now()) {}
129 bool in_progress;
130 int throttle_delay;
131 Time check_start;
134 ExtensionUpdater::ExtensionUpdater(ExtensionServiceInterface* service,
135 ExtensionPrefs* extension_prefs,
136 PrefService* prefs,
137 Profile* profile,
138 int frequency_seconds,
139 ExtensionCache* cache)
140 : alive_(false),
141 weak_ptr_factory_(this),
142 service_(service), frequency_seconds_(frequency_seconds),
143 will_check_soon_(false), extension_prefs_(extension_prefs),
144 prefs_(prefs), profile_(profile),
145 next_request_id_(0),
146 crx_install_is_running_(false),
147 extension_cache_(cache) {
148 DCHECK_GE(frequency_seconds_, 5);
149 DCHECK_LE(frequency_seconds_, kMaxUpdateFrequencySeconds);
150 #ifdef NDEBUG
151 // In Release mode we enforce that update checks don't happen too often.
152 frequency_seconds_ = std::max(frequency_seconds_, kMinUpdateFrequencySeconds);
153 #endif
154 frequency_seconds_ = std::min(frequency_seconds_, kMaxUpdateFrequencySeconds);
156 registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_INSTALLED,
157 content::NotificationService::AllBrowserContextsAndSources());
160 ExtensionUpdater::~ExtensionUpdater() {
161 Stop();
164 // The overall goal here is to balance keeping clients up to date while
165 // avoiding a thundering herd against update servers.
166 TimeDelta ExtensionUpdater::DetermineFirstCheckDelay() {
167 DCHECK(alive_);
168 // If someone's testing with a quick frequency, just allow it.
169 if (frequency_seconds_ < kStartupWaitSeconds)
170 return TimeDelta::FromSeconds(frequency_seconds_);
172 // If we've never scheduled a check before, start at frequency_seconds_.
173 if (!prefs_->HasPrefPath(pref_names::kNextUpdateCheck))
174 return TimeDelta::FromSeconds(frequency_seconds_);
176 // If it's been a long time since our last actual check, we want to do one
177 // relatively soon.
178 Time now = Time::Now();
179 Time last = Time::FromInternalValue(prefs_->GetInt64(
180 pref_names::kLastUpdateCheck));
181 int days = (now - last).InDays();
182 if (days >= 30) {
183 // Wait 5-10 minutes.
184 return TimeDelta::FromSeconds(RandInt(kStartupWaitSeconds,
185 kStartupWaitSeconds * 2));
186 } else if (days >= 14) {
187 // Wait 10-20 minutes.
188 return TimeDelta::FromSeconds(RandInt(kStartupWaitSeconds * 2,
189 kStartupWaitSeconds * 4));
190 } else if (days >= 3) {
191 // Wait 20-40 minutes.
192 return TimeDelta::FromSeconds(RandInt(kStartupWaitSeconds * 4,
193 kStartupWaitSeconds * 8));
196 // Read the persisted next check time, and use that if it isn't too soon.
197 // Otherwise pick something random.
198 Time saved_next = Time::FromInternalValue(prefs_->GetInt64(
199 pref_names::kNextUpdateCheck));
200 Time earliest = now + TimeDelta::FromSeconds(kStartupWaitSeconds);
201 if (saved_next >= earliest) {
202 return saved_next - now;
203 } else {
204 return TimeDelta::FromSeconds(RandInt(kStartupWaitSeconds,
205 frequency_seconds_));
209 void ExtensionUpdater::Start() {
210 DCHECK(!alive_);
211 // If these are NULL, then that means we've been called after Stop()
212 // has been called.
213 DCHECK(service_);
214 DCHECK(extension_prefs_);
215 DCHECK(prefs_);
216 DCHECK(profile_);
217 DCHECK(!weak_ptr_factory_.HasWeakPtrs());
218 alive_ = true;
219 // Make sure our prefs are registered, then schedule the first check.
220 ScheduleNextCheck(DetermineFirstCheckDelay());
223 void ExtensionUpdater::Stop() {
224 weak_ptr_factory_.InvalidateWeakPtrs();
225 alive_ = false;
226 service_ = NULL;
227 extension_prefs_ = NULL;
228 prefs_ = NULL;
229 profile_ = NULL;
230 timer_.Stop();
231 will_check_soon_ = false;
232 downloader_.reset();
235 void ExtensionUpdater::ScheduleNextCheck(const TimeDelta& target_delay) {
236 DCHECK(alive_);
237 DCHECK(!timer_.IsRunning());
238 DCHECK(target_delay >= TimeDelta::FromSeconds(1));
240 // Add +/- 10% random jitter.
241 double delay_ms = target_delay.InMillisecondsF();
242 double jitter_factor = (RandDouble() * .2) - 0.1;
243 delay_ms += delay_ms * jitter_factor;
244 TimeDelta actual_delay = TimeDelta::FromMilliseconds(
245 static_cast<int64>(delay_ms));
247 // Save the time of next check.
248 Time next = Time::Now() + actual_delay;
249 prefs_->SetInt64(pref_names::kNextUpdateCheck, next.ToInternalValue());
251 timer_.Start(FROM_HERE, actual_delay, this, &ExtensionUpdater::TimerFired);
254 void ExtensionUpdater::TimerFired() {
255 DCHECK(alive_);
256 CheckNow(default_params_);
258 // If the user has overridden the update frequency, don't bother reporting
259 // this.
260 if (frequency_seconds_ == extensions::kDefaultUpdateFrequencySeconds) {
261 Time last = Time::FromInternalValue(prefs_->GetInt64(
262 pref_names::kLastUpdateCheck));
263 if (last.ToInternalValue() != 0) {
264 // Use counts rather than time so we can use minutes rather than millis.
265 UMA_HISTOGRAM_CUSTOM_COUNTS("Extensions.UpdateCheckGap",
266 (Time::Now() - last).InMinutes(),
267 TimeDelta::FromSeconds(kStartupWaitSeconds).InMinutes(),
268 TimeDelta::FromDays(40).InMinutes(),
269 50); // 50 buckets seems to be the default.
273 // Save the last check time, and schedule the next check.
274 int64 now = Time::Now().ToInternalValue();
275 prefs_->SetInt64(pref_names::kLastUpdateCheck, now);
276 ScheduleNextCheck(TimeDelta::FromSeconds(frequency_seconds_));
279 void ExtensionUpdater::CheckSoon() {
280 DCHECK(alive_);
281 if (will_check_soon_)
282 return;
283 if (BrowserThread::PostTask(
284 BrowserThread::UI, FROM_HERE,
285 base::Bind(&ExtensionUpdater::DoCheckSoon,
286 weak_ptr_factory_.GetWeakPtr()))) {
287 will_check_soon_ = true;
288 } else {
289 NOTREACHED();
293 bool ExtensionUpdater::WillCheckSoon() const {
294 return will_check_soon_;
297 void ExtensionUpdater::DoCheckSoon() {
298 DCHECK(will_check_soon_);
299 CheckNow(default_params_);
300 will_check_soon_ = false;
303 void ExtensionUpdater::AddToDownloader(
304 const ExtensionSet* extensions,
305 const std::list<std::string>& pending_ids,
306 int request_id) {
307 InProgressCheck& request = requests_in_progress_[request_id];
308 for (ExtensionSet::const_iterator extension_iter = extensions->begin();
309 extension_iter != extensions->end(); ++extension_iter) {
310 const Extension& extension = *extension_iter->get();
311 if (!Manifest::IsAutoUpdateableLocation(extension.location())) {
312 VLOG(2) << "Extension " << extension.id() << " is not auto updateable";
313 continue;
315 // An extension might be overwritten by policy, and have its update url
316 // changed. Make sure existing extensions aren't fetched again, if a
317 // pending fetch for an extension with the same id already exists.
318 std::list<std::string>::const_iterator pending_id_iter = std::find(
319 pending_ids.begin(), pending_ids.end(), extension.id());
320 if (pending_id_iter == pending_ids.end()) {
321 if (downloader_->AddExtension(extension, request_id))
322 request.in_progress_ids_.push_back(extension.id());
327 void ExtensionUpdater::CheckNow(const CheckParams& params) {
328 int request_id = next_request_id_++;
330 VLOG(2) << "Starting update check " << request_id;
331 if (params.ids.empty())
332 NotifyStarted();
334 DCHECK(alive_);
336 InProgressCheck& request = requests_in_progress_[request_id];
337 request.callback = params.callback;
338 request.install_immediately = params.install_immediately;
340 if (!downloader_.get()) {
341 downloader_.reset(
342 new ExtensionDownloader(this, profile_->GetRequestContext()));
345 // Add fetch records for extensions that should be fetched by an update URL.
346 // These extensions are not yet installed. They come from group policy
347 // and external install sources.
348 const PendingExtensionManager* pending_extension_manager =
349 service_->pending_extension_manager();
351 std::list<std::string> pending_ids;
353 if (params.ids.empty()) {
354 // If no extension ids are specified, check for updates for all extensions.
355 pending_extension_manager->GetPendingIdsForUpdateCheck(&pending_ids);
357 std::list<std::string>::const_iterator iter;
358 for (iter = pending_ids.begin(); iter != pending_ids.end(); ++iter) {
359 const PendingExtensionInfo* info = pending_extension_manager->GetById(
360 *iter);
361 if (!Manifest::IsAutoUpdateableLocation(info->install_source())) {
362 VLOG(2) << "Extension " << *iter << " is not auto updateable";
363 continue;
365 if (downloader_->AddPendingExtension(*iter, info->update_url(),
366 request_id))
367 request.in_progress_ids_.push_back(*iter);
370 ExtensionRegistry* registry = ExtensionRegistry::Get(profile_);
371 AddToDownloader(&registry->enabled_extensions(), pending_ids, request_id);
372 AddToDownloader(&registry->disabled_extensions(), pending_ids, request_id);
373 } else {
374 for (std::list<std::string>::const_iterator it = params.ids.begin();
375 it != params.ids.end(); ++it) {
376 const Extension* extension = service_->GetExtensionById(*it, true);
377 DCHECK(extension);
378 if (downloader_->AddExtension(*extension, request_id))
379 request.in_progress_ids_.push_back(extension->id());
383 // StartAllPending() might call OnExtensionDownloadFailed/Finished before
384 // it returns, which would cause NotifyIfFinished to incorrectly try to
385 // send out a notification. So check before we call StartAllPending if any
386 // extensions are going to be updated, and use that to figure out if
387 // NotifyIfFinished should be called.
388 bool noChecks = request.in_progress_ids_.empty();
390 // StartAllPending() will call OnExtensionDownloadFailed or
391 // OnExtensionDownloadFinished for each extension that was checked.
392 downloader_->StartAllPending(extension_cache_);
394 if (noChecks)
395 NotifyIfFinished(request_id);
398 bool ExtensionUpdater::CheckExtensionSoon(const std::string& extension_id,
399 const FinishedCallback& callback) {
400 bool have_throttle_info = ContainsKey(throttle_info_, extension_id);
401 ThrottleInfo& info = throttle_info_[extension_id];
402 if (have_throttle_info) {
403 // We already had a ThrottleInfo object for this extension, check if the
404 // update check request should be allowed.
406 // If another check is in progress, don't start a new check.
407 if (info.in_progress)
408 return false;
410 Time now = Time::Now();
411 Time last = info.check_start;
412 // If somehow time moved back, we don't want to infinitely keep throttling.
413 if (now < last) {
414 last = now;
415 info.check_start = now;
417 Time earliest = last + TimeDelta::FromSeconds(info.throttle_delay);
418 // If check is too soon, throttle.
419 if (now < earliest)
420 return false;
422 // TODO(mek): Somehow increase time between allowing checks when checks
423 // are repeatedly throttled and don't result in updates being installed.
425 // It's okay to start a check, update values.
426 info.check_start = now;
427 info.in_progress = true;
430 CheckParams params;
431 params.ids.push_back(extension_id);
432 params.callback = base::Bind(&ExtensionUpdater::ExtensionCheckFinished,
433 weak_ptr_factory_.GetWeakPtr(),
434 extension_id, callback);
435 CheckNow(params);
436 return true;
439 void ExtensionUpdater::ExtensionCheckFinished(
440 const std::string& extension_id,
441 const FinishedCallback& callback) {
442 std::map<std::string, ThrottleInfo>::iterator it =
443 throttle_info_.find(extension_id);
444 if (it != throttle_info_.end()) {
445 it->second.in_progress = false;
447 callback.Run();
450 void ExtensionUpdater::OnExtensionDownloadFailed(
451 const std::string& id,
452 Error error,
453 const PingResult& ping,
454 const std::set<int>& request_ids) {
455 DCHECK(alive_);
456 UpdatePingData(id, ping);
457 bool install_immediately = false;
458 for (std::set<int>::const_iterator it = request_ids.begin();
459 it != request_ids.end(); ++it) {
460 InProgressCheck& request = requests_in_progress_[*it];
461 install_immediately |= request.install_immediately;
462 request.in_progress_ids_.remove(id);
463 NotifyIfFinished(*it);
466 // This method is called if no updates were found. However a previous update
467 // check might have queued an update for this extension already. If a
468 // current update check has |install_immediately| set the previously
469 // queued update should be installed now.
470 if (install_immediately && service_->GetPendingExtensionUpdate(id))
471 service_->FinishDelayedInstallation(id);
474 void ExtensionUpdater::OnExtensionDownloadFinished(
475 const std::string& id,
476 const base::FilePath& path,
477 bool file_ownership_passed,
478 const GURL& download_url,
479 const std::string& version,
480 const PingResult& ping,
481 const std::set<int>& request_ids) {
482 DCHECK(alive_);
483 UpdatePingData(id, ping);
485 VLOG(2) << download_url << " written to " << path.value();
487 FetchedCRXFile fetched(id, path, file_ownership_passed, download_url,
488 request_ids);
489 fetched_crx_files_.push(fetched);
491 // MaybeInstallCRXFile() removes extensions from |in_progress_ids_| after
492 // starting the crx installer.
493 MaybeInstallCRXFile();
496 bool ExtensionUpdater::GetPingDataForExtension(
497 const std::string& id,
498 ManifestFetchData::PingData* ping_data) {
499 DCHECK(alive_);
500 ping_data->rollcall_days = CalculatePingDays(
501 extension_prefs_->LastPingDay(id));
502 ping_data->is_enabled = service_->IsExtensionEnabled(id);
503 ping_data->active_days =
504 CalculateActivePingDays(extension_prefs_->LastActivePingDay(id),
505 extension_prefs_->GetActiveBit(id));
506 return true;
509 std::string ExtensionUpdater::GetUpdateUrlData(const std::string& id) {
510 DCHECK(alive_);
511 return extension::GetUpdateURLData(extension_prefs_, id);
514 bool ExtensionUpdater::IsExtensionPending(const std::string& id) {
515 DCHECK(alive_);
516 return service_->pending_extension_manager()->IsIdPending(id);
519 bool ExtensionUpdater::GetExtensionExistingVersion(const std::string& id,
520 std::string* version) {
521 DCHECK(alive_);
522 const Extension* extension = service_->GetExtensionById(id, true);
523 if (!extension)
524 return false;
525 const Extension* update = service_->GetPendingExtensionUpdate(id);
526 if (update)
527 *version = update->VersionString();
528 else
529 *version = extension->VersionString();
530 return true;
533 void ExtensionUpdater::UpdatePingData(const std::string& id,
534 const PingResult& ping_result) {
535 DCHECK(alive_);
536 if (ping_result.did_ping)
537 extension_prefs_->SetLastPingDay(id, ping_result.day_start);
538 if (extension_prefs_->GetActiveBit(id)) {
539 extension_prefs_->SetActiveBit(id, false);
540 extension_prefs_->SetLastActivePingDay(id, ping_result.day_start);
544 void ExtensionUpdater::MaybeInstallCRXFile() {
545 if (crx_install_is_running_ || fetched_crx_files_.empty())
546 return;
548 std::set<int> request_ids;
550 while (!fetched_crx_files_.empty() && !crx_install_is_running_) {
551 const FetchedCRXFile& crx_file = fetched_crx_files_.top();
553 VLOG(2) << "updating " << crx_file.extension_id
554 << " with " << crx_file.path.value();
556 // The ExtensionService is now responsible for cleaning up the temp file
557 // at |crx_file.path|.
558 CrxInstaller* installer = NULL;
559 if (service_->UpdateExtension(crx_file.extension_id,
560 crx_file.path,
561 crx_file.file_ownership_passed,
562 crx_file.download_url,
563 &installer)) {
564 crx_install_is_running_ = true;
565 current_crx_file_ = crx_file;
567 for (std::set<int>::const_iterator it = crx_file.request_ids.begin();
568 it != crx_file.request_ids.end(); ++it) {
569 InProgressCheck& request = requests_in_progress_[*it];
570 if (request.install_immediately) {
571 installer->set_install_wait_for_idle(false);
572 break;
576 // Source parameter ensures that we only see the completion event for the
577 // the installer we started.
578 registrar_.Add(this,
579 chrome::NOTIFICATION_CRX_INSTALLER_DONE,
580 content::Source<CrxInstaller>(installer));
581 } else {
582 for (std::set<int>::const_iterator it = crx_file.request_ids.begin();
583 it != crx_file.request_ids.end(); ++it) {
584 InProgressCheck& request = requests_in_progress_[*it];
585 request.in_progress_ids_.remove(crx_file.extension_id);
587 request_ids.insert(crx_file.request_ids.begin(),
588 crx_file.request_ids.end());
590 fetched_crx_files_.pop();
593 for (std::set<int>::const_iterator it = request_ids.begin();
594 it != request_ids.end(); ++it) {
595 NotifyIfFinished(*it);
599 void ExtensionUpdater::Observe(int type,
600 const content::NotificationSource& source,
601 const content::NotificationDetails& details) {
602 switch (type) {
603 case chrome::NOTIFICATION_CRX_INSTALLER_DONE: {
604 // No need to listen for CRX_INSTALLER_DONE anymore.
605 registrar_.Remove(this,
606 chrome::NOTIFICATION_CRX_INSTALLER_DONE,
607 source);
608 crx_install_is_running_ = false;
610 const FetchedCRXFile& crx_file = current_crx_file_;
611 for (std::set<int>::const_iterator it = crx_file.request_ids.begin();
612 it != crx_file.request_ids.end(); ++it) {
613 InProgressCheck& request = requests_in_progress_[*it];
614 request.in_progress_ids_.remove(crx_file.extension_id);
615 NotifyIfFinished(*it);
618 // If any files are available to update, start one.
619 MaybeInstallCRXFile();
620 break;
622 case chrome::NOTIFICATION_EXTENSION_INSTALLED: {
623 const Extension* extension =
624 content::Details<const InstalledExtensionInfo>(details)->extension;
625 if (extension)
626 throttle_info_.erase(extension->id());
627 break;
629 default:
630 NOTREACHED();
634 void ExtensionUpdater::NotifyStarted() {
635 content::NotificationService::current()->Notify(
636 chrome::NOTIFICATION_EXTENSION_UPDATING_STARTED,
637 content::Source<Profile>(profile_),
638 content::NotificationService::NoDetails());
641 void ExtensionUpdater::NotifyIfFinished(int request_id) {
642 DCHECK(ContainsKey(requests_in_progress_, request_id));
643 const InProgressCheck& request = requests_in_progress_[request_id];
644 if (request.in_progress_ids_.empty()) {
645 VLOG(2) << "Finished update check " << request_id;
646 if (!request.callback.is_null())
647 request.callback.Run();
648 requests_in_progress_.erase(request_id);
652 } // namespace extensions