| Index: chrome/browser/extensions/extension_service.cc
|
| diff --git a/chrome/browser/extensions/extension_service.cc b/chrome/browser/extensions/extension_service.cc
|
| index 8d4f40eab60c862d49b9e8404d3c389aa47ba313..abc616b804d9093d40c3ad86deddb24574210061 100644
|
| --- a/chrome/browser/extensions/extension_service.cc
|
| +++ b/chrome/browser/extensions/extension_service.cc
|
| @@ -105,6 +105,8 @@
|
| #include "content/public/browser/notification_types.h"
|
| #include "content/public/browser/plugin_service.h"
|
| #include "content/public/browser/render_process_host.h"
|
| +#include "content/public/browser/site_instance.h"
|
| +#include "content/public/browser/storage_partition.h"
|
| #include "content/public/common/pepper_plugin_info.h"
|
| #include "extensions/common/error_utils.h"
|
| #include "googleurl/src/gurl.h"
|
| @@ -374,6 +376,7 @@ ExtensionService::ExtensionService(Profile* profile,
|
| event_routers_initialized_(false),
|
| update_once_all_providers_are_ready_(false),
|
| browser_terminating_(false),
|
| + installs_delayed_(false),
|
| wipeout_is_active_(false),
|
| app_sync_bundle_(ALLOW_THIS_IN_INITIALIZER_LIST(this)),
|
| extension_sync_bundle_(ALLOW_THIS_IN_INITIALIZER_LIST(this)),
|
| @@ -589,6 +592,12 @@ const Extension* ExtensionService::GetExtensionById(
|
| return GetExtensionById(id, include_mask);
|
| }
|
|
|
| +GURL ExtensionService::GetSiteForExtensionId(const std::string& extension_id) {
|
| + return content::SiteInstance::GetSiteForURL(
|
| + profile_,
|
| + Extension::GetBaseURLFromExtensionId(extension_id));
|
| +}
|
| +
|
| const Extension* ExtensionService::GetExtensionById(
|
| const std::string& id, int include_mask) const {
|
| std::string lowercase_id = StringToLowerASCII(id);
|
| @@ -621,8 +630,8 @@ void ExtensionService::Init() {
|
| DCHECK(!ready_); // Can't redo init.
|
| DCHECK_EQ(extensions_.size(), 0u);
|
|
|
| - // TODO(mek): It might be cleaner to do the FinishIdleInstallInfo stuff here
|
| - // instead of in installedloader
|
| + // TODO(mek): It might be cleaner to do the FinishDelayedInstallInfo stuff
|
| + // here instead of in installedloader.
|
| component_loader_->LoadAll();
|
| extensions::InstalledLoader(this).LoadAllExtensions();
|
|
|
| @@ -652,6 +661,11 @@ void ExtensionService::Init() {
|
| GarbageCollectExtensions();
|
| }
|
| }
|
| +
|
| + if (extension_prefs_->NeedsStorageGarbageCollection()) {
|
| + GarbageCollectIsolatedStorage();
|
| + extension_prefs_->SetNeedsStorageGarbageCollection(false);
|
| + }
|
| }
|
|
|
| bool ExtensionService::UpdateExtension(const std::string& id,
|
| @@ -783,7 +797,7 @@ void ExtensionService::ReloadExtensionWithEvents(
|
| path = unloaded_extension_paths_[extension_id];
|
| }
|
|
|
| - if (pending_extension_updates_.Contains(extension_id)) {
|
| + if (delayed_updates_for_idle_.Contains(extension_id)) {
|
| FinishDelayedInstallation(extension_id);
|
| return;
|
| }
|
| @@ -881,14 +895,22 @@ bool ExtensionService::UninstallExtension(
|
| launch_web_url_origin = launch_web_url_origin.GetOrigin();
|
| bool is_storage_isolated = extension->is_storage_isolated();
|
|
|
| - if (extension->is_hosted_app() &&
|
| - !profile_->GetExtensionSpecialStoragePolicy()->
|
| - IsStorageProtected(launch_web_url_origin)) {
|
| - extensions::DataDeleter::StartDeleting(
|
| - profile_, extension_id, launch_web_url_origin, is_storage_isolated);
|
| + if (is_storage_isolated) {
|
| + BrowserContext::AsyncObliterateStoragePartition(
|
| + profile_,
|
| + GetSiteForExtensionId(extension_id),
|
| + base::Bind(&ExtensionService::OnNeedsToGarbageCollectIsolatedStorage,
|
| + AsWeakPtr()));
|
| + } else {
|
| + if (extension->is_hosted_app() &&
|
| + !profile_->GetExtensionSpecialStoragePolicy()->
|
| + IsStorageProtected(launch_web_url_origin)) {
|
| + extensions::DataDeleter::StartDeleting(
|
| + profile_, extension_id, launch_web_url_origin);
|
| + }
|
| + extensions::DataDeleter::StartDeleting(profile_, extension_id,
|
| + extension->url());
|
| }
|
| - extensions::DataDeleter::StartDeleting(
|
| - profile_, extension_id, extension->url(), is_storage_isolated);
|
|
|
| UntrackTerminatedExtension(extension_id);
|
|
|
| @@ -906,7 +928,8 @@ bool ExtensionService::UninstallExtension(
|
| extension_sync_bundle_.ProcessDeletion(extension_id, sync_change);
|
| }
|
|
|
| - pending_extension_updates_.Remove(extension_id);
|
| + delayed_updates_for_idle_.Remove(extension_id);
|
| + delayed_installs_.Remove(extension_id);
|
|
|
| // Track the uninstallation.
|
| UMA_HISTOGRAM_ENUMERATION("Extensions.ExtensionUninstalled", 1, 2);
|
| @@ -2071,7 +2094,7 @@ void ExtensionService::GarbageCollectExtensions() {
|
| extension_paths.insert(std::make_pair(info->at(i)->extension_id,
|
| info->at(i)->extension_path));
|
|
|
| - info = extension_prefs_->GetAllIdleInstallInfo();
|
| + info = extension_prefs_->GetAllDelayedInstallInfo();
|
| for (size_t i = 0; i < info->size(); ++i)
|
| extension_paths.insert(std::make_pair(info->at(i)->extension_id,
|
| info->at(i)->extension_path));
|
| @@ -2203,8 +2226,8 @@ void ExtensionService::AddComponentExtension(const Extension* extension) {
|
| << old_version_string << "' to " << extension->version()->GetString();
|
|
|
| AddNewOrUpdatedExtension(extension,
|
| - syncer::StringOrdinal(),
|
| - Extension::ENABLED_COMPONENT);
|
| + Extension::ENABLED_COMPONENT,
|
| + syncer::StringOrdinal());
|
| return;
|
| }
|
|
|
| @@ -2463,15 +2486,14 @@ void ExtensionService::OnExtensionInstalled(
|
| // auto-acknowledge any extension that came from one of them.
|
| if (extension->location() == Extension::EXTERNAL_POLICY_DOWNLOAD)
|
| AcknowledgeExternalExtension(extension->id());
|
| -
|
| + const Extension::State initial_state =
|
| + initial_enable ? Extension::ENABLED : Extension::DISABLED;
|
| if (ShouldDelayExtensionUpdate(id, wait_for_idle)) {
|
| - extension_prefs_->SetIdleInstallInfo(
|
| - extension,
|
| - initial_enable ? Extension::ENABLED : Extension::DISABLED,
|
| - page_ordinal);
|
| + extension_prefs_->SetDelayedInstallInfo(extension, initial_state,
|
| + page_ordinal);
|
|
|
| // Transfer ownership of |extension|.
|
| - pending_extension_updates_.Insert(extension);
|
| + delayed_updates_for_idle_.Insert(extension);
|
|
|
| // Notify extension of available update.
|
| extensions::RuntimeEventRouter::DispatchOnUpdateAvailableEvent(
|
| @@ -2479,17 +2501,19 @@ void ExtensionService::OnExtensionInstalled(
|
| return;
|
| }
|
|
|
| - // Transfer ownership of |extension|.
|
| - AddNewOrUpdatedExtension(
|
| - extension,
|
| - page_ordinal,
|
| - initial_enable ? Extension::ENABLED : Extension::DISABLED);
|
| + if (installs_delayed()) {
|
| + extension_prefs_->SetDelayedInstallInfo(extension, initial_state,
|
| + page_ordinal);
|
| + delayed_installs_.Insert(extension);
|
| + } else {
|
| + AddNewOrUpdatedExtension(extension, initial_state, page_ordinal);
|
| + }
|
| }
|
|
|
| void ExtensionService::AddNewOrUpdatedExtension(
|
| const Extension* extension,
|
| - const syncer::StringOrdinal& page_ordinal,
|
| - Extension::State initial_state) {
|
| + Extension::State initial_state,
|
| + const syncer::StringOrdinal& page_ordinal) {
|
| CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
|
|
|
| extension_prefs_->OnExtensionInstalled(
|
| @@ -2497,20 +2521,13 @@ void ExtensionService::AddNewOrUpdatedExtension(
|
| initial_state,
|
| page_ordinal);
|
|
|
| - // Unpacked extensions default to allowing file access, but if that has been
|
| - // overridden, don't reset the value.
|
| - if (Extension::ShouldAlwaysAllowFileAccess(extension->location()) &&
|
| - !extension_prefs_->HasAllowFileAccessSetting(extension->id())) {
|
| - extension_prefs_->SetAllowFileAccess(extension->id(), true);
|
| - }
|
| -
|
| FinishInstallation(extension);
|
| }
|
|
|
| void ExtensionService::MaybeFinishDelayedInstallation(
|
| const std::string& extension_id) {
|
| // Check if the extension already got updated.
|
| - if (!pending_extension_updates_.Contains(extension_id))
|
| + if (!delayed_updates_for_idle_.Contains(extension_id))
|
| return;
|
| // Check if the extension is idle.
|
| if (!IsExtensionIdle(extension_id))
|
| @@ -2524,9 +2541,9 @@ void ExtensionService::FinishDelayedInstallation(
|
| scoped_refptr<const Extension> extension(
|
| GetPendingExtensionUpdate(extension_id));
|
| CHECK(extension);
|
| - pending_extension_updates_.Remove(extension_id);
|
| + delayed_updates_for_idle_.Remove(extension_id);
|
|
|
| - if (!extension_prefs_->FinishIdleInstallInfo(extension_id))
|
| + if (!extension_prefs_->FinishDelayedInstallInfo(extension_id))
|
| NOTREACHED();
|
|
|
| FinishInstallation(extension);
|
| @@ -2540,6 +2557,13 @@ void ExtensionService::FinishInstallation(const Extension* extension) {
|
|
|
| bool unacknowledged_external = IsUnacknowledgedExternalExtension(extension);
|
|
|
| + // Unpacked extensions default to allowing file access, but if that has been
|
| + // overridden, don't reset the value.
|
| + if (Extension::ShouldAlwaysAllowFileAccess(extension->location()) &&
|
| + !extension_prefs_->HasAllowFileAccessSetting(extension->id())) {
|
| + extension_prefs_->SetAllowFileAccess(extension->id(), true);
|
| + }
|
| +
|
| AddExtension(extension);
|
|
|
| #if defined(ENABLE_THEMES)
|
| @@ -2569,7 +2593,7 @@ void ExtensionService::FinishInstallation(const Extension* extension) {
|
|
|
| const Extension* ExtensionService::GetPendingExtensionUpdate(
|
| const std::string& id) const {
|
| - return pending_extension_updates_.GetByID(id);
|
| + return delayed_updates_for_idle_.GetByID(id);
|
| }
|
|
|
| void ExtensionService::TrackTerminatedExtension(const Extension* extension) {
|
| @@ -2815,7 +2839,7 @@ void ExtensionService::Observe(int type,
|
| extensions::ExtensionHost* host =
|
| content::Details<extensions::ExtensionHost>(details).ptr();
|
| std::string extension_id = host->extension_id();
|
| - if (pending_extension_updates_.Contains(extension_id)) {
|
| + if (delayed_updates_for_idle_.Contains(extension_id)) {
|
| // We were waiting for this extension to become idle, it now might have,
|
| // so maybe finish installation.
|
| MessageLoop::current()->PostDelayedTask(
|
| @@ -3103,6 +3127,46 @@ bool ExtensionService::ShouldDelayExtensionUpdate(
|
| }
|
| }
|
|
|
| +void ExtensionService::GarbageCollectIsolatedStorage() {
|
| + scoped_ptr<base::hash_set<FilePath> > active_paths(
|
| + new base::hash_set<FilePath>());
|
| + for (ExtensionSet::const_iterator it = extensions_.begin();
|
| + it != extensions_.end(); ++it) {
|
| + if ((*it)->is_storage_isolated()) {
|
| + active_paths->insert(
|
| + BrowserContext::GetStoragePartitionForSite(
|
| + profile_,
|
| + GetSiteForExtensionId((*it)->id()))->GetPath());
|
| + }
|
| + }
|
| +
|
| + DCHECK(!installs_delayed());
|
| + set_installs_delayed(true);
|
| + BrowserContext::GarbageCollectStoragePartitions(
|
| + profile_, active_paths.Pass(),
|
| + base::Bind(&ExtensionService::OnGarbageCollectIsolatedStorageFinished,
|
| + AsWeakPtr()));
|
| +}
|
| +
|
| +void ExtensionService::OnGarbageCollectIsolatedStorageFinished() {
|
| + set_installs_delayed(false);
|
| + for (ExtensionSet::const_iterator it = delayed_installs_.begin();
|
| + it != delayed_installs_.end();
|
| + ++it) {
|
| + FinishDelayedInstallation((*it)->id());
|
| + }
|
| + for (ExtensionSet::const_iterator it = delayed_updates_for_idle_.begin();
|
| + it != delayed_updates_for_idle_.end();
|
| + ++it) {
|
| + MaybeFinishDelayedInstallation((*it)->id());
|
| + }
|
| + delayed_installs_.Clear();
|
| +}
|
| +
|
| +void ExtensionService::OnNeedsToGarbageCollectIsolatedStorage() {
|
| + extension_prefs_->SetNeedsStorageGarbageCollection(true);
|
| +}
|
| +
|
| void ExtensionService::OnBlacklistUpdated() {
|
| blacklist_->GetBlacklistedIDs(
|
| GenerateInstalledExtensionsSet()->GetIDs(),
|
|
|