Chromium Code Reviews| Index: chrome/browser/extensions/extension_service.cc |
| diff --git a/chrome/browser/extensions/extension_service.cc b/chrome/browser/extensions/extension_service.cc |
| index 5617fb921cc72ee43c69857c9835ff5e360edb15..6f7ab514e48a0ceb28d6cd0aa1b3eac4b3df3765 100644 |
| --- a/chrome/browser/extensions/extension_service.cc |
| +++ b/chrome/browser/extensions/extension_service.cc |
| @@ -47,6 +47,7 @@ |
| #include "chrome/browser/extensions/extension_error_ui.h" |
| #include "chrome/browser/extensions/extension_host.h" |
| #include "chrome/browser/extensions/extension_install_ui.h" |
| +#include "chrome/browser/extensions/extension_install_ui_default.h" |
| #include "chrome/browser/extensions/extension_process_manager.h" |
| #include "chrome/browser/extensions/extension_sorting.h" |
| #include "chrome/browser/extensions/extension_special_storage_policy.h" |
| @@ -107,6 +108,7 @@ |
| #include "net/base/registry_controlled_domains/registry_controlled_domain.h" |
| #include "sync/api/sync_change.h" |
| #include "sync/api/sync_error_factory.h" |
| +#include "ui/base/l10n/l10n_util.h" |
| #include "webkit/database/database_tracker.h" |
| #include "webkit/database/database_util.h" |
| @@ -124,6 +126,7 @@ using extensions::CrxInstaller; |
| using extensions::Extension; |
| using extensions::ExtensionIdSet; |
| using extensions::ExtensionInfo; |
| +using extensions::ExtensionList; |
| using extensions::FeatureSwitch; |
| using extensions::Manifest; |
| using extensions::PermissionMessage; |
| @@ -759,7 +762,10 @@ void ExtensionService::ReloadExtensionWithEvents( |
| extension_prefs_->GetInstalledExtensionInfo(extension_id)); |
| if (installed_extension.get() && |
| installed_extension->extension_manifest.get()) { |
| - extensions::InstalledLoader(this).Load(*installed_extension, false); |
| + // The extension is being reloaded so it couldn't have been blacklisted, so |
| + // it probably isn't blacklisted now either... |
| + AddNonBlacklistedExtension( |
| + extensions::InstalledLoader(this).Load(*installed_extension, false)); |
| } else { |
| // Otherwise, the extension is unpacked (location LOAD). |
| // We should always be able to remember the extension's path. If it's not in |
| @@ -2045,86 +2051,34 @@ void ExtensionService::OnLoadedInstalledExtensions() { |
| content::NotificationService::NoDetails()); |
| } |
| -void ExtensionService::AddExtension(const Extension* extension) { |
| - // TODO(jstritar): We may be able to get rid of this branch by overriding the |
| - // default extension state to DISABLED when the --disable-extensions flag |
| - // is set (http://crbug.com/29067). |
| - if (!extensions_enabled() && |
| - !extension->is_theme() && |
| - extension->location() != Manifest::COMPONENT && |
| - !Manifest::IsExternalLocation(extension->location())) { |
| +void ExtensionService::AddExtensions(const ExtensionList& extensions) { |
|
Matt Perry
2013/02/07 01:05:35
Rather than adding a new API, couldn't you instead
not at google - send to devlin
2013/02/07 02:11:37
Done.
|
| + if (extensions.empty()) |
| return; |
| - } |
| - SetBeingUpgraded(extension, false); |
| - |
| - // The extension is now loaded, remove its data from unloaded extension map. |
| - unloaded_extension_paths_.erase(extension->id()); |
| - |
| - // If a terminated extension is loaded, remove it from the terminated list. |
| - UntrackTerminatedExtension(extension->id()); |
| - |
| - // If the extension was disabled for a reload, then enable it. |
| - if (disabled_extension_paths_.erase(extension->id()) > 0) |
| - EnableExtension(extension->id()); |
| - |
| - // Check if the extension's privileges have changed and disable the |
| - // extension if necessary. |
| - InitializePermissions(extension); |
| - |
| - // If this extension is a sideloaded extension and we've not performed a |
| - // wipeout before, we might disable this extension here. |
| - MaybeWipeout(extension); |
| - |
| - // Communicated to the Blacklist. |
| + std::set<std::string> all_ids; |
| std::set<std::string> already_in_blacklist; |
| - if (extension_prefs_->IsExtensionBlacklisted(extension->id())) { |
| - // Don't check the Blacklist yet because it's asynchronous (we do it at |
| - // the end). This pre-emptive check is because we will always store the |
| - // blacklisted state of *installed* extensions in prefs, and it's important |
| - // not to re-enable blacklisted extensions. |
| - blacklisted_extensions_.Insert(extension); |
| - already_in_blacklist.insert(extension->id()); |
| - } else if (extension_prefs_->IsExtensionDisabled(extension->id())) { |
| - disabled_extensions_.Insert(extension); |
| - SyncExtensionChangeIfNeeded(*extension); |
| - content::NotificationService::current()->Notify( |
| - chrome::NOTIFICATION_EXTENSION_UPDATE_DISABLED, |
| - content::Source<Profile>(profile_), |
| - content::Details<const Extension>(extension)); |
| - |
| - // Show the extension disabled error if a permissions increase was the |
| - // only reason it was disabled. |
| - if (extension_prefs_->GetDisableReasons(extension->id()) == |
| - Extension::DISABLE_PERMISSIONS_INCREASE) { |
| - extensions::AddExtensionDisabledError(this, extension); |
| - } |
| - } else { |
| - // All apps that are displayed in the launcher are ordered by their ordinals |
| - // so we must ensure they have valid ordinals. |
| - if (extension->RequiresSortOrdinal()) { |
| - extension_prefs_->extension_sorting()->EnsureValidOrdinals( |
| - extension->id(), syncer::StringOrdinal()); |
| - } |
| - |
| - extensions_.Insert(extension); |
| - SyncExtensionChangeIfNeeded(*extension); |
| - NotifyExtensionLoaded(extension); |
| - DoPostLoadTasks(extension); |
| + for (ExtensionList::const_iterator it = extensions.begin(); |
| + it != extensions.end(); ++it) { |
| + const std::string& id = (*it)->id(); |
| + // Well... this is a lie, it might actually be blacklisted, but we check |
| + // that below asynchronously. |
| + if (!AddNonBlacklistedExtension(*it)) |
| + already_in_blacklist.insert(id); |
| + all_ids.insert(id); |
| } |
| - // Lastly, begin the process for checking the blacklist status of extensions. |
| - // This may need to go to other threads so is asynchronous. |
| - std::set<std::string> id_set; |
| - id_set.insert(extension->id()); |
| blacklist_->GetBlacklistedIDs( |
| - id_set, |
| + all_ids, |
| base::Bind(&ExtensionService::ManageBlacklist, |
| AsWeakPtr(), |
| already_in_blacklist)); |
| } |
| +void ExtensionService::AddExtension(const Extension* extension) { |
| + AddExtensions(ExtensionList(1, make_scoped_refptr(extension))); |
| +} |
| + |
| void ExtensionService::AddComponentExtension(const Extension* extension) { |
| const std::string old_version_string( |
| extension_prefs_->GetVersionString(extension->id())); |
| @@ -2141,7 +2095,7 @@ void ExtensionService::AddComponentExtension(const Extension* extension) { |
| return; |
| } |
| - AddExtension(extension); |
| + AddNonBlacklistedExtension(extension); |
| } |
| void ExtensionService::InitializePermissions(const Extension* extension) { |
| @@ -2322,7 +2276,55 @@ void ExtensionService::UpdateActiveExtensionsInCrashReporter() { |
| child_process_logging::SetActiveExtensions(extension_ids); |
| } |
| -void ExtensionService::OnExtensionInstalled( |
| +namespace { |
| + |
| +// Runs |closure| if |extension| isn't blacklisted, and runs |on_done| either |
| +// way. |
| +void RunIfNotBlacklisted(Profile* profile, |
| + const scoped_refptr<const Extension>& extension, |
| + const base::Closure& closure, |
| + const base::Callback<void(bool)>& on_done, |
| + const std::set<std::string>& blacklist) { |
| + if (blacklist.count(extension->id())) { |
| + ExtensionInstallUIDefault(profile).OnInstallFailure( |
| + extensions::CrxInstallerError( |
| + l10n_util::GetStringFUTF16(IDS_EXTENSION_IS_BLACKLISTED, |
| + UTF8ToUTF16(extension->name())))); |
| + on_done.Run(false); |
| + return; |
| + } |
| + |
| + closure.Run(); |
| + on_done.Run(true); |
| +} |
| + |
| +} // namespace |
| + |
| +void ExtensionService::InstallExtensionAsync( |
| + const Extension* extension, |
| + const syncer::StringOrdinal& page_ordinal, |
| + bool has_requirement_errors, |
| + bool wait_for_idle, |
| + const base::Callback<void(bool)>& on_done) { |
| + std::set<std::string> id; |
| + id.insert(extension->id()); |
| + blacklist_->GetBlacklistedIDs( |
| + id, |
| + base::Bind(&RunIfNotBlacklisted, |
| + profile_, |
| + // Note: binding extension here to a scoped_ptr keeps it in |
| + // scope all the way to InstallExtensionNow. |
| + make_scoped_refptr(extension), |
| + base::Bind(&ExtensionService::InstallExtensionNow, |
| + AsWeakPtr(), |
| + extension, |
| + page_ordinal, |
| + has_requirement_errors, |
| + wait_for_idle), |
| + on_done)); |
| +} |
| + |
| +void ExtensionService::InstallExtensionNow( |
| const Extension* extension, |
| const syncer::StringOrdinal& page_ordinal, |
| bool has_requirement_errors, |
| @@ -2481,10 +2483,10 @@ void ExtensionService::FinishInstallation(const Extension* extension) { |
| AddExtension(extension); |
| #if defined(ENABLE_THEMES) |
| - // We do this here since AddExtension() is always called on browser |
| - // startup, and we only really care about the last theme installed. |
| - // If that ever changes and we have to move this code somewhere |
| - // else, it should be somewhere that's not in the startup path. |
| + // We do this here since AddExtensions() is always called on browser startup, |
| + // and we only really care about the last theme installed. If that ever |
| + // changes and we have to move this code somewhere else, it should be |
| + // somewhere that's not in the startup path. |
| if (extension->is_theme() && extensions_.GetByID(extension->id())) { |
| DCHECK_EQ(extensions_.GetByID(extension->id()), extension); |
| // Now that the theme extension is visible from outside the |
| @@ -2522,6 +2524,76 @@ void ExtensionService::UntrackTerminatedExtension(const std::string& id) { |
| terminated_extensions_.Remove(lowercase_id); |
| } |
| +bool ExtensionService::AddNonBlacklistedExtension(const Extension* extension) { |
| + // TODO(jstritar): We may be able to get rid of this branch by overriding the |
| + // default extension state to DISABLED when the --disable-extensions flag |
| + // is set (http://crbug.com/29067). |
| + if (!extensions_enabled() && |
| + !extension->is_theme() && |
| + extension->location() != Manifest::COMPONENT && |
| + !Manifest::IsExternalLocation(extension->location())) { |
| + return true; |
| + } |
| + |
| + SetBeingUpgraded(extension, false); |
| + |
| + // The extension is now loaded, remove its data from unloaded extension map. |
| + unloaded_extension_paths_.erase(extension->id()); |
| + |
| + // If a terminated extension is loaded, remove it from the terminated list. |
| + UntrackTerminatedExtension(extension->id()); |
| + |
| + // If the extension was disabled for a reload, then enable it. |
| + if (disabled_extension_paths_.erase(extension->id()) > 0) |
| + EnableExtension(extension->id()); |
| + |
| + // Check if the extension's privileges have changed and disable the |
| + // extension if necessary. |
| + InitializePermissions(extension); |
| + |
| + // If this extension is a sideloaded extension and we've not performed a |
| + // wipeout before, we might disable this extension here. |
| + MaybeWipeout(extension); |
| + |
| + // Communicated to the Blacklist. |
| + bool was_prefs_blacklisted = false; |
| + |
| + if (extension_prefs_->IsExtensionBlacklisted(extension->id())) { |
| + // We always store the blacklisted state of *installed* extensions in |
| + // prefs, and it's important not to re-enable them. |
| + blacklisted_extensions_.Insert(extension); |
| + was_prefs_blacklisted = true; |
| + } else if (extension_prefs_->IsExtensionDisabled(extension->id())) { |
| + disabled_extensions_.Insert(extension); |
| + SyncExtensionChangeIfNeeded(*extension); |
| + content::NotificationService::current()->Notify( |
| + chrome::NOTIFICATION_EXTENSION_UPDATE_DISABLED, |
| + content::Source<Profile>(profile_), |
| + content::Details<const Extension>(extension)); |
| + |
| + // Show the extension disabled error if a permissions increase was the |
| + // only reason it was disabled. |
| + if (extension_prefs_->GetDisableReasons(extension->id()) == |
| + Extension::DISABLE_PERMISSIONS_INCREASE) { |
| + extensions::AddExtensionDisabledError(this, extension); |
| + } |
| + } else { |
| + // All apps that are displayed in the launcher are ordered by their ordinals |
| + // so we must ensure they have valid ordinals. |
| + if (extension->RequiresSortOrdinal()) { |
| + extension_prefs_->extension_sorting()->EnsureValidOrdinals( |
| + extension->id(), syncer::StringOrdinal()); |
| + } |
| + |
| + extensions_.Insert(extension); |
| + SyncExtensionChangeIfNeeded(*extension); |
| + NotifyExtensionLoaded(extension); |
| + DoPostLoadTasks(extension); |
| + } |
| + |
| + return !was_prefs_blacklisted; |
| +} |
| + |
| const Extension* ExtensionService::GetTerminatedExtension( |
| const std::string& id) const { |
| return GetExtensionById(id, INCLUDE_TERMINATED); |
| @@ -3107,7 +3179,7 @@ void ExtensionService::ManageBlacklist( |
| if (!extension) |
| continue; |
| blacklisted_extensions_.Remove(*it); |
| - AddExtension(extension); |
| + AddNonBlacklistedExtension(extension); |
| } |
| for (std::set<std::string>::iterator it = not_yet_blacklisted.begin(); |