diff options
author | mek@chromium.org <mek@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-11-14 21:01:06 +0000 |
---|---|---|
committer | mek@chromium.org <mek@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-11-14 21:01:06 +0000 |
commit | 42774e4a2cffae20a5ab38ed43ed79ef9376e2fd (patch) | |
tree | 4e15852e85c196f8345b51595676d658fd8a1dbe /chrome/browser/extensions/updater/extension_updater.cc | |
parent | 8116f33fd183f21a50a0da79ff9a8f1a9448754d (diff) | |
download | chromium_src-42774e4a2cffae20a5ab38ed43ed79ef9376e2fd.zip chromium_src-42774e4a2cffae20a5ab38ed43ed79ef9376e2fd.tar.gz chromium_src-42774e4a2cffae20a5ab38ed43ed79ef9376e2fd.tar.bz2 |
add chrome.runtime.requestUpdateCheck method.
To prevent bad-behaving extensions from potentially overloading the network, an extension is currently limited to checking for updates ones every 5 seconds.
TBR=jhawkins@chromium.org
BUG=88945
Review URL: https://chromiumcodereview.appspot.com/11339047
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@167741 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/browser/extensions/updater/extension_updater.cc')
-rw-r--r-- | chrome/browser/extensions/updater/extension_updater.cc | 179 |
1 files changed, 141 insertions, 38 deletions
diff --git a/chrome/browser/extensions/updater/extension_updater.cc b/chrome/browser/extensions/updater/extension_updater.cc index e35f327..d26159d 100644 --- a/chrome/browser/extensions/updater/extension_updater.cc +++ b/chrome/browser/extensions/updater/extension_updater.cc @@ -53,6 +53,10 @@ const int kStartupWaitSeconds = 60 * 5; const int kMinUpdateFrequencySeconds = 30; const int kMaxUpdateFrequencySeconds = 60 * 60 * 24 * 7; // 7 days +// Require at least 5 seconds between consecutive non-succesful extension update +// checks. +const int kMinUpdateThrottleTime = 5; + // When we've computed a days value, we want to make sure we don't send a // negative value (due to the system clock being set backwards, etc.), since -1 // is a special sentinel value that means "never pinged", and other negative @@ -85,6 +89,11 @@ int CalculateActivePingDays(const Time& last_active_ping_day, namespace extensions { +ExtensionUpdater::CheckParams::CheckParams() + : check_blacklist(true) {} + +ExtensionUpdater::CheckParams::~CheckParams() {} + ExtensionUpdater::FetchedCRXFile::FetchedCRXFile( const std::string& i, const FilePath& p, @@ -107,6 +116,17 @@ ExtensionUpdater::InProgressCheck::InProgressCheck() ExtensionUpdater::InProgressCheck::~InProgressCheck() {} +struct ExtensionUpdater::ThrottleInfo { + ThrottleInfo() + : in_progress(true), + throttle_delay(kMinUpdateThrottleTime), + check_start(Time::Now()) {} + + bool in_progress; + int throttle_delay; + Time check_start; +}; + ExtensionUpdater::ExtensionUpdater(ExtensionServiceInterface* service, ExtensionPrefs* extension_prefs, PrefService* prefs, @@ -116,8 +136,7 @@ ExtensionUpdater::ExtensionUpdater(ExtensionServiceInterface* service, weak_ptr_factory_(ALLOW_THIS_IN_INITIALIZER_LIST(this)), service_(service), frequency_seconds_(frequency_seconds), will_check_soon_(false), extension_prefs_(extension_prefs), - prefs_(prefs), profile_(profile), blacklist_checks_enabled_(true), - next_request_id_(0), + prefs_(prefs), profile_(profile), next_request_id_(0), crx_install_is_running_(false) { DCHECK_GE(frequency_seconds_, 5); DCHECK_LE(frequency_seconds_, kMaxUpdateFrequencySeconds); @@ -126,6 +145,9 @@ ExtensionUpdater::ExtensionUpdater(ExtensionServiceInterface* service, frequency_seconds_ = std::max(frequency_seconds_, kMinUpdateFrequencySeconds); #endif frequency_seconds_ = std::min(frequency_seconds_, kMaxUpdateFrequencySeconds); + + registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_INSTALLED, + content::NotificationService::AllBrowserContextsAndSources()); } ExtensionUpdater::~ExtensionUpdater() { @@ -224,7 +246,7 @@ void ExtensionUpdater::ScheduleNextCheck(const TimeDelta& target_delay) { void ExtensionUpdater::TimerFired() { DCHECK(alive_); - CheckNow(base::Closure()); + CheckNow(default_params_); // If the user has overridden the update frequency, don't bother reporting // this. @@ -267,7 +289,7 @@ bool ExtensionUpdater::WillCheckSoon() const { void ExtensionUpdater::DoCheckSoon() { DCHECK(will_check_soon_); - CheckNow(base::Closure()); + CheckNow(default_params_); will_check_soon_ = false; } @@ -294,16 +316,18 @@ void ExtensionUpdater::AddToDownloader( } } -void ExtensionUpdater::CheckNow(const FinishedCallback& callback) { +void ExtensionUpdater::CheckNow(const CheckParams& params) { int request_id = next_request_id_++; VLOG(2) << "Starting update check " << request_id; + if (params.ids.empty()) + NotifyStarted(); + DCHECK(alive_); - NotifyStarted(); InProgressCheck* request = &requests_in_progress_[request_id]; request->id = request_id; - request->callback = callback; + request->callback = params.callback; if (!downloader_.get()) { downloader_.reset( @@ -317,25 +341,38 @@ void ExtensionUpdater::CheckNow(const FinishedCallback& callback) { service_->pending_extension_manager(); std::list<std::string> pending_ids; - pending_extension_manager->GetPendingIdsForUpdateCheck(&pending_ids); - - std::list<std::string>::const_iterator iter; - for (iter = pending_ids.begin(); iter != pending_ids.end(); ++iter) { - const PendingExtensionInfo* info = pending_extension_manager->GetById( - *iter); - if (!Extension::IsAutoUpdateableLocation(info->install_source())) { - VLOG(2) << "Extension " << *iter << " is not auto updateable"; - continue; + + if (params.ids.empty()) { + // If no extension ids are specified, check for updates for all extensions. + pending_extension_manager->GetPendingIdsForUpdateCheck(&pending_ids); + + std::list<std::string>::const_iterator iter; + for (iter = pending_ids.begin(); iter != pending_ids.end(); ++iter) { + const PendingExtensionInfo* info = pending_extension_manager->GetById( + *iter); + if (!Extension::IsAutoUpdateableLocation(info->install_source())) { + VLOG(2) << "Extension " << *iter << " is not auto updateable"; + continue; + } + if (downloader_->AddPendingExtension(*iter, info->update_url(), + request_id)) + request->in_progress_ids_.push_back(*iter); } - if (downloader_->AddPendingExtension(*iter, info->update_url(), request_id)) - request->in_progress_ids_.push_back(*iter); - } - AddToDownloader(service_->extensions(), pending_ids, request); - AddToDownloader(service_->disabled_extensions(), pending_ids, request); + AddToDownloader(service_->extensions(), pending_ids, request); + AddToDownloader(service_->disabled_extensions(), pending_ids, request); + } else { + for (std::list<std::string>::const_iterator it = params.ids.begin(); + it != params.ids.end(); ++it) { + const Extension* extension = service_->GetExtensionById(*it, true); + DCHECK(extension); + if (downloader_->AddExtension(*extension, request->id)) + request->in_progress_ids_.push_back(extension->id()); + } + } // Start a fetch of the blacklist if needed. - if (blacklist_checks_enabled_) { + if (params.check_blacklist) { ManifestFetchData::PingData ping_data; ping_data.rollcall_days = CalculatePingDays(extension_prefs_->BlacklistLastPingDay()); @@ -361,6 +398,59 @@ void ExtensionUpdater::CheckNow(const FinishedCallback& callback) { NotifyIfFinished(request_id); } +bool ExtensionUpdater::CheckExtensionSoon(const std::string& extension_id, + const FinishedCallback& callback) { + bool have_throttle_info = ContainsKey(throttle_info_, extension_id); + ThrottleInfo& info = throttle_info_[extension_id]; + if (have_throttle_info) { + // We already had a ThrottleInfo object for this extension, check if the + // update check request should be allowed. + + // If another check is in progress, don't start a new check. + if (info.in_progress) + return false; + + Time now = Time::Now(); + Time last = info.check_start; + // If somehow time moved back, we don't want to infinitely keep throttling. + if (now < last) { + last = now; + info.check_start = now; + } + Time earliest = last + TimeDelta::FromSeconds(info.throttle_delay); + // If check is too soon, throttle. + if (now < earliest) + return false; + + // TODO(mek): Somehow increase time between allowing checks when checks + // are repeatedly throttled and don't result in updates being installed. + + // It's okay to start a check, update values. + info.check_start = now; + info.in_progress = true; + } + + CheckParams params; + params.ids.push_back(extension_id); + params.check_blacklist = false; + params.callback = base::Bind(&ExtensionUpdater::ExtensionCheckFinished, + weak_ptr_factory_.GetWeakPtr(), + extension_id, callback); + CheckNow(params); + return true; +} + +void ExtensionUpdater::ExtensionCheckFinished( + const std::string& extension_id, + const FinishedCallback& callback) { + std::map<std::string, ThrottleInfo>::iterator it = + throttle_info_.find(extension_id); + if (it != throttle_info_.end()) { + it->second.in_progress = false; + } + callback.Run(); +} + void ExtensionUpdater::OnExtensionDownloadFailed( const std::string& id, Error error, @@ -532,23 +622,36 @@ void ExtensionUpdater::MaybeInstallCRXFile() { void ExtensionUpdater::Observe(int type, const content::NotificationSource& source, const content::NotificationDetails& details) { - DCHECK(type == chrome::NOTIFICATION_CRX_INSTALLER_DONE); - - // No need to listen for CRX_INSTALLER_DONE anymore. - registrar_.Remove(this, - chrome::NOTIFICATION_CRX_INSTALLER_DONE, - source); - crx_install_is_running_ = false; - - const FetchedCRXFile& crx_file = current_crx_file_; - for (std::set<int>::const_iterator it = crx_file.request_ids.begin(); - it != crx_file.request_ids.end(); ++it) { - requests_in_progress_[*it].in_progress_ids_.remove(crx_file.extension_id); - NotifyIfFinished(*it); - } + switch (type) { + case chrome::NOTIFICATION_CRX_INSTALLER_DONE: { + // No need to listen for CRX_INSTALLER_DONE anymore. + registrar_.Remove(this, + chrome::NOTIFICATION_CRX_INSTALLER_DONE, + source); + crx_install_is_running_ = false; + + const FetchedCRXFile& crx_file = current_crx_file_; + for (std::set<int>::const_iterator it = crx_file.request_ids.begin(); + it != crx_file.request_ids.end(); ++it) { + InProgressCheck& request = requests_in_progress_[*it]; + request.in_progress_ids_.remove(crx_file.extension_id); + NotifyIfFinished(*it); + } - // If any files are available to update, start one. - MaybeInstallCRXFile(); + // If any files are available to update, start one. + MaybeInstallCRXFile(); + break; + } + case chrome::NOTIFICATION_EXTENSION_INSTALLED: { + const Extension* extension = + content::Details<const Extension>(details).ptr(); + if (extension) + throttle_info_.erase(extension->id()); + break; + } + default: + NOTREACHED(); + } } void ExtensionUpdater::NotifyStarted() { |