| Index: chrome/browser/extensions/updater/extension_updater.cc | 
| diff --git a/chrome/browser/extensions/updater/extension_updater.cc b/chrome/browser/extensions/updater/extension_updater.cc | 
| index 484029f71db74dfa723e412e0ae3775d94ecc07d..bd93ba3b385d7093298ad6792e09957f2980da21 100644 | 
| --- a/chrome/browser/extensions/updater/extension_updater.cc | 
| +++ b/chrome/browser/extensions/updater/extension_updater.cc | 
| @@ -60,6 +60,10 @@ | 
| #endif | 
| 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 | 
| @@ -124,6 +128,17 @@ | 
| const InProgressCheck& other) = default; | 
|  | 
| 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, | 
| @@ -142,6 +157,7 @@ | 
| prefs_(prefs), | 
| profile_(profile), | 
| next_request_id_(0), | 
| +      extension_registry_observer_(this), | 
| crx_install_is_running_(false), | 
| extension_cache_(cache), | 
| weak_ptr_factory_(this) { | 
| @@ -152,6 +168,8 @@ | 
| frequency_seconds_ = std::max(frequency_seconds_, kMinUpdateFrequencySeconds); | 
| #endif | 
| frequency_seconds_ = std::min(frequency_seconds_, kMaxUpdateFrequencySeconds); | 
| + | 
| +  extension_registry_observer_.Add(ExtensionRegistry::Get(profile)); | 
| } | 
|  | 
| ExtensionUpdater::~ExtensionUpdater() { | 
| @@ -404,12 +422,56 @@ | 
| NotifyIfFinished(request_id); | 
| } | 
|  | 
| -void ExtensionUpdater::CheckExtensionSoon(const std::string& extension_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.callback = callback; | 
| +  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( | 
| @@ -597,6 +659,14 @@ | 
| MaybeInstallCRXFile(); | 
| } | 
|  | 
| +void ExtensionUpdater::OnExtensionWillBeInstalled( | 
| +    content::BrowserContext* browser_context, | 
| +    const Extension* extension, | 
| +    bool is_update, | 
| +    const std::string& old_name) { | 
| +  throttle_info_.erase(extension->id()); | 
| +} | 
| + | 
| void ExtensionUpdater::NotifyStarted() { | 
| content::NotificationService::current()->Notify( | 
| extensions::NOTIFICATION_EXTENSION_UPDATING_STARTED, | 
|  |