extension_updater.cc revision 5d1f7b1de12d16ceb2c938c56701a3e8bfa558f7
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/updater/extension_downloader.h"
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/profiles/profile.h"
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/common/pref_names.h"
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/browser/browser_thread.h"
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/browser/notification_details.h"
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/browser/notification_service.h"
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/browser/notification_source.h"
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "crypto/sha2.h"
315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "extensions/browser/extension_registry.h"
32f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "extensions/browser/pending_extension_manager.h"
335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "extensions/browser/pref_names.h"
3468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)#include "extensions/common/constants.h"
35f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "extensions/common/extension.h"
365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "extensions/common/extension_set.h"
373551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)#include "extensions/common/manifest.h"
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using base::RandDouble;
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using base::RandInt;
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using base::Time;
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using base::TimeDelta;
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using content::BrowserThread;
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.
554e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#ifdef NDEBUG
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const int kMinUpdateFrequencySeconds = 30;
574e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#endif
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const int kMaxUpdateFrequencySeconds = 60 * 60 * 24 * 7;  // 7 days
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Require at least 5 seconds between consecutive non-succesful extension update
612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// checks.
622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const int kMinUpdateThrottleTime = 5;
632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// When we've computed a days value, we want to make sure we don't send a
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// negative value (due to the system clock being set backwards, etc.), since -1
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// is a special sentinel value that means "never pinged", and other negative
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// values don't make sense.
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int SanitizeDays(int days) {
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (days < 0)
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return 0;
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return days;
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Calculates the value to use for the ping days parameter.
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int CalculatePingDays(const Time& last_ping_day) {
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int days = extensions::ManifestFetchData::kNeverPinged;
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!last_ping_day.is_null()) {
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    days = SanitizeDays((Time::Now() - last_ping_day).InDays());
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return days;
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int CalculateActivePingDays(const Time& last_active_ping_day,
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                            bool hasActiveBit) {
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!hasActiveBit)
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return 0;
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (last_active_ping_day.is_null())
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return extensions::ManifestFetchData::kNeverPinged;
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return SanitizeDays((Time::Now() - last_active_ping_day).InDays());
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace extensions {
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)ExtensionUpdater::CheckParams::CheckParams()
9768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    : install_immediately(false) {}
982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)ExtensionUpdater::CheckParams::~CheckParams() {}
1002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)ExtensionUpdater::FetchedCRXFile::FetchedCRXFile(
1022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const std::string& i,
1032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const base::FilePath& p,
1045d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    bool file_ownership_passed,
1052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const GURL& u,
1062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const std::set<int>& request_ids)
1072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    : extension_id(i),
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      path(p),
1095d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      file_ownership_passed(file_ownership_passed),
1102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      download_url(u),
1112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      request_ids(request_ids) {}
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)ExtensionUpdater::FetchedCRXFile::FetchedCRXFile()
1145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    : path(), file_ownership_passed(true), download_url() {}
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ExtensionUpdater::FetchedCRXFile::~FetchedCRXFile() {}
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)ExtensionUpdater::InProgressCheck::InProgressCheck()
1192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    : install_immediately(false) {}
1202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)ExtensionUpdater::InProgressCheck::~InProgressCheck() {}
1222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)struct ExtensionUpdater::ThrottleInfo {
1242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ThrottleInfo()
1252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      : in_progress(true),
1262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        throttle_delay(kMinUpdateThrottleTime),
1272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        check_start(Time::Now()) {}
1282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  bool in_progress;
1302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  int throttle_delay;
1312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  Time check_start;
1322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)};
1332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ExtensionUpdater::ExtensionUpdater(ExtensionServiceInterface* service,
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                   ExtensionPrefs* extension_prefs,
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                   PrefService* prefs,
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                   Profile* profile,
1385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                   int frequency_seconds,
1395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                   ExtensionCache* cache)
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    : alive_(false),
141c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      weak_ptr_factory_(this),
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      service_(service), frequency_seconds_(frequency_seconds),
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      will_check_soon_(false), extension_prefs_(extension_prefs),
14468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)      prefs_(prefs), profile_(profile),
1452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      next_request_id_(0),
1465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      crx_install_is_running_(false),
1475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      extension_cache_(cache) {
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK_GE(frequency_seconds_, 5);
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK_LE(frequency_seconds_, kMaxUpdateFrequencySeconds);
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#ifdef NDEBUG
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // In Release mode we enforce that update checks don't happen too often.
1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  frequency_seconds_ = std::max(frequency_seconds_, kMinUpdateFrequencySeconds);
1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  frequency_seconds_ = std::min(frequency_seconds_, kMaxUpdateFrequencySeconds);
1552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_INSTALLED,
1572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                 content::NotificationService::AllBrowserContextsAndSources());
1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ExtensionUpdater::~ExtensionUpdater() {
1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Stop();
1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// The overall goal here is to balance keeping clients up to date while
1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// avoiding a thundering herd against update servers.
1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)TimeDelta ExtensionUpdater::DetermineFirstCheckDelay() {
1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(alive_);
1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // If someone's testing with a quick frequency, just allow it.
1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (frequency_seconds_ < kStartupWaitSeconds)
1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return TimeDelta::FromSeconds(frequency_seconds_);
1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // If we've never scheduled a check before, start at frequency_seconds_.
1735d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (!prefs_->HasPrefPath(pref_names::kNextUpdateCheck))
1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return TimeDelta::FromSeconds(frequency_seconds_);
1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // If it's been a long time since our last actual check, we want to do one
1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // relatively soon.
1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Time now = Time::Now();
1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Time last = Time::FromInternalValue(prefs_->GetInt64(
1805d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      pref_names::kLastUpdateCheck));
1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int days = (now - last).InDays();
1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (days >= 30) {
1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Wait 5-10 minutes.
1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return TimeDelta::FromSeconds(RandInt(kStartupWaitSeconds,
1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                          kStartupWaitSeconds * 2));
1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else if (days >= 14) {
1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Wait 10-20 minutes.
1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return TimeDelta::FromSeconds(RandInt(kStartupWaitSeconds * 2,
1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                          kStartupWaitSeconds * 4));
1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else if (days >= 3) {
1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Wait 20-40 minutes.
1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return TimeDelta::FromSeconds(RandInt(kStartupWaitSeconds * 4,
1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                          kStartupWaitSeconds * 8));
1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Read the persisted next check time, and use that if it isn't too soon.
1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Otherwise pick something random.
1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Time saved_next = Time::FromInternalValue(prefs_->GetInt64(
1995d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      pref_names::kNextUpdateCheck));
2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Time earliest = now + TimeDelta::FromSeconds(kStartupWaitSeconds);
2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (saved_next >= earliest) {
2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return saved_next - now;
2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return TimeDelta::FromSeconds(RandInt(kStartupWaitSeconds,
2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                          frequency_seconds_));
2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void ExtensionUpdater::Start() {
2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(!alive_);
2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // If these are NULL, then that means we've been called after Stop()
2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // has been called.
2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(service_);
2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(extension_prefs_);
2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(prefs_);
2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(profile_);
2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(!weak_ptr_factory_.HasWeakPtrs());
2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  alive_ = true;
2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Make sure our prefs are registered, then schedule the first check.
2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ScheduleNextCheck(DetermineFirstCheckDelay());
2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void ExtensionUpdater::Stop() {
2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  weak_ptr_factory_.InvalidateWeakPtrs();
2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  alive_ = false;
2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  service_ = NULL;
2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  extension_prefs_ = NULL;
2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  prefs_ = NULL;
2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  profile_ = NULL;
2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  timer_.Stop();
2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  will_check_soon_ = false;
2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  downloader_.reset();
2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void ExtensionUpdater::ScheduleNextCheck(const TimeDelta& target_delay) {
2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(alive_);
2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(!timer_.IsRunning());
2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(target_delay >= TimeDelta::FromSeconds(1));
2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Add +/- 10% random jitter.
2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  double delay_ms = target_delay.InMillisecondsF();
2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  double jitter_factor = (RandDouble() * .2) - 0.1;
2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  delay_ms += delay_ms * jitter_factor;
2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  TimeDelta actual_delay = TimeDelta::FromMilliseconds(
2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      static_cast<int64>(delay_ms));
2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Save the time of next check.
2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Time next = Time::Now() + actual_delay;
2495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  prefs_->SetInt64(pref_names::kNextUpdateCheck, next.ToInternalValue());
2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  timer_.Start(FROM_HERE, actual_delay, this, &ExtensionUpdater::TimerFired);
2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void ExtensionUpdater::TimerFired() {
2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(alive_);
2562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  CheckNow(default_params_);
2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // If the user has overridden the update frequency, don't bother reporting
2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // this.
26068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  if (frequency_seconds_ == extensions::kDefaultUpdateFrequencySeconds) {
2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Time last = Time::FromInternalValue(prefs_->GetInt64(
2625d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        pref_names::kLastUpdateCheck));
2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (last.ToInternalValue() != 0) {
2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // Use counts rather than time so we can use minutes rather than millis.
2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      UMA_HISTOGRAM_CUSTOM_COUNTS("Extensions.UpdateCheckGap",
2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          (Time::Now() - last).InMinutes(),
2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          TimeDelta::FromSeconds(kStartupWaitSeconds).InMinutes(),
2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          TimeDelta::FromDays(40).InMinutes(),
2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          50);  // 50 buckets seems to be the default.
2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Save the last check time, and schedule the next check.
2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int64 now = Time::Now().ToInternalValue();
2755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  prefs_->SetInt64(pref_names::kLastUpdateCheck, now);
2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ScheduleNextCheck(TimeDelta::FromSeconds(frequency_seconds_));
2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void ExtensionUpdater::CheckSoon() {
2805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(alive_);
2815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (will_check_soon_)
2825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
2835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (BrowserThread::PostTask(
2845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          BrowserThread::UI, FROM_HERE,
2855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          base::Bind(&ExtensionUpdater::DoCheckSoon,
2865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                     weak_ptr_factory_.GetWeakPtr()))) {
2875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    will_check_soon_ = true;
2885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
2895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    NOTREACHED();
2905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool ExtensionUpdater::WillCheckSoon() const {
2945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return will_check_soon_;
2955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void ExtensionUpdater::DoCheckSoon() {
2985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(will_check_soon_);
2992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  CheckNow(default_params_);
3005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  will_check_soon_ = false;
3015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void ExtensionUpdater::AddToDownloader(
3042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const ExtensionSet* extensions,
3052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const std::list<std::string>& pending_ids,
3062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    int request_id) {
3072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  InProgressCheck& request = requests_in_progress_[request_id];
3085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (ExtensionSet::const_iterator extension_iter = extensions->begin();
3095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       extension_iter != extensions->end(); ++extension_iter) {
3107d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    const Extension& extension = *extension_iter->get();
3112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (!Manifest::IsAutoUpdateableLocation(extension.location())) {
3125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      VLOG(2) << "Extension " << extension.id() << " is not auto updateable";
3135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      continue;
3145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
3155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // An extension might be overwritten by policy, and have its update url
3165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // changed. Make sure existing extensions aren't fetched again, if a
3175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // pending fetch for an extension with the same id already exists.
3185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    std::list<std::string>::const_iterator pending_id_iter = std::find(
3195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        pending_ids.begin(), pending_ids.end(), extension.id());
3205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (pending_id_iter == pending_ids.end()) {
3212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      if (downloader_->AddExtension(extension, request_id))
3222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        request.in_progress_ids_.push_back(extension.id());
3235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
3245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void ExtensionUpdater::CheckNow(const CheckParams& params) {
3282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  int request_id = next_request_id_++;
3292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  VLOG(2) << "Starting update check " << request_id;
3312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (params.ids.empty())
3322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    NotifyStarted();
3332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(alive_);
3352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  InProgressCheck& request = requests_in_progress_[request_id];
3372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  request.callback = params.callback;
3382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  request.install_immediately = params.install_immediately;
3395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!downloader_.get()) {
3415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    downloader_.reset(
3425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        new ExtensionDownloader(this, profile_->GetRequestContext()));
3435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Add fetch records for extensions that should be fetched by an update URL.
3465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // These extensions are not yet installed. They come from group policy
3475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // and external install sources.
3485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const PendingExtensionManager* pending_extension_manager =
3495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      service_->pending_extension_manager();
3505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::list<std::string> pending_ids;
3522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (params.ids.empty()) {
3542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // If no extension ids are specified, check for updates for all extensions.
3552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    pending_extension_manager->GetPendingIdsForUpdateCheck(&pending_ids);
3562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    std::list<std::string>::const_iterator iter;
3582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    for (iter = pending_ids.begin(); iter != pending_ids.end(); ++iter) {
3592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      const PendingExtensionInfo* info = pending_extension_manager->GetById(
3602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          *iter);
3612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      if (!Manifest::IsAutoUpdateableLocation(info->install_source())) {
3622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        VLOG(2) << "Extension " << *iter << " is not auto updateable";
3632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        continue;
3642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      }
3652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      if (downloader_->AddPendingExtension(*iter, info->update_url(),
3662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                           request_id))
3672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        request.in_progress_ids_.push_back(*iter);
3685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
3695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3705d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    ExtensionRegistry* registry = ExtensionRegistry::Get(profile_);
3715d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    AddToDownloader(&registry->enabled_extensions(), pending_ids, request_id);
3725d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    AddToDownloader(&registry->disabled_extensions(), pending_ids, request_id);
3732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  } else {
3742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    for (std::list<std::string>::const_iterator it = params.ids.begin();
3752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)         it != params.ids.end(); ++it) {
3762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      const Extension* extension = service_->GetExtensionById(*it, true);
3772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      DCHECK(extension);
3782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      if (downloader_->AddExtension(*extension, request_id))
3792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        request.in_progress_ids_.push_back(extension->id());
3802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
3812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
3825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // StartAllPending() might call OnExtensionDownloadFailed/Finished before
3842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // it returns, which would cause NotifyIfFinished to incorrectly try to
3852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // send out a notification. So check before we call StartAllPending if any
3862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // extensions are going to be updated, and use that to figure out if
3872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // NotifyIfFinished should be called.
3882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  bool noChecks = request.in_progress_ids_.empty();
3892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // StartAllPending() will call OnExtensionDownloadFailed or
3912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // OnExtensionDownloadFinished for each extension that was checked.
3925d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  downloader_->StartAllPending(extension_cache_);
3932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (noChecks)
3952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    NotifyIfFinished(request_id);
3962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
3972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool ExtensionUpdater::CheckExtensionSoon(const std::string& extension_id,
3992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                          const FinishedCallback& callback) {
4002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  bool have_throttle_info = ContainsKey(throttle_info_, extension_id);
4012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ThrottleInfo& info = throttle_info_[extension_id];
4022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (have_throttle_info) {
4032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // We already had a ThrottleInfo object for this extension, check if the
4042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // update check request should be allowed.
4052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // If another check is in progress, don't start a new check.
4072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (info.in_progress)
4082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      return false;
4092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    Time now = Time::Now();
4112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    Time last = info.check_start;
4122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // If somehow time moved back, we don't want to infinitely keep throttling.
4132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (now < last) {
4142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      last = now;
4152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      info.check_start = now;
4162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
4172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    Time earliest = last + TimeDelta::FromSeconds(info.throttle_delay);
4182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // If check is too soon, throttle.
4192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (now < earliest)
4202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      return false;
4212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // TODO(mek): Somehow increase time between allowing checks when checks
4232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // are repeatedly throttled and don't result in updates being installed.
4242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // It's okay to start a check, update values.
4262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    info.check_start = now;
4272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    info.in_progress = true;
4282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
4292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  CheckParams params;
4312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  params.ids.push_back(extension_id);
4322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  params.callback = base::Bind(&ExtensionUpdater::ExtensionCheckFinished,
4332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                               weak_ptr_factory_.GetWeakPtr(),
4342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                               extension_id, callback);
4352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  CheckNow(params);
4362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return true;
4375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void ExtensionUpdater::ExtensionCheckFinished(
4402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const std::string& extension_id,
4412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const FinishedCallback& callback) {
4422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  std::map<std::string, ThrottleInfo>::iterator it =
4432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      throttle_info_.find(extension_id);
4442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (it != throttle_info_.end()) {
4452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    it->second.in_progress = false;
4462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
4472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  callback.Run();
4482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
4492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void ExtensionUpdater::OnExtensionDownloadFailed(
4512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const std::string& id,
4522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    Error error,
4532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const PingResult& ping,
4542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const std::set<int>& request_ids) {
4555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(alive_);
4565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  UpdatePingData(id, ping);
4572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  bool install_immediately = false;
4582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  for (std::set<int>::const_iterator it = request_ids.begin();
4592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)       it != request_ids.end(); ++it) {
4602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    InProgressCheck& request = requests_in_progress_[*it];
4612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    install_immediately |= request.install_immediately;
4622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    request.in_progress_ids_.remove(id);
4632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    NotifyIfFinished(*it);
4642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
4652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // This method is called if no updates were found. However a previous update
4672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // check might have queued an update for this extension already. If a
4682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // current update check has |install_immediately| set the previously
4692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // queued update should be installed now.
4702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (install_immediately && service_->GetPendingExtensionUpdate(id))
4712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    service_->FinishDelayedInstallation(id);
4725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void ExtensionUpdater::OnExtensionDownloadFinished(
4752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const std::string& id,
4762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const base::FilePath& path,
4775d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    bool file_ownership_passed,
4782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const GURL& download_url,
4792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const std::string& version,
4802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const PingResult& ping,
4812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const std::set<int>& request_ids) {
4825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(alive_);
4835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  UpdatePingData(id, ping);
4845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  VLOG(2) << download_url << " written to " << path.value();
4865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  FetchedCRXFile fetched(id, path, file_ownership_passed, download_url,
4885d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                         request_ids);
4895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  fetched_crx_files_.push(fetched);
4905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // MaybeInstallCRXFile() removes extensions from |in_progress_ids_| after
4925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // starting the crx installer.
4935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  MaybeInstallCRXFile();
4945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool ExtensionUpdater::GetPingDataForExtension(
4975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::string& id,
4985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ManifestFetchData::PingData* ping_data) {
4995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(alive_);
5005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ping_data->rollcall_days = CalculatePingDays(
5015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      extension_prefs_->LastPingDay(id));
5022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ping_data->is_enabled = service_->IsExtensionEnabled(id);
5035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ping_data->active_days =
5045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      CalculateActivePingDays(extension_prefs_->LastActivePingDay(id),
5055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                              extension_prefs_->GetActiveBit(id));
5065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
5075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)std::string ExtensionUpdater::GetUpdateUrlData(const std::string& id) {
5105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(alive_);
51190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  return extension::GetUpdateURLData(extension_prefs_, id);
5125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool ExtensionUpdater::IsExtensionPending(const std::string& id) {
5155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(alive_);
5165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return service_->pending_extension_manager()->IsIdPending(id);
5175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool ExtensionUpdater::GetExtensionExistingVersion(const std::string& id,
5205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                   std::string* version) {
5215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(alive_);
5225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const Extension* extension = service_->GetExtensionById(id, true);
5235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!extension)
5245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
5252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  const Extension* update = service_->GetPendingExtensionUpdate(id);
5262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (update)
5272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    *version = update->VersionString();
5282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  else
5292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    *version = extension->VersionString();
5305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
5315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void ExtensionUpdater::UpdatePingData(const std::string& id,
5345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                      const PingResult& ping_result) {
5355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(alive_);
53668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  if (ping_result.did_ping)
53768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    extension_prefs_->SetLastPingDay(id, ping_result.day_start);
5385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (extension_prefs_->GetActiveBit(id)) {
5395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    extension_prefs_->SetActiveBit(id, false);
5405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    extension_prefs_->SetLastActivePingDay(id, ping_result.day_start);
5415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
5425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void ExtensionUpdater::MaybeInstallCRXFile() {
5455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (crx_install_is_running_ || fetched_crx_files_.empty())
5465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
5475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  std::set<int> request_ids;
5492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
5505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  while (!fetched_crx_files_.empty() && !crx_install_is_running_) {
5515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const FetchedCRXFile& crx_file = fetched_crx_files_.top();
5525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    VLOG(2) << "updating " << crx_file.extension_id
5542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            << " with " << crx_file.path.value();
5555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // The ExtensionService is now responsible for cleaning up the temp file
5575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // at |crx_file.path|.
5585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    CrxInstaller* installer = NULL;
5592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (service_->UpdateExtension(crx_file.extension_id,
5605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                  crx_file.path,
5615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                  crx_file.file_ownership_passed,
5625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                  crx_file.download_url,
5635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                  &installer)) {
5645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      crx_install_is_running_ = true;
5652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      current_crx_file_ = crx_file;
5662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
5672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      for (std::set<int>::const_iterator it = crx_file.request_ids.begin();
5682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          it != crx_file.request_ids.end(); ++it) {
5692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        InProgressCheck& request = requests_in_progress_[*it];
5702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        if (request.install_immediately) {
5712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          installer->set_install_wait_for_idle(false);
5722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          break;
5732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        }
5742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      }
5755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // Source parameter ensures that we only see the completion event for the
5775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // the installer we started.
5785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      registrar_.Add(this,
5795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                     chrome::NOTIFICATION_CRX_INSTALLER_DONE,
5805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                     content::Source<CrxInstaller>(installer));
5812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    } else {
5822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      for (std::set<int>::const_iterator it = crx_file.request_ids.begin();
5832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)           it != crx_file.request_ids.end(); ++it) {
5842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        InProgressCheck& request = requests_in_progress_[*it];
5852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        request.in_progress_ids_.remove(crx_file.extension_id);
5862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      }
5872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      request_ids.insert(crx_file.request_ids.begin(),
5882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                         crx_file.request_ids.end());
5895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
5905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    fetched_crx_files_.pop();
5915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
5925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  for (std::set<int>::const_iterator it = request_ids.begin();
5942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)       it != request_ids.end(); ++it) {
5952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    NotifyIfFinished(*it);
5962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
5975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void ExtensionUpdater::Observe(int type,
6005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                               const content::NotificationSource& source,
6015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                               const content::NotificationDetails& details) {
6022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  switch (type) {
6032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    case chrome::NOTIFICATION_CRX_INSTALLER_DONE: {
6042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      // No need to listen for CRX_INSTALLER_DONE anymore.
6052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      registrar_.Remove(this,
6062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                        chrome::NOTIFICATION_CRX_INSTALLER_DONE,
6072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                        source);
6082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      crx_install_is_running_ = false;
6092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
6102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      const FetchedCRXFile& crx_file = current_crx_file_;
6112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      for (std::set<int>::const_iterator it = crx_file.request_ids.begin();
6122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          it != crx_file.request_ids.end(); ++it) {
6132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        InProgressCheck& request = requests_in_progress_[*it];
6142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        request.in_progress_ids_.remove(crx_file.extension_id);
6152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        NotifyIfFinished(*it);
6162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      }
6172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
6182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      // If any files are available to update, start one.
6192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      MaybeInstallCRXFile();
6202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      break;
6212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
6222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    case chrome::NOTIFICATION_EXTENSION_INSTALLED: {
6232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      const Extension* extension =
624c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)          content::Details<const InstalledExtensionInfo>(details)->extension;
6252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      if (extension)
6262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        throttle_info_.erase(extension->id());
6272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      break;
6282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
6292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    default:
6302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      NOTREACHED();
6312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
6325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void ExtensionUpdater::NotifyStarted() {
6355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  content::NotificationService::current()->Notify(
6365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      chrome::NOTIFICATION_EXTENSION_UPDATING_STARTED,
6375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      content::Source<Profile>(profile_),
6385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      content::NotificationService::NoDetails());
6395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void ExtensionUpdater::NotifyIfFinished(int request_id) {
6422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(ContainsKey(requests_in_progress_, request_id));
6432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  const InProgressCheck& request = requests_in_progress_[request_id];
6442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (request.in_progress_ids_.empty()) {
6452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    VLOG(2) << "Finished update check " << request_id;
6462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (!request.callback.is_null())
6472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      request.callback.Run();
6482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    requests_in_progress_.erase(request_id);
6495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
6505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace extensions
653