From a1257b12bd288161e1eadeff9f2378de9b6e029a Mon Sep 17 00:00:00 2001 From: "finnur@chromium.org" Date: Fri, 12 Jun 2009 02:51:34 +0000 Subject: Factor out the code that deals with installing external extensions through Registry and Preferences into separate classes. While I was at it, I removed the EXTERNAL_INSTALL file, since we now keep track of this in the Preferences. This also takes care of the virtualization problem in the unit tests for vista (see bug). BUG=13063 TEST=None, covered by automated tests. Review URL: http://codereview.chromium.org/122004 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@18247 0039d316-1c4b-4281-b951-d872f2087c98 --- chrome/browser/extensions/extensions_service.cc | 299 +++++++++------------ chrome/browser/extensions/extensions_service.h | 66 +++-- .../extensions/extensions_service_unittest.cc | 165 ++++++++---- .../extensions/external_extension_provider.h | 46 ++++ .../extensions/external_pref_extension_provider.cc | 84 ++++++ .../extensions/external_pref_extension_provider.h | 33 +++ .../external_registry_extension_provider_win.cc | 88 ++++++ .../external_registry_extension_provider_win.h | 30 +++ chrome/browser/profile.cc | 3 +- chrome/chrome.gyp | 5 + 10 files changed, 583 insertions(+), 236 deletions(-) create mode 100644 chrome/browser/extensions/external_extension_provider.h create mode 100644 chrome/browser/extensions/external_pref_extension_provider.cc create mode 100644 chrome/browser/extensions/external_pref_extension_provider.h create mode 100644 chrome/browser/extensions/external_registry_extension_provider_win.cc create mode 100644 chrome/browser/extensions/external_registry_extension_provider_win.h diff --git a/chrome/browser/extensions/extensions_service.cc b/chrome/browser/extensions/extensions_service.cc index 94c1dd5..487d617 100644 --- a/chrome/browser/extensions/extensions_service.cc +++ b/chrome/browser/extensions/extensions_service.cc @@ -22,6 +22,8 @@ #include "chrome/browser/chrome_thread.h" #include "chrome/browser/extensions/extension_browser_event_router.h" #include "chrome/browser/extensions/extension_process_manager.h" +#include "chrome/browser/extensions/external_extension_provider.h" +#include "chrome/browser/extensions/external_pref_extension_provider.h" #include "chrome/browser/profile.h" #include "chrome/browser/utility_process_host.h" #include "chrome/common/chrome_switches.h" @@ -40,8 +42,8 @@ #if defined(OS_WIN) #include "app/win_util.h" -#include "base/registry.h" #include "base/win_util.h" +#include "chrome/browser/extensions/external_registry_extension_provider_win.h" #endif // ExtensionsService. @@ -60,25 +62,6 @@ const wchar_t kExternalExtensionsPref[] = L"extensions.settings"; const wchar_t kLocation[] = L"location"; const wchar_t kState[] = L"state"; -// Registry key where registry defined extension installers live. -// TODO(port): Assuming this becomes a similar key into the appropriate -// platform system. -const char kRegistryExtensions[] = "Software\\Google\\Chrome\\Extensions"; - -#if defined(OS_WIN) - -// Registry value of of that key that defines the path to the .crx file. -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"; - -#endif - -// A marker file to indicate that an extension was installed from an external -// source. -const char kExternalInstallFile[] = "EXTERNAL_INSTALL"; - // A temporary subdirectory where we unpack extensions. const char* kUnpackExtensionDir = "TEMP_UNPACK"; @@ -216,19 +199,21 @@ class ExtensionsServiceBackend::UnpackerClient ExtensionsService::ExtensionsService(Profile* profile, MessageLoop* frontend_loop, - MessageLoop* backend_loop, - const std::string& registry_path) + MessageLoop* backend_loop) : prefs_(profile->GetPrefs()), backend_loop_(backend_loop), install_directory_(profile->GetPath().AppendASCII(kInstallDirectoryName)), extensions_enabled_( CommandLine::ForCurrentProcess()-> HasSwitch(switches::kEnableExtensions)), - show_extensions_prompts_(true), - backend_(new ExtensionsServiceBackend( - install_directory_, g_browser_process->resource_dispatcher_host(), - frontend_loop, registry_path)) { + show_extensions_prompts_(true) { + // We pass ownership of this object to the Backend. + DictionaryValue* external_extensions = new DictionaryValue; prefs_->RegisterDictionaryPref(kExternalExtensionsPref); + GetExternalExtensions(external_extensions, NULL); + backend_ = new ExtensionsServiceBackend( + install_directory_, g_browser_process->resource_dispatcher_host(), + frontend_loop, external_extensions); } ExtensionsService::~ExtensionsService() { @@ -252,7 +237,6 @@ bool ExtensionsService::Init() { backend_loop_->PostTask(FROM_HERE, NewRunnableMethod(backend_.get(), &ExtensionsServiceBackend::CheckForExternalUpdates, *killed_extensions.get(), - external_extensions.get(), scoped_refptr(this))); backend_loop_->PostTask(FROM_HERE, NewRunnableMethod(backend_.get(), @@ -322,7 +306,7 @@ void ExtensionsService::OnExtensionsLoaded(ExtensionList* new_extensions) { // Filter out any extensions we don't want to enable. Themes are always // enabled, but other extensions are only loaded if --enable-extensions is // present. - ExtensionList enabled_extensions; + ExtensionList enabled_extensions; for (ExtensionList::iterator iter = new_extensions->begin(); iter != new_extensions->end(); ++iter) { if (extensions_enabled() || (*iter)->IsTheme()) { @@ -340,7 +324,7 @@ void ExtensionsService::OnExtensionsLoaded(ExtensionList* new_extensions) { DictionaryValue* pref = GetOrCreateExtensionPref(extension_id); int location; int state; - + // Ensure all loaded extensions have a preference set. This deals with a // legacy problem where some extensions were installed before we were // storing state in the preferences. @@ -469,6 +453,18 @@ DictionaryValue* ExtensionsService::GetOrCreateExtensionPref( return extension; } +void ExtensionsService::ClearProvidersForTesting() { + backend_loop_->PostTask(FROM_HERE, NewRunnableMethod(backend_.get(), + &ExtensionsServiceBackend::ClearProvidersForTesting)); +} + +void ExtensionsService::SetProviderForTesting( + Extension::Location location, ExternalExtensionProvider* test_provider) { + backend_loop_->PostTask(FROM_HERE, NewRunnableMethod(backend_.get(), + &ExtensionsServiceBackend::SetProviderForTesting, + location, test_provider)); +} + bool ExtensionsService::UpdateExtensionPref(const std::wstring& extension_id, const std::wstring& key, Value* data_value, @@ -489,17 +485,23 @@ bool ExtensionsService::UpdateExtensionPref(const std::wstring& extension_id, ExtensionsServiceBackend::ExtensionsServiceBackend( const FilePath& install_directory, ResourceDispatcherHost* rdh, - MessageLoop* frontend_loop, const std::string& registry_path) + MessageLoop* frontend_loop, DictionaryValue* extension_prefs) : frontend_(NULL), install_directory_(install_directory), resource_dispatcher_host_(rdh), alert_on_error_(false), - frontend_loop_(frontend_loop), - registry_path_(registry_path) { - // Default the registry path if unspecified. - if (registry_path_.empty()) { - registry_path_ = kRegistryExtensions; - } + frontend_loop_(frontend_loop) { + external_extension_providers_[Extension::EXTERNAL_PREF] = + new ExternalPrefExtensionProvider(extension_prefs); +#if defined(OS_WIN) + external_extension_providers_[Extension::EXTERNAL_REGISTRY] = + new ExternalRegistryExtensionProvider(); +#endif +} + +ExtensionsServiceBackend::~ExtensionsServiceBackend() { + STLDeleteContainerPairSecondPointers(external_extension_providers_.begin(), + external_extension_providers_.end()); } void ExtensionsServiceBackend::LoadExtensionsFromInstallDirectory( @@ -539,7 +541,7 @@ void ExtensionsServiceBackend::LoadExtensionsFromInstallDirectory( // Find all child directories in the install directory and load their // manifests. Post errors and results to the frontend. file_util::FileEnumerator enumerator(install_directory_, - false, // not recursive + false, // Not recursive. file_util::FileEnumerator::DIRECTORIES); FilePath extension_path; for (extension_path = enumerator.Next(); !extension_path.value().empty(); @@ -567,17 +569,21 @@ void ExtensionsServiceBackend::LoadExtensionsFromInstallDirectory( if (!ReadCurrentVersion(extension_path, ¤t_version)) continue; - int location; + Extension::Location location = Extension::INVALID; + int location_value; DictionaryValue* pref = NULL; external_extensions->GetDictionary(ASCIIToWide(extension_id), &pref); if (!pref || - !pref->GetInteger(kLocation, &location)) { - location = Extension::INTERNAL; + !pref->GetInteger(kLocation, &location_value)) { + // Check with the external providers. + if (!LookupExternalExtension(extension_id, NULL, &location)) + location = Extension::INTERNAL; + } else { + location = static_cast(location_value); } - Extension::Location ext_location = - static_cast(location); + FilePath version_path = extension_path.AppendASCII(current_version); - if (Extension::IsExternalLocation(ext_location) && + if (Extension::IsExternalLocation(location) && CheckExternalUninstall(external_extensions.get(), version_path, extension_id)) { // TODO(erikkay): Possibly defer this operation to avoid slowing initial @@ -589,7 +595,9 @@ void ExtensionsServiceBackend::LoadExtensionsFromInstallDirectory( continue; } - Extension* extension = LoadExtension(version_path, true); // require id + Extension* extension = LoadExtension(version_path, + location, + true); // require id if (extension) extensions->push_back(extension); } @@ -613,9 +621,9 @@ void ExtensionsServiceBackend::LoadSingleExtension( WideToASCII(extension_path.BaseName().ToWStringHack()); Extension* extension = LoadExtension(extension_path, + Extension::LOAD, false); // don't require ID if (extension) { - extension->set_location(Extension::LOAD); ExtensionList* extensions = new ExtensionList; extensions->push_back(extension); ReportExtensionsLoaded(extensions); @@ -623,7 +631,9 @@ void ExtensionsServiceBackend::LoadSingleExtension( } Extension* ExtensionsServiceBackend::LoadExtension( - const FilePath& extension_path, bool require_id) { + const FilePath& extension_path, + Extension::Location location, + bool require_id) { FilePath manifest_path = extension_path.AppendASCII(Extension::kManifestFilename); if (!file_util::PathExists(manifest_path)) { @@ -651,13 +661,7 @@ Extension* ExtensionsServiceBackend::LoadExtension( return NULL; } - FilePath external_marker = extension_path.AppendASCII(kExternalInstallFile); - if (file_util::PathExists(external_marker)) { - extension->set_location( - extension->ExternalExtensionInstallType(registry_path_)); - } else { - extension->set_location(Extension::INTERNAL); - } + extension->set_location(location); // Theme resource validation. if (extension->IsTheme()) { @@ -909,7 +913,7 @@ void ExtensionsServiceBackend::OnExtensionUnpacked( } #if defined(OS_WIN) - if (!extension.IsTheme() && + if (!extension.IsTheme() && !from_external && frontend_->show_extensions_prompts() && win_util::MessageBox(GetActiveWindow(), L"Are you sure you want to install this extension?\n\n" @@ -1020,14 +1024,11 @@ void ExtensionsServiceBackend::OnExtensionUnpacked( if (!SetCurrentVersion(dest_dir, version)) return; - // To mark that this extension was installed from an external source, create a - // zero-length file. At load time, this is used to indicate that the - // extension should be uninstalled. - // TODO(erikkay): move this into per-extension config storage when it appears. - if (from_external) { - FilePath marker = version_dir.AppendASCII(kExternalInstallFile); - file_util::WriteFile(marker, NULL, 0); - } + Extension::Location location = Extension::INVALID; + if (from_external) + LookupExternalExtension(extension.id(), NULL, &location); + else + location = Extension::INTERNAL; // Load the extension immediately and then report installation success. We // don't load extensions for external installs because external installation @@ -1036,7 +1037,9 @@ void ExtensionsServiceBackend::OnExtensionUnpacked( // the preferences for these extensions to reflect that they've just been // installed. if (!from_external) { - Extension* extension = LoadExtension(version_dir, true); // require id + Extension* extension = LoadExtension(version_dir, + location, + true); // require id CHECK(extension); frontend_loop_->PostTask(FROM_HERE, NewRunnableMethod( @@ -1053,8 +1056,7 @@ void ExtensionsServiceBackend::OnExtensionUnpacked( } else { frontend_loop_->PostTask(FROM_HERE, NewRunnableMethod( frontend_, &ExtensionsService::OnExternalExtensionInstalled, - extension.id(), - extension.ExternalExtensionInstallType(registry_path_))); + extension.id(), location)); } scoped_version_dir.Take(); @@ -1088,12 +1090,28 @@ bool ExtensionsServiceBackend::ShouldSkipInstallingExtension( } void ExtensionsServiceBackend::CheckVersionAndInstallExtension( - const std::string& id, const std::string& extension_version, + const std::string& id, const Version* extension_version, const FilePath& extension_path, bool from_external) { if (ShouldInstall(id, extension_version)) InstallOrUpdateExtension(FilePath(extension_path), id, from_external); } +bool ExtensionsServiceBackend::LookupExternalExtension( + const std::string& id, Version** version, Extension::Location* location) { + scoped_ptr extension_version; + for (ProviderMap::const_iterator i = external_extension_providers_.begin(); + i != external_extension_providers_.end(); ++i) { + const ExternalExtensionProvider* provider = i->second; + extension_version.reset(provider->RegisteredVersion(id, location)); + if (extension_version.get()) { + if (version) + *version = extension_version.release(); + return true; + } + } + return false; +} + // 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 @@ -1102,7 +1120,6 @@ void ExtensionsServiceBackend::CheckVersionAndInstallExtension( // a new version is available. void ExtensionsServiceBackend::CheckForExternalUpdates( std::set ids_to_ignore, - DictionaryValue* extension_prefs, scoped_refptr frontend) { // Note that this installation is intentionally silent (since it didn't // go through the front-end). Extensions that are registered in this @@ -1112,115 +1129,43 @@ void ExtensionsServiceBackend::CheckForExternalUpdates( alert_on_error_ = false; frontend_ = frontend; - for (DictionaryValue::key_iterator i = extension_prefs->begin_keys(); - i != extension_prefs->end_keys(); ++i) { - const std::wstring& extension_id = *i; - if (ShouldSkipInstallingExtension(ids_to_ignore, WideToASCII(extension_id))) - continue; - - DictionaryValue* extension = NULL; - if (!extension_prefs->GetDictionary(extension_id, &extension)) { - NOTREACHED() << "Cannot read extension " << extension_id.c_str() - << " from dictionary."; - continue; - } - - int location; - if (extension->GetInteger(kLocation, &location) && - location != Extension::EXTERNAL_PREF) { - continue; - } - int state; - if (extension->GetInteger(kState, &state) && - state == Extension::KILLBIT) { - continue; - } - - FilePath::StringType external_crx; - std::string external_version; - if (!extension->GetString(L"external_crx", &external_crx) || - !extension->GetString(L"external_version", &external_version)) { - LOG(WARNING) << "Malformed extension dictionary for extension: " - << extension_id.c_str(); - continue; - } - - bool from_external = true; - CheckVersionAndInstallExtension(WideToASCII(extension_id), external_version, - FilePath(external_crx), from_external); - } - -#if defined(OS_WIN) - // TODO(port): Pull this out into an interface. That will also allow us to - // test the behavior of external extensions. - HKEY reg_root = HKEY_LOCAL_MACHINE; - RegistryKeyIterator iterator(reg_root, ASCIIToWide(registry_path_).c_str()); - while (iterator.Valid()) { - // Fold - std::string id = StringToLowerASCII(WideToASCII(iterator.Name())); - if (ShouldSkipInstallingExtension(ids_to_ignore, id)) { - ++iterator; - continue; - } - - RegKey key; - std::wstring key_path = ASCIIToWide(registry_path_); - key_path.append(L"\\"); - key_path.append(iterator.Name()); - if (key.Open(reg_root, key_path.c_str())) { - std::wstring extension_path; - if (key.ReadValue(kRegistryExtensionPath, &extension_path)) { - std::wstring extension_version; - if (key.ReadValue(kRegistryExtensionVersion, &extension_version)) { - bool from_external = true; - CheckVersionAndInstallExtension( - id, WideToASCII(extension_version), FilePath(extension_path), - from_external); - } else { - // TODO(erikkay): find a way to get this into about:extensions - LOG(WARNING) << "Missing value " << kRegistryExtensionVersion << - " for key " << key_path; - } - } else { - // TODO(erikkay): find a way to get this into about:extensions - LOG(WARNING) << "Missing value " << kRegistryExtensionPath << - " for key " << key_path; - } - } - ++iterator; + // Ask each external extension provider to give us a call back for each + // extension they know about. See OnExternalExtensionFound. + for (ProviderMap::const_iterator i = external_extension_providers_.begin(); + i != external_extension_providers_.end(); ++i) { + ExternalExtensionProvider* provider = i->second; + provider->VisitRegisteredExtension(this, ids_to_ignore); } -#endif } bool ExtensionsServiceBackend::CheckExternalUninstall( DictionaryValue* extension_prefs, const FilePath& version_path, const std::string& id) { // First check the preferences for the kill-bit. - int location = Extension::INVALID; + int location_value = Extension::INVALID; DictionaryValue* extension = NULL; - if (extension_prefs->GetDictionary(ASCIIToWide(id), &extension)) { - int state; - if (extension->GetInteger(kLocation, &location) && - location == Extension::EXTERNAL_PREF) { - return extension->GetInteger(kState, &state) && - state == Extension::KILLBIT; - } + if (!extension_prefs->GetDictionary(ASCIIToWide(id), &extension)) + return false; + int state; + if (extension->GetInteger(kLocation, &location_value) && + location_value == Extension::EXTERNAL_PREF) { + return extension->GetInteger(kState, &state) && + state == Extension::KILLBIT; } -#if defined(OS_WIN) - if (location == Extension::EXTERNAL_REGISTRY) { - HKEY reg_root = HKEY_LOCAL_MACHINE; - RegKey key; - std::wstring key_path = ASCIIToWide(registry_path_); - key_path.append(L"\\"); - key_path.append(ASCIIToWide(id)); - - // If the key doesn't exist, then we should uninstall. - return !key.Open(reg_root, key_path.c_str()); + Extension::Location location = + static_cast(location_value); + + // Check if the providers know about this extension. + ProviderMap::const_iterator i = external_extension_providers_.find(location); + if (i != external_extension_providers_.end()) { + scoped_ptr version; + version.reset(i->second->RegisteredVersion(id, NULL)); + if (version.get()) + return false; // Yup, known extension, don't uninstall. } -#endif - return false; + return true; // This is not a known extension, uninstall. } // Assumes that the extension isn't currently loaded or in use. @@ -1248,7 +1193,7 @@ void ExtensionsServiceBackend::UninstallExtension( } } - // Ok, now try and delete the entire rest of the directory. One major place + // OK, now try and delete the entire rest of the directory. One major place // this can fail is if the extension contains a plugin (stupid plugins). It's // not a big deal though, because we'll notice next time we startup that the // Current Version file is gone and finish the delete then. @@ -1258,12 +1203,28 @@ void ExtensionsServiceBackend::UninstallExtension( } } +void ExtensionsServiceBackend::ClearProvidersForTesting() { + external_extension_providers_.clear(); +} + +void ExtensionsServiceBackend::SetProviderForTesting( + Extension::Location location, + ExternalExtensionProvider* test_provider) { + DCHECK(test_provider); + external_extension_providers_[location] = test_provider; +} + +void ExtensionsServiceBackend::OnExternalExtensionFound( + const std::string& id, const Version* version, const FilePath& path) { + bool from_external = true; + CheckVersionAndInstallExtension(id, version, path, from_external); +} + bool ExtensionsServiceBackend::ShouldInstall(const std::string& id, - const std::string& version) { + const Version* version) { FilePath dir(install_directory_.AppendASCII(id.c_str())); std::string current_version; - if (ReadCurrentVersion(dir, ¤t_version)) { - return CheckCurrentVersion(version, current_version, dir); - } + if (ReadCurrentVersion(dir, ¤t_version)) + return CheckCurrentVersion(version->GetString(), current_version, dir); return true; } diff --git a/chrome/browser/extensions/extensions_service.h b/chrome/browser/extensions/extensions_service.h index f72a63a..fb0feaf 100644 --- a/chrome/browser/extensions/extensions_service.h +++ b/chrome/browser/extensions/extensions_service.h @@ -5,6 +5,7 @@ #ifndef CHROME_BROWSER_EXTENSIONS_EXTENSIONS_SERVICE_H_ #define CHROME_BROWSER_EXTENSIONS_EXTENSIONS_SERVICE_H_ +#include #include #include #include @@ -15,6 +16,7 @@ #include "base/ref_counted.h" #include "base/task.h" #include "base/values.h" +#include "chrome/browser/extensions/external_extension_provider.h" #include "chrome/common/chrome_switches.h" #include "chrome/common/extensions/extension.h" @@ -38,8 +40,7 @@ class ExtensionsService public: ExtensionsService(Profile* profile, MessageLoop* frontend_loop, - MessageLoop* backend_loop, - const std::string& registry_path); + MessageLoop* backend_loop); ~ExtensionsService(); // Gets the list of currently installed extensions. @@ -86,6 +87,14 @@ class ExtensionsService Value* data_value, bool schedule_save); + // Clear all ExternalExtensionProviders. + void ClearProvidersForTesting(); + + // Sets an ExternalExtensionProvider for the service to use during testing. + // |location| specifies what type of provider should be added. + void SetProviderForTesting(Extension::Location location, + ExternalExtensionProvider* test_provider); + // The name of the file that the current active version number is stored in. static const char* kCurrentVersionFileName; @@ -148,15 +157,18 @@ class ExtensionsService // Implements IO for the ExtensionsService. // TODO(aa): This can probably move into the .cc file. class ExtensionsServiceBackend - : public base::RefCountedThreadSafe { + : public base::RefCountedThreadSafe, + public ExternalExtensionProvider::Visitor { public: // |rdh| can be NULL in the case of test environment. - // |registry_path| can be NULL *except* in the case of the test environment, - // where it is specified to a temp location. + // |extension_prefs| contains a dictionary value that points to the extension + // preferences. ExtensionsServiceBackend(const FilePath& install_directory, - ResourceDispatcherHost* rdh, - MessageLoop* frontend_loop, - const std::string& registry_path); + ResourceDispatcherHost* rdh, + MessageLoop* frontend_loop, + DictionaryValue* extension_prefs); + + virtual ~ExtensionsServiceBackend(); // Loads extensions from the install directory. The extensions are assumed to // be unpacked in directories that are direct children of the specified path. @@ -186,7 +198,6 @@ class ExtensionsServiceBackend // Errors are reported through ExtensionErrorReporter. Succcess is not // reported. void CheckForExternalUpdates(std::set ids_to_ignore, - DictionaryValue* extension_prefs, scoped_refptr frontend); // Deletes all versions of the extension from the filesystem. Note that only @@ -194,13 +205,27 @@ class ExtensionsServiceBackend // uninstall other extensions will silently fail. void UninstallExtension(const std::string& extension_id); + // Clear all ExternalExtensionProviders. + void ClearProvidersForTesting(); + + // Sets an ExternalExtensionProvider for the service to use during testing. + // |location| specifies what type of provider should be added. + void SetProviderForTesting(Extension::Location location, + ExternalExtensionProvider* test_provider); + + // ExternalExtensionProvider::Visitor implementation. + virtual void OnExternalExtensionFound(const std::string& id, + const Version* version, + const FilePath& path); private: class UnpackerClient; friend class UnpackerClient; // Load a single extension from |extension_path|, the top directory of // a specific extension where its manifest file lives. - Extension* LoadExtension(const FilePath& extension_path, bool require_id); + Extension* LoadExtension(const FilePath& extension_path, + Extension::Location location, + bool require_id); // Load a single extension from |extension_path|, the top directory of // a versioned extension where its Current Version file lives. @@ -251,10 +276,20 @@ class ExtensionsServiceBackend // Installs the extension if the extension is a newer version or if the // extension hasn't been installed before. void CheckVersionAndInstallExtension(const std::string& id, - const std::string& extension_version, + const Version* extension_version, const FilePath& extension_path, bool from_external); + // Lookup an external extension by |id| by going through all registered + // external extension providers until we find a provider that contains an + // extension that matches. If |version| is not NULL, the extension version + // will be returned (caller is responsible for deleting that pointer). + // |location| can also be null, if not needed. Returns true if extension is + // found, false otherwise. + bool LookupExternalExtension(const std::string& id, + Version** version, + Extension::Location* location); + // Read the manifest from the front of the extension file. // Caller takes ownership of return value. DictionaryValue* ReadManifest(const FilePath& extension_path); @@ -286,7 +321,7 @@ class ExtensionsServiceBackend // Should an extension of |id| and |version| be installed? // Returns true if no extension of type |id| is installed or if |version| // is greater than the current installed version. - bool ShouldInstall(const std::string& id, const std::string& version); + bool ShouldInstall(const std::string& id, const Version* version); // The name of a temporary directory to install an extension into for // validation before finalizing install. @@ -308,10 +343,9 @@ class ExtensionsServiceBackend // The message loop to use to call the frontend. MessageLoop* frontend_loop_; - // The path to look for externally registered extensions in. This is a - // registry key on windows, but it could be a similar string for the - // appropriate system on other platforms in the future. - std::string registry_path_; + // A map of all external extension providers. + typedef std::map ProviderMap; + ProviderMap external_extension_providers_; DISALLOW_COPY_AND_ASSIGN(ExtensionsServiceBackend); }; diff --git a/chrome/browser/extensions/extensions_service_unittest.cc b/chrome/browser/extensions/extensions_service_unittest.cc index ef41940..1411d78 100644 --- a/chrome/browser/extensions/extensions_service_unittest.cc +++ b/chrome/browser/extensions/extensions_service_unittest.cc @@ -14,6 +14,7 @@ #include "base/time.h" #include "chrome/browser/extensions/extension_creator.h" #include "chrome/browser/extensions/extensions_service.h" +#include "chrome/browser/extensions/external_extension_provider.h" #include "chrome/common/extensions/extension.h" #include "chrome/common/extensions/url_pattern.h" #include "chrome/common/chrome_paths.h" @@ -27,10 +28,6 @@ #include "testing/gtest/include/gtest/gtest.h" #include "testing/platform_test.h" -#if defined(OS_WIN) -#include "base/registry.h" -#endif - namespace { // Extension ids used during testing. @@ -71,6 +68,54 @@ static std::vector GetErrors() { } // namespace +class MockExtensionProvider : public ExternalExtensionProvider { + public: + explicit MockExtensionProvider(Extension::Location location) + : location_(location) {} + virtual ~MockExtensionProvider() {} + + void UpdateOrAddExtension(const std::string& id, + const std::string& version, + FilePath path) { + extension_map_[id] = std::make_pair(version, path); + } + + void RemoveExtension(const std::string& id) { + extension_map_.erase(id); + } + + // ExternalExtensionProvider implementation: + virtual void VisitRegisteredExtension( + Visitor* visitor, const std::set& ids_to_ignore) const { + for (DataMap::const_iterator i = extension_map_.begin(); + i != extension_map_.end(); ++i) { + if (ids_to_ignore.find(i->first) != ids_to_ignore.end()) + continue; + scoped_ptr version; + version.reset(Version::GetVersionFromString(i->second.first)); + + visitor->OnExternalExtensionFound( + i->first, version.get(), i->second.second); + } + } + + virtual Version* RegisteredVersion(std::string id, + Extension::Location* location) const { + DataMap::const_iterator it = extension_map_.find(id); + if (it == extension_map_.end()) + return NULL; + + if (location) + *location = location_; + return Version::GetVersionFromString(it->second.first); + } + + private: + typedef std::map< std::string, std::pair > DataMap; + DataMap extension_map_; + Extension::Location location_; +}; + class ExtensionsServiceTest : public testing::Test, public NotificationObserver { public: @@ -84,16 +129,18 @@ class ExtensionsServiceTest registrar_.Add(this, NotificationType::THEME_INSTALLED, NotificationService::AllSources()); - // Create a temporary area in the registry to test external extensions. - registry_path_ = "Software\\Google\\Chrome\\ExtensionsServiceTest_"; - registry_path_ += IntToString( - static_cast(base::Time::Now().ToDoubleT())); - profile_.reset(new TestingProfile()); - service_ = new ExtensionsService(profile_.get(), &loop_, &loop_, - registry_path_); + service_ = new ExtensionsService(profile_.get(), &loop_, &loop_); service_->set_extensions_enabled(true); service_->set_show_extensions_prompts(false); + + // When we start up, we want to make sure there is no external provider, + // since the ExtensionService on Windows will use the Registry as a default + // provider and if there is something already registered there then it will + // interfere with the tests. Those tests that need an external provider + // will register one specifically. + service_->ClearProvidersForTesting(); + total_successes_ = 0; } @@ -139,6 +186,11 @@ class ExtensionsServiceTest service_->set_extensions_enabled(enabled); } + void SetMockExternalProvider(Extension::Location location, + ExternalExtensionProvider* provider) { + service_->SetProviderForTesting(location, provider); + } + protected: void InstallExtension(const FilePath& path, bool should_succeed) { @@ -151,7 +203,7 @@ class ExtensionsServiceTest EXPECT_TRUE(installed_) << path.value(); - EXPECT_EQ(1u, loaded_.size()) << path.value(); + ASSERT_EQ(1u, loaded_.size()) << path.value(); EXPECT_EQ(0u, errors.size()) << path.value(); EXPECT_EQ(total_successes_, service_->extensions()->size()) << path.value(); @@ -200,6 +252,23 @@ class ExtensionsServiceTest EXPECT_EQ(must_equal, val) << msg; } + void SetPref(std::string extension_id, std::wstring pref_path, int value) { + std::wstring msg = L" while setting: "; + msg += ASCIIToWide(extension_id); + msg += L" "; + msg += pref_path; + msg += L" = "; + msg += IntToWString(value); + + const DictionaryValue* dict = + profile_->GetPrefs()->GetMutableDictionary(L"extensions.settings"); + ASSERT_TRUE(dict != NULL) << msg; + DictionaryValue* pref = NULL; + ASSERT_TRUE(dict->GetDictionary(ASCIIToWide(extension_id), &pref)) << msg; + EXPECT_TRUE(pref != NULL) << msg; + pref->SetInteger(pref_path, value); + } + protected: scoped_ptr profile_; scoped_refptr service_; @@ -208,7 +277,6 @@ class ExtensionsServiceTest std::vector loaded_; std::string unloaded_id_; Extension* installed_; - std::string registry_path_; private: NotificationRegistrar registrar_; @@ -457,9 +525,9 @@ TEST_F(ExtensionsServiceTest, PackExtension) { // Test Packaging and installing an extension using an openssl generated key. // The openssl is generated with the following: -// > openssl genrsa -out privkey.pem 1024 +// > openssl genrsa -out privkey.pem 1024 // > openssl pkcs8 -topk8 -nocrypt -in privkey.pem -out privkey_asn1.pem -// The privkey.pem is a PrivateKey, and the pcks8 -topk8 creates a +// The privkey.pem is a PrivateKey, and the pcks8 -topk8 creates a // PrivateKeyInfo ASN.1 structure, we our RSAPrivateKey expects. TEST_F(ExtensionsServiceTest, PackExtensionOpenSSLKey) { SetExtensionsEnabled(true); @@ -488,7 +556,7 @@ TEST_F(ExtensionsServiceTest, PackExtensionOpenSSLKey) { file_util::Delete(crx_path, false); } -#endif // defined(OS_WIN) +#endif // defined(OS_WIN) TEST_F(ExtensionsServiceTest, InstallTheme) { FilePath extensions_path; @@ -690,17 +758,23 @@ TEST_F(ExtensionsServiceTest, GenerateID) { #if defined(OS_WIN) TEST_F(ExtensionsServiceTest, ExternalInstallRegistry) { - // Register a test extension externally using the registry. + // Verify that starting with no providers loads no extensions. + service_->Init(); + loop_.RunAllPending(); + ASSERT_EQ(0u, loaded_.size()); + + // Now add providers. Extension system takes ownership of the objects. + MockExtensionProvider* reg_provider = + new MockExtensionProvider(Extension::EXTERNAL_REGISTRY); + SetMockExternalProvider(Extension::EXTERNAL_REGISTRY, reg_provider); + + // Register a test extension externally using the mock registry provider. FilePath source_path; ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &source_path)); source_path = source_path.AppendASCII("extensions").AppendASCII("good.crx"); - RegKey key; - std::wstring reg_path = ASCIIToWide(registry_path_); - reg_path += L"\\00123456789ABCDEF0123456789ABCDEF0123456"; - ASSERT_TRUE(key.Create(HKEY_LOCAL_MACHINE, reg_path.c_str(), KEY_WRITE)); - ASSERT_TRUE(key.WriteValue(L"path", source_path.ToWStringHack().c_str())); - ASSERT_TRUE(key.WriteValue(L"version", L"1.0.0.0")); + // Add the extension. + reg_provider->UpdateOrAddExtension(good_crx, "1.0.0.0", source_path); // Start up the service, it should find our externally registered extension // and install it. @@ -728,8 +802,7 @@ TEST_F(ExtensionsServiceTest, ExternalInstallRegistry) { // Now update the extension with a new version. We should get upgraded. source_path = source_path.DirName().AppendASCII("good2.crx"); - ASSERT_TRUE(key.WriteValue(L"path", source_path.ToWStringHack().c_str())); - ASSERT_TRUE(key.WriteValue(L"version", L"1.0.0.1")); + reg_provider->UpdateOrAddExtension(good_crx, "1.0.0.1", source_path); loaded_.clear(); service_->Init(); @@ -762,13 +835,7 @@ TEST_F(ExtensionsServiceTest, ExternalInstallRegistry) { // Now clear the preference, reinstall, then remove the reg key. The extension // should be uninstalled. - std::wstring pref_path = L"extensions.settings."; - pref_path += ASCIIToWide(good_crx); - profile_->GetPrefs()->RegisterDictionaryPref(pref_path.c_str()); - DictionaryValue* extension_prefs; - extension_prefs = - profile_->GetPrefs()->GetMutableDictionary(pref_path.c_str()); - extension_prefs->SetInteger(L"state", 0); + SetPref(good_crx, L"state", Extension::ENABLED); profile_->GetPrefs()->ScheduleSavePersistentPrefs(); loaded_.clear(); @@ -779,9 +846,8 @@ TEST_F(ExtensionsServiceTest, ExternalInstallRegistry) { ValidatePref(good_crx, L"state", Extension::ENABLED); ValidatePref(good_crx, L"location", Extension::EXTERNAL_REGISTRY); - RegKey parent_key; - key.Open(HKEY_LOCAL_MACHINE, ASCIIToWide(registry_path_).c_str(), KEY_WRITE); - key.DeleteKey(ASCIIToWide(id).c_str()); + reg_provider->RemoveExtension(good_crx); + loaded_.clear(); service_->Init(); loop_.RunAllPending(); @@ -791,20 +857,23 @@ TEST_F(ExtensionsServiceTest, ExternalInstallRegistry) { #endif TEST_F(ExtensionsServiceTest, ExternalInstallPref) { + // Verify that starting with no providers loads no extensions. + service_->Init(); + loop_.RunAllPending(); + ASSERT_EQ(0u, loaded_.size()); + + // Now add providers. Extension system takes ownership of the objects. + MockExtensionProvider* pref_provider = + new MockExtensionProvider(Extension::EXTERNAL_PREF); + SetMockExternalProvider(Extension::EXTERNAL_PREF, pref_provider); + // Register a external extension using preinstalled preferences. FilePath source_path; ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &source_path)); source_path = source_path.AppendASCII("extensions").AppendASCII("good.crx"); - DictionaryValue* extension_prefs; - extension_prefs = - profile_->GetPrefs()->GetMutableDictionary(L"extensions.settings"); - - DictionaryValue* extension = new DictionaryValue(); - ASSERT_TRUE(extension->SetString(L"external_crx", - source_path.ToWStringHack())); - ASSERT_TRUE(extension->SetString(L"external_version", L"1.0")); - ASSERT_TRUE(extension_prefs->Set(ASCIIToWide(good_crx), extension)); + // Add the extension. + pref_provider->UpdateOrAddExtension(good_crx, "1.0", source_path); // Start up the service, it should find our externally registered extension // and install it. @@ -834,9 +903,7 @@ TEST_F(ExtensionsServiceTest, ExternalInstallPref) { // Now update the extension with a new version. We should get upgraded. source_path = source_path.DirName().AppendASCII("good2.crx"); - ASSERT_TRUE(extension->SetString(L"external_crx", - source_path.ToWStringHack())); - ASSERT_TRUE(extension->SetString(L"external_version", L"1.0.0.1")); + pref_provider->UpdateOrAddExtension(good_crx, "1.0.0.1", source_path); loaded_.clear(); service_->Init(); @@ -870,7 +937,7 @@ TEST_F(ExtensionsServiceTest, ExternalInstallPref) { ValidatePref(good_crx, L"location", Extension::EXTERNAL_PREF); // Now clear the preference and reinstall. - extension->SetInteger(L"state", Extension::ENABLED); + SetPref(good_crx, L"state", Extension::ENABLED); profile_->GetPrefs()->ScheduleSavePersistentPrefs(); loaded_.clear(); @@ -883,7 +950,7 @@ TEST_F(ExtensionsServiceTest, ExternalInstallPref) { ValidatePref(good_crx, L"location", Extension::EXTERNAL_PREF); // Now set the kill bit and watch the extension go away. - extension->SetInteger(L"state", Extension::KILLBIT); + SetPref(good_crx, L"state", Extension::KILLBIT); profile_->GetPrefs()->ScheduleSavePersistentPrefs(); loaded_.clear(); diff --git a/chrome/browser/extensions/external_extension_provider.h b/chrome/browser/extensions/external_extension_provider.h new file mode 100644 index 0000000..dafa665 --- /dev/null +++ b/chrome/browser/extensions/external_extension_provider.h @@ -0,0 +1,46 @@ +// 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_EXTENSION_PROVIDER_H_ +#define CHROME_BROWSER_EXTENSIONS_EXTERNAL_EXTENSION_PROVIDER_H_ + +#include +#include + +#include "base/version.h" +#include "chrome/common/extensions/extension.h" + +class FilePath; + +// This class is an abstract class for implementing external extensions +// providers. +class ExternalExtensionProvider { + 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 { + public: + virtual void OnExternalExtensionFound(const std::string& id, + const Version* version, + const FilePath& path) = 0; + }; + + virtual ~ExternalExtensionProvider() {} + + // 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 std::set& ids_to_ignore) const = 0; + + // Gets the version of extension with |id| and its |location|. |location| can + // be NULL. The caller is responsible for cleaning up the Version object + // returned. This function returns NULL if the extension is not found. + virtual Version* RegisteredVersion(std::string id, + Extension::Location* location) const = 0; +}; + +#endif // CHROME_BROWSER_EXTENSIONS_EXTERNAL_EXTENSION_PROVIDER_H_ diff --git a/chrome/browser/extensions/external_pref_extension_provider.cc b/chrome/browser/extensions/external_pref_extension_provider.cc new file mode 100644 index 0000000..6db3355 --- /dev/null +++ b/chrome/browser/extensions/external_pref_extension_provider.cc @@ -0,0 +1,84 @@ +// 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. + +#include "chrome/browser/extensions/external_pref_extension_provider.h" + +#include "base/file_path.h" +#include "base/string_util.h" +#include "base/version.h" + +// Constants for keeping track of extension preferences. +const wchar_t kLocation[] = L"location"; +const wchar_t kState[] = L"state"; +const wchar_t kExternalCrx[] = L"external_crx"; +const wchar_t kExternalVersion[] = L"external_version"; + +ExternalPrefExtensionProvider::ExternalPrefExtensionProvider( + DictionaryValue* prefs) { + DCHECK(prefs); + prefs_.reset(prefs); +} + +ExternalPrefExtensionProvider::~ExternalPrefExtensionProvider() { +} + +void ExternalPrefExtensionProvider::VisitRegisteredExtension( + Visitor* visitor, const std::set& ids_to_ignore) const { + for (DictionaryValue::key_iterator i = prefs_->begin_keys(); + i != prefs_->end_keys(); ++i) { + const std::wstring& extension_id = *i; + if (ids_to_ignore.find(WideToASCII(extension_id)) != ids_to_ignore.end()) + continue; + + DictionaryValue* extension = NULL; + if (!prefs_->GetDictionary(extension_id, &extension)) { + NOTREACHED() << "Cannot read extension " << extension_id.c_str() + << " from dictionary."; + continue; + } + + int location; + if (extension->GetInteger(kLocation, &location) && + location != Extension::EXTERNAL_PREF) { + continue; + } + int state; + if (extension->GetInteger(kState, &state) && + state == Extension::KILLBIT) { + continue; + } + + FilePath::StringType external_crx; + std::string external_version; + if (!extension->GetString(kExternalCrx, &external_crx) || + !extension->GetString(kExternalVersion, &external_version)) { + LOG(WARNING) << "Malformed extension dictionary for extension: " + << extension_id.c_str(); + continue; + } + + scoped_ptr version; + version.reset(Version::GetVersionFromString(external_version)); + visitor->OnExternalExtensionFound( + WideToASCII(extension_id), version.get(), FilePath(external_crx)); + } +} + +Version* ExternalPrefExtensionProvider::RegisteredVersion( + std::string id, Extension::Location* location) const { + DictionaryValue* extension = NULL; + if (!prefs_->GetDictionary(ASCIIToWide(id), &extension)) { + NOTREACHED() << "Cannot read extension " << id.c_str() + << " from dictionary."; + return NULL; + } + + std::string external_version; + if (!extension->GetString(kExternalVersion, &external_version)) + return NULL; + + if (location) + *location = Extension::EXTERNAL_PREF; + return Version::GetVersionFromString(external_version); +} diff --git a/chrome/browser/extensions/external_pref_extension_provider.h b/chrome/browser/extensions/external_pref_extension_provider.h new file mode 100644 index 0000000..a52be411 --- /dev/null +++ b/chrome/browser/extensions/external_pref_extension_provider.h @@ -0,0 +1,33 @@ +// 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_ + +#include +#include + +#include "chrome/browser/extensions/external_extension_provider.h" + +class DictionaryValue; +class Version; + +// A specialization of the ExternalExtensionProvider that uses preferences to +// look up which external extensions are registered. +class ExternalPrefExtensionProvider : public ExternalExtensionProvider { + public: + explicit ExternalPrefExtensionProvider(DictionaryValue* prefs); + virtual ~ExternalPrefExtensionProvider(); + + // ExternalExtensionProvider implementation: + virtual void VisitRegisteredExtension( + Visitor* visitor, const std::set& ids_to_ignore) const; + + virtual Version* RegisteredVersion(std::string id, + Extension::Location* location) const; + protected: + scoped_ptr prefs_; +}; + +#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_provider_win.cc new file mode 100644 index 0000000..f820be4 --- /dev/null +++ b/chrome/browser/extensions/external_registry_extension_provider_win.cc @@ -0,0 +1,88 @@ +// 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. + +#include "chrome/browser/extensions/external_registry_extension_provider_win.h" + +#include "base/file_path.h" +#include "base/registry.h" +#include "base/string_util.h" +#include "base/version.h" + +// The Registry hive where to look for external extensions. +const HKEY kRegRoot = HKEY_LOCAL_MACHINE; + +// The Registry subkey that contains information about external extensions. +const char kRegistryExtensions[] = "Software\\Google\\Chrome\\Extensions"; + +// Registry value of of that key that defines the path to the .crx file. +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"; + +ExternalRegistryExtensionProvider::ExternalRegistryExtensionProvider() { +} + +ExternalRegistryExtensionProvider::~ExternalRegistryExtensionProvider() { +} + +void ExternalRegistryExtensionProvider::VisitRegisteredExtension( + Visitor* visitor, const std::set& ids_to_ignore) const { + RegistryKeyIterator iterator(kRegRoot, + ASCIIToWide(kRegistryExtensions).c_str()); + while (iterator.Valid()) { + RegKey key; + std::wstring key_path = ASCIIToWide(kRegistryExtensions); + key_path.append(L"\\"); + key_path.append(iterator.Name()); + if (key.Open(kRegRoot, key_path.c_str())) { + std::wstring extension_path; + if (key.ReadValue(kRegistryExtensionPath, &extension_path)) { + std::wstring extension_version; + if (key.ReadValue(kRegistryExtensionVersion, &extension_version)) { + std::string id = WideToASCII(iterator.Name()); + StringToLowerASCII(&id); + if (ids_to_ignore.find(id) != ids_to_ignore.end()) { + ++iterator; + continue; + } + + scoped_ptr version; + version.reset(Version::GetVersionFromString(extension_version)); + FilePath path = FilePath::FromWStringHack(extension_path); + visitor->OnExternalExtensionFound(id, version.get(), path); + } else { + // TODO(erikkay): find a way to get this into about:extensions + LOG(WARNING) << "Missing value " << kRegistryExtensionVersion << + " for key " << key_path; + } + } else { + // TODO(erikkay): find a way to get this into about:extensions + LOG(WARNING) << "Missing value " << kRegistryExtensionPath << + " for key " << key_path; + } + } + ++iterator; + } +} + +Version* ExternalRegistryExtensionProvider::RegisteredVersion( + std::string id, + Extension::Location* location) const { + RegKey key; + std::wstring key_path = ASCIIToWide(kRegistryExtensions); + key_path.append(L"\\"); + key_path.append(ASCIIToWide(id)); + + if (!key.Open(kRegRoot, key_path.c_str())) + return NULL; + + std::wstring extension_version; + if (!key.ReadValue(kRegistryExtensionVersion, &extension_version)) + return NULL; + + if (location) + *location = Extension::EXTERNAL_REGISTRY; + return Version::GetVersionFromString(extension_version); +} diff --git a/chrome/browser/extensions/external_registry_extension_provider_win.h b/chrome/browser/extensions/external_registry_extension_provider_win.h new file mode 100644 index 0000000..88f472f --- /dev/null +++ b/chrome/browser/extensions/external_registry_extension_provider_win.h @@ -0,0 +1,30 @@ +// 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_ + +#include +#include + +#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 std::set& ids_to_ignore) const; + + virtual Version* RegisteredVersion(std::string id, + Extension::Location* location) const; +}; + +#endif // CHROME_BROWSER_EXTENSIONS_EXTERNAL_REGISTRY_EXTENSION_PROVIDER_WIN_H_ diff --git a/chrome/browser/profile.cc b/chrome/browser/profile.cc index 1aed4ee..b19fb2d7 100644 --- a/chrome/browser/profile.cc +++ b/chrome/browser/profile.cc @@ -475,8 +475,7 @@ void ProfileImpl::InitExtensions() { script_dir); extensions_service_ = new ExtensionsService( this, MessageLoop::current(), - g_browser_process->file_thread()->message_loop(), - std::string()); // Use default registry path + g_browser_process->file_thread()->message_loop()); extensions_service_->Init(); } diff --git a/chrome/chrome.gyp b/chrome/chrome.gyp index 38881f1..583cafa 100644 --- a/chrome/chrome.gyp +++ b/chrome/chrome.gyp @@ -871,6 +871,11 @@ 'browser/extensions/extensions_service.h', 'browser/extensions/extensions_ui.cc', 'browser/extensions/extensions_ui.h', + 'browser/extensions/external_extension_provider.h', + 'browser/extensions/external_registry_extension_provider_win.cc', + 'browser/extensions/external_registry_extension_provider_win.h', + 'browser/extensions/external_pref_extension_provider.cc', + 'browser/extensions/external_pref_extension_provider.h', 'browser/extensions/user_script_master.cc', 'browser/extensions/user_script_master.h', 'browser/external_protocol_handler.cc', -- cgit v1.1