diff options
Diffstat (limited to 'chrome')
4 files changed, 225 insertions, 114 deletions
diff --git a/chrome/browser/chromeos/extensions/external_cache.cc b/chrome/browser/chromeos/extensions/external_cache.cc index e9c3676..a7350cc 100644 --- a/chrome/browser/chromeos/extensions/external_cache.cc +++ b/chrome/browser/chromeos/extensions/external_cache.cc @@ -6,9 +6,11 @@ #include "base/bind.h" #include "base/bind_helpers.h" +#include "base/callback.h" #include "base/file_util.h" #include "base/files/file_enumerator.h" #include "base/location.h" +#include "base/logging.h" #include "base/strings/string_util.h" #include "base/values.h" #include "base/version.h" @@ -33,25 +35,28 @@ const char kCRXFileExtension[] = ".crx"; // Name of flag file that indicates that cache is ready (import finished). const char kCacheReadyFlagFileName[] = ".initialized"; -// Delay between checking cache ready flag file. -const int64_t kCacheReadyDelayMs = 1000; +// Delay between checks for flag file presence when waiting for the cache to +// become ready. +const int64_t kCacheStatusPollingDelayMs = 1000; } // namespace ExternalCache::ExternalCache(const std::string& cache_dir, net::URLRequestContextGetter* request_context, + const scoped_refptr<base::SequencedTaskRunner>& + backend_task_runner, Delegate* delegate, bool always_check_updates, - bool wait_cache_initialization) + bool wait_for_cache_initialization) : cache_dir_(cache_dir), request_context_(request_context), delegate_(delegate), + shutdown_(false), always_check_updates_(always_check_updates), - wait_cache_initialization_(wait_cache_initialization), + wait_for_cache_initialization_(wait_for_cache_initialization), cached_extensions_(new base::DictionaryValue()), - weak_ptr_factory_(this), - worker_pool_token_( - content::BrowserThread::GetBlockingPool()->GetSequenceToken()) { + backend_task_runner_(backend_task_runner), + weak_ptr_factory_(this) { notification_registrar_.Add( this, chrome::NOTIFICATION_EXTENSION_INSTALL_ERROR, @@ -61,8 +66,19 @@ ExternalCache::ExternalCache(const std::string& cache_dir, ExternalCache::~ExternalCache() { } +void ExternalCache::Shutdown(const base::Closure& callback) { + DCHECK(!shutdown_); + shutdown_ = true; + backend_task_runner_->PostTask(FROM_HERE, + base::Bind(&ExternalCache::BackendShudown, + callback)); +} + void ExternalCache::UpdateExtensionsList( scoped_ptr<base::DictionaryValue> prefs) { + if (shutdown_) + return; + extensions_ = prefs.Pass(); if (extensions_->empty()) { // Don't check cache and clear it if there are no extensions in the list. @@ -73,11 +89,14 @@ void ExternalCache::UpdateExtensionsList( cached_extensions_->Clear(); UpdateExtensionLoader(); } else { - CheckCacheNow(); + CheckCache(); } } void ExternalCache::OnDamagedFileDetected(const base::FilePath& path) { + if (shutdown_) + return; + for (base::DictionaryValue::Iterator it(*cached_extensions_.get()); !it.IsAtEnd(); it.Advance()) { const base::DictionaryValue* entry = NULL; @@ -99,10 +118,11 @@ void ExternalCache::OnDamagedFileDetected(const base::FilePath& path) { // The file will be downloaded again on the next restart. if (base::FilePath(cache_dir_).IsParent(path)) { - // Don't delete files out of cache_dir_. - content::BrowserThread::PostTask( - content::BrowserThread::FILE, FROM_HERE, - base::Bind(base::IgnoreResult(base::DeleteFile), path, true)); + backend_task_runner_->PostTask( + FROM_HERE, + base::Bind(base::IgnoreResult(base::DeleteFile), + path, + true)); } // Don't try to DownloadMissingExtensions() from here, @@ -116,6 +136,9 @@ void ExternalCache::OnDamagedFileDetected(const base::FilePath& path) { void ExternalCache::Observe(int type, const content::NotificationSource& source, const content::NotificationDetails& details) { + if (shutdown_) + return; + switch (type) { case chrome::NOTIFICATION_EXTENSION_INSTALL_ERROR: { extensions::CrxInstaller* installer = @@ -134,6 +157,9 @@ void ExternalCache::OnExtensionDownloadFailed( extensions::ExtensionDownloaderDelegate::Error error, const extensions::ExtensionDownloaderDelegate::PingResult& ping_result, const std::set<int>& request_ids) { + if (shutdown_) + return; + if (error == NO_UPDATE_AVAILABLE) { if (!cached_extensions_->HasKey(id)) { LOG(ERROR) << "ExternalCache extension " << id @@ -152,15 +178,17 @@ void ExternalCache::OnExtensionDownloadFinished( const std::string& version, const extensions::ExtensionDownloaderDelegate::PingResult& ping_result, const std::set<int>& request_ids) { - // The explicit copy ctors are to make sure that Bind() binds a copy and not - // a reference to the arguments. - PostBlockingTask(FROM_HERE, - base::Bind(&ExternalCache::BlockingInstallCacheEntry, - weak_ptr_factory_.GetWeakPtr(), - std::string(cache_dir_), - std::string(id), - base::FilePath(path), - std::string(version))); + if (shutdown_) + return; + + backend_task_runner_->PostTask( + FROM_HERE, + base::Bind(&ExternalCache::BackendInstallCacheEntry, + weak_ptr_factory_.GetWeakPtr(), + cache_dir_, + id, + path, + version)); } bool ExternalCache::IsExtensionPending(const std::string& id) { @@ -179,57 +207,86 @@ bool ExternalCache::GetExtensionExistingVersion(const std::string& id, return false; } -void ExternalCache::CheckCacheNow() { - scoped_ptr<DictionaryValue> prefs(extensions_->DeepCopy()); - PostBlockingTask(FROM_HERE, - base::Bind(&ExternalCache::BlockingCheckCache, - weak_ptr_factory_.GetWeakPtr(), - worker_pool_token_, - std::string(cache_dir_), - base::Passed(&prefs), - wait_cache_initialization_)); -} - void ExternalCache::UpdateExtensionLoader() { + if (shutdown_) + return; + VLOG(1) << "Notify ExternalCache delegate about cache update"; if (delegate_) delegate_->OnExtensionListsUpdated(cached_extensions_.get()); } +void ExternalCache::CheckCache() { + if (wait_for_cache_initialization_) { + backend_task_runner_->PostTask( + FROM_HERE, + base::Bind(&ExternalCache::BackendCheckCacheStatus, + weak_ptr_factory_.GetWeakPtr(), + cache_dir_)); + } else { + CheckCacheContents(); + } +} + // static -void ExternalCache::BlockingCheckCache( +void ExternalCache::BackendCheckCacheStatus( base::WeakPtr<ExternalCache> external_cache, - base::SequencedWorkerPool::SequenceToken sequence_token, - const std::string& cache_dir, - scoped_ptr<base::DictionaryValue> prefs, - bool wait_cache_initialization) { + const std::string& cache_dir) { + const base::FilePath dir(cache_dir); + content::BrowserThread::PostTask( + content::BrowserThread::UI, + FROM_HERE, + base::Bind(&ExternalCache::OnCacheStatusChecked, + external_cache, + base::PathExists(dir.AppendASCII(kCacheReadyFlagFileName)))); +} - base::FilePath dir(cache_dir); - if (wait_cache_initialization && - !base::PathExists(dir.AppendASCII(kCacheReadyFlagFileName))) { - content::BrowserThread::GetBlockingPool()->PostDelayedSequencedWorkerTask( - sequence_token, - FROM_HERE, - base::Bind(&ExternalCache::BlockingCheckCache, - external_cache, - sequence_token, - std::string(cache_dir), - base::Passed(&prefs), - wait_cache_initialization), - base::TimeDelta::FromMilliseconds(kCacheReadyDelayMs)); +void ExternalCache::OnCacheStatusChecked(bool ready) { + if (shutdown_) return; + + if (ready) { + CheckCacheContents(); + } else { + content::BrowserThread::PostDelayedTask( + content::BrowserThread::UI, + FROM_HERE, + base::Bind(&ExternalCache::CheckCache, + weak_ptr_factory_.GetWeakPtr()), + base::TimeDelta::FromMilliseconds(kCacheStatusPollingDelayMs)); } +} - BlockingCheckCacheInternal(cache_dir, prefs.get()); - content::BrowserThread::PostTask(content::BrowserThread::UI, FROM_HERE, - base::Bind(&ExternalCache::OnCacheUpdated, - external_cache, - base::Passed(&prefs))); +void ExternalCache::CheckCacheContents() { + if (shutdown_) + return; + + backend_task_runner_->PostTask( + FROM_HERE, + base::Bind(&ExternalCache::BackendCheckCacheContents, + weak_ptr_factory_.GetWeakPtr(), + cache_dir_, + base::Passed(make_scoped_ptr(extensions_->DeepCopy())))); } // static -void ExternalCache::BlockingCheckCacheInternal(const std::string& cache_dir, - base::DictionaryValue* prefs) { +void ExternalCache::BackendCheckCacheContents( + base::WeakPtr<ExternalCache> external_cache, + const std::string& cache_dir, + scoped_ptr<base::DictionaryValue> prefs) { + const base::FilePath dir(cache_dir); + BackendCheckCacheContentsInternal(cache_dir, prefs.get()); + content::BrowserThread::PostTask(content::BrowserThread::UI, + FROM_HERE, + base::Bind(&ExternalCache::OnCacheUpdated, + external_cache, + base::Passed(&prefs))); +} + +// static +void ExternalCache::BackendCheckCacheContentsInternal( + const std::string& cache_dir, + base::DictionaryValue* prefs) { // Start by verifying that the cache dir exists. base::FilePath dir(cache_dir); if (!base::DirectoryExists(dir)) { @@ -350,6 +407,8 @@ void ExternalCache::BlockingCheckCacheInternal(const std::string& cache_dir, void ExternalCache::OnCacheUpdated(scoped_ptr<base::DictionaryValue> prefs) { DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); + if (shutdown_) + return; // If request_context_ is missing we can't download anything. if (!downloader_ && request_context_) { @@ -407,7 +466,7 @@ void ExternalCache::OnCacheUpdated(scoped_ptr<base::DictionaryValue> prefs) { } // static -void ExternalCache::BlockingInstallCacheEntry( +void ExternalCache::BackendInstallCacheEntry( base::WeakPtr<ExternalCache> external_cache, const std::string& app_cache_dir, const std::string& id, @@ -448,17 +507,22 @@ void ExternalCache::BlockingInstallCacheEntry( return; } - content::BrowserThread::PostTask(content::BrowserThread::UI, FROM_HERE, - base::Bind(&ExternalCache::OnCacheEntryInstalled, - external_cache, - std::string(id), - cached_crx_path.value(), - std::string(version))); + content::BrowserThread::PostTask( + content::BrowserThread::UI, + FROM_HERE, + base::Bind(&ExternalCache::OnCacheEntryInstalled, + external_cache, + id, + cached_crx_path.value(), + version)); } void ExternalCache::OnCacheEntryInstalled(const std::string& id, const std::string& path, const std::string& version) { + if (shutdown_) + return; + VLOG(1) << "AppPack installed a new extension in the cache: " << path; base::DictionaryValue* entry = NULL; @@ -484,12 +548,11 @@ void ExternalCache::OnCacheEntryInstalled(const std::string& id, UpdateExtensionLoader(); } -void ExternalCache::PostBlockingTask(const tracked_objects::Location& location, - const base::Closure& task) { - content::BrowserThread::GetBlockingPool()-> - PostSequencedWorkerTaskWithShutdownBehavior( - worker_pool_token_, location, task, - base::SequencedWorkerPool::SKIP_ON_SHUTDOWN); +// static +void ExternalCache::BackendShudown(const base::Closure& callback) { + content::BrowserThread::PostTask(content::BrowserThread::UI, + FROM_HERE, + callback); } } // namespace chromeos diff --git a/chrome/browser/chromeos/extensions/external_cache.h b/chrome/browser/chromeos/extensions/external_cache.h index b69301c..0daa83e 100644 --- a/chrome/browser/chromeos/extensions/external_cache.h +++ b/chrome/browser/chromeos/extensions/external_cache.h @@ -8,10 +8,12 @@ #include <string> #include "base/basictypes.h" -#include "base/callback.h" +#include "base/callback_forward.h" #include "base/files/file_path.h" +#include "base/memory/ref_counted.h" +#include "base/memory/scoped_ptr.h" #include "base/memory/weak_ptr.h" -#include "base/threading/sequenced_worker_pool.h" +#include "base/sequenced_task_runner.h" #include "chrome/browser/extensions/updater/extension_downloader_delegate.h" #include "content/public/browser/notification_observer.h" #include "content/public/browser/notification_registrar.h" @@ -28,13 +30,9 @@ namespace net { class URLRequestContextGetter; } -namespace tracked_objects { -class Location; -} - namespace chromeos { -// The ExternalCache manages cache for external extensions. +// The ExternalCache manages a cache for external extensions. class ExternalCache : public content::NotificationObserver, public extensions::ExtensionDownloaderDelegate { public: @@ -46,15 +44,19 @@ class ExternalCache : public content::NotificationObserver, const base::DictionaryValue* prefs) = 0; }; - // The |request_context| is used for the update checks. - // By default updates are checked for the extensions with external_update_url. - // If |always_check_webstore| set, updates will be check for external_crx too. - // If |wait_cache_initialization|, cache will wait for flag file in cache dir. + // The |request_context| is used for update checks. All file I/O is done via + // the |backend_task_runner|. If |always_check_updates| is |false|, update + // checks are performed for extensions that have an |external_update_url| + // only. If |wait_for_cache_initialization| is |true|, the cache contents will + // not be read until a flag file appears in the cache directory, signaling + // that the cache is ready. ExternalCache(const std::string& cache_dir, net::URLRequestContextGetter* request_context, + const scoped_refptr<base::SequencedTaskRunner>& + backend_task_runner, Delegate* delegate, bool always_check_updates, - bool wait_cache_initialization); + bool wait_for_cache_initialization); virtual ~ExternalCache(); // Returns already cached extensions. @@ -62,8 +64,12 @@ class ExternalCache : public content::NotificationObserver, return cached_extensions_.get(); } - // Update list of extensions in cache and force update check for them. - // ExternalCache gets ownership of |prefs|. + // Shut down the cache. The |callback| will be invoked when the cache has shut + // down completely and there are no more pending file I/O operations. + void Shutdown(const base::Closure& callback); + + // Replace the list of extensions to cache with |prefs| and perform update + // checks for these. void UpdateExtensionsList(scoped_ptr<base::DictionaryValue> prefs); // If a user of one of the ExternalCache's extensions detects that @@ -97,37 +103,53 @@ class ExternalCache : public content::NotificationObserver, virtual bool GetExtensionExistingVersion(const std::string& id, std::string* version) OVERRIDE; - // Starts a cache update check immediately. - void CheckCacheNow(); - // Notifies the that the cache has been updated, providing // extensions loader with an updated list of extensions. void UpdateExtensionLoader(); - // Performs a cache update check on the blocking pool. |external_cache| is - // used to reply in the UI thread. |prefs| contains the list extensions - // anything else is invalid, and should be removed from the cache. - // Ownership of |prefs| is transferred to this function. - static void BlockingCheckCache( + // Checks the cache contents and deletes any entries no longer referenced by + // |extensions_|. If |wait_for_cache_initialization_| is |true|, waits for the + // cache to become ready first, as indicated by the presence of a flag file. + void CheckCache(); + + // Checks whether a flag file exists in the |cache_dir|, indicating that the + // cache is ready. This method is invoked via the |backend_task_runner_| and + // posts its result back to the |external_cache| on the UI thread. + static void BackendCheckCacheStatus( base::WeakPtr<ExternalCache> external_cache, - base::SequencedWorkerPool::SequenceToken token, - const std::string& app_cache_dir, - scoped_ptr<base::DictionaryValue> prefs, - bool wait_cache_initialization); - - // Helper for BlockingCheckCache(), updates |prefs|. - static void BlockingCheckCacheInternal( - const std::string& app_cache_dir, + const std::string& cache_dir); + + // Invoked on the UI thread after checking whether the cache is ready. If the + // cache is not ready yet, posts a delayed task that will repeat the check, + // thus polling for cache readiness. + void OnCacheStatusChecked(bool ready); + + // Checks the cache contents. This is a helper that invokes the actual check + // by posting to the |backend_task_runner_|. + void CheckCacheContents(); + + // Checks the cache contents, deleting any entries no longer referenced by + // |prefs|. This method is invoked via the |backend_task_runner_| and posts + // back a list of cache entries to the |external_cache| on the UI thread. + static void BackendCheckCacheContents( + base::WeakPtr<ExternalCache> external_cache, + const std::string& cache_dir, + scoped_ptr<base::DictionaryValue> prefs); + + // Helper for BackendCheckCacheContents() that updates |prefs|. + static void BackendCheckCacheContentsInternal( + const std::string& cache_dir, base::DictionaryValue* prefs); // Invoked when the cache has been updated. |prefs| contains all the currently // valid crx files in the cache, ownerships is transfered to this function. void OnCacheUpdated(scoped_ptr<base::DictionaryValue> prefs); - // Invoked to install the downloaded crx file at |path| in the cache. - static void BlockingInstallCacheEntry( + // Installs the downloaded crx file at |path| in the |cache_dir|. This method + // is invoked via the |backend_task_runner_|. + static void BackendInstallCacheEntry( base::WeakPtr<ExternalCache> external_cache, - const std::string& app_cache_dir, + const std::string& cache_dir, const std::string& id, const base::FilePath& path, const std::string& version); @@ -137,11 +159,12 @@ class ExternalCache : public content::NotificationObserver, const std::string& path, const std::string& version); - // Helper to post blocking IO tasks to the blocking pool. - void PostBlockingTask(const tracked_objects::Location& from_here, - const base::Closure& task); + // Posted to the |backend_task_runner_| during cache shutdown so that it runs + // after all file I/O has been completed. Invokes |callback| on the UI thread + // to indicate that the cache has been shut down completely. + static void BackendShudown(const base::Closure& callback); - // Path to the dir where apps cache is stored. + // Path to the directory where the extension cache is stored. std::string cache_dir_; // Request context used by the |downloader_|. @@ -150,11 +173,14 @@ class ExternalCache : public content::NotificationObserver, // Delegate that would like to get notifications about cache updates. Delegate* delegate_; + // Whether the cache shutdown has been initiated. + bool shutdown_; + // Updates needs to be check for the extensions with external_crx too. bool always_check_updates_; // Set to true if cache should wait for initialization flag file. - bool wait_cache_initialization_; + bool wait_for_cache_initialization_; // This is the list of extensions currently configured. scoped_ptr<base::DictionaryValue> extensions_; @@ -166,14 +192,14 @@ class ExternalCache : public content::NotificationObserver, // Used to download the extensions and to check for updates. scoped_ptr<extensions::ExtensionDownloader> downloader_; - base::WeakPtrFactory<ExternalCache> weak_ptr_factory_; + // Task runner for executing file I/O tasks. + scoped_refptr<base::SequencedTaskRunner> backend_task_runner_; // Observes failures to install CRX files. content::NotificationRegistrar notification_registrar_; - // Unique sequence token so that tasks posted by the ExternalCache are - // executed sequentially in the blocking pool. - base::SequencedWorkerPool::SequenceToken worker_pool_token_; + // Weak factory for callbacks from the backend and delayed tasks. + base::WeakPtrFactory<ExternalCache> weak_ptr_factory_; DISALLOW_COPY_AND_ASSIGN(ExternalCache); }; diff --git a/chrome/browser/chromeos/extensions/external_pref_cache_loader.cc b/chrome/browser/chromeos/extensions/external_pref_cache_loader.cc index d05a269..37b6074 100644 --- a/chrome/browser/chromeos/extensions/external_pref_cache_loader.cc +++ b/chrome/browser/chromeos/extensions/external_pref_cache_loader.cc @@ -6,8 +6,11 @@ #include "base/bind.h" #include "base/bind_helpers.h" +#include "base/memory/ref_counted.h" #include "base/memory/singleton.h" #include "base/observer_list.h" +#include "base/sequenced_task_runner.h" +#include "base/threading/sequenced_worker_pool.h" #include "base/values.h" #include "chrome/browser/browser_process.h" #include "chrome/browser/chromeos/extensions/external_cache.h" @@ -73,7 +76,14 @@ class ExternalCacheDispatcher : public ExternalCache::Delegate { ExternalCacheDispatcher() : external_cache_(kPreinstalledAppsCacheDir, g_browser_process->system_request_context(), - this, true, true), + content::BrowserThread::GetBlockingPool()-> + GetSequencedTaskRunnerWithShutdownBehavior( + content::BrowserThread::GetBlockingPool()-> + GetSequenceToken(), + base::SequencedWorkerPool::SKIP_ON_SHUTDOWN), + this, + true, + true), base_path_id_(0), is_extensions_list_ready_(false) { } diff --git a/chrome/browser/chromeos/policy/app_pack_updater.cc b/chrome/browser/chromeos/policy/app_pack_updater.cc index 59a6baa..b9d10d7 100644 --- a/chrome/browser/chromeos/policy/app_pack_updater.cc +++ b/chrome/browser/chromeos/policy/app_pack_updater.cc @@ -5,6 +5,9 @@ #include "chrome/browser/chromeos/policy/app_pack_updater.h" #include "base/bind.h" +#include "base/memory/ref_counted.h" +#include "base/sequenced_task_runner.h" +#include "base/threading/sequenced_worker_pool.h" #include "base/values.h" #include "chrome/browser/chromeos/policy/enterprise_install_attributes.h" #include "chrome/browser/chromeos/settings/cros_settings.h" @@ -62,7 +65,16 @@ AppPackUpdater::AppPackUpdater(net::URLRequestContextGetter* request_context, : weak_ptr_factory_(this), created_extension_loader_(false), install_attributes_(install_attributes), - external_cache_(kAppPackCacheDir, request_context, this, false, false) { + external_cache_(kAppPackCacheDir, + request_context, + content::BrowserThread::GetBlockingPool()-> + GetSequencedTaskRunnerWithShutdownBehavior( + content::BrowserThread::GetBlockingPool()-> + GetSequenceToken(), + base::SequencedWorkerPool::SKIP_ON_SHUTDOWN), + this, + false, + false) { app_pack_subscription_ = chromeos::CrosSettings::Get()->AddSettingsObserver( chromeos::kAppPack, base::Bind(&AppPackUpdater::AppPackChanged, base::Unretained(this))); |