extension_updater.cc revision 68043e1e95eeb07d5cae7aca370b26518b0867d6
15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/extensions/updater/extension_updater.h"
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <algorithm>
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <set>
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <vector>
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/bind.h"
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/logging.h"
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/metrics/histogram.h"
142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/prefs/pref_service.h"
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/rand_util.h"
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/stl_util.h"
172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/strings/string_number_conversions.h"
182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/strings/string_split.h"
197dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch#include "chrome/browser/chrome_notification_types.h"
2090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include "chrome/browser/extensions/api/module/module.h"
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/extensions/crx_installer.h"
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/extensions/extension_service.h"
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/extensions/pending_extension_manager.h"
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/extensions/updater/extension_downloader.h"
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/profiles/profile.h"
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/common/extensions/extension.h"
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/common/extensions/extension_set.h"
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/common/pref_names.h"
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/browser/browser_thread.h"
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/browser/notification_details.h"
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/browser/notification_service.h"
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/browser/notification_source.h"
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "crypto/sha2.h"
3468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)#include "extensions/common/constants.h"
353551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)#include "extensions/common/manifest.h"
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using base::RandDouble;
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using base::RandInt;
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using base::Time;
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using base::TimeDelta;
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using content::BrowserThread;
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using prefs::kLastExtensionsUpdateCheck;
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using prefs::kNextExtensionsUpdateCheck;
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)typedef extensions::ExtensionDownloaderDelegate::Error Error;
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)typedef extensions::ExtensionDownloaderDelegate::PingResult PingResult;
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace {
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Wait at least 5 minutes after browser startup before we do any checks. If you
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// change this value, make sure to update comments where it is used.
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const int kStartupWaitSeconds = 60 * 5;
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// For sanity checking on update frequency - enforced in release mode only.
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const int kMinUpdateFrequencySeconds = 30;
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const int kMaxUpdateFrequencySeconds = 60 * 60 * 24 * 7;  // 7 days
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Require at least 5 seconds between consecutive non-succesful extension update
592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// checks.
602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const int kMinUpdateThrottleTime = 5;
612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// When we've computed a days value, we want to make sure we don't send a
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// negative value (due to the system clock being set backwards, etc.), since -1
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// is a special sentinel value that means "never pinged", and other negative
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// values don't make sense.
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int SanitizeDays(int days) {
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (days < 0)
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return 0;
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return days;
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Calculates the value to use for the ping days parameter.
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int CalculatePingDays(const Time& last_ping_day) {
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int days = extensions::ManifestFetchData::kNeverPinged;
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!last_ping_day.is_null()) {
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    days = SanitizeDays((Time::Now() - last_ping_day).InDays());
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return days;
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int CalculateActivePingDays(const Time& last_active_ping_day,
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                            bool hasActiveBit) {
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!hasActiveBit)
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return 0;
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (last_active_ping_day.is_null())
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return extensions::ManifestFetchData::kNeverPinged;
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return SanitizeDays((Time::Now() - last_active_ping_day).InDays());
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace extensions {
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)ExtensionUpdater::CheckParams::CheckParams()
9568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    : install_immediately(false) {}
962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)ExtensionUpdater::CheckParams::~CheckParams() {}
982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)ExtensionUpdater::FetchedCRXFile::FetchedCRXFile(
1002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const std::string& i,
1012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const base::FilePath& p,
1022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const GURL& u,
1032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const std::set<int>& request_ids)
1042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    : extension_id(i),
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      path(p),
1062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      download_url(u),
1072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      request_ids(request_ids) {}
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
109c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)ExtensionUpdater::FetchedCRXFile::FetchedCRXFile() : path(), download_url() {}
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ExtensionUpdater::FetchedCRXFile::~FetchedCRXFile() {}
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)ExtensionUpdater::InProgressCheck::InProgressCheck()
1142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    : install_immediately(false) {}
1152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)ExtensionUpdater::InProgressCheck::~InProgressCheck() {}
1172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)struct ExtensionUpdater::ThrottleInfo {
1192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ThrottleInfo()
1202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      : in_progress(true),
1212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        throttle_delay(kMinUpdateThrottleTime),
1222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        check_start(Time::Now()) {}
1232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  bool in_progress;
1252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  int throttle_delay;
1262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  Time check_start;
1272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)};
1282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ExtensionUpdater::ExtensionUpdater(ExtensionServiceInterface* service,
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                   ExtensionPrefs* extension_prefs,
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                   PrefService* prefs,
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                   Profile* profile,
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                   int frequency_seconds)
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    : alive_(false),
135c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      weak_ptr_factory_(this),
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      service_(service), frequency_seconds_(frequency_seconds),
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      will_check_soon_(false), extension_prefs_(extension_prefs),
13868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)      prefs_(prefs), profile_(profile),
1392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      next_request_id_(0),
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      crx_install_is_running_(false) {
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK_GE(frequency_seconds_, 5);
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK_LE(frequency_seconds_, kMaxUpdateFrequencySeconds);
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#ifdef NDEBUG
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // In Release mode we enforce that update checks don't happen too often.
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  frequency_seconds_ = std::max(frequency_seconds_, kMinUpdateFrequencySeconds);
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  frequency_seconds_ = std::min(frequency_seconds_, kMaxUpdateFrequencySeconds);
1482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_INSTALLED,
1502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                 content::NotificationService::AllBrowserContextsAndSources());
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ExtensionUpdater::~ExtensionUpdater() {
1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Stop();
1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// The overall goal here is to balance keeping clients up to date while
1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// avoiding a thundering herd against update servers.
1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)TimeDelta ExtensionUpdater::DetermineFirstCheckDelay() {
1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(alive_);
1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // If someone's testing with a quick frequency, just allow it.
1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (frequency_seconds_ < kStartupWaitSeconds)
1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return TimeDelta::FromSeconds(frequency_seconds_);
1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // If we've never scheduled a check before, start at frequency_seconds_.
1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!prefs_->HasPrefPath(kNextExtensionsUpdateCheck))
1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return TimeDelta::FromSeconds(frequency_seconds_);
1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // If it's been a long time since our last actual check, we want to do one
1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // relatively soon.
1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Time now = Time::Now();
1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Time last = Time::FromInternalValue(prefs_->GetInt64(
1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      kLastExtensionsUpdateCheck));
1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int days = (now - last).InDays();
1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (days >= 30) {
1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Wait 5-10 minutes.
1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return TimeDelta::FromSeconds(RandInt(kStartupWaitSeconds,
1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                          kStartupWaitSeconds * 2));
1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else if (days >= 14) {
1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Wait 10-20 minutes.
1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return TimeDelta::FromSeconds(RandInt(kStartupWaitSeconds * 2,
1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                          kStartupWaitSeconds * 4));
1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else if (days >= 3) {
1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Wait 20-40 minutes.
1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return TimeDelta::FromSeconds(RandInt(kStartupWaitSeconds * 4,
1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                          kStartupWaitSeconds * 8));
1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Read the persisted next check time, and use that if it isn't too soon.
1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Otherwise pick something random.
1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Time saved_next = Time::FromInternalValue(prefs_->GetInt64(
1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      kNextExtensionsUpdateCheck));
1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Time earliest = now + TimeDelta::FromSeconds(kStartupWaitSeconds);
1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (saved_next >= earliest) {
1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return saved_next - now;
1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return TimeDelta::FromSeconds(RandInt(kStartupWaitSeconds,
1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                          frequency_seconds_));
1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void ExtensionUpdater::Start() {
2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(!alive_);
2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // If these are NULL, then that means we've been called after Stop()
2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // has been called.
2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(service_);
2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(extension_prefs_);
2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(prefs_);
2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(profile_);
2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(!weak_ptr_factory_.HasWeakPtrs());
2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  alive_ = true;
2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Make sure our prefs are registered, then schedule the first check.
2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ScheduleNextCheck(DetermineFirstCheckDelay());
2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void ExtensionUpdater::Stop() {
2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  weak_ptr_factory_.InvalidateWeakPtrs();
2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  alive_ = false;
2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  service_ = NULL;
2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  extension_prefs_ = NULL;
2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  prefs_ = NULL;
2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  profile_ = NULL;
2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  timer_.Stop();
2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  will_check_soon_ = false;
2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  downloader_.reset();
2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void ExtensionUpdater::ScheduleNextCheck(const TimeDelta& target_delay) {
2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(alive_);
2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(!timer_.IsRunning());
2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(target_delay >= TimeDelta::FromSeconds(1));
2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Add +/- 10% random jitter.
2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  double delay_ms = target_delay.InMillisecondsF();
2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  double jitter_factor = (RandDouble() * .2) - 0.1;
2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  delay_ms += delay_ms * jitter_factor;
2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  TimeDelta actual_delay = TimeDelta::FromMilliseconds(
2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      static_cast<int64>(delay_ms));
2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Save the time of next check.
2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Time next = Time::Now() + actual_delay;
2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  prefs_->SetInt64(kNextExtensionsUpdateCheck, next.ToInternalValue());
2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  timer_.Start(FROM_HERE, actual_delay, this, &ExtensionUpdater::TimerFired);
2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void ExtensionUpdater::TimerFired() {
2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(alive_);
2492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  CheckNow(default_params_);
2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // If the user has overridden the update frequency, don't bother reporting
2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // this.
25368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  if (frequency_seconds_ == extensions::kDefaultUpdateFrequencySeconds) {
2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Time last = Time::FromInternalValue(prefs_->GetInt64(
2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        kLastExtensionsUpdateCheck));
2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (last.ToInternalValue() != 0) {
2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // Use counts rather than time so we can use minutes rather than millis.
2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      UMA_HISTOGRAM_CUSTOM_COUNTS("Extensions.UpdateCheckGap",
2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          (Time::Now() - last).InMinutes(),
2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          TimeDelta::FromSeconds(kStartupWaitSeconds).InMinutes(),
2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          TimeDelta::FromDays(40).InMinutes(),
2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          50);  // 50 buckets seems to be the default.
2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Save the last check time, and schedule the next check.
2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int64 now = Time::Now().ToInternalValue();
2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  prefs_->SetInt64(kLastExtensionsUpdateCheck, now);
2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ScheduleNextCheck(TimeDelta::FromSeconds(frequency_seconds_));
2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void ExtensionUpdater::CheckSoon() {
2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(alive_);
2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (will_check_soon_)
2755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (BrowserThread::PostTask(
2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          BrowserThread::UI, FROM_HERE,
2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          base::Bind(&ExtensionUpdater::DoCheckSoon,
2795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                     weak_ptr_factory_.GetWeakPtr()))) {
2805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    will_check_soon_ = true;
2815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
2825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    NOTREACHED();
2835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool ExtensionUpdater::WillCheckSoon() const {
2875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return will_check_soon_;
2885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void ExtensionUpdater::DoCheckSoon() {
2915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(will_check_soon_);
2922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  CheckNow(default_params_);
2935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  will_check_soon_ = false;
2945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void ExtensionUpdater::AddToDownloader(
2972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const ExtensionSet* extensions,
2982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const std::list<std::string>& pending_ids,
2992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    int request_id) {
3002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  InProgressCheck& request = requests_in_progress_[request_id];
3015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (ExtensionSet::const_iterator extension_iter = extensions->begin();
3025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       extension_iter != extensions->end(); ++extension_iter) {
3037d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    const Extension& extension = *extension_iter->get();
3042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (!Manifest::IsAutoUpdateableLocation(extension.location())) {
3055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      VLOG(2) << "Extension " << extension.id() << " is not auto updateable";
3065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      continue;
3075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
3085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // An extension might be overwritten by policy, and have its update url
3095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // changed. Make sure existing extensions aren't fetched again, if a
3105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // pending fetch for an extension with the same id already exists.
3115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    std::list<std::string>::const_iterator pending_id_iter = std::find(
3125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        pending_ids.begin(), pending_ids.end(), extension.id());
3135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (pending_id_iter == pending_ids.end()) {
3142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      if (downloader_->AddExtension(extension, request_id))
3152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        request.in_progress_ids_.push_back(extension.id());
3165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
3175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void ExtensionUpdater::CheckNow(const CheckParams& params) {
3212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  int request_id = next_request_id_++;
3222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  VLOG(2) << "Starting update check " << request_id;
3242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (params.ids.empty())
3252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    NotifyStarted();
3262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(alive_);
3282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  InProgressCheck& request = requests_in_progress_[request_id];
3302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  request.callback = params.callback;
3312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  request.install_immediately = params.install_immediately;
3325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!downloader_.get()) {
3345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    downloader_.reset(
3355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        new ExtensionDownloader(this, profile_->GetRequestContext()));
3365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Add fetch records for extensions that should be fetched by an update URL.
3395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // These extensions are not yet installed. They come from group policy
3405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // and external install sources.
3415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const PendingExtensionManager* pending_extension_manager =
3425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      service_->pending_extension_manager();
3435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::list<std::string> pending_ids;
3452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (params.ids.empty()) {
3472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // If no extension ids are specified, check for updates for all extensions.
3482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    pending_extension_manager->GetPendingIdsForUpdateCheck(&pending_ids);
3492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    std::list<std::string>::const_iterator iter;
3512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    for (iter = pending_ids.begin(); iter != pending_ids.end(); ++iter) {
3522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      const PendingExtensionInfo* info = pending_extension_manager->GetById(
3532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          *iter);
3542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      if (!Manifest::IsAutoUpdateableLocation(info->install_source())) {
3552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        VLOG(2) << "Extension " << *iter << " is not auto updateable";
3562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        continue;
3572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      }
3582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      if (downloader_->AddPendingExtension(*iter, info->update_url(),
3592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                           request_id))
3602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        request.in_progress_ids_.push_back(*iter);
3615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
3625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    AddToDownloader(service_->extensions(), pending_ids, request_id);
3642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    AddToDownloader(service_->disabled_extensions(), pending_ids, request_id);
3652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  } else {
3662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    for (std::list<std::string>::const_iterator it = params.ids.begin();
3672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)         it != params.ids.end(); ++it) {
3682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      const Extension* extension = service_->GetExtensionById(*it, true);
3692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      DCHECK(extension);
3702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      if (downloader_->AddExtension(*extension, request_id))
3712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        request.in_progress_ids_.push_back(extension->id());
3722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
3732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
3745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // StartAllPending() might call OnExtensionDownloadFailed/Finished before
3762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // it returns, which would cause NotifyIfFinished to incorrectly try to
3772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // send out a notification. So check before we call StartAllPending if any
3782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // extensions are going to be updated, and use that to figure out if
3792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // NotifyIfFinished should be called.
3802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  bool noChecks = request.in_progress_ids_.empty();
3812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // StartAllPending() will call OnExtensionDownloadFailed or
3832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // OnExtensionDownloadFinished for each extension that was checked.
3845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  downloader_->StartAllPending();
3855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (noChecks)
3882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    NotifyIfFinished(request_id);
3892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
3902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool ExtensionUpdater::CheckExtensionSoon(const std::string& extension_id,
3922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                          const FinishedCallback& callback) {
3932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  bool have_throttle_info = ContainsKey(throttle_info_, extension_id);
3942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ThrottleInfo& info = throttle_info_[extension_id];
3952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (have_throttle_info) {
3962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // We already had a ThrottleInfo object for this extension, check if the
3972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // update check request should be allowed.
3982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // If another check is in progress, don't start a new check.
4002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (info.in_progress)
4012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      return false;
4022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    Time now = Time::Now();
4042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    Time last = info.check_start;
4052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // If somehow time moved back, we don't want to infinitely keep throttling.
4062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (now < last) {
4072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      last = now;
4082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      info.check_start = now;
4092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
4102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    Time earliest = last + TimeDelta::FromSeconds(info.throttle_delay);
4112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // If check is too soon, throttle.
4122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (now < earliest)
4132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      return false;
4142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // TODO(mek): Somehow increase time between allowing checks when checks
4162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // are repeatedly throttled and don't result in updates being installed.
4172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // It's okay to start a check, update values.
4192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    info.check_start = now;
4202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    info.in_progress = true;
4212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
4222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  CheckParams params;
4242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  params.ids.push_back(extension_id);
4252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  params.callback = base::Bind(&ExtensionUpdater::ExtensionCheckFinished,
4262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                               weak_ptr_factory_.GetWeakPtr(),
4272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                               extension_id, callback);
4282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  CheckNow(params);
4292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return true;
4305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void ExtensionUpdater::ExtensionCheckFinished(
4332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const std::string& extension_id,
4342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const FinishedCallback& callback) {
4352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  std::map<std::string, ThrottleInfo>::iterator it =
4362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      throttle_info_.find(extension_id);
4372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (it != throttle_info_.end()) {
4382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    it->second.in_progress = false;
4392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
4402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  callback.Run();
4412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
4422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void ExtensionUpdater::OnExtensionDownloadFailed(
4442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const std::string& id,
4452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    Error error,
4462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const PingResult& ping,
4472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const std::set<int>& request_ids) {
4485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(alive_);
4495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  UpdatePingData(id, ping);
4502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  bool install_immediately = false;
4512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  for (std::set<int>::const_iterator it = request_ids.begin();
4522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)       it != request_ids.end(); ++it) {
4532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    InProgressCheck& request = requests_in_progress_[*it];
4542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    install_immediately |= request.install_immediately;
4552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    request.in_progress_ids_.remove(id);
4562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    NotifyIfFinished(*it);
4572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
4582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // This method is called if no updates were found. However a previous update
4602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // check might have queued an update for this extension already. If a
4612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // current update check has |install_immediately| set the previously
4622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // queued update should be installed now.
4632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (install_immediately && service_->GetPendingExtensionUpdate(id))
4642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    service_->FinishDelayedInstallation(id);
4655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void ExtensionUpdater::OnExtensionDownloadFinished(
4682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const std::string& id,
4692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const base::FilePath& path,
4702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const GURL& download_url,
4712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const std::string& version,
4722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const PingResult& ping,
4732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const std::set<int>& request_ids) {
4745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(alive_);
4755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  UpdatePingData(id, ping);
4765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  VLOG(2) << download_url << " written to " << path.value();
4785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  FetchedCRXFile fetched(id, path, download_url, request_ids);
4805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  fetched_crx_files_.push(fetched);
4815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // MaybeInstallCRXFile() removes extensions from |in_progress_ids_| after
4835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // starting the crx installer.
4845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  MaybeInstallCRXFile();
4855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool ExtensionUpdater::GetPingDataForExtension(
4885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::string& id,
4895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ManifestFetchData::PingData* ping_data) {
4905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(alive_);
4915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ping_data->rollcall_days = CalculatePingDays(
4925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      extension_prefs_->LastPingDay(id));
4932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ping_data->is_enabled = service_->IsExtensionEnabled(id);
4945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ping_data->active_days =
4955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      CalculateActivePingDays(extension_prefs_->LastActivePingDay(id),
4965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                              extension_prefs_->GetActiveBit(id));
4975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
4985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)std::string ExtensionUpdater::GetUpdateUrlData(const std::string& id) {
5015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(alive_);
50290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  return extension::GetUpdateURLData(extension_prefs_, id);
5035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool ExtensionUpdater::IsExtensionPending(const std::string& id) {
5065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(alive_);
5075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return service_->pending_extension_manager()->IsIdPending(id);
5085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool ExtensionUpdater::GetExtensionExistingVersion(const std::string& id,
5115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                   std::string* version) {
5125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(alive_);
5135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const Extension* extension = service_->GetExtensionById(id, true);
5145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!extension)
5155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
5162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  const Extension* update = service_->GetPendingExtensionUpdate(id);
5172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (update)
5182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    *version = update->VersionString();
5192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  else
5202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    *version = extension->VersionString();
5215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
5225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void ExtensionUpdater::UpdatePingData(const std::string& id,
5255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                      const PingResult& ping_result) {
5265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(alive_);
52768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  if (ping_result.did_ping)
52868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    extension_prefs_->SetLastPingDay(id, ping_result.day_start);
5295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (extension_prefs_->GetActiveBit(id)) {
5305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    extension_prefs_->SetActiveBit(id, false);
5315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    extension_prefs_->SetLastActivePingDay(id, ping_result.day_start);
5325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
5335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void ExtensionUpdater::MaybeInstallCRXFile() {
5365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (crx_install_is_running_ || fetched_crx_files_.empty())
5375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
5385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  std::set<int> request_ids;
5402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
5415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  while (!fetched_crx_files_.empty() && !crx_install_is_running_) {
5425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const FetchedCRXFile& crx_file = fetched_crx_files_.top();
5435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    VLOG(2) << "updating " << crx_file.extension_id
5452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            << " with " << crx_file.path.value();
5465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // The ExtensionService is now responsible for cleaning up the temp file
5485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // at |crx_file.path|.
5495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    CrxInstaller* installer = NULL;
5502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (service_->UpdateExtension(crx_file.extension_id,
5515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                  crx_file.path,
5525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                  crx_file.download_url,
5535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                  &installer)) {
5545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      crx_install_is_running_ = true;
5552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      current_crx_file_ = crx_file;
5562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
5572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      for (std::set<int>::const_iterator it = crx_file.request_ids.begin();
5582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          it != crx_file.request_ids.end(); ++it) {
5592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        InProgressCheck& request = requests_in_progress_[*it];
5602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        if (request.install_immediately) {
5612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          installer->set_install_wait_for_idle(false);
5622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          break;
5632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        }
5642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      }
5655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // Source parameter ensures that we only see the completion event for the
5675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // the installer we started.
5685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      registrar_.Add(this,
5695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                     chrome::NOTIFICATION_CRX_INSTALLER_DONE,
5705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                     content::Source<CrxInstaller>(installer));
5712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    } else {
5722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      for (std::set<int>::const_iterator it = crx_file.request_ids.begin();
5732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)           it != crx_file.request_ids.end(); ++it) {
5742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        InProgressCheck& request = requests_in_progress_[*it];
5752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        request.in_progress_ids_.remove(crx_file.extension_id);
5762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      }
5772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      request_ids.insert(crx_file.request_ids.begin(),
5782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                         crx_file.request_ids.end());
5795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
5805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    fetched_crx_files_.pop();
5815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
5825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  for (std::set<int>::const_iterator it = request_ids.begin();
5842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)       it != request_ids.end(); ++it) {
5852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    NotifyIfFinished(*it);
5862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
5875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void ExtensionUpdater::Observe(int type,
5905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                               const content::NotificationSource& source,
5915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                               const content::NotificationDetails& details) {
5922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  switch (type) {
5932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    case chrome::NOTIFICATION_CRX_INSTALLER_DONE: {
5942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      // No need to listen for CRX_INSTALLER_DONE anymore.
5952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      registrar_.Remove(this,
5962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                        chrome::NOTIFICATION_CRX_INSTALLER_DONE,
5972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                        source);
5982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      crx_install_is_running_ = false;
5992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
6002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      const FetchedCRXFile& crx_file = current_crx_file_;
6012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      for (std::set<int>::const_iterator it = crx_file.request_ids.begin();
6022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          it != crx_file.request_ids.end(); ++it) {
6032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        InProgressCheck& request = requests_in_progress_[*it];
6042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        request.in_progress_ids_.remove(crx_file.extension_id);
6052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        NotifyIfFinished(*it);
6062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      }
6072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
6082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      // If any files are available to update, start one.
6092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      MaybeInstallCRXFile();
6102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      break;
6112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
6122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    case chrome::NOTIFICATION_EXTENSION_INSTALLED: {
6132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      const Extension* extension =
614c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)          content::Details<const InstalledExtensionInfo>(details)->extension;
6152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      if (extension)
6162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        throttle_info_.erase(extension->id());
6172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      break;
6182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
6192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    default:
6202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      NOTREACHED();
6212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
6225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void ExtensionUpdater::NotifyStarted() {
6255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  content::NotificationService::current()->Notify(
6265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      chrome::NOTIFICATION_EXTENSION_UPDATING_STARTED,
6275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      content::Source<Profile>(profile_),
6285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      content::NotificationService::NoDetails());
6295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void ExtensionUpdater::NotifyIfFinished(int request_id) {
6322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(ContainsKey(requests_in_progress_, request_id));
6332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  const InProgressCheck& request = requests_in_progress_[request_id];
6342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (request.in_progress_ids_.empty()) {
6352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    VLOG(2) << "Finished update check " << request_id;
6362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (!request.callback.is_null())
6372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      request.callback.Run();
6382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    requests_in_progress_.erase(request_id);
6395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
6405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace extensions
643