diff options
author | jamescook@chromium.org <jamescook@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-12-21 03:09:14 +0000 |
---|---|---|
committer | jamescook@chromium.org <jamescook@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-12-21 03:09:14 +0000 |
commit | bb1bc9b30627f0f454c89ac91637c89a17352769 (patch) | |
tree | 2141a8a6ae3a14d89ff7a18001e0bac5c1140ae7 | |
parent | ddc78c802e48e2084ffccf537b7aca7c6f2c825c (diff) | |
download | chromium_src-bb1bc9b30627f0f454c89ac91637c89a17352769.zip chromium_src-bb1bc9b30627f0f454c89ac91637c89a17352769.tar.gz chromium_src-bb1bc9b30627f0f454c89ac91637c89a17352769.tar.bz2 |
Extract an ExtensionRegistry from ExtensionService
This new class holds the various sets of enabled/disabled/terminated/etc.
extensions. It lives in src/extensions/browser so it can be used by
app_shell.
This CL renames some members and methods to clarify which set of extensions is the enabled set and also renames some methods that are only used in test code.
BUG=none
TEST=unit_tests ExtensionRegistryTest and ExtensionServiceTest
Review URL: https://codereview.chromium.org/111873008
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@242248 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r-- | chrome/browser/extensions/extension_crash_recovery_browsertest.cc | 2 | ||||
-rw-r--r-- | chrome/browser/extensions/extension_service.cc | 209 | ||||
-rw-r--r-- | chrome/browser/extensions/extension_service.h | 32 | ||||
-rw-r--r-- | chrome/browser/extensions/extension_service_unittest.cc | 59 | ||||
-rw-r--r-- | chrome/chrome_tests_unit.gypi | 1 | ||||
-rw-r--r-- | extensions/browser/extension_registry.cc | 60 | ||||
-rw-r--r-- | extensions/browser/extension_registry.h | 94 | ||||
-rw-r--r-- | extensions/browser/extension_registry_unittest.cc | 102 | ||||
-rw-r--r-- | extensions/extensions.gyp | 2 |
9 files changed, 433 insertions, 128 deletions
diff --git a/chrome/browser/extensions/extension_crash_recovery_browsertest.cc b/chrome/browser/extensions/extension_crash_recovery_browsertest.cc index f5eac57..4b49a8d 100644 --- a/chrome/browser/extensions/extension_crash_recovery_browsertest.cc +++ b/chrome/browser/extensions/extension_crash_recovery_browsertest.cc @@ -534,7 +534,7 @@ IN_PROC_BROWSER_TEST_F(MAYBE_ExtensionCrashRecoveryTest, ASSERT_EQ(crash_size_before + 1, GetExtensionService()->terminated_extensions()->size()); - GetExtensionService()->UnloadAllExtensions(); + GetExtensionService()->UnloadAllExtensionsForTest(); ASSERT_EQ(crash_size_before, GetExtensionService()->terminated_extensions()->size()); } diff --git a/chrome/browser/extensions/extension_service.cc b/chrome/browser/extensions/extension_service.cc index 730bda5..8b931f13 100644 --- a/chrome/browser/extensions/extension_service.cc +++ b/chrome/browser/extensions/extension_service.cc @@ -76,6 +76,7 @@ #include "content/public/browser/url_data_source.h" #include "extensions/browser/app_sorting.h" #include "extensions/browser/event_router.h" +#include "extensions/browser/extension_registry.h" #include "extensions/browser/extensions_browser_client.h" #include "extensions/browser/external_provider_interface.h" #include "extensions/browser/management_policy.h" @@ -274,7 +275,7 @@ bool ExtensionService::OnExternalExtensionUpdateUrlFound( const Extension* ExtensionService::GetInstalledExtensionByUrl( const GURL& url) const { - return extensions_.GetExtensionOrAppByURL(url); + return registry_->enabled_extensions().GetExtensionOrAppByURL(url); } const Extension* ExtensionService::GetInstalledApp(const GURL& url) const { @@ -328,6 +329,7 @@ ExtensionService::ExtensionService(Profile* profile, blacklist_(blacklist), settings_frontend_(extensions::SettingsFrontend::Create(profile)), extension_sync_service_(NULL), + registry_(new extensions::ExtensionRegistry), pending_extension_manager_(*this), install_directory_(install_directory), extensions_enabled_(extensions_enabled), @@ -409,19 +411,19 @@ ExtensionService::ExtensionService(Profile* profile, } const ExtensionSet* ExtensionService::extensions() const { - return &extensions_; + return ®istry_->enabled_extensions(); } const ExtensionSet* ExtensionService::disabled_extensions() const { - return &disabled_extensions_; + return ®istry_->disabled_extensions(); } const ExtensionSet* ExtensionService::terminated_extensions() const { - return &terminated_extensions_; + return ®istry_->terminated_extensions(); } const ExtensionSet* ExtensionService::blacklisted_extensions() const { - return &blacklisted_extensions_; + return ®istry_->blacklisted_extensions(); } const ExtensionSet* ExtensionService::delayed_installs() const { @@ -431,11 +433,11 @@ const ExtensionSet* ExtensionService::delayed_installs() const { scoped_ptr<ExtensionSet> ExtensionService::GenerateInstalledExtensionsSet() const { scoped_ptr<ExtensionSet> installed_extensions(new ExtensionSet()); - installed_extensions->InsertAll(extensions_); - installed_extensions->InsertAll(disabled_extensions_); - installed_extensions->InsertAll(terminated_extensions_); - installed_extensions->InsertAll(blacklisted_extensions_); - return installed_extensions.PassAs<ExtensionSet>(); + installed_extensions->InsertAll(registry_->enabled_extensions()); + installed_extensions->InsertAll(registry_->disabled_extensions()); + installed_extensions->InsertAll(registry_->terminated_extensions()); + installed_extensions->InsertAll(registry_->blacklisted_extensions()); + return installed_extensions.Pass(); } extensions::PendingExtensionManager* @@ -482,22 +484,26 @@ const Extension* ExtensionService::GetExtensionById( const std::string& id, int include_mask) const { std::string lowercase_id = StringToLowerASCII(id); if (include_mask & INCLUDE_ENABLED) { - const Extension* extension = extensions_.GetByID(lowercase_id); + const Extension* extension = + registry_->enabled_extensions().GetByID(lowercase_id); if (extension) return extension; } if (include_mask & INCLUDE_DISABLED) { - const Extension* extension = disabled_extensions_.GetByID(lowercase_id); + const Extension* extension = + registry_->disabled_extensions().GetByID(lowercase_id); if (extension) return extension; } if (include_mask & INCLUDE_TERMINATED) { - const Extension* extension = terminated_extensions_.GetByID(lowercase_id); + const Extension* extension = + registry_->terminated_extensions().GetByID(lowercase_id); if (extension) return extension; } if (include_mask & INCLUDE_BLACKLISTED) { - const Extension* extension = blacklisted_extensions_.GetByID(lowercase_id); + const Extension* extension = + registry_->blacklisted_extensions().GetByID(lowercase_id); if (extension) return extension; } @@ -510,7 +516,7 @@ void ExtensionService::Init() { base::Time begin_time = base::Time::Now(); DCHECK(!is_ready()); // Can't redo init. - DCHECK_EQ(extensions_.size(), 0u); + DCHECK_EQ(registry_->enabled_extensions().size(), 0u); const CommandLine* cmd_line = CommandLine::ForCurrentProcess(); if (cmd_line->HasSwitch(switches::kInstallFromWebstore) || @@ -529,8 +535,9 @@ void ExtensionService::Init() { // Attempt to re-enable extensions whose only disable reason is reloading. std::vector<std::string> extensions_to_enable; - for (ExtensionSet::const_iterator iter = disabled_extensions_.begin(); - iter != disabled_extensions_.end(); ++iter) { + const ExtensionSet& disabled_extensions = registry_->disabled_extensions(); + for (ExtensionSet::const_iterator iter = disabled_extensions.begin(); + iter != disabled_extensions.end(); ++iter) { const Extension* e = iter->get(); if (extension_prefs_->GetDisableReasons(e->id()) == Extension::DISABLE_RELOAD) { @@ -620,8 +627,9 @@ void ExtensionService::FinishVerifyAllExtensions(bool success) { // Check to see if any currently unverified extensions became verified. InstallVerifier* verifier = extensions::ExtensionSystem::Get(profile_)->install_verifier(); - for (ExtensionSet::const_iterator i = disabled_extensions_.begin(); - i != disabled_extensions_.end(); ++i) { + const ExtensionSet& disabled_extensions = registry_->disabled_extensions(); + for (ExtensionSet::const_iterator i = disabled_extensions.begin(); + i != disabled_extensions.end(); ++i) { const Extension& extension = **i; int disable_reasons = extension_prefs_->GetDisableReasons(extension.id()); if (disable_reasons & Extension::DISABLE_NOT_VERIFIED && @@ -921,13 +929,13 @@ bool ExtensionService::UninstallExtension( bool ExtensionService::IsExtensionEnabled( const std::string& extension_id) const { - if (extensions_.Contains(extension_id) || - terminated_extensions_.Contains(extension_id)) { + if (registry_->enabled_extensions().Contains(extension_id) || + registry_->terminated_extensions().Contains(extension_id)) { return true; } - if (disabled_extensions_.Contains(extension_id) || - blacklisted_extensions_.Contains(extension_id)) { + if (registry_->disabled_extensions().Contains(extension_id) || + registry_->blacklisted_extensions().Contains(extension_id)) { return false; } @@ -947,7 +955,8 @@ void ExtensionService::EnableExtension(const std::string& extension_id) { if (IsExtensionEnabled(extension_id)) return; - const Extension* extension = disabled_extensions_.GetByID(extension_id); + const Extension* extension = + registry_->disabled_extensions().GetByID(extension_id); ManagementPolicy* policy = system_->management_policy(); if (extension && policy->MustRemainDisabled(extension, NULL, NULL)) { @@ -980,8 +989,8 @@ void ExtensionService::EnableExtension(const std::string& extension_id) { } // Move it over to the enabled list. - extensions_.Insert(make_scoped_refptr(extension)); - disabled_extensions_.Remove(extension->id()); + registry_->AddEnabled(make_scoped_refptr(extension)); + registry_->RemoveDisabled(extension->id()); NotifyExtensionLoaded(extension); @@ -1027,12 +1036,12 @@ void ExtensionService::DisableExtension( // Move it over to the disabled list. Don't send a second unload notification // for terminated extensions being disabled. - disabled_extensions_.Insert(make_scoped_refptr(extension)); - if (extensions_.Contains(extension->id())) { - extensions_.Remove(extension->id()); + registry_->AddDisabled(make_scoped_refptr(extension)); + if (registry_->enabled_extensions().Contains(extension->id())) { + registry_->RemoveEnabled(extension->id()); NotifyExtensionUnloaded(extension, UnloadedExtensionInfo::REASON_DISABLE); } else { - terminated_extensions_.Remove(extension->id()); + registry_->RemoveTerminated(extension->id()); } if (extension_sync_service_) @@ -1045,13 +1054,15 @@ void ExtensionService::DisableUserExtensions( system_->management_policy(); extensions::ExtensionList to_disable; - for (ExtensionSet::const_iterator extension = extensions_.begin(); - extension != extensions_.end(); ++extension) { + const ExtensionSet& enabled_set = registry_->enabled_extensions(); + for (ExtensionSet::const_iterator extension = enabled_set.begin(); + extension != enabled_set.end(); ++extension) { if (management_policy->UserMayModifySettings(extension->get(), NULL)) to_disable.push_back(*extension); } - for (ExtensionSet::const_iterator extension = terminated_extensions_.begin(); - extension != terminated_extensions_.end(); ++extension) { + const ExtensionSet& terminated_set = registry_->terminated_extensions(); + for (ExtensionSet::const_iterator extension = terminated_set.begin(); + extension != terminated_set.end(); ++extension) { if (management_policy->UserMayModifySettings(extension->get(), NULL)) to_disable.push_back(*extension); } @@ -1272,8 +1283,9 @@ void ExtensionService::CheckManagementPolicy() { // Loop through the extensions list, finding extensions we need to unload or // disable. - for (ExtensionSet::const_iterator iter = extensions_.begin(); - iter != extensions_.end(); ++iter) { + const ExtensionSet& extensions = registry_->enabled_extensions(); + for (ExtensionSet::const_iterator iter = extensions.begin(); + iter != extensions.end(); ++iter) { const Extension* extension = (iter->get()); if (!system_->management_policy()->UserMayLoad(extension, NULL)) to_unload.push_back(extension->id()); @@ -1431,8 +1443,9 @@ bool ExtensionService::PopulateExtensionErrorUI( bool needs_alert = false; // Extensions that are blacklisted. - for (ExtensionSet::const_iterator it = blacklisted_extensions_.begin(); - it != blacklisted_extensions_.end(); ++it) { + const ExtensionSet& blacklisted_set = registry_->blacklisted_extensions(); + for (ExtensionSet::const_iterator it = blacklisted_set.begin(); + it != blacklisted_set.end(); ++it) { std::string id = (*it)->id(); if (!extension_prefs_->IsBlacklistedExtensionAcknowledged(id)) { extension_error_ui->AddBlacklistedExtension(id); @@ -1440,8 +1453,9 @@ bool ExtensionService::PopulateExtensionErrorUI( } } - for (ExtensionSet::const_iterator iter = extensions_.begin(); - iter != extensions_.end(); ++iter) { + const ExtensionSet& enabled_set = registry_->enabled_extensions(); + for (ExtensionSet::const_iterator iter = enabled_set.begin(); + iter != enabled_set.end(); ++iter) { const Extension* e = iter->get(); // Skip for extensions that have pending updates. They will be checked again @@ -1495,19 +1509,21 @@ bool ExtensionService::IsUnacknowledgedExternalExtension( void ExtensionService::ReconcileKnownDisabled() { ExtensionIdSet known_disabled_ids; if (!extension_prefs_->GetKnownDisabled(&known_disabled_ids)) { - extension_prefs_->SetKnownDisabled(disabled_extensions_.GetIDs()); + extension_prefs_->SetKnownDisabled( + registry_->disabled_extensions().GetIDs()); UMA_HISTOGRAM_BOOLEAN("Extensions.KnownDisabledInitialized", true); return; } - // Both |known_disabled_ids| and |extensions_| are ordered (by definition + // Both |known_disabled_ids| and |extensions| are ordered (by definition // of std::map and std::set). Iterate forward over both sets in parallel // to find matching IDs and disable the corresponding extensions. - ExtensionSet::const_iterator extensions_it = extensions_.begin(); + const ExtensionSet& enabled_set = registry_->enabled_extensions(); + ExtensionSet::const_iterator extensions_it = enabled_set.begin(); ExtensionIdSet::const_iterator known_disabled_ids_it = known_disabled_ids.begin(); int known_disabled_count = 0; - while (extensions_it != extensions_.end() && + while (extensions_it != enabled_set.end() && known_disabled_ids_it != known_disabled_ids.end()) { const std::string& extension_id = extensions_it->get()->id(); const int comparison = extension_id.compare(*known_disabled_ids_it); @@ -1529,7 +1545,7 @@ void ExtensionService::ReconcileKnownDisabled() { // Update the list of known disabled to reflect every change to // |disabled_extensions_| from this point forward. - disabled_extensions_.set_modification_callback( + registry_->SetDisabledModificationCallback( base::Bind(&extensions::ExtensionPrefs::SetKnownDisabled, base::Unretained(extension_prefs_))); } @@ -1547,8 +1563,9 @@ void ExtensionService::UpdateExternalExtensionAlert() { return; const Extension* extension = NULL; - for (ExtensionSet::const_iterator iter = disabled_extensions_.begin(); - iter != disabled_extensions_.end(); ++iter) { + const ExtensionSet& disabled_extensions = registry_->disabled_extensions(); + for (ExtensionSet::const_iterator iter = disabled_extensions.begin(); + iter != disabled_extensions.end(); ++iter) { const Extension* e = iter->get(); if (IsUnacknowledgedExternalExtension(e)) { extension = e; @@ -1620,15 +1637,15 @@ void ExtensionService::UnloadExtension( // Clean up runtime data. extension_runtime_data_.erase(extension_id); - if (disabled_extensions_.Contains(extension->id())) { - disabled_extensions_.Remove(extension->id()); + if (registry_->disabled_extensions().Contains(extension->id())) { + registry_->RemoveDisabled(extension->id()); // Make sure the profile cleans up its RequestContexts when an already // disabled extension is unloaded (since they are also tracking the disabled // extensions). system_->UnregisterExtensionWithRequestContexts(extension_id, reason); } else { - // Remove the extension from our list. - extensions_.Remove(extension->id()); + // Remove the extension from the enabled list. + registry_->RemoveEnabled(extension->id()); NotifyExtensionUnloaded(extension.get(), reason); } @@ -1649,21 +1666,14 @@ void ExtensionService::RemoveComponentExtension( content::Details<const Extension>(extension.get())); } -void ExtensionService::UnloadAllExtensions() { - profile_->GetExtensionSpecialStoragePolicy()->RevokeRightsForAllExtensions(); - - extensions_.Clear(); - disabled_extensions_.Clear(); - terminated_extensions_.Clear(); - extension_runtime_data_.clear(); - - // TODO(erikkay) should there be a notification for this? We can't use - // EXTENSION_UNLOADED since that implies that the extension has been disabled - // or uninstalled, and UnloadAll is just part of shutdown. +void ExtensionService::UnloadAllExtensionsForTest() { + UnloadAllExtensionsInternal(); } -void ExtensionService::ReloadExtensions() { - UnloadAllExtensions(); +void ExtensionService::ReloadExtensionsForTest() { + // Calling UnloadAllExtensionsForTest here triggers a false-positive presubmit + // warning about calling test code in production. + UnloadAllExtensionsInternal(); component_loader_->LoadAll(); extensions::InstalledLoader(this).LoadAllExtensions(); // Don't call SetReadyAndNotifyListeners() since tests call this multiple @@ -1778,10 +1788,10 @@ void ExtensionService::AddExtension(const Extension* extension) { // blacklist before calling into here, e.g. CrxInstaller checks before // installation then threads through the install and pending install flow // of this class, and we check when loading installed extensions. - blacklisted_extensions_.Insert(extension); + registry_->AddBlacklisted(extension); } else if (!reloading && extension_prefs_->IsExtensionDisabled(extension->id())) { - disabled_extensions_.Insert(extension); + registry_->AddDisabled(extension); if (extension_sync_service_) extension_sync_service_->SyncExtensionChangeIfNeeded(*extension); content::NotificationService::current()->Notify( @@ -1797,7 +1807,7 @@ void ExtensionService::AddExtension(const Extension* extension) { } } else if (reloading) { // Replace the old extension with the new version. - CHECK(!disabled_extensions_.Insert(extension)); + CHECK(!registry_->AddDisabled(extension)); EnableExtension(extension->id()); } else { // All apps that are displayed in the launcher are ordered by their ordinals @@ -1810,7 +1820,7 @@ void ExtensionService::AddExtension(const Extension* extension) { extension->id(), syncer::StringOrdinal()); } - extensions_.Insert(extension); + registry_->AddEnabled(extension); if (extension_sync_service_) extension_sync_service_->SyncExtensionChangeIfNeeded(*extension); NotifyExtensionLoaded(extension); @@ -1973,8 +1983,9 @@ void ExtensionService::CheckPermissionsIncrease(const Extension* extension, void ExtensionService::UpdateActiveExtensionsInCrashReporter() { std::set<std::string> extension_ids; - for (ExtensionSet::const_iterator iter = extensions_.begin(); - iter != extensions_.end(); ++iter) { + const ExtensionSet& extensions = registry_->enabled_extensions(); + for (ExtensionSet::const_iterator iter = extensions.begin(); + iter != extensions.end(); ++iter) { const Extension* extension = iter->get(); if (!extension->is_theme() && extension->location() != Manifest::COMPONENT) extension_ids.insert(extension->id()); @@ -2047,9 +2058,9 @@ scoped_ptr<const ExtensionSet> scoped_ptr<ExtensionSet> dependents(new ExtensionSet()); scoped_ptr<ExtensionSet> set_to_check(new ExtensionSet()); if (SharedModuleInfo::IsSharedModule(extension)) { - set_to_check->InsertAll(disabled_extensions_); + set_to_check->InsertAll(registry_->disabled_extensions()); set_to_check->InsertAll(delayed_installs_); - set_to_check->InsertAll(extensions_); + set_to_check->InsertAll(registry_->enabled_extensions()); for (ExtensionSet::const_iterator iter = set_to_check->begin(); iter != set_to_check->end(); ++iter) { if (SharedModuleInfo::ImportsExtensionById(iter->get(), @@ -2340,16 +2351,16 @@ const Extension* ExtensionService::GetPendingExtensionUpdate( } void ExtensionService::TrackTerminatedExtension(const Extension* extension) { - if (!terminated_extensions_.Contains(extension->id())) - terminated_extensions_.Insert(make_scoped_refptr(extension)); - + // No need to check for duplicates; inserting a duplicate is a no-op. + registry_->AddTerminated(make_scoped_refptr(extension)); UnloadExtension(extension->id(), UnloadedExtensionInfo::REASON_TERMINATE); } void ExtensionService::UntrackTerminatedExtension(const std::string& id) { std::string lowercase_id = StringToLowerASCII(id); - const Extension* extension = terminated_extensions_.GetByID(lowercase_id); - terminated_extensions_.Remove(lowercase_id); + const Extension* extension = + registry_->terminated_extensions().GetByID(lowercase_id); + registry_->RemoveTerminated(lowercase_id); if (extension) { content::NotificationService::current()->Notify( chrome::NOTIFICATION_EXTENSION_REMOVED, @@ -2374,13 +2385,15 @@ const Extension* ExtensionService::GetInstalledExtension( bool ExtensionService::ExtensionBindingsAllowed(const GURL& url) { // Allow bindings for all packaged extensions and component hosted apps. - const Extension* extension = extensions_.GetExtensionOrAppByURL(url); + const Extension* extension = + registry_->enabled_extensions().GetExtensionOrAppByURL(url); return extension && (!extension->is_hosted_app() || extension->location() == Manifest::COMPONENT); } bool ExtensionService::ShouldBlockUrlInBrowserTab(GURL* url) { - const Extension* extension = extensions_.GetExtensionOrAppByURL(*url); + const Extension* extension = + registry_->enabled_extensions().GetExtensionOrAppByURL(*url); if (extension && extension->is_platform_app()) { *url = GURL(chrome::kExtensionInvalidRequestURL); return true; @@ -2465,7 +2478,8 @@ bool ExtensionService::OnExternalExtensionFileFound( scoped_ptr<DictionaryValue> ExtensionService::GetExtensionInfo( const std::string& extension_id) const { scoped_ptr<DictionaryValue> dictionary(new DictionaryValue); - const extensions::Extension* extension = extensions_.GetByID(extension_id); + const extensions::Extension* extension = + registry_->enabled_extensions().GetByID(extension_id); if (extension) { GURL icon = extensions::ExtensionIconSource::GetIconURL( extension, extension_misc::EXTENSION_ICON_SMALLISH, @@ -2569,8 +2583,9 @@ void ExtensionService::Observe(int type, // Loaded extensions. std::vector<ExtensionMsg_Loaded_Params> loaded_extensions; - for (ExtensionSet::const_iterator iter = extensions_.begin(); - iter != extensions_.end(); ++iter) { + const ExtensionSet& extensions = registry_->enabled_extensions(); + for (ExtensionSet::const_iterator iter = extensions.begin(); + iter != extensions.end(); ++iter) { // Renderers don't need to know about themes. if (!(*iter)->is_theme()) loaded_extensions.push_back(ExtensionMsg_Loaded_Params(iter->get())); @@ -2635,8 +2650,9 @@ bool ExtensionService::HasApps() const { ExtensionIdSet ExtensionService::GetAppIds() const { ExtensionIdSet result; - for (ExtensionSet::const_iterator it = extensions_.begin(); - it != extensions_.end(); ++it) { + const ExtensionSet& extensions = registry_->enabled_extensions(); + for (ExtensionSet::const_iterator it = extensions.begin(); + it != extensions.end(); ++it) { if ((*it)->is_app() && (*it)->location() != Manifest::COMPONENT) result.insert((*it)->id()); } @@ -2751,8 +2767,9 @@ bool ExtensionService::ShouldDelayExtensionUpdate( void ExtensionService::GarbageCollectIsolatedStorage() { scoped_ptr<base::hash_set<base::FilePath> > active_paths( new base::hash_set<base::FilePath>()); - for (ExtensionSet::const_iterator it = extensions_.begin(); - it != extensions_.end(); ++it) { + const ExtensionSet& extensions = registry_->enabled_extensions(); + for (ExtensionSet::const_iterator it = extensions.begin(); + it != extensions.end(); ++it) { if (extensions::AppIsolationInfo::HasIsolatedStorage(it->get())) { active_paths->insert(BrowserContext::GetStoragePartitionForSite( profile_, GetSiteForExtensionId((*it)->id()))->GetPath()); @@ -2799,7 +2816,7 @@ void ExtensionService::OnBlacklistUpdated() { void ExtensionService::ManageBlacklist(const std::set<std::string>& updated) { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); - std::set<std::string> before = blacklisted_extensions_.GetIDs(); + std::set<std::string> before = registry_->blacklisted_extensions().GetIDs(); std::set<std::string> no_longer_blacklisted = base::STLSetDifference<std::set<std::string> >(before, updated); std::set<std::string> not_yet_blacklisted = @@ -2808,13 +2825,13 @@ void ExtensionService::ManageBlacklist(const std::set<std::string>& updated) { for (std::set<std::string>::iterator it = no_longer_blacklisted.begin(); it != no_longer_blacklisted.end(); ++it) { scoped_refptr<const Extension> extension = - blacklisted_extensions_.GetByID(*it); + registry_->blacklisted_extensions().GetByID(*it); if (!extension.get()) { NOTREACHED() << "Extension " << *it << " no longer blacklisted, " << "but it was never blacklisted."; continue; } - blacklisted_extensions_.Remove(*it); + registry_->RemoveBlacklisted(*it); extension_prefs_->SetExtensionBlacklisted(extension->id(), false); AddExtension(extension.get()); UMA_HISTOGRAM_ENUMERATION("ExtensionBlacklist.UnblacklistInstalled", @@ -2830,7 +2847,7 @@ void ExtensionService::ManageBlacklist(const std::set<std::string>& updated) { << "blacklisted, but it's not installed."; continue; } - blacklisted_extensions_.Insert(extension); + registry_->AddBlacklisted(extension); extension_prefs_->SetExtensionBlacklisted(extension->id(), true); UnloadExtension(*it, UnloadedExtensionInfo::REASON_BLACKLIST); UMA_HISTOGRAM_ENUMERATION("ExtensionBlacklist.BlacklistInstalled", @@ -2848,3 +2865,15 @@ void ExtensionService::RemoveUpdateObserver( extensions::UpdateObserver* observer) { update_observers_.RemoveObserver(observer); } + +// Used only by test code. +void ExtensionService::UnloadAllExtensionsInternal() { + profile_->GetExtensionSpecialStoragePolicy()->RevokeRightsForAllExtensions(); + + registry_->ClearAll(); + extension_runtime_data_.clear(); + + // TODO(erikkay) should there be a notification for this? We can't use + // EXTENSION_UNLOADED since that implies that the extension has been disabled + // or uninstalled. +} diff --git a/chrome/browser/extensions/extension_service.h b/chrome/browser/extensions/extension_service.h index 17d62ec..f8d86c1 100644 --- a/chrome/browser/extensions/extension_service.h +++ b/chrome/browser/extensions/extension_service.h @@ -55,6 +55,7 @@ class ComponentLoader; class ContentSettingsStore; class CrxInstaller; class ExtensionActionStorageManager; +class ExtensionRegistry; class ExtensionSystem; class ExtensionUpdater; class PendingExtensionManager; @@ -325,12 +326,11 @@ class ExtensionService virtual void RemoveComponentExtension(const std::string& extension_id) OVERRIDE; - // Unload all extensions. This is currently only called on shutdown, and - // does not send notifications. - void UnloadAllExtensions(); + // Unload all extensions. Does not send notifications. + void UnloadAllExtensionsForTest(); - // Called only by testing. - void ReloadExtensions(); + // Reloads all extensions. Does not notify that extensions are ready. + void ReloadExtensionsForTest(); // Scan the extension directory and clean up the cruft. void GarbageCollectExtensions(); @@ -718,6 +718,9 @@ class ExtensionService } bool installs_delayed_for_gc() const { return installs_delayed_for_gc_; } + // Used only by test code. + void UnloadAllExtensionsInternal(); + // The normal profile associated with this ExtensionService. Profile* profile_; @@ -736,23 +739,12 @@ class ExtensionService // The ExtensionSyncService that is used by this ExtensionService. ExtensionSyncService* extension_sync_service_; - // The current list of installed extensions. - extensions::ExtensionSet extensions_; - - // The list of installed extensions that have been disabled. - extensions::ExtensionSet disabled_extensions_; - - // The list of installed extensions that have been terminated. - extensions::ExtensionSet terminated_extensions_; - - // The list of installed extensions that have been blacklisted. Generally - // these shouldn't be considered as installed by the extension platform: we - // only keep them around so that if extensions are blacklisted by mistake - // they can easily be un-blacklisted. - extensions::ExtensionSet blacklisted_extensions_; + // TODO(jamescook): Convert this to a BrowserContextKeyedService. + scoped_ptr<extensions::ExtensionRegistry> registry_; // The list of extension installs delayed for various reasons. The reason - // for delayed install is stored in ExtensionPrefs. + // for delayed install is stored in ExtensionPrefs. These are not part of + // ExtensionRegistry because they are not yet installed. extensions::ExtensionSet delayed_installs_; // Hold the set of pending extensions. diff --git a/chrome/browser/extensions/extension_service_unittest.cc b/chrome/browser/extensions/extension_service_unittest.cc index 2b659c9..2700d22 100644 --- a/chrome/browser/extensions/extension_service_unittest.cc +++ b/chrome/browser/extensions/extension_service_unittest.cc @@ -2158,7 +2158,7 @@ TEST_F(ExtensionServiceTest, GrantedAPIAndHostPermissions) { // updating the browser to a version which recognizes a new API permission). SetPref(extension_id, "granted_permissions.api", new ListValue(), "granted_permissions.api"); - service_->ReloadExtensions(); + service_->ReloadExtensionsForTest(); EXPECT_EQ(1u, service_->disabled_extensions()->size()); extension = service_->disabled_extensions()->begin()->get(); @@ -2201,7 +2201,7 @@ TEST_F(ExtensionServiceTest, GrantedAPIAndHostPermissions) { SetPrefStringSet( extension_id, "granted_permissions.scriptable_host", host_permissions); - service_->ReloadExtensions(); + service_->ReloadExtensionsForTest(); EXPECT_EQ(1u, service_->disabled_extensions()->size()); extension = service_->disabled_extensions()->begin()->get(); @@ -2538,7 +2538,7 @@ TEST_F(ExtensionServiceTest, UnpackedExtensionCanChangeID) { loaded_.clear(); // Reload the extensions. - service_->ReloadExtensions(); + service_->ReloadExtensionsForTest(); const Extension* extension = service_->GetExtensionById(unpacked, false); EXPECT_EQ(unpacked, extension->id()); ASSERT_EQ(1u, loaded_.size()); @@ -2837,7 +2837,7 @@ TEST_F(ExtensionServiceTest, FromWebStore) { ASSERT_TRUE(ValidateBooleanPref(good_crx, "from_webstore", true)); // Reload so extension gets reinitialized with new value. - service_->ReloadExtensions(); + service_->ReloadExtensionsForTest(); extension = service_->GetExtensionById(id, false); ASSERT_TRUE(extension->from_webstore()); @@ -3913,18 +3913,39 @@ TEST_F(ExtensionServiceTest, DisableExtension) { InitializeEmptyExtensionService(); InstallCRX(data_dir_.AppendASCII("good.crx"), INSTALL_NEW); - EXPECT_FALSE(service_->extensions()->is_empty()); EXPECT_TRUE(service_->GetExtensionById(good_crx, true)); EXPECT_TRUE(service_->GetExtensionById(good_crx, false)); - EXPECT_TRUE(service_->disabled_extensions()->is_empty()); + EXPECT_EQ(1u, service_->extensions()->size()); + EXPECT_EQ(0u, service_->disabled_extensions()->size()); + EXPECT_EQ(0u, service_->terminated_extensions()->size()); + EXPECT_EQ(0u, service_->blacklisted_extensions()->size()); // Disable it. service_->DisableExtension(good_crx, Extension::DISABLE_USER_ACTION); - EXPECT_TRUE(service_->extensions()->is_empty()); EXPECT_TRUE(service_->GetExtensionById(good_crx, true)); EXPECT_FALSE(service_->GetExtensionById(good_crx, false)); - EXPECT_FALSE(service_->disabled_extensions()->is_empty()); + EXPECT_EQ(0u, service_->extensions()->size()); + EXPECT_EQ(1u, service_->disabled_extensions()->size()); + EXPECT_EQ(0u, service_->terminated_extensions()->size()); + EXPECT_EQ(0u, service_->blacklisted_extensions()->size()); +} + +TEST_F(ExtensionServiceTest, TerminateExtension) { + InitializeEmptyExtensionService(); + + InstallCRX(data_dir_.AppendASCII("good.crx"), INSTALL_NEW); + EXPECT_EQ(1u, service_->extensions()->size()); + EXPECT_EQ(0u, service_->disabled_extensions()->size()); + EXPECT_EQ(0u, service_->terminated_extensions()->size()); + EXPECT_EQ(0u, service_->blacklisted_extensions()->size()); + + TerminateExtension(good_crx); + + EXPECT_EQ(0u, service_->extensions()->size()); + EXPECT_EQ(0u, service_->disabled_extensions()->size()); + EXPECT_EQ(1u, service_->terminated_extensions()->size()); + EXPECT_EQ(0u, service_->blacklisted_extensions()->size()); } TEST_F(ExtensionServiceTest, DisableTerminatedExtension) { @@ -3939,7 +3960,11 @@ TEST_F(ExtensionServiceTest, DisableTerminatedExtension) { EXPECT_FALSE(service_->GetTerminatedExtension(good_crx)); EXPECT_TRUE(service_->GetExtensionById(good_crx, true)); - EXPECT_FALSE(service_->disabled_extensions()->is_empty()); + + EXPECT_EQ(0u, service_->extensions()->size()); + EXPECT_EQ(1u, service_->disabled_extensions()->size()); + EXPECT_EQ(0u, service_->terminated_extensions()->size()); + EXPECT_EQ(0u, service_->blacklisted_extensions()->size()); } // Tests disabling all extensions (simulating --disable-extensions flag). @@ -3954,7 +3979,7 @@ TEST_F(ExtensionServiceTest, DisableAllExtensions) { // Disable extensions. service_->set_extensions_enabled(false); - service_->ReloadExtensions(); + service_->ReloadExtensionsForTest(); // There shouldn't be extensions in either list. EXPECT_EQ(0u, service_->extensions()->size()); @@ -3962,7 +3987,7 @@ TEST_F(ExtensionServiceTest, DisableAllExtensions) { // This shouldn't do anything when all extensions are disabled. service_->EnableExtension(good_crx); - service_->ReloadExtensions(); + service_->ReloadExtensionsForTest(); // There still shouldn't be extensions in either list. EXPECT_EQ(0u, service_->extensions()->size()); @@ -3970,7 +3995,7 @@ TEST_F(ExtensionServiceTest, DisableAllExtensions) { // And then re-enable the extensions. service_->set_extensions_enabled(true); - service_->ReloadExtensions(); + service_->ReloadExtensionsForTest(); EXPECT_EQ(1u, service_->extensions()->size()); EXPECT_EQ(0u, service_->disabled_extensions()->size()); @@ -3990,7 +4015,7 @@ TEST_F(ExtensionServiceTest, ReloadExtensions) { EXPECT_EQ(0u, service_->extensions()->size()); EXPECT_EQ(1u, service_->disabled_extensions()->size()); - service_->ReloadExtensions(); + service_->ReloadExtensionsForTest(); // The creation flags should not change when reloading the extension. const Extension* extension = service_->GetExtensionById(good_crx, true); @@ -4011,7 +4036,7 @@ TEST_F(ExtensionServiceTest, ReloadExtensions) { // EnableExtension() call above inserted into it and // UnloadAllExtensions() doesn't send out notifications. loaded_.clear(); - service_->ReloadExtensions(); + service_->ReloadExtensionsForTest(); // Extension counts shouldn't change. EXPECT_EQ(1u, service_->extensions()->size()); @@ -4553,7 +4578,7 @@ void ExtensionServiceTest::TestExternalProvider( // Reload extensions without changing anything. The extension should be // loaded again. loaded_.clear(); - service_->ReloadExtensions(); + service_->ReloadExtensionsForTest(); base::RunLoop().RunUntilIdle(); ASSERT_EQ(0u, GetErrors().size()); ASSERT_EQ(1u, loaded_.size()); @@ -4751,7 +4776,7 @@ TEST_F(ExtensionServiceTest, ExternalUninstall) { // Verify that it's not the disabled extensions flag causing it not to load. set_extensions_enabled(true); - service_->ReloadExtensions(); + service_->ReloadExtensionsForTest(); base::RunLoop().RunUntilIdle(); ASSERT_EQ(0u, GetErrors().size()); @@ -5211,7 +5236,7 @@ TEST_F(ExtensionServiceTest, ComponentExtensions) { // Reload all extensions, and make sure it comes back. std::string extension_id = (*service_->extensions()->begin())->id(); loaded_.clear(); - service_->ReloadExtensions(); + service_->ReloadExtensionsForTest(); ASSERT_EQ(1u, service_->extensions()->size()); EXPECT_EQ(extension_id, (*service_->extensions()->begin())->id()); } diff --git a/chrome/chrome_tests_unit.gypi b/chrome/chrome_tests_unit.gypi index 7fcf4c4..7f3393b 100644 --- a/chrome/chrome_tests_unit.gypi +++ b/chrome/chrome_tests_unit.gypi @@ -529,6 +529,7 @@ '../extensions/browser/admin_policy_unittest.cc', '../extensions/browser/event_listener_map_unittest.cc', '../extensions/browser/event_router_unittest.cc', + '../extensions/browser/extension_registry_unittest.cc', '../extensions/browser/file_highlighter_unittest.cc', '../extensions/browser/file_reader_unittest.cc', '../extensions/browser/info_map_unittest.cc', diff --git a/extensions/browser/extension_registry.cc b/extensions/browser/extension_registry.cc new file mode 100644 index 0000000..9391b40 --- /dev/null +++ b/extensions/browser/extension_registry.cc @@ -0,0 +1,60 @@ +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "extensions/browser/extension_registry.h" + +namespace extensions { + +ExtensionRegistry::ExtensionRegistry() {} +ExtensionRegistry::~ExtensionRegistry() {} + +bool ExtensionRegistry::AddEnabled( + const scoped_refptr<const Extension>& extension) { + return enabled_extensions_.Insert(extension); +} + +bool ExtensionRegistry::RemoveEnabled(const std::string& id) { + return enabled_extensions_.Remove(id); +} + +bool ExtensionRegistry::AddDisabled( + const scoped_refptr<const Extension>& extension) { + return disabled_extensions_.Insert(extension); +} + +bool ExtensionRegistry::RemoveDisabled(const std::string& id) { + return disabled_extensions_.Remove(id); +} + +bool ExtensionRegistry::AddTerminated( + const scoped_refptr<const Extension>& extension) { + return terminated_extensions_.Insert(extension); +} + +bool ExtensionRegistry::RemoveTerminated(const std::string& id) { + return terminated_extensions_.Remove(id); +} + +bool ExtensionRegistry::AddBlacklisted( + const scoped_refptr<const Extension>& extension) { + return blacklisted_extensions_.Insert(extension); +} + +bool ExtensionRegistry::RemoveBlacklisted(const std::string& id) { + return blacklisted_extensions_.Remove(id); +} + +void ExtensionRegistry::ClearAll() { + enabled_extensions_.Clear(); + disabled_extensions_.Clear(); + terminated_extensions_.Clear(); + blacklisted_extensions_.Clear(); +} + +void ExtensionRegistry::SetDisabledModificationCallback( + const ExtensionSet::ModificationCallback& callback) { + disabled_extensions_.set_modification_callback(callback); +} + +} // namespace extensions diff --git a/extensions/browser/extension_registry.h b/extensions/browser/extension_registry.h new file mode 100644 index 0000000..c051fbb --- /dev/null +++ b/extensions/browser/extension_registry.h @@ -0,0 +1,94 @@ +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef EXTENSIONS_BROWSER_EXTENSION_REGISTRY_H_ +#define EXTENSIONS_BROWSER_EXTENSION_REGISTRY_H_ + +#include <string> + +#include "base/memory/ref_counted.h" +#include "extensions/common/extension_set.h" + +namespace extensions { +class Extension; + +// ExtensionRegistry holds sets of the installed extensions for a given +// BrowserContext. +// TODO(jamescook): Convert this to a BrowserContextKeyedService. +class ExtensionRegistry { + public: + ExtensionRegistry(); + ~ExtensionRegistry(); + + // NOTE: These sets are *eventually* mututally exclusive, but an extension can + // appear in two sets for short periods of time. + const ExtensionSet& enabled_extensions() const { + return enabled_extensions_; + } + const ExtensionSet& disabled_extensions() const { + return disabled_extensions_; + } + const ExtensionSet& terminated_extensions() const { + return terminated_extensions_; + } + const ExtensionSet& blacklisted_extensions() const { + return blacklisted_extensions_; + } + + // Adds the specified extension to the enabled set. The registry becomes an + // owner. Any previous extension with the same ID is removed. + // Returns true if there is no previous extension. + // NOTE: You probably want to use ExtensionService instead of calling this + // method directly. + bool AddEnabled(const scoped_refptr<const Extension>& extension); + + // Removes the specified extension from the enabled set. + // Returns true if the set contained the specified extension. + // NOTE: You probably want to use ExtensionService instead of calling this + // method directly. + bool RemoveEnabled(const std::string& id); + + // As above, but for the disabled set. + bool AddDisabled(const scoped_refptr<const Extension>& extension); + bool RemoveDisabled(const std::string& id); + + // As above, but for the terminated set. + bool AddTerminated(const scoped_refptr<const Extension>& extension); + bool RemoveTerminated(const std::string& id); + + // As above, but for the blacklisted set. + bool AddBlacklisted(const scoped_refptr<const Extension>& extension); + bool RemoveBlacklisted(const std::string& id); + + // Removes all extensions from all sets. + void ClearAll(); + + // Sets a callback to run when the disabled extension set is modified. + // TODO(jamescook): This is too specific for a generic registry; find some + // other way to do this. + void SetDisabledModificationCallback( + const ExtensionSet::ModificationCallback& callback); + + private: + // Extensions that are installed, enabled and not terminated. + ExtensionSet enabled_extensions_; + + // Extensions that are installed and disabled. + ExtensionSet disabled_extensions_; + + // Extensions that are installed and terminated. + ExtensionSet terminated_extensions_; + + // Extensions that are installed and blacklisted. Generally these shouldn't be + // considered as installed by the extension platform: we only keep them around + // so that if extensions are blacklisted by mistake they can easily be + // un-blacklisted. + ExtensionSet blacklisted_extensions_; + + DISALLOW_COPY_AND_ASSIGN(ExtensionRegistry); +}; + +} // namespace extensions + +#endif // EXTENSIONS_BROWSER_EXTENSION_REGISTRY_H_ diff --git a/extensions/browser/extension_registry_unittest.cc b/extensions/browser/extension_registry_unittest.cc new file mode 100644 index 0000000..4243dea --- /dev/null +++ b/extensions/browser/extension_registry_unittest.cc @@ -0,0 +1,102 @@ +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "extensions/browser/extension_registry.h" + +#include <string> + +#include "base/files/file_path.h" +#include "base/memory/ref_counted.h" +#include "base/values.h" +#include "extensions/common/extension.h" +#include "extensions/common/extension_builder.h" +#include "extensions/common/value_builder.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace extensions { +namespace { + +// Creates a very simple extension. +scoped_refptr<Extension> CreateExtensionWithID(const std::string& id) { + return ExtensionBuilder() + .SetManifest( + DictionaryBuilder().Set("name", "Echo").Set("version", "1.0")) + .SetID(id) + .Build(); +} + +typedef testing::Test ExtensionRegistryTest; + +TEST_F(ExtensionRegistryTest, FillAndClearRegistry) { + ExtensionRegistry registry; + scoped_refptr<Extension> extension1 = CreateExtensionWithID("id1"); + scoped_refptr<Extension> extension2 = CreateExtensionWithID("id2"); + scoped_refptr<Extension> extension3 = CreateExtensionWithID("id3"); + scoped_refptr<Extension> extension4 = CreateExtensionWithID("id4"); + + // All the sets start empty. + EXPECT_EQ(0u, registry.enabled_extensions().size()); + EXPECT_EQ(0u, registry.disabled_extensions().size()); + EXPECT_EQ(0u, registry.terminated_extensions().size()); + EXPECT_EQ(0u, registry.blacklisted_extensions().size()); + + // Extensions can be added to each set. + registry.AddEnabled(extension1); + registry.AddDisabled(extension2); + registry.AddTerminated(extension3); + registry.AddBlacklisted(extension4); + + EXPECT_EQ(1u, registry.enabled_extensions().size()); + EXPECT_EQ(1u, registry.disabled_extensions().size()); + EXPECT_EQ(1u, registry.terminated_extensions().size()); + EXPECT_EQ(1u, registry.blacklisted_extensions().size()); + + // Clearing the registry clears all sets. + registry.ClearAll(); + + EXPECT_EQ(0u, registry.enabled_extensions().size()); + EXPECT_EQ(0u, registry.disabled_extensions().size()); + EXPECT_EQ(0u, registry.terminated_extensions().size()); + EXPECT_EQ(0u, registry.blacklisted_extensions().size()); +} + +// A simple test of adding and removing things from sets. +TEST_F(ExtensionRegistryTest, AddAndRemoveExtensionFromRegistry) { + ExtensionRegistry registry; + + // Adding an extension works. + scoped_refptr<Extension> extension = CreateExtensionWithID("id"); + EXPECT_TRUE(registry.AddEnabled(extension)); + EXPECT_EQ(1u, registry.enabled_extensions().size()); + + // The extension was only added to one set. + EXPECT_EQ(0u, registry.disabled_extensions().size()); + EXPECT_EQ(0u, registry.terminated_extensions().size()); + EXPECT_EQ(0u, registry.blacklisted_extensions().size()); + + // Removing an extension works. + EXPECT_TRUE(registry.RemoveEnabled(extension->id())); + EXPECT_EQ(0u, registry.enabled_extensions().size()); + + // Trying to remove an extension that isn't in the set fails cleanly. + EXPECT_FALSE(registry.RemoveEnabled(extension->id())); +} + +TEST_F(ExtensionRegistryTest, AddExtensionToRegistryTwice) { + ExtensionRegistry registry; + scoped_refptr<Extension> extension = CreateExtensionWithID("id"); + + // An extension can exist in two sets at once. It would be nice to eliminate + // this functionality, but some users of ExtensionRegistry need it. + EXPECT_TRUE(registry.AddEnabled(extension)); + EXPECT_TRUE(registry.AddDisabled(extension)); + + EXPECT_EQ(1u, registry.enabled_extensions().size()); + EXPECT_EQ(1u, registry.disabled_extensions().size()); + EXPECT_EQ(0u, registry.terminated_extensions().size()); + EXPECT_EQ(0u, registry.blacklisted_extensions().size()); +} + +} // namespace +} // namespace extensions diff --git a/extensions/extensions.gyp b/extensions/extensions.gyp index 4609d46..fa07292 100644 --- a/extensions/extensions.gyp +++ b/extensions/extensions.gyp @@ -169,6 +169,8 @@ 'browser/extension_error.h', 'browser/extension_function.cc', 'browser/extension_function.h', + 'browser/extension_registry.cc', + 'browser/extension_registry.h', 'browser/extensions_browser_client.cc', 'browser/extensions_browser_client.h', 'browser/external_provider_interface.h', |