diff options
28 files changed, 898 insertions, 719 deletions
diff --git a/base/base.gypi b/base/base.gypi index 27ec764..e2c659a 100644 --- a/base/base.gypi +++ b/base/base.gypi @@ -287,8 +287,6 @@ 'utf_string_conversions.h', 'values.cc', 'values.h', - 'values_util.cc', - 'values_util.h', 'version.cc', 'version.h', 'vlog.cc', diff --git a/base/values_util.cc b/base/values_util.cc deleted file mode 100644 index fbc616b..0000000 --- a/base/values_util.cc +++ /dev/null @@ -1,18 +0,0 @@ -// Copyright (c) 2010 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 "base/values_util.h" - -RefCountedList::RefCountedList(ListValue* list) { - list_ = list; -} - -RefCountedList::~RefCountedList() { - if (list_) - delete list_; -} - -ListValue* RefCountedList::Get() { - return list_; -} diff --git a/base/values_util.h b/base/values_util.h deleted file mode 100644 index 1626bb5..0000000 --- a/base/values_util.h +++ /dev/null @@ -1,26 +0,0 @@ -// Copyright (c) 2010 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 BASE_VALUES_UTIL_H_ -#define BASE_VALUES_UTIL_H_ -#pragma once - -#include "base/values.h" -#include "base/ref_counted.h" - -class RefCountedList : public base::RefCountedThreadSafe<RefCountedList> { - public: - // Takes ownership of |list|. - explicit RefCountedList(ListValue* list); - virtual ~RefCountedList(); - - virtual ListValue* Get(); - - private: - ListValue* list_; - - DISALLOW_COPY_AND_ASSIGN(RefCountedList); -}; - -#endif // BASE_VALUES_UTIL_H_ diff --git a/chrome/app/policy/policy_templates.json b/chrome/app/policy/policy_templates.json index 84cac8f..249b9b6 100644 --- a/chrome/app/policy/policy_templates.json +++ b/chrome/app/policy/policy_templates.json @@ -659,7 +659,7 @@ 'type': 'list', 'supported_on': ['chrome.*:9-'], 'annotations': { - 'features': {'dynamic_refresh': 0}, + 'features': {'dynamic_refresh': 1}, 'example_value': ['lcncmkcnkcdbbanbjakcencbaoegdjlp;https://clients2.google.com/service/update2/crx'], }, 'caption': '''Configure the list of force-installed extensions''', diff --git a/chrome/browser/extensions/extension_management_browsertest.cc b/chrome/browser/extensions/extension_management_browsertest.cc index a1eb2f6..4239940 100644 --- a/chrome/browser/extensions/extension_management_browsertest.cc +++ b/chrome/browser/extensions/extension_management_browsertest.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2009 The Chromium Authors. All rights reserved. +// Copyright (c) 2011 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. @@ -352,8 +352,8 @@ IN_PROC_BROWSER_TEST_F(ExtensionManagementTest, ExternalPolicyRefresh) { prefs->GetMutableList(prefs::kExtensionInstallForceList); ASSERT_TRUE(forcelist->empty()); forcelist->Append(Value::CreateStringValue( - "ogjcoiohnmldgjemafoockdghcjciccf;" - "http://localhost/autoupdate/manifest")); + std::string(kExtensionId) + + ";http://localhost/autoupdate/manifest")); } // Check if the extension got installed. @@ -365,6 +365,13 @@ IN_PROC_BROWSER_TEST_F(ExtensionManagementTest, ExternalPolicyRefresh) { EXPECT_EQ(Extension::EXTERNAL_POLICY_DOWNLOAD, extensions->at(size_before)->location()); - // Check that emptying the list doesn't cause any trouble. - prefs->ClearPref(prefs::kExtensionInstallForceList); + // Check that emptying the list triggers uninstall. + { + ScopedPrefUpdate pref_update(prefs, prefs::kExtensionInstallForceList); + prefs->ClearPref(prefs::kExtensionInstallForceList); + } + EXPECT_EQ(size_before, extensions->size()); + ExtensionList::const_iterator i; + for (i = extensions->begin(); i != extensions->end(); ++i) + EXPECT_NE(kExtensionId, (*i)->id()); } diff --git a/chrome/browser/extensions/extension_service.cc b/chrome/browser/extensions/extension_service.cc index 67cb44e..5ad45e9 100644 --- a/chrome/browser/extensions/extension_service.cc +++ b/chrome/browser/extensions/extension_service.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Copyright (c) 2011 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. @@ -19,7 +19,6 @@ #include "base/time.h" #include "base/utf_string_conversions.h" #include "base/values.h" -#include "base/values_util.h" #include "base/version.h" #include "chrome/browser/browser_process.h" #include "chrome/browser/themes/browser_theme_provider.h" @@ -42,9 +41,8 @@ #include "chrome/browser/extensions/extension_processes_api.h" #include "chrome/browser/extensions/extension_updater.h" #include "chrome/browser/extensions/extension_webnavigation_api.h" -#include "chrome/browser/extensions/external_extension_provider.h" -#include "chrome/browser/extensions/external_policy_extension_provider.h" -#include "chrome/browser/extensions/external_pref_extension_provider.h" +#include "chrome/browser/extensions/external_extension_provider_interface.h" +#include "chrome/browser/extensions/external_extension_provider_impl.h" #include "chrome/browser/net/chrome_url_request_context.h" #include "chrome/browser/prefs/pref_service.h" #include "chrome/browser/profiles/profile.h" @@ -67,10 +65,6 @@ #include "webkit/database/database_tracker.h" #include "webkit/database/database_util.h" -#if defined(OS_WIN) -#include "chrome/browser/extensions/external_registry_extension_provider_win.h" -#endif - using base::Time; namespace errors = extension_manifest_errors; @@ -184,12 +178,10 @@ const char* ExtensionService::kCurrentVersionFileName = "Current Version"; // Implements IO for the ExtensionService. class ExtensionServiceBackend - : public base::RefCountedThreadSafe<ExtensionServiceBackend>, - public ExternalExtensionProvider::Visitor { + : public base::RefCountedThreadSafe<ExtensionServiceBackend> { public: // |install_directory| is a path where to look for extensions to load. - ExtensionServiceBackend(PrefService* prefs, - const FilePath& install_directory); + explicit ExtensionServiceBackend(const FilePath& install_directory); // Loads a single extension from |path| where |path| is the top directory of // a specific extension where its manifest file lives. @@ -200,36 +192,6 @@ class ExtensionServiceBackend void LoadSingleExtension(const FilePath &path, scoped_refptr<ExtensionService> frontend); - // Check externally updated extensions for updates and install if necessary. - // Errors are reported through ExtensionErrorReporter. Succcess is not - // reported. - void CheckForExternalUpdates(scoped_refptr<ExtensionService> frontend); - - // For the extension in |version_path| with |id|, check to see if it's an - // externally managed extension. If so, tell the frontend to uninstall it. - void CheckExternalUninstall(scoped_refptr<ExtensionService> frontend, - const std::string& id); - - // Clear all ExternalExtensionProviders. - void ClearProvidersForTesting(); - - // Adds an ExternalExtensionProvider for the service to use during testing. - // Takes ownership of |test_provider|. - void AddProviderForTesting(ExternalExtensionProvider* test_provider); - - // ExternalExtensionProvider::Visitor implementation. - virtual void OnExternalExtensionFileFound(const std::string& id, - const Version* version, - const FilePath& path, - Extension::Location location); - - virtual void OnExternalExtensionUpdateUrlFound(const std::string& id, - const GURL& update_url, - Extension::Location location); - - virtual void UpdateExternalPolicyExtensionProvider( - scoped_refptr<RefCountedList> forcelist); - private: friend class base::RefCountedThreadSafe<ExtensionServiceBackend>; @@ -261,48 +223,14 @@ class ExtensionServiceBackend // Whether errors result in noisy alerts. bool alert_on_error_; - // A collection of external extension providers. Each provider reads - // a source of external extension information. Examples include the - // windows registry and external_extensions.json. - typedef std::vector<linked_ptr<ExternalExtensionProvider> > - ProviderCollection; - ProviderCollection external_extension_providers_; - linked_ptr<ExternalPolicyExtensionProvider> - external_policy_extension_provider_; - - // Set to true by OnExternalExtensionUpdateUrlFound() when an external - // extension URL is found. Used in CheckForExternalUpdates() to see - // if an update check is needed to install pending extensions. - bool external_extension_added_; - DISALLOW_COPY_AND_ASSIGN(ExtensionServiceBackend); }; ExtensionServiceBackend::ExtensionServiceBackend( - PrefService* prefs, const FilePath& install_directory) : frontend_(NULL), install_directory_(install_directory), - alert_on_error_(false), - external_extension_added_(false) { - // TODO(aa): This ends up doing blocking IO on the UI thread because it reads - // pref data in the ctor and that is called on the UI thread. Would be better - // to re-read data each time we list external extensions, anyway. - external_extension_providers_.push_back( - linked_ptr<ExternalExtensionProvider>( - new ExternalPrefExtensionProvider())); -#if defined(OS_WIN) - external_extension_providers_.push_back( - linked_ptr<ExternalExtensionProvider>( - new ExternalRegistryExtensionProvider())); -#endif - // The policy-controlled extension provider is also stored in a member - // variable so that UpdateExternalPolicyExtensionProvider can access it and - // update its extension list later. - external_policy_extension_provider_.reset( - new ExternalPolicyExtensionProvider( - prefs->GetList(prefs::kExtensionInstallForceList))); - external_extension_providers_.push_back(external_policy_extension_provider_); + alert_on_error_(false) { } ExtensionServiceBackend::~ExtensionServiceBackend() { @@ -352,108 +280,44 @@ void ExtensionServiceBackend::ReportExtensionLoadError( error, NotificationType::EXTENSION_INSTALL_ERROR, alert_on_error_)); } -// Some extensions will autoupdate themselves externally from Chrome. These -// are typically part of some larger client application package. To support -// these, the extension will register its location in the the preferences file -// (and also, on Windows, in the registry) and this code will periodically -// check that location for a .crx file, which it will then install locally if -// a new version is available. -void ExtensionServiceBackend::CheckForExternalUpdates( - scoped_refptr<ExtensionService> frontend) { - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); - - // Note that this installation is intentionally silent (since it didn't - // go through the front-end). Extensions that are registered in this - // way are effectively considered 'pre-bundled', and so implicitly - // trusted. In general, if something has HKLM or filesystem access, - // they could install an extension manually themselves anyway. - alert_on_error_ = false; - frontend_ = frontend; - external_extension_added_ = false; - - // Ask each external extension provider to give us a call back for each - // extension they know about. See OnExternalExtension(File|UpdateUrl)Found. - ProviderCollection::const_iterator i; - for (i = external_extension_providers_.begin(); - i != external_extension_providers_.end(); ++i) { - ExternalExtensionProvider* provider = i->get(); - provider->VisitRegisteredExtension(this); - } - - if (external_extension_added_ && frontend->updater()) { - BrowserThread::PostTask( - BrowserThread::UI, FROM_HERE, - NewRunnableMethod( - frontend->updater(), &ExtensionUpdater::CheckNow)); - } -} - -void ExtensionServiceBackend::CheckExternalUninstall( - scoped_refptr<ExtensionService> frontend, const std::string& id) { - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); +void ExtensionService::CheckExternalUninstall(const std::string& id) { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); // Check if the providers know about this extension. ProviderCollection::const_iterator i; for (i = external_extension_providers_.begin(); i != external_extension_providers_.end(); ++i) { + DCHECK(i->get()->IsReady()); if (i->get()->HasExtension(id)) return; // Yup, known extension, don't uninstall. } // This is an external extension that we don't have registered. Uninstall. - BrowserThread::PostTask( - BrowserThread::UI, FROM_HERE, - NewRunnableMethod( - frontend.get(), &ExtensionService::UninstallExtension, id, true)); -} - -void ExtensionServiceBackend::UpdateExternalPolicyExtensionProvider( - scoped_refptr<RefCountedList> forcelist) { - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); - external_policy_extension_provider_->SetPreferences(forcelist->Get()); + UninstallExtension(id, true); } -void ExtensionServiceBackend::ClearProvidersForTesting() { +void ExtensionService::ClearProvidersForTesting() { external_extension_providers_.clear(); } -void ExtensionServiceBackend::AddProviderForTesting( - ExternalExtensionProvider* test_provider) { +void ExtensionService::AddProviderForTesting( + ExternalExtensionProviderInterface* test_provider) { DCHECK(test_provider); external_extension_providers_.push_back( - linked_ptr<ExternalExtensionProvider>(test_provider)); + linked_ptr<ExternalExtensionProviderInterface>(test_provider)); } -void ExtensionServiceBackend::OnExternalExtensionFileFound( - const std::string& id, const Version* version, const FilePath& path, - Extension::Location location) { - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); - - DCHECK(version); - BrowserThread::PostTask( - BrowserThread::UI, FROM_HERE, - NewRunnableMethod( - frontend_, &ExtensionService::OnExternalExtensionFileFound, id, - version->GetString(), path, location)); -} - -void ExtensionServiceBackend::OnExternalExtensionUpdateUrlFound( +void ExtensionService::OnExternalExtensionUpdateUrlFound( const std::string& id, const GURL& update_url, Extension::Location location) { - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); - if (frontend_->GetExtensionById(id, true)) { + if (GetExtensionById(id, true)) { // Already installed. Do not change the update URL that the extension set. return; } - - BrowserThread::PostTask( - BrowserThread::UI, FROM_HERE, - NewRunnableMethod( - frontend_, - &ExtensionService::AddPendingExtensionFromExternalUpdateUrl, - id, update_url, location)); + AddPendingExtensionFromExternalUpdateUrl(id, update_url, location); external_extension_added_ |= true; } @@ -570,7 +434,6 @@ ExtensionService::ExtensionService(Profile* profile, pref_change_registrar_.Init(profile->GetPrefs()); pref_change_registrar_.Add(prefs::kExtensionInstallAllowList, this); pref_change_registrar_.Add(prefs::kExtensionInstallDenyList, this); - pref_change_registrar_.Add(prefs::kExtensionInstallForceList, this); // Set up the ExtensionUpdater if (autoupdate_enabled) { @@ -585,8 +448,10 @@ ExtensionService::ExtensionService(Profile* profile, update_frequency); } - backend_ = new ExtensionServiceBackend(profile->GetPrefs(), - install_directory_); + backend_ = new ExtensionServiceBackend(install_directory_); + + ExternalExtensionProviderImpl::CreateExternalProviders( + this, profile_, &external_extension_providers_); // Use monochrome icons for Omnibox icons. omnibox_popup_icon_manager_.set_monochrome(true); @@ -621,6 +486,12 @@ ExtensionService::~ExtensionService() { if (updater_.get()) { updater_->Stop(); } + ProviderCollection::const_iterator i; + for (i = external_extension_providers_.begin(); + i != external_extension_providers_.end(); ++i) { + ExternalExtensionProviderInterface* provider = i->get(); + provider->ServiceShutdown(); + } } void ExtensionService::InitEventRouters() { @@ -1205,16 +1076,6 @@ void ExtensionService::LoadInstalledExtension(const ExtensionInfo& info, extension_prefs_->UpdateManifest(extension); OnExtensionLoaded(extension); - - if (Extension::IsExternalLocation(info.extension_location)) { - BrowserThread::PostTask( - BrowserThread::FILE, FROM_HERE, - NewRunnableMethod( - backend_.get(), - &ExtensionServiceBackend::CheckExternalUninstall, - scoped_refptr<ExtensionService>(this), - info.extension_id)); - } } void ExtensionService::NotifyExtensionLoaded(const Extension* extension) { @@ -1460,31 +1321,69 @@ bool ExtensionService::GetBrowserActionVisibility(const Extension* extension) { } void ExtensionService::SetBrowserActionVisibility(const Extension* extension, - bool visible) { + bool visible) { extension_prefs_->SetBrowserActionVisibility(extension, visible); } +// Some extensions will autoupdate themselves externally from Chrome. These +// are typically part of some larger client application package. To support +// these, the extension will register its location in the the preferences file +// (and also, on Windows, in the registry) and this code will periodically +// check that location for a .crx file, which it will then install locally if +// a new version is available. +// Errors are reported through ExtensionErrorReporter. Succcess is not +// reported. void ExtensionService::CheckForExternalUpdates() { - BrowserThread::PostTask( - BrowserThread::FILE, FROM_HERE, - NewRunnableMethod( - backend_.get(), &ExtensionServiceBackend::CheckForExternalUpdates, - scoped_refptr<ExtensionService>(this))); + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); + + // Note that this installation is intentionally silent (since it didn't + // go through the front-end). Extensions that are registered in this + // way are effectively considered 'pre-bundled', and so implicitly + // trusted. In general, if something has HKLM or filesystem access, + // they could install an extension manually themselves anyway. + external_extension_added_ = false; + + // Ask each external extension provider to give us a call back for each + // extension they know about. See OnExternalExtension(File|UpdateUrl)Found. + ProviderCollection::const_iterator i; + for (i = external_extension_providers_.begin(); + i != external_extension_providers_.end(); ++i) { + ExternalExtensionProviderInterface* provider = i->get(); + provider->VisitRegisteredExtension(); + } + + // Uninstall of unclaimed extensions will happen after all the providers + // had reported ready. Trigger uninstall even if there are no providers + // installed: + OnExternalProviderReady(); } -void ExtensionService::UpdateExternalPolicyExtensionProvider() { - const ListValue* list_pref = - profile_->GetPrefs()->GetList(prefs::kExtensionInstallForceList); - ListValue* list_copy = NULL; - if (list_pref) - list_copy = static_cast<ListValue*>(list_pref->DeepCopy()); - BrowserThread::PostTask( - BrowserThread::FILE, FROM_HERE, - NewRunnableMethod( - backend_.get(), - &ExtensionServiceBackend::UpdateExternalPolicyExtensionProvider, - scoped_refptr<RefCountedList>( - new RefCountedList(list_copy)))); +void ExtensionService::OnExternalProviderReady() { + // An external provider has finished loading. We only take action + // if all of them are finished. So we check them first. + ProviderCollection::const_iterator i; + for (i = external_extension_providers_.begin(); + i != external_extension_providers_.end(); ++i) { + ExternalExtensionProviderInterface* provider = i->get(); + if (!provider->IsReady()) { + return; + } + } + + // All the providers are ready. Install any pending extensions. + if (external_extension_added_ && updater()) { + external_extension_added_ = false; + updater()->CheckNow(); + } + + // Uninstall all the unclaimed extensions. + scoped_ptr<ExtensionPrefs::ExtensionsInfo> extensions_info( + extension_prefs_->GetInstalledExtensionsInfo()); + for (size_t i = 0; i < extensions_info->size(); ++i) { + ExtensionInfo* info = extensions_info->at(i).get(); + if (Extension::IsExternalLocation(info->extension_location)) + CheckExternalUninstall(info->extension_id); + } } void ExtensionService::UnloadExtension( @@ -1919,38 +1818,23 @@ const SkBitmap& ExtensionService::GetOmniboxPopupIcon( return omnibox_popup_icon_manager_.GetIcon(extension_id); } -void ExtensionService::ClearProvidersForTesting() { - BrowserThread::PostTask( - BrowserThread::FILE, FROM_HERE, - NewRunnableMethod( - backend_.get(), &ExtensionServiceBackend::ClearProvidersForTesting)); -} - -void ExtensionService::AddProviderForTesting( - ExternalExtensionProvider* test_provider) { - BrowserThread::PostTask( - BrowserThread::FILE, FROM_HERE, - NewRunnableMethod( - backend_.get(), &ExtensionServiceBackend::AddProviderForTesting, - test_provider)); -} - void ExtensionService::OnExternalExtensionFileFound( const std::string& id, - const std::string& version, + const Version* version, const FilePath& path, Extension::Location location) { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); if (extension_prefs_->IsExtensionKilled(id)) return; + DCHECK(version); + // Before even bothering to unpack, check and see if we already have this // version. This is important because these extensions are going to get // installed on every startup. const Extension* existing = GetExtensionById(id, true); - scoped_ptr<Version> other(Version::GetVersionFromString(version)); if (existing) { - switch (existing->version()->CompareTo(*other)) { + switch (existing->version()->CompareTo(*version)) { case -1: // existing version is older, we should upgrade break; case 0: // existing version is same, do nothing @@ -2044,12 +1928,6 @@ void ExtensionService::Observe(NotificationType type, if (*pref_name == prefs::kExtensionInstallAllowList || *pref_name == prefs::kExtensionInstallDenyList) { CheckAdminBlacklist(); - } else if (*pref_name == prefs::kExtensionInstallForceList) { - UpdateExternalPolicyExtensionProvider(); - CheckForExternalUpdates(); - // TODO(gfeher): Also check for external extensions that can be - // uninstalled because they were removed from the pref. - // (crbug.com/63667) } else { NOTREACHED() << "Unexpected preference name."; } diff --git a/chrome/browser/extensions/extension_service.h b/chrome/browser/extensions/extension_service.h index 21c4a57..7849762 100644 --- a/chrome/browser/extensions/extension_service.h +++ b/chrome/browser/extensions/extension_service.h @@ -1,4 +1,4 @@ -// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Copyright (c) 2011 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. @@ -26,7 +26,7 @@ #include "chrome/browser/extensions/extension_process_manager.h" #include "chrome/browser/extensions/extension_toolbar_model.h" #include "chrome/browser/extensions/extensions_quota_service.h" -#include "chrome/browser/extensions/external_extension_provider.h" +#include "chrome/browser/extensions/external_extension_provider_interface.h" #include "chrome/browser/extensions/sandboxed_extension_unpacker.h" #include "chrome/browser/prefs/pref_change_registrar.h" #include "chrome/common/notification_observer.h" @@ -99,6 +99,7 @@ class ExtensionService : public base::RefCountedThreadSafe<ExtensionService, BrowserThread::DeleteOnUIThread>, public ExtensionUpdateService, + public ExternalExtensionProviderInterface::VisitorInterface, public NotificationObserver { public: // Information about a registered component extension. @@ -298,10 +299,6 @@ class ExtensionService // Check for updates (or potentially new extensions from external providers) void CheckForExternalUpdates(); - // Copies the list of force-installed extensions from the user PrefService - // to ExternalPolicyExtensionProvider. - void UpdateExternalPolicyExtensionProvider(); - // Unload the specified extension. void UnloadExtension(const std::string& extension_id, UnloadedExtensionInfo::Reason reason); @@ -343,13 +340,6 @@ class ExtensionService // extension. const SkBitmap& GetOmniboxPopupIcon(const std::string& extension_id); - // Clear all ExternalExtensionProviders. - void ClearProvidersForTesting(); - - // Sets an ExternalExtensionProvider for the service to use during testing. - // Takes ownership of |test_provider|. - void AddProviderForTesting(ExternalExtensionProvider* test_provider); - // Called when the initial extensions load has completed. virtual void OnLoadedInstalledExtensions(); @@ -359,12 +349,6 @@ class ExtensionService // Called by the backend when an extension has been installed. void OnExtensionInstalled(const Extension* extension); - // Called by the backend when an external extension is found. - void OnExternalExtensionFileFound(const std::string& id, - const std::string& version, - const FilePath& path, - Extension::Location location); - // Checks if the privileges requested by |extension| have increased, and if // so, disables the extension and prompts the user to approve the change. void DisableIfPrivilegeIncrease(const Extension* extension); @@ -426,6 +410,29 @@ class ExtensionService // view has been created. void DidCreateRenderViewForBackgroundPage(ExtensionHost* host); + // For the extension in |version_path| with |id|, check to see if it's an + // externally managed extension. If so, uninstall it. + void CheckExternalUninstall(const std::string& id); + + // Clear all ExternalExtensionProviders. + void ClearProvidersForTesting(); + + // Adds an ExternalExtensionProviderInterface for the service to use during + // testing. Takes ownership of |test_provider|. + void AddProviderForTesting(ExternalExtensionProviderInterface* test_provider); + + // ExternalExtensionProvider::Visitor implementation. + virtual void OnExternalExtensionFileFound(const std::string& id, + const Version* version, + const FilePath& path, + Extension::Location location); + + virtual void OnExternalExtensionUpdateUrlFound(const std::string& id, + const GURL& update_url, + Extension::Location location); + + virtual void OnExternalProviderReady(); + // NotificationObserver virtual void Observe(NotificationType type, const NotificationSource& source, @@ -601,6 +608,16 @@ class ExtensionService // Flag to make sure event routers are only initialized once. bool event_routers_initialized_; + // A collection of external extension providers. Each provider reads + // a source of external extension information. Examples include the + // windows registry and external_extensions.json. + ProviderCollection external_extension_providers_; + + // Set to true by OnExternalExtensionUpdateUrlFound() when an external + // extension URL is found. Used in CheckForExternalUpdates() to see + // if an update check is needed to install pending extensions. + bool external_extension_added_; + FRIEND_TEST_ALL_PREFIXES(ExtensionServiceTest, UpdatePendingExtensionAlreadyInstalled); FRIEND_TEST_ALL_PREFIXES(ExtensionServiceTest, diff --git a/chrome/browser/extensions/extension_service_unittest.cc b/chrome/browser/extensions/extension_service_unittest.cc index d9f8596..15fd66a 100644 --- a/chrome/browser/extensions/extension_service_unittest.cc +++ b/chrome/browser/extensions/extension_service_unittest.cc @@ -28,8 +28,9 @@ #include "chrome/browser/extensions/extension_creator.h" #include "chrome/browser/extensions/extension_error_reporter.h" #include "chrome/browser/extensions/extension_service.h" -#include "chrome/browser/extensions/external_extension_provider.h" -#include "chrome/browser/extensions/external_pref_extension_provider.h" +#include "chrome/browser/extensions/external_extension_provider_interface.h" +#include "chrome/browser/extensions/external_extension_provider_impl.h" +#include "chrome/browser/extensions/external_pref_extension_loader.h" #include "chrome/browser/extensions/pack_extension_job.cc" #include "chrome/browser/file_system/browser_file_system_helper.h" #include "chrome/browser/in_process_webkit/dom_storage_context.h" @@ -125,10 +126,13 @@ static void AssertEqualExtents(ExtensionExtent* extent1, } // namespace -class MockExtensionProvider : public ExternalExtensionProvider { +class MockExtensionProvider : public ExternalExtensionProviderInterface { public: - explicit MockExtensionProvider(Extension::Location location) - : location_(location), visit_count_(0) {} + explicit MockExtensionProvider( + VisitorInterface* visitor, + Extension::Location location) + : location_(location), visitor_(visitor), visit_count_(0) { + } virtual ~MockExtensionProvider() {} void UpdateOrAddExtension(const std::string& id, @@ -142,16 +146,17 @@ class MockExtensionProvider : public ExternalExtensionProvider { } // ExternalExtensionProvider implementation: - virtual void VisitRegisteredExtension(Visitor* visitor) const { + virtual void VisitRegisteredExtension() const { visit_count_++; for (DataMap::const_iterator i = extension_map_.begin(); i != extension_map_.end(); ++i) { scoped_ptr<Version> version; version.reset(Version::GetVersionFromString(i->second.first)); - visitor->OnExternalExtensionFileFound( + visitor_->OnExternalExtensionFileFound( i->first, version.get(), i->second.second, location_); } + visitor_->OnExternalProviderReady(); } virtual bool HasExtension(const std::string& id) const { @@ -173,6 +178,14 @@ class MockExtensionProvider : public ExternalExtensionProvider { return true; } + + virtual bool IsReady() { + return true; + } + + virtual void ServiceShutdown() { + } + int visit_count() const { return visit_count_; } void set_visit_count(int visit_count) { visit_count_ = visit_count; @@ -182,6 +195,7 @@ class MockExtensionProvider : public ExternalExtensionProvider { typedef std::map< std::string, std::pair<std::string, FilePath> > DataMap; DataMap extension_map_; Extension::Location location_; + VisitorInterface* visitor_; // visit_count_ tracks the number of calls to VisitRegisteredExtension(). // Mutable because it must be incremented on each call to @@ -192,15 +206,19 @@ class MockExtensionProvider : public ExternalExtensionProvider { DISALLOW_COPY_AND_ASSIGN(MockExtensionProvider); }; -class MockProviderVisitor : public ExternalExtensionProvider::Visitor { +class MockProviderVisitor + : public ExternalExtensionProviderInterface::VisitorInterface { public: MockProviderVisitor() : ids_found_(0) { } int Visit(const std::string& json_data) { // Give the test json file to the provider for parsing. - provider_.reset(new ExternalPrefExtensionProvider()); - provider_->SetPreferencesForTesting(json_data); + provider_.reset(new ExternalExtensionProviderImpl( + this, + new ExternalTestingExtensionLoader(json_data), + Extension::EXTERNAL_PREF, + Extension::EXTERNAL_PREF_DOWNLOAD)); // We also parse the file into a dictionary to compare what we get back // from the provider. @@ -219,7 +237,7 @@ class MockProviderVisitor : public ExternalExtensionProvider::Visitor { // Reset our counter. ids_found_ = 0; // Ask the provider to look up all extensions and return them. - provider_->VisitRegisteredExtension(this); + provider_->VisitRegisteredExtension(); return ids_found_; } @@ -285,10 +303,14 @@ class MockProviderVisitor : public ExternalExtensionProvider::Visitor { } } + virtual void OnExternalProviderReady() { + EXPECT_TRUE(provider_->IsReady()); + } + private: int ids_found_; - scoped_ptr<ExternalPrefExtensionProvider> provider_; + scoped_ptr<ExternalExtensionProviderImpl> provider_; scoped_ptr<DictionaryValue> prefs_; DISALLOW_COPY_AND_ASSIGN(MockProviderVisitor); @@ -471,7 +493,7 @@ class ExtensionServiceTest } } - void AddMockExternalProvider(ExternalExtensionProvider* provider) { + void AddMockExternalProvider(ExternalExtensionProviderInterface* provider) { service_->AddProviderForTesting(provider); } @@ -1071,8 +1093,10 @@ TEST_F(ExtensionServiceTest, KilledExtensions) { FilePath path = extensions_path.AppendASCII("good.crx"); set_extensions_enabled(true); + scoped_ptr<Version> version; + version.reset(Version::GetVersionFromString("1.0.0.0")); // Install an external extension. - service_->OnExternalExtensionFileFound(good_crx, "1.0.0.0", + service_->OnExternalExtensionFileFound(good_crx, version.get(), path, Extension::EXTERNAL_PREF); loop_.RunAllPending(); ASSERT_TRUE(NULL != service_->GetExtensionById(good_crx, false)); @@ -1083,15 +1107,16 @@ TEST_F(ExtensionServiceTest, KilledExtensions) { ValidateIntegerPref(good_crx, "location", Extension::KILLBIT); // Try to re-install it externally. This should fail because of the killbit. - service_->OnExternalExtensionFileFound(good_crx, "1.0.0.0", + service_->OnExternalExtensionFileFound(good_crx, version.get(), path, Extension::EXTERNAL_PREF); loop_.RunAllPending(); ASSERT_TRUE(NULL == service_->GetExtensionById(good_crx, false)); ValidateIntegerPref(good_crx, "location", Extension::KILLBIT); + version.reset(Version::GetVersionFromString("1.0.0.1")); // Repeat the same thing with a newer version of the extension. path = extensions_path.AppendASCII("good2.crx"); - service_->OnExternalExtensionFileFound(good_crx, "1.0.0.1", + service_->OnExternalExtensionFileFound(good_crx, version.get(), path, Extension::EXTERNAL_PREF); loop_.RunAllPending(); ASSERT_TRUE(NULL == service_->GetExtensionById(good_crx, false)); @@ -2862,8 +2887,7 @@ void ExtensionServiceTest::TestExternalProvider( provider->RemoveExtension(good_crx); loaded_.clear(); - service_->UnloadAllExtensions(); - service_->LoadAllExtensions(); + service_->OnExternalProviderReady(); loop_.RunAllPending(); ASSERT_EQ(0u, loaded_.size()); ValidatePrefKeyCount(0); @@ -2909,7 +2933,7 @@ TEST_F(ExtensionServiceTest, ExternalInstallRegistry) { // Now add providers. Extension system takes ownership of the objects. MockExtensionProvider* reg_provider = - new MockExtensionProvider(Extension::EXTERNAL_REGISTRY); + new MockExtensionProvider(service_.get(), Extension::EXTERNAL_REGISTRY); AddMockExternalProvider(reg_provider); TestExternalProvider(reg_provider, Extension::EXTERNAL_REGISTRY); } @@ -2920,7 +2944,7 @@ TEST_F(ExtensionServiceTest, ExternalInstallPref) { // Now add providers. Extension system takes ownership of the objects. MockExtensionProvider* pref_provider = - new MockExtensionProvider(Extension::EXTERNAL_PREF); + new MockExtensionProvider(service_.get(), Extension::EXTERNAL_PREF); AddMockExternalProvider(pref_provider); TestExternalProvider(pref_provider, Extension::EXTERNAL_PREF); @@ -2939,7 +2963,8 @@ TEST_F(ExtensionServiceTest, ExternalInstallPrefUpdateUrl) { // what the visitor does results in an extension being downloaded and // installed. MockExtensionProvider* pref_provider = - new MockExtensionProvider(Extension::EXTERNAL_PREF_DOWNLOAD); + new MockExtensionProvider(service_.get(), + Extension::EXTERNAL_PREF_DOWNLOAD); AddMockExternalProvider(pref_provider); TestExternalProvider(pref_provider, Extension::EXTERNAL_PREF_DOWNLOAD); } @@ -3119,7 +3144,7 @@ TEST(ExtensionServiceTestSimple, Enabledness) { // By default, we are enabled. command_line.reset(new CommandLine(CommandLine::NO_PROGRAM)); service = profile->CreateExtensionService(command_line.get(), - install_dir); + install_dir); EXPECT_TRUE(service->extensions_enabled()); service->Init(); loop.RunAllPending(); @@ -3140,7 +3165,7 @@ TEST(ExtensionServiceTestSimple, Enabledness) { profile.reset(new TestingProfile()); profile->GetPrefs()->SetBoolean(prefs::kDisableExtensions, true); service = profile->CreateExtensionService(command_line.get(), - install_dir); + install_dir); EXPECT_FALSE(service->extensions_enabled()); service->Init(); loop.RunAllPending(); diff --git a/chrome/browser/extensions/external_extension_loader.cc b/chrome/browser/extensions/external_extension_loader.cc new file mode 100644 index 0000000..79fc787 --- /dev/null +++ b/chrome/browser/extensions/external_extension_loader.cc @@ -0,0 +1,29 @@ +// Copyright (c) 2011 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 "chrome/browser/extensions/external_extension_loader.h" + +#include "base/logging.h" +#include "base/values.h" +#include "chrome/browser/browser_thread.h" +#include "chrome/browser/extensions/external_extension_provider_impl.h" + +void ExternalExtensionLoader::Init( + ExternalExtensionProviderImpl* owner) { + CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); + owner_ = owner; +} + +void ExternalExtensionLoader::OwnerShutdown() { + CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); + owner_ = NULL; +} + +void ExternalExtensionLoader::LoadFinished() { + CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); + running_ = false; + if (owner_) { + owner_->SetPrefs(prefs_.release()); + } +} diff --git a/chrome/browser/extensions/external_extension_loader.h b/chrome/browser/extensions/external_extension_loader.h new file mode 100644 index 0000000..594fb9e --- /dev/null +++ b/chrome/browser/extensions/external_extension_loader.h @@ -0,0 +1,71 @@ +// Copyright (c) 2011 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 CHROME_BROWSER_EXTENSIONS_EXTERNAL_EXTENSION_LOADER_H_ +#define CHROME_BROWSER_EXTENSIONS_EXTERNAL_EXTENSION_LOADER_H_ +#pragma once + +#include "base/ref_counted.h" +#include "base/scoped_ptr.h" + +class DictionaryValue; +class ExternalExtensionProviderImpl; + +// Base class for gathering a list of external extensions. Subclasses +// implement loading from registry, JSON file, policy. +// Instances are owned by ExternalExtensionProviderImpl objects. +// Instances are created on the UI thread and expect public method calls from +// the UI thread. Some subclasses introduce new methods that are executed on the +// FILE thread. +// The sequence of loading the extension list: +// 1.) StartLoading() - checks if a loading task is already running +// 2.) Load() - implemented in subclasses +// 3.) FinishLoading() +// 4.) owner_->SetPrefs() +class ExternalExtensionLoader + : public base::RefCountedThreadSafe<ExternalExtensionLoader> { + public: + explicit ExternalExtensionLoader() : running_(false) {} + + // Specifies the provider that owns this object. + void Init(ExternalExtensionProviderImpl* owner); + + // Called by the owner before it gets deleted. + void OwnerShutdown(); + + // Initiates the possibly asynchronous loading of extension list. + // It is the responsibility of the caller to ensure that calls to + // this method do not overlap with each other. + // Implementations of this method should save the loaded results + // in prefs_ and then call LoadFinished. + virtual void StartLoading() = 0; + + protected: + virtual ~ExternalExtensionLoader() {} + + // Notifies the provider that the list of extensions has been loaded. + void LoadFinished(); + + // Used for passing the list of extensions from the method that loads them + // to |LoadFinished|. To ensure thread safety, the rules are the following: + // if this value is written on another thread than the UI, then it should + // only be written in a task that was posted from |StartLoading|. After that, + // this task should invoke |LoadFinished| with a PostTask. This scheme of + // posting tasks will avoid concurrent access and imply the necessary memory + // barriers. + scoped_ptr<DictionaryValue> prefs_; + + private: + friend class base::RefCountedThreadSafe<ExternalExtensionLoader>; + + ExternalExtensionProviderImpl* owner_; // weak + + // Set to true if loading the extensions is already running. New requests + // are ignored while this is set true. + bool running_; + + DISALLOW_COPY_AND_ASSIGN(ExternalExtensionLoader); +}; + +#endif // CHROME_BROWSER_EXTENSIONS_EXTERNAL_EXTENSION_LOADER_H_ diff --git a/chrome/browser/extensions/stateful_external_extension_provider.cc b/chrome/browser/extensions/external_extension_provider_impl.cc index fd1a42a..9856cee 100644 --- a/chrome/browser/extensions/stateful_external_extension_provider.cc +++ b/chrome/browser/extensions/external_extension_provider_impl.cc @@ -1,44 +1,70 @@ -// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Copyright (c) 2011 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 "chrome/browser/extensions/stateful_external_extension_provider.h" +#include "chrome/browser/extensions/external_extension_provider_impl.h" #include "app/app_paths.h" #include "base/file_path.h" #include "base/logging.h" +#include "base/linked_ptr.h" #include "base/path_service.h" #include "base/values.h" #include "base/version.h" #include "chrome/browser/browser_thread.h" - -namespace { - -// Constants for keeping track of extension preferences. -const char kLocation[] = "location"; -const char kState[] = "state"; -const char kExternalCrx[] = "external_crx"; -const char kExternalVersion[] = "external_version"; -const char kExternalUpdateUrl[] = "external_update_url"; - -} - -StatefulExternalExtensionProvider::StatefulExternalExtensionProvider( +#include "chrome/browser/extensions/external_extension_provider_interface.h" +#include "chrome/browser/extensions/external_policy_extension_loader.h" +#include "chrome/browser/extensions/external_pref_extension_loader.h" +#include "chrome/browser/profiles/profile.h" + +#if defined(OS_WIN) +#include "chrome/browser/extensions/external_registry_extension_loader_win.h" +#endif + +// Constants for keeping track of extension preferences in a dictionary. +const char ExternalExtensionProviderImpl::kLocation[] = "location"; +const char ExternalExtensionProviderImpl::kState[] = "state"; +const char ExternalExtensionProviderImpl::kExternalCrx[] = "external_crx"; +const char ExternalExtensionProviderImpl::kExternalVersion[] = + "external_version"; +const char ExternalExtensionProviderImpl::kExternalUpdateUrl[] = + "external_update_url"; + +ExternalExtensionProviderImpl::ExternalExtensionProviderImpl( + VisitorInterface* service, + ExternalExtensionLoader* loader, Extension::Location crx_location, Extension::Location download_location) : crx_location_(crx_location), - download_location_(download_location) { - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); + download_location_(download_location), + service_(service), + prefs_(NULL), + ready_(false), + loader_(loader) { + loader_->Init(this); } -StatefulExternalExtensionProvider::~StatefulExternalExtensionProvider() { - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); +ExternalExtensionProviderImpl::~ExternalExtensionProviderImpl() { + CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); + loader_->OwnerShutdown(); } -void StatefulExternalExtensionProvider::VisitRegisteredExtension( - Visitor* visitor) const { - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); - DCHECK(prefs_.get()); +void ExternalExtensionProviderImpl::VisitRegisteredExtension() const { + // The loader will call back to SetPrefs. + loader_->StartLoading(); +} + +void ExternalExtensionProviderImpl::SetPrefs(DictionaryValue* prefs) { + CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); + + // Check if the service is still alive. It is possible that it had went + // away while |loader_| was working on the FILE thread. + if (!service_) return; + + prefs_.reset(prefs); + ready_ = true; // Queries for extensions are allowed from this point. + + // Notify ExtensionService about all the extensions this provider has. for (DictionaryValue::key_iterator i = prefs_->begin_keys(); i != prefs_->end_keys(); ++i) { const std::string& extension_id = *i; @@ -100,10 +126,10 @@ void StatefulExternalExtensionProvider::VisitRegisteredExtension( << external_version << "\"."; continue; } - visitor->OnExternalExtensionFileFound(extension_id, version.get(), path, + service_->OnExternalExtensionFileFound(extension_id, version.get(), path, crx_location_); } else { // if (has_external_update_url) - DCHECK(has_external_update_url); // Checking of keys above ensures this. + CHECK(has_external_update_url); // Checking of keys above ensures this. if (download_location_ == Extension::INVALID) { LOG(WARNING) << "This provider does not support installing external " << "extensions from update URLs."; @@ -117,24 +143,36 @@ void StatefulExternalExtensionProvider::VisitRegisteredExtension( << "\"."; continue; } - visitor->OnExternalExtensionUpdateUrlFound( + service_->OnExternalExtensionUpdateUrlFound( extension_id, update_url, download_location_); } } + + service_->OnExternalProviderReady(); +} + +void ExternalExtensionProviderImpl::ServiceShutdown() { + service_ = NULL; +} + +bool ExternalExtensionProviderImpl::IsReady() { + return ready_; } -bool StatefulExternalExtensionProvider::HasExtension( +bool ExternalExtensionProviderImpl::HasExtension( const std::string& id) const { - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); - DCHECK(prefs_.get()); + CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); + CHECK(prefs_.get()); + CHECK(ready_); return prefs_->HasKey(id); } -bool StatefulExternalExtensionProvider::GetExtensionDetails( +bool ExternalExtensionProviderImpl::GetExtensionDetails( const std::string& id, Extension::Location* location, scoped_ptr<Version>* version) const { - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); - DCHECK(prefs_.get()); + CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); + CHECK(prefs_.get()); + CHECK(ready_); DictionaryValue* extension = NULL; if (!prefs_->GetDictionary(id, &extension)) return false; @@ -164,6 +202,32 @@ bool StatefulExternalExtensionProvider::GetExtensionDetails( return true; } -void StatefulExternalExtensionProvider::set_prefs(DictionaryValue* prefs) { - prefs_.reset(prefs); +// static +void ExternalExtensionProviderImpl::CreateExternalProviders( + VisitorInterface* service, + Profile* profile, + ProviderCollection* provider_list) { + provider_list->push_back( + linked_ptr<ExternalExtensionProviderInterface>( + new ExternalExtensionProviderImpl( + service, + new ExternalPrefExtensionLoader, + Extension::EXTERNAL_PREF, + Extension::EXTERNAL_PREF_DOWNLOAD))); +#if defined(OS_WIN) + provider_list->push_back( + linked_ptr<ExternalExtensionProviderInterface>( + new ExternalExtensionProviderImpl( + service, + new ExternalRegistryExtensionLoader, + Extension::EXTERNAL_REGISTRY, + Extension::INVALID))); +#endif + provider_list->push_back( + linked_ptr<ExternalExtensionProviderInterface>( + new ExternalExtensionProviderImpl( + service, + new ExternalPolicyExtensionLoader(profile), + Extension::INVALID, + Extension::EXTERNAL_POLICY_DOWNLOAD))); } diff --git a/chrome/browser/extensions/external_extension_provider_impl.h b/chrome/browser/extensions/external_extension_provider_impl.h new file mode 100644 index 0000000..2856db9 --- /dev/null +++ b/chrome/browser/extensions/external_extension_provider_impl.h @@ -0,0 +1,99 @@ +// Copyright (c) 2011 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 CHROME_BROWSER_EXTENSIONS_EXTERNAL_EXTENSION_PROVIDER_IMPL_H_ +#define CHROME_BROWSER_EXTENSIONS_EXTERNAL_EXTENSION_PROVIDER_IMPL_H_ +#pragma once + +#include "chrome/browser/extensions/external_extension_provider_interface.h" + +#include "base/ref_counted.h" +#include "chrome/browser/extensions/external_extension_loader.h" + +class DictionaryValue; +class ExternalExtensionLoader; +class Profile; +class ValueSerializer; +class Version; + +// A specialization of the ExternalExtensionProvider that uses an instance +// of ExternalExtensionLoader to provide external extensions. This class +// can be seen as a bridge between the extension system and an +// ExternalExtensionLoader. Instances live their entire life on the UI thread. +class ExternalExtensionProviderImpl + : public ExternalExtensionProviderInterface { + public: + // The constructed provider will provide the extensions loaded from |loader| + // to |service|, that will deal with the installation. The location + // attributes of the provided extensions are also specified here: + // |crx_location|: extensions originating from crx files + // |download_location|: extensions originating from update URLs + // If either of the origins is not supported by this provider, then it should + // be initialized as Extensions::INVALID. + ExternalExtensionProviderImpl( + VisitorInterface* service, + ExternalExtensionLoader* loader, + Extension::Location crx_location, + Extension::Location download_location); + + virtual ~ExternalExtensionProviderImpl(); + + // Populates a list with providers for all known sources. + static void CreateExternalProviders( + VisitorInterface* service, + Profile* profile, + ProviderCollection* provider_list); + + // Sets underlying prefs and notifies provider. Only to be called by the + // owned ExternalExtensionLoader instance. + void SetPrefs(DictionaryValue* prefs); + + // ExternalExtensionProvider implementation: + virtual void VisitRegisteredExtension() const; + + virtual bool HasExtension(const std::string& id) const; + + virtual bool GetExtensionDetails(const std::string& id, + Extension::Location* location, + scoped_ptr<Version>* version) const; + + virtual void ServiceShutdown(); + + virtual bool IsReady(); + + static const char kLocation[]; + static const char kState[]; + static const char kExternalCrx[]; + static const char kExternalVersion[]; + static const char kExternalUpdateUrl[]; + + private: + // Location for external extensions that are provided by this provider from + // local crx files. + const Extension::Location crx_location_; + + // Location for external extensions that are provided by this provider from + // update URLs. + const Extension::Location download_location_; + + private: + // Weak pointer to the object that consumes the external extensions. + // This is zeroed out by: ServiceShutdown() + VisitorInterface* service_; // weak + + // Dictionary of the external extensions that are provided by this provider. + scoped_ptr<DictionaryValue> prefs_; + + // Indicates that the extensions provided by this provider are loaded + // entirely. + bool ready_; + + // The loader that loads the list of external extensions and reports them + // via |SetPrefs|. + scoped_refptr<ExternalExtensionLoader> loader_; + + DISALLOW_COPY_AND_ASSIGN(ExternalExtensionProviderImpl); +}; + +#endif // CHROME_BROWSER_EXTENSIONS_EXTERNAL_EXTENSION_PROVIDER_IMPL_H_ diff --git a/chrome/browser/extensions/external_extension_provider.h b/chrome/browser/extensions/external_extension_provider_interface.h index 5bcce1d5..7f9d3c4 100644 --- a/chrome/browser/extensions/external_extension_provider.h +++ b/chrome/browser/extensions/external_extension_provider_interface.h @@ -1,11 +1,14 @@ -// Copyright (c) 2009 The Chromium Authors. All rights reserved. +// Copyright (c) 2011 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 CHROME_BROWSER_EXTENSIONS_EXTERNAL_EXTENSION_PROVIDER_H_ -#define CHROME_BROWSER_EXTENSIONS_EXTERNAL_EXTENSION_PROVIDER_H_ +#ifndef CHROME_BROWSER_EXTENSIONS_EXTERNAL_EXTENSION_PROVIDER_INTERFACE_H_ +#define CHROME_BROWSER_EXTENSIONS_EXTERNAL_EXTENSION_PROVIDER_INTERFACE_H_ #pragma once +#include <vector> + +#include "base/linked_ptr.h" #include "chrome/common/extensions/extension.h" class FilePath; @@ -13,13 +16,13 @@ class Version; // This class is an abstract class for implementing external extensions // providers. -class ExternalExtensionProvider { +class ExternalExtensionProviderInterface { public: // ExternalExtensionProvider uses this interface to communicate back to the // caller what extensions are registered, and which |id|, |version| and |path| // they have. See also VisitRegisteredExtension below. Ownership of |version| // is not transferred to the visitor. - class Visitor { + class VisitorInterface { public: virtual void OnExternalExtensionFileFound( const std::string& id, @@ -32,16 +35,23 @@ class ExternalExtensionProvider { const GURL& update_url, Extension::Location location) = 0; + // Called after all the external extensions have been reported through + // the above two methods. + virtual void OnExternalProviderReady() = 0; + protected: - virtual ~Visitor() {} + virtual ~VisitorInterface() {} }; - virtual ~ExternalExtensionProvider() {} + virtual ~ExternalExtensionProviderInterface() {} + + // The visitor (ExtensionsService) calls this function before it goes away. + virtual void ServiceShutdown() = 0; - // Enumerate registered extension, calling OnExternalExtensionFound on - // the |visitor| object for each registered extension found. |ids_to_ignore| - // contains a list of extension ids that should not result in a call back. - virtual void VisitRegisteredExtension(Visitor* visitor) const = 0; + // Enumerate registered extensions, calling + // OnExternalExtension(File|UpdateUrl)Found on the |visitor| object for each + // registered extension found. + virtual void VisitRegisteredExtension() const = 0; // Test if this provider has an extension with id |id| registered. virtual bool HasExtension(const std::string& id) const = 0; @@ -53,6 +63,13 @@ class ExternalExtensionProvider { virtual bool GetExtensionDetails(const std::string& id, Extension::Location* location, scoped_ptr<Version>* version) const = 0; + + // Determines if this provider had loaded the list of external extensions + // from its source. + virtual bool IsReady() = 0; }; -#endif // CHROME_BROWSER_EXTENSIONS_EXTERNAL_EXTENSION_PROVIDER_H_ +typedef std::vector<linked_ptr<ExternalExtensionProviderInterface> > + ProviderCollection; + +#endif // CHROME_BROWSER_EXTENSIONS_EXTERNAL_EXTENSION_PROVIDER_INTERFACE_H_ diff --git a/chrome/browser/extensions/external_policy_extension_loader.cc b/chrome/browser/extensions/external_policy_extension_loader.cc new file mode 100644 index 0000000..99f2922 --- /dev/null +++ b/chrome/browser/extensions/external_policy_extension_loader.cc @@ -0,0 +1,103 @@ +// Copyright (c) 2011 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 "chrome/browser/extensions/external_policy_extension_loader.h" + +#include "base/logging.h" +#include "base/values.h" +#include "chrome/common/extensions/extension.h" +#include "chrome/common/notification_service.h" +#include "chrome/common/notification_type.h" +#include "chrome/common/pref_names.h" +#include "chrome/browser/browser_thread.h" +#include "chrome/browser/prefs/pref_service.h" +#include "chrome/browser/profiles/profile.h" +#include "googleurl/src/gurl.h" + +namespace { + +// Check an extension ID and an URL to be syntactically correct. +bool CheckExtension(std::string id, std::string update_url) { + GURL url(update_url); + if (!url.is_valid()) { + LOG(WARNING) << "Policy specifies invalid update URL for external " + << "extension: " << update_url; + return false; + } + if (!Extension::IdIsValid(id)) { + LOG(WARNING) << "Policy specifies invalid ID for external " + << "extension: " << id; + return false; + } + return true; +} + +} // namespace + +ExternalPolicyExtensionLoader::ExternalPolicyExtensionLoader( + Profile* profile) + : profile_(profile) { + pref_change_registrar_.Init(profile_->GetPrefs()); + pref_change_registrar_.Add(prefs::kExtensionInstallForceList, this); + notification_registrar_.Add(this, + NotificationType::PROFILE_DESTROYED, + Source<Profile>(profile_)); +} + +void ExternalPolicyExtensionLoader::StartLoading() { + const ListValue* forcelist = + profile_->GetPrefs()->GetList(prefs::kExtensionInstallForceList); + DictionaryValue* result = new DictionaryValue(); + if (forcelist != NULL) { + std::string extension_desc; + for (ListValue::const_iterator it = forcelist->begin(); + it != forcelist->end(); ++it) { + if (!(*it)->GetAsString(&extension_desc)) { + LOG(WARNING) << "Failed to read forcelist string."; + } else { + // Each string item of the list has the following form: + // extension_id_code;extension_update_url + // The update URL might also contain semicolons. + size_t pos = extension_desc.find(';'); + std::string id = extension_desc.substr(0, pos); + std::string update_url = extension_desc.substr(pos+1); + if (CheckExtension(id, update_url)) { + result->SetString(id + ".external_update_url", update_url); + } + } + } + } + prefs_.reset(result); + LoadFinished(); +} + +void ExternalPolicyExtensionLoader::Observe( + NotificationType type, + const NotificationSource& source, + const NotificationDetails& details) { + if (profile_ == NULL) return; + switch (type.value) { + case NotificationType::PREF_CHANGED: { + if (Source<PrefService>(source).ptr() == profile_->GetPrefs()) { + std::string* pref_name = Details<std::string>(details).ptr(); + if (*pref_name == prefs::kExtensionInstallForceList) { + StartLoading(); + } else { + NOTREACHED() << "Unexpected preference name."; + } + } + break; + } + case NotificationType::PROFILE_DESTROYED: { + if (Source<Profile>(source).ptr() == profile_) { + notification_registrar_.RemoveAll(); + pref_change_registrar_.RemoveAll(); + profile_ = NULL; + } + break; + } + default: + NOTREACHED() << "Unexpected notification type."; + } +} diff --git a/chrome/browser/extensions/external_policy_extension_loader.h b/chrome/browser/extensions/external_policy_extension_loader.h new file mode 100644 index 0000000..7a78071 --- /dev/null +++ b/chrome/browser/extensions/external_policy_extension_loader.h @@ -0,0 +1,49 @@ +// Copyright (c) 2011 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 CHROME_BROWSER_EXTENSIONS_EXTERNAL_POLICY_EXTENSION_LOADER_H_ +#define CHROME_BROWSER_EXTENSIONS_EXTERNAL_POLICY_EXTENSION_LOADER_H_ +#pragma once + +#include "chrome/browser/extensions/external_extension_loader.h" + +#include "chrome/browser/prefs/pref_change_registrar.h" +#include "chrome/common/notification_observer.h" +#include "chrome/common/notification_registrar.h" + +class ListValue; +class MockExternalPolicyExtensionProviderVisitor; +class Profile; + +// A specialization of the ExternalExtensionProvider that uses +// prefs::kExtensionInstallForceList to look up which external extensions are +// registered. +class ExternalPolicyExtensionLoader + : public ExternalExtensionLoader, + public NotificationObserver { + public: + explicit ExternalPolicyExtensionLoader(Profile* profile); + + // NotificationObserver implementation + virtual void Observe(NotificationType type, + const NotificationSource& source, + const NotificationDetails& details); + + protected: + virtual void StartLoading(); + + private: + friend class base::RefCountedThreadSafe<ExternalExtensionLoader>; + + virtual ~ExternalPolicyExtensionLoader() {} + + PrefChangeRegistrar pref_change_registrar_; + NotificationRegistrar notification_registrar_; + + Profile* profile_; + + DISALLOW_COPY_AND_ASSIGN(ExternalPolicyExtensionLoader); +}; + +#endif // CHROME_BROWSER_EXTENSIONS_EXTERNAL_POLICY_EXTENSION_LOADER_H_ diff --git a/chrome/browser/extensions/external_policy_extension_provider_unittest.cc b/chrome/browser/extensions/external_policy_extension_loader_unittest.cc index cd5a3df..d72f91c 100644 --- a/chrome/browser/extensions/external_policy_extension_provider_unittest.cc +++ b/chrome/browser/extensions/external_policy_extension_loader_unittest.cc @@ -1,36 +1,41 @@ -// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Copyright (c) 2011 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 <string> #include "base/logging.h" +#include "base/message_loop.h" #include "base/values.h" #include "base/version.h" #include "chrome/browser/browser_thread.h" -#include "chrome/browser/extensions/external_policy_extension_provider.h" +#include "chrome/browser/extensions/external_extension_provider_interface.h" +#include "chrome/browser/extensions/external_extension_provider_impl.h" +#include "chrome/browser/extensions/external_policy_extension_loader.h" #include "chrome/common/extensions/extension.h" +#include "chrome/common/pref_names.h" +#include "chrome/test/testing_pref_service.h" +#include "chrome/test/testing_profile.h" #include "testing/gtest/include/gtest/gtest.h" class ExternalPolicyExtensionProviderTest : public testing::Test { public: ExternalPolicyExtensionProviderTest() : loop_(MessageLoop::TYPE_IO), - ui_thread_(BrowserThread::UI, &loop_), - file_thread_(BrowserThread::FILE, &loop_) { + ui_thread_(BrowserThread::UI, &loop_) { } - virtual ~ExternalPolicyExtensionProviderTest() { - } + virtual ~ExternalPolicyExtensionProviderTest() {} private: + // We need these to satisfy BrowserThread::CurrentlyOn(BrowserThread::UI) + // checks in ExternalExtensionProviderImpl. MessageLoop loop_; BrowserThread ui_thread_; - BrowserThread file_thread_; }; class MockExternalPolicyExtensionProviderVisitor - : public ExternalExtensionProvider::Visitor { + : public ExternalExtensionProviderInterface::VisitorInterface { public: MockExternalPolicyExtensionProviderVisitor() { } @@ -40,12 +45,20 @@ class MockExternalPolicyExtensionProviderVisitor void Visit(ListValue* policy_forcelist, ListValue* policy_validlist, const std::set<std::string>& ignore_list) { - provider_.reset(new ExternalPolicyExtensionProvider(policy_forcelist)); + profile_.reset(new TestingProfile); + profile_->GetTestingPrefService()->SetManagedPref( + prefs::kExtensionInstallForceList, + policy_forcelist->DeepCopy()); + provider_.reset(new ExternalExtensionProviderImpl( + this, + new ExternalPolicyExtensionLoader(profile_.get()), + Extension::INVALID, + Extension::EXTERNAL_POLICY_DOWNLOAD)); // Extensions will be removed from this list as they visited, // so it should be emptied by the end. remaining_extensions = policy_validlist; - provider_->VisitRegisteredExtension(this); + provider_->VisitRegisteredExtension(); EXPECT_EQ(0u, remaining_extensions->GetSize()); } @@ -74,10 +87,16 @@ class MockExternalPolicyExtensionProviderVisitor EXPECT_NE(-1, remaining_extensions->Remove(ext_str)); } + virtual void OnExternalProviderReady() { + EXPECT_TRUE(provider_->IsReady()); + } + private: ListValue* remaining_extensions; - scoped_ptr<ExternalPolicyExtensionProvider> provider_; + scoped_ptr<TestingProfile> profile_; + + scoped_ptr<ExternalExtensionProviderImpl> provider_; DISALLOW_COPY_AND_ASSIGN(MockExternalPolicyExtensionProviderVisitor); }; diff --git a/chrome/browser/extensions/external_policy_extension_provider.cc b/chrome/browser/extensions/external_policy_extension_provider.cc deleted file mode 100644 index ccb5b03..0000000 --- a/chrome/browser/extensions/external_policy_extension_provider.cc +++ /dev/null @@ -1,77 +0,0 @@ -// Copyright (c) 2010 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 "chrome/browser/extensions/external_policy_extension_provider.h" - -#include <string> - -#include "base/logging.h" -#include "base/values.h" -#include "chrome/browser/browser_thread.h" -#include "chrome/browser/extensions/stateful_external_extension_provider.h" -#include "chrome/browser/prefs/pref_service.h" - -namespace { - -// Check an extension ID and an URL to be syntactically correct. -bool CheckExtension(std::string id, std::string update_url) { - GURL url(update_url); - if (!url.is_valid()) { - LOG(WARNING) << "Policy specifies invalid update URL for external " - << "extension: " << update_url; - return false; - } - if (!Extension::IdIsValid(id)) { - LOG(WARNING) << "Policy specifies invalid ID for external " - << "extension: " << id; - return false; - } - return true; -} - -} // namespace - -ExternalPolicyExtensionProvider::ExternalPolicyExtensionProvider( - const ListValue* forcelist) - : StatefulExternalExtensionProvider( - Extension::INVALID, - Extension::EXTERNAL_POLICY_DOWNLOAD) { - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); - ProcessPreferences(forcelist); -} - -ExternalPolicyExtensionProvider::~ExternalPolicyExtensionProvider() { - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); -} - -void ExternalPolicyExtensionProvider::SetPreferences( - const ListValue* forcelist) { - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); - ProcessPreferences(forcelist); -} - -void ExternalPolicyExtensionProvider::ProcessPreferences( - const ListValue* forcelist) { - DictionaryValue* result = new DictionaryValue(); - if (forcelist != NULL) { - std::string extension_desc; - for (ListValue::const_iterator it = forcelist->begin(); - it != forcelist->end(); ++it) { - if (!(*it)->GetAsString(&extension_desc)) { - LOG(WARNING) << "Failed to read forcelist string."; - } else { - // Each string item of the list has the following form: - // extension_id_code;extension_update_url - // The update URL might also contain semicolons. - size_t pos = extension_desc.find(';'); - std::string id = extension_desc.substr(0, pos); - std::string update_url = extension_desc.substr(pos+1); - if (CheckExtension(id, update_url)) { - result->SetString(id + ".external_update_url", update_url); - } - } - } - } - set_prefs(result); -} diff --git a/chrome/browser/extensions/external_policy_extension_provider.h b/chrome/browser/extensions/external_policy_extension_provider.h deleted file mode 100644 index 9c36960..0000000 --- a/chrome/browser/extensions/external_policy_extension_provider.h +++ /dev/null @@ -1,39 +0,0 @@ -// Copyright (c) 2009 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 CHROME_BROWSER_EXTENSIONS_EXTERNAL_POLICY_EXTENSION_PROVIDER_H_ -#define CHROME_BROWSER_EXTENSIONS_EXTERNAL_POLICY_EXTENSION_PROVIDER_H_ -#pragma once - -#include "chrome/browser/extensions/stateful_external_extension_provider.h" - -class ListValue; -class MockExternalPolicyExtensionProviderVisitor; -class PrefService; - -// A specialization of the ExternalExtensionProvider that uses -// prefs::kExtensionInstallForceList to look up which external extensions are -// registered. The value of this preference is received via the constructor and -// via |SetPreferences| in case of run-time updates. -// Instances of this class are expected to be created and destroyed on the UI -// thread and they are expecting public method calls from the FILE thread. -class ExternalPolicyExtensionProvider - : public StatefulExternalExtensionProvider { - public: - explicit ExternalPolicyExtensionProvider(const ListValue* forcelist); - virtual ~ExternalPolicyExtensionProvider(); - - // Set the internal list of extensions based on |forcelist|. - // Does not take ownership of |forcelist|. - void SetPreferences(const ListValue* forcelist); - - private: - friend class MockExternalPolicyExtensionProviderVisitor; - - // Set the internal list of extensions based on |forcelist|. - // Does not take ownership of |forcelist|. - void ProcessPreferences(const ListValue* forcelist); -}; - -#endif // CHROME_BROWSER_EXTENSIONS_EXTERNAL_POLICY_EXTENSION_PROVIDER_H_ diff --git a/chrome/browser/extensions/external_pref_extension_loader.cc b/chrome/browser/extensions/external_pref_extension_loader.cc new file mode 100644 index 0000000..b1b5d47 --- /dev/null +++ b/chrome/browser/extensions/external_pref_extension_loader.cc @@ -0,0 +1,82 @@ +// Copyright (c) 2011 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 "chrome/browser/extensions/external_pref_extension_loader.h" + +#include "app/app_paths.h" +#include "base/file_path.h" +#include "base/file_util.h" +#include "base/logging.h" +#include "base/path_service.h" +#include "chrome/browser/browser_thread.h" +#include "chrome/common/json_value_serializer.h" + +namespace { + +// Caller takes ownership of the returned dictionary +DictionaryValue* ExtractPrefs(ValueSerializer* serializer) { + std::string error_msg; + Value* extensions = serializer->Deserialize(NULL, &error_msg); + if (!extensions) { + LOG(WARNING) << "Unable to deserialize json data: " << error_msg; + } else { + if (!extensions->IsType(Value::TYPE_DICTIONARY)) { + NOTREACHED() << "Invalid json data"; + } else { + return static_cast<DictionaryValue*>(extensions); + } + } + return new DictionaryValue; +} + +} // namespace + +ExternalPrefExtensionLoader::ExternalPrefExtensionLoader() { + CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); +} + +void ExternalPrefExtensionLoader::StartLoading() { + CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); + BrowserThread::PostTask( + BrowserThread::FILE, FROM_HERE, + NewRunnableMethod( + this, + &ExternalPrefExtensionLoader::LoadOnFileThread)); +} + +void ExternalPrefExtensionLoader::LoadOnFileThread() { + CHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); + FilePath json_file; + PathService::Get(app::DIR_EXTERNAL_EXTENSIONS, &json_file); + json_file = json_file.Append(FILE_PATH_LITERAL("external_extensions.json")); + scoped_ptr<DictionaryValue> prefs; + + if (file_util::PathExists(json_file)) { + JSONFileValueSerializer serializer(json_file); + prefs.reset(ExtractPrefs(&serializer)); + } else { + prefs.reset(new DictionaryValue()); + } + + prefs_.reset(prefs.release()); + BrowserThread::PostTask( + BrowserThread::UI, FROM_HERE, + NewRunnableMethod( + this, + &ExternalPrefExtensionLoader::LoadFinished)); +} + +ExternalTestingExtensionLoader::ExternalTestingExtensionLoader( + const std::string& json_data) { + CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); + JSONStringValueSerializer serializer(json_data); + testing_prefs_.reset(ExtractPrefs(&serializer)); +} + +void ExternalTestingExtensionLoader::StartLoading() { + CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); + prefs_.reset( + static_cast<DictionaryValue*>(testing_prefs_->DeepCopy())); + LoadFinished(); +} diff --git a/chrome/browser/extensions/external_pref_extension_loader.h b/chrome/browser/extensions/external_pref_extension_loader.h new file mode 100644 index 0000000..9224b3b --- /dev/null +++ b/chrome/browser/extensions/external_pref_extension_loader.h @@ -0,0 +1,56 @@ +// Copyright (c) 2011 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 CHROME_BROWSER_EXTENSIONS_EXTERNAL_PREF_EXTENSION_LOADER_H_ +#define CHROME_BROWSER_EXTENSIONS_EXTERNAL_PREF_EXTENSION_LOADER_H_ +#pragma once + +#include "chrome/browser/extensions/external_extension_loader.h" + +#include <string> + +#include "base/scoped_ptr.h" +#include "base/values.h" + +// A specialization of the ExternalExtensionLoader that uses a json file to +// look up which external extensions are registered. +// Instances of this class are expected to be created and destroyed on the UI +// thread and they are expecting public method calls from the UI thread. +class ExternalPrefExtensionLoader : public ExternalExtensionLoader { + public: + ExternalPrefExtensionLoader(); + + protected: + virtual void StartLoading(); + + private: + friend class base::RefCountedThreadSafe<ExternalExtensionLoader>; + + virtual ~ExternalPrefExtensionLoader() {} + + void LoadOnFileThread(); + + DISALLOW_COPY_AND_ASSIGN(ExternalPrefExtensionLoader); +}; + +// A simplified version of ExternalPrefExtensionLoader that loads the dictionary +// from json data specified in a string. +class ExternalTestingExtensionLoader : public ExternalExtensionLoader { + public: + explicit ExternalTestingExtensionLoader(const std::string& json_data); + + protected: + virtual void StartLoading(); + + private: + friend class base::RefCountedThreadSafe<ExternalExtensionLoader>; + + virtual ~ExternalTestingExtensionLoader() {} + + scoped_ptr<DictionaryValue> testing_prefs_; + + DISALLOW_COPY_AND_ASSIGN(ExternalTestingExtensionLoader); +}; + +#endif // CHROME_BROWSER_EXTENSIONS_EXTERNAL_PREF_EXTENSION_LOADER_H_ diff --git a/chrome/browser/extensions/external_pref_extension_provider.cc b/chrome/browser/extensions/external_pref_extension_provider.cc deleted file mode 100644 index 7ea5f4a..0000000 --- a/chrome/browser/extensions/external_pref_extension_provider.cc +++ /dev/null @@ -1,57 +0,0 @@ -// Copyright (c) 2010 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 "chrome/browser/extensions/external_pref_extension_provider.h" - -#include "app/app_paths.h" -#include "base/file_path.h" -#include "base/file_util.h" -#include "base/logging.h" -#include "base/path_service.h" -#include "chrome/browser/browser_thread.h" -#include "chrome/browser/extensions/stateful_external_extension_provider.h" -#include "chrome/common/json_value_serializer.h" - -ExternalPrefExtensionProvider::ExternalPrefExtensionProvider() - : StatefulExternalExtensionProvider(Extension::EXTERNAL_PREF, - Extension::EXTERNAL_PREF_DOWNLOAD) { - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); - FilePath json_file; - PathService::Get(app::DIR_EXTERNAL_EXTENSIONS, &json_file); - json_file = json_file.Append(FILE_PATH_LITERAL("external_extensions.json")); - - if (file_util::PathExists(json_file)) { - JSONFileValueSerializer serializer(json_file); - SetPreferences(&serializer); - } else { - set_prefs(new DictionaryValue()); - } -} - -ExternalPrefExtensionProvider::~ExternalPrefExtensionProvider() { - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); -} - -void ExternalPrefExtensionProvider::SetPreferencesForTesting( - const std::string& json_data_for_testing) { - JSONStringValueSerializer serializer(json_data_for_testing); - SetPreferences(&serializer); -} - -void ExternalPrefExtensionProvider::SetPreferences( - ValueSerializer* serializer) { - std::string error_msg; - Value* extensions = serializer->Deserialize(NULL, &error_msg); - scoped_ptr<DictionaryValue> dictionary(new DictionaryValue()); - if (!extensions) { - LOG(WARNING) << "Unable to deserialize json data: " << error_msg; - } else { - if (!extensions->IsType(Value::TYPE_DICTIONARY)) { - NOTREACHED() << "Invalid json data"; - } else { - dictionary.reset(static_cast<DictionaryValue*>(extensions)); - } - } - set_prefs(dictionary.release()); -} diff --git a/chrome/browser/extensions/external_pref_extension_provider.h b/chrome/browser/extensions/external_pref_extension_provider.h deleted file mode 100644 index b74be39..0000000 --- a/chrome/browser/extensions/external_pref_extension_provider.h +++ /dev/null @@ -1,28 +0,0 @@ -// Copyright (c) 2009 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 CHROME_BROWSER_EXTENSIONS_EXTERNAL_PREF_EXTENSION_PROVIDER_H_ -#define CHROME_BROWSER_EXTENSIONS_EXTERNAL_PREF_EXTENSION_PROVIDER_H_ -#pragma once - -#include "chrome/browser/extensions/stateful_external_extension_provider.h" - -// A specialization of the ExternalExtensionProvider that uses a json file to -// look up which external extensions are registered. -// Instances of this class are expected to be created and destroyed on the UI -// thread and they are expecting public method calls from the FILE thread. -class ExternalPrefExtensionProvider : public StatefulExternalExtensionProvider { - public: - explicit ExternalPrefExtensionProvider(); - virtual ~ExternalPrefExtensionProvider(); - - // Used only during testing to not use the json file for external extensions, - // but instead parse a json file specified by the test. - void SetPreferencesForTesting(const std::string& json_data_for_testing); - - private: - void SetPreferences(ValueSerializer* serializer); -}; - -#endif // CHROME_BROWSER_EXTENSIONS_EXTERNAL_PREF_EXTENSION_PROVIDER_H_ diff --git a/chrome/browser/extensions/external_registry_extension_provider_win.cc b/chrome/browser/extensions/external_registry_extension_loader_win.cc index 16b107f..7f2df55 100644 --- a/chrome/browser/extensions/external_registry_extension_provider_win.cc +++ b/chrome/browser/extensions/external_registry_extension_loader_win.cc @@ -2,13 +2,16 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "chrome/browser/extensions/external_registry_extension_provider_win.h" +#include "chrome/browser/extensions/external_registry_extension_loader_win.h" #include "base/file_path.h" #include "base/string_util.h" #include "base/utf_string_conversions.h" +#include "base/values.h" #include "base/version.h" #include "base/win/registry.h" +#include "chrome/browser/browser_thread.h" +#include "chrome/browser/extensions/external_extension_provider_impl.h" namespace { @@ -24,24 +27,21 @@ const wchar_t kRegistryExtensionPath[] = L"path"; // Registry value of that key that defines the current version of the .crx file. const wchar_t kRegistryExtensionVersion[] = L"version"; -bool OpenKeyById(const std::string& id, base::win::RegKey *key) { - std::wstring key_path = ASCIIToWide(kRegistryExtensions); - key_path.append(L"\\"); - key_path.append(ASCIIToWide(id)); - - return key->Open(kRegRoot, key_path.c_str(), KEY_READ); -} - } // namespace -ExternalRegistryExtensionProvider::ExternalRegistryExtensionProvider() { +void ExternalRegistryExtensionLoader::StartLoading() { + CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); + BrowserThread::PostTask( + BrowserThread::FILE, FROM_HERE, + NewRunnableMethod( + this, + &ExternalRegistryExtensionLoader::LoadOnFileThread)); } -ExternalRegistryExtensionProvider::~ExternalRegistryExtensionProvider() { -} +void ExternalRegistryExtensionLoader::LoadOnFileThread() { + CHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); + scoped_ptr<DictionaryValue> prefs(new DictionaryValue); -void ExternalRegistryExtensionProvider::VisitRegisteredExtension( - Visitor* visitor) const { base::win::RegistryKeyIterator iterator( kRegRoot, ASCIIToWide(kRegistryExtensions).c_str()); while (iterator.Valid()) { @@ -57,19 +57,12 @@ void ExternalRegistryExtensionProvider::VisitRegisteredExtension( std::string id = WideToASCII(iterator.Name()); StringToLowerASCII(&id); - scoped_ptr<Version> version; - version.reset(Version::GetVersionFromString( - WideToASCII(extension_version))); - if (!version.get()) { - LOG(ERROR) << "Invalid version value " << extension_version - << " for key " << key_path; - ++iterator; - continue; - } - - FilePath path = FilePath::FromWStringHack(extension_path); - visitor->OnExternalExtensionFileFound(id, version.get(), path, - Extension::EXTERNAL_REGISTRY); + prefs->SetString( + id + "." + ExternalExtensionProviderImpl::kExternalVersion, + WideToASCII(extension_version)); + prefs->SetString( + id + "." + ExternalExtensionProviderImpl::kExternalCrx, + extension_path); } else { // TODO(erikkay): find a way to get this into about:extensions LOG(ERROR) << "Missing value " << kRegistryExtensionVersion @@ -83,33 +76,11 @@ void ExternalRegistryExtensionProvider::VisitRegisteredExtension( } ++iterator; } -} - - -bool ExternalRegistryExtensionProvider::HasExtension( - const std::string& id) const { - base::win::RegKey key; - return OpenKeyById(id, &key); -} - -bool ExternalRegistryExtensionProvider::GetExtensionDetails( - const std::string& id, - Extension::Location* location, - scoped_ptr<Version>* version) const { - base::win::RegKey key; - if (!OpenKeyById(id, &key)) - return false; - - std::wstring extension_version; - if (!key.ReadValue(kRegistryExtensionVersion, &extension_version)) - return false; - - if (version) { - version->reset(Version::GetVersionFromString( - WideToASCII(extension_version))); - } - if (location) - *location = Extension::EXTERNAL_REGISTRY; - return true; + prefs_.reset(prefs.release()); + BrowserThread::PostTask( + BrowserThread::UI, FROM_HERE, + NewRunnableMethod( + this, + &ExternalRegistryExtensionLoader::LoadFinished)); } diff --git a/chrome/browser/extensions/external_registry_extension_loader_win.h b/chrome/browser/extensions/external_registry_extension_loader_win.h new file mode 100644 index 0000000..7b0d189 --- /dev/null +++ b/chrome/browser/extensions/external_registry_extension_loader_win.h @@ -0,0 +1,28 @@ +// Copyright (c) 2010 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 CHROME_BROWSER_EXTENSIONS_EXTERNAL_REGISTRY_EXTENSION_LOADER_WIN_H_ +#define CHROME_BROWSER_EXTENSIONS_EXTERNAL_REGISTRY_EXTENSION_LOADER_WIN_H_ +#pragma once + +#include "chrome/browser/extensions/external_extension_loader.h" + +class ExternalRegistryExtensionLoader : public ExternalExtensionLoader { + public: + ExternalRegistryExtensionLoader() {} + + protected: + virtual void StartLoading(); + + private: + friend class base::RefCountedThreadSafe<ExternalExtensionLoader>; + + virtual ~ExternalRegistryExtensionLoader() {} + + void LoadOnFileThread(); + + DISALLOW_COPY_AND_ASSIGN(ExternalRegistryExtensionLoader); +}; + +#endif // CHROME_BROWSER_EXTENSIONS_EXTERNAL_REGISTRY_EXTENSION_LOADER_WIN_H_ diff --git a/chrome/browser/extensions/external_registry_extension_provider_win.h b/chrome/browser/extensions/external_registry_extension_provider_win.h deleted file mode 100644 index 34899ae..0000000 --- a/chrome/browser/extensions/external_registry_extension_provider_win.h +++ /dev/null @@ -1,30 +0,0 @@ -// Copyright (c) 2009 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 CHROME_BROWSER_EXTENSIONS_EXTERNAL_REGISTRY_EXTENSION_PROVIDER_WIN_H_ -#define CHROME_BROWSER_EXTENSIONS_EXTERNAL_REGISTRY_EXTENSION_PROVIDER_WIN_H_ -#pragma once - -#include "chrome/browser/extensions/external_extension_provider.h" - -class Version; - -// A specialization of the ExternalExtensionProvider that uses the Registry to -// look up which external extensions are registered. -class ExternalRegistryExtensionProvider : public ExternalExtensionProvider { - public: - ExternalRegistryExtensionProvider(); - virtual ~ExternalRegistryExtensionProvider(); - - // ExternalExtensionProvider implementation: - virtual void VisitRegisteredExtension(Visitor* visitor) const; - - virtual bool HasExtension(const std::string& id) const; - - virtual bool GetExtensionDetails(const std::string& id, - Extension::Location* location, - scoped_ptr<Version>* version) const; -}; - -#endif // CHROME_BROWSER_EXTENSIONS_EXTERNAL_REGISTRY_EXTENSION_PROVIDER_WIN_H_ diff --git a/chrome/browser/extensions/stateful_external_extension_provider.h b/chrome/browser/extensions/stateful_external_extension_provider.h deleted file mode 100644 index 2fd481c..0000000 --- a/chrome/browser/extensions/stateful_external_extension_provider.h +++ /dev/null @@ -1,61 +0,0 @@ -// Copyright (c) 2009 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 CHROME_BROWSER_EXTENSIONS_STATEFUL_EXTERNAL_EXTENSION_PROVIDER_H_ -#define CHROME_BROWSER_EXTENSIONS_STATEFUL_EXTERNAL_EXTENSION_PROVIDER_H_ -#pragma once - -#include "chrome/browser/extensions/external_extension_provider.h" - -class DictionaryValue; -class ValueSerializer; -class Version; - -// A specialization of the ExternalExtensionProvider that stores the registered -// external extensions in a dictionary. This dictionary (|prefs_|) will be used -// by HasExtension() and GetExtensionDetails() to return information about the -// stored external extensions. It is the responsibility of specialized -// subclasses to initialize this internal dictionary. -// This provider can provide external extensions from two sources: crx files -// and udpate URLs. The locations that the provider will report for these -// are specified at the constructor. -// Instances of this class are expected to be created and destroyed on the UI -// thread and they are expecting public method calls from the FILE thread. -class StatefulExternalExtensionProvider : public ExternalExtensionProvider { - public: - // Initialize the location for external extensions originating from crx - // files: |crx_location|, and originating from update URLs: - // |download_location|. If either of the origins is not supported by this - // provider, then it should be initialized as Extensions::INVALID. - StatefulExternalExtensionProvider( - Extension::Location crx_location, - Extension::Location download_location); - virtual ~StatefulExternalExtensionProvider(); - - // ExternalExtensionProvider implementation: - virtual void VisitRegisteredExtension(Visitor* visitor) const; - - virtual bool HasExtension(const std::string& id) const; - - virtual bool GetExtensionDetails(const std::string& id, - Extension::Location* location, - scoped_ptr<Version>* version) const; - protected: - // Location for external extensions that are provided by this provider from - // local crx files. - const Extension::Location crx_location_; - // Location for external extensions that are provided by this provider from - // update URLs. - const Extension::Location download_location_; - - // Stores the dictionary of external extensions internally. Takes ownership - // of |prefs|. - void set_prefs(DictionaryValue* prefs); - - private: - // Dictionary of the external extensions that are provided by this provider. - scoped_ptr<DictionaryValue> prefs_; -}; - -#endif // CHROME_BROWSER_EXTENSIONS_STATEFUL_EXTERNAL_EXTENSION_PROVIDER_H_ diff --git a/chrome/chrome_browser.gypi b/chrome/chrome_browser.gypi index 3cbdc1d..68b508f 100644 --- a/chrome/chrome_browser.gypi +++ b/chrome/chrome_browser.gypi @@ -1200,13 +1200,17 @@ 'browser/extensions/extensions_startup.h', 'browser/extensions/extensions_ui.cc', 'browser/extensions/extensions_ui.h', - 'browser/extensions/external_extension_provider.h', - 'browser/extensions/external_pref_extension_provider.cc', - 'browser/extensions/external_pref_extension_provider.h', - 'browser/extensions/external_policy_extension_provider.cc', - 'browser/extensions/external_policy_extension_provider.h', - 'browser/extensions/external_registry_extension_provider_win.cc', - 'browser/extensions/external_registry_extension_provider_win.h', + 'browser/extensions/external_extension_provider_interface.h', + 'browser/extensions/external_extension_provider_impl.cc', + 'browser/extensions/external_extension_provider_impl.h', + 'browser/extensions/external_extension_loader.cc', + 'browser/extensions/external_extension_loader.h', + 'browser/extensions/external_pref_extension_loader.cc', + 'browser/extensions/external_pref_extension_loader.h', + 'browser/extensions/external_policy_extension_loader.cc', + 'browser/extensions/external_policy_extension_loader.h', + 'browser/extensions/external_registry_extension_loader_win.cc', + 'browser/extensions/external_registry_extension_loader_win.h', 'browser/extensions/file_reader.cc', 'browser/extensions/file_reader.h', 'browser/extensions/gtk_theme_installed_infobar_delegate.cc', @@ -1217,8 +1221,6 @@ 'browser/extensions/pack_extension_job.h', 'browser/extensions/sandboxed_extension_unpacker.cc', 'browser/extensions/sandboxed_extension_unpacker.h', - 'browser/extensions/stateful_external_extension_provider.cc', - 'browser/extensions/stateful_external_extension_provider.h', 'browser/extensions/theme_installed_infobar_delegate.cc', 'browser/extensions/theme_installed_infobar_delegate.h', 'browser/extensions/user_script_listener.cc', diff --git a/chrome/chrome_tests.gypi b/chrome/chrome_tests.gypi index 1db511a..931e3a7 100644 --- a/chrome/chrome_tests.gypi +++ b/chrome/chrome_tests.gypi @@ -1175,7 +1175,7 @@ 'browser/extensions/extension_updater_unittest.cc', 'browser/extensions/extension_webnavigation_unittest.cc', 'browser/extensions/extensions_quota_service_unittest.cc', - 'browser/extensions/external_policy_extension_provider_unittest.cc', + 'browser/extensions/external_policy_extension_loader_unittest.cc', 'browser/extensions/file_reader_unittest.cc', 'browser/extensions/image_loading_tracker_unittest.cc', 'browser/extensions/sandboxed_extension_unpacker_unittest.cc', |