Move ExtensionsServiceBackend class into the .cc file.
(Note: This was a TODO for Aaron).
BUG=None
TEST=trybots
Review URL: http://codereview.chromium.org/3429003
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@59613 0039d316-1c4b-4281-b951-d872f2087c98
diff --git a/chrome/browser/extensions/extensions_service.cc b/chrome/browser/extensions/extensions_service.cc
index b71e7859..f1cae3c 100644
--- a/chrome/browser/extensions/extensions_service.cc
+++ b/chrome/browser/extensions/extensions_service.cc
@@ -173,6 +173,328 @@
} // namespace
+// Implements IO for the ExtensionsService.
+
+class ExtensionsServiceBackend
+ : public base::RefCountedThreadSafe<ExtensionsServiceBackend>,
+ public ExternalExtensionProvider::Visitor {
+ public:
+ // |rdh| can be NULL in the case of test environment.
+ // |extension_prefs| contains a dictionary value that points to the extension
+ // preferences.
+ explicit ExtensionsServiceBackend(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.
+ // Errors are reported through ExtensionErrorReporter. On success,
+ // OnExtensionLoaded() is called.
+ // TODO(erikkay): It might be useful to be able to load a packed extension
+ // (presumably into memory) without installing it.
+ void LoadSingleExtension(const FilePath &path,
+ scoped_refptr<ExtensionsService> frontend);
+
+ // Check externally updated extensions for updates and install if necessary.
+ // Errors are reported through ExtensionErrorReporter. Succcess is not
+ // reported.
+ void CheckForExternalUpdates(std::set<std::string> ids_to_ignore,
+ scoped_refptr<ExtensionsService> 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<ExtensionsService> frontend,
+ const std::string& id,
+ Extension::Location location);
+
+ // 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 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,
+ bool enable_incognito_on_install);
+
+ // Reloads the given extensions from their manifests on disk (instead of what
+ // we have cached in the prefs).
+ void ReloadExtensionManifests(
+ ExtensionPrefs::ExtensionsInfo* extensions_to_reload,
+ base::TimeTicks start_time,
+ scoped_refptr<ExtensionsService> frontend);
+
+ private:
+ friend class base::RefCountedThreadSafe<ExtensionsServiceBackend>;
+
+ virtual ~ExtensionsServiceBackend();
+
+ // Finish installing the extension in |crx_path| after it has been unpacked to
+ // |unpacked_path|. If |expected_id| is not empty, it's verified against the
+ // extension's manifest before installation. If |silent| is true, there will
+ // be no install confirmation dialog. |from_gallery| indicates whether the
+ // crx was installed from our gallery, which results in different UI.
+ //
+ // Note: We take ownership of |extension|.
+ void OnExtensionUnpacked(const FilePath& crx_path,
+ const FilePath& unpacked_path,
+ Extension* extension,
+ const std::string expected_id);
+
+ // Notify the frontend that there was an error loading an extension.
+ void ReportExtensionLoadError(const FilePath& extension_path,
+ const std::string& error);
+
+ // 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);
+
+ // This is a naked pointer which is set by each entry point.
+ // The entry point is responsible for ensuring lifetime.
+ ExtensionsService* frontend_;
+
+ // The top-level extensions directory being installed to.
+ FilePath install_directory_;
+
+ // Whether errors result in noisy alerts.
+ bool alert_on_error_;
+
+ // A map of all external extension providers.
+ typedef std::map<Extension::Location,
+ linked_ptr<ExternalExtensionProvider> > ProviderMap;
+ ProviderMap 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_;
+
+ DISALLOW_COPY_AND_ASSIGN(ExtensionsServiceBackend);
+};
+
+ExtensionsServiceBackend::ExtensionsServiceBackend(
+ 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_[Extension::EXTERNAL_PREF] =
+ linked_ptr<ExternalExtensionProvider>(
+ new ExternalPrefExtensionProvider());
+#if defined(OS_WIN)
+ external_extension_providers_[Extension::EXTERNAL_REGISTRY] =
+ linked_ptr<ExternalExtensionProvider>(
+ new ExternalRegistryExtensionProvider());
+#endif
+}
+
+ExtensionsServiceBackend::~ExtensionsServiceBackend() {
+}
+
+void ExtensionsServiceBackend::LoadSingleExtension(
+ const FilePath& path_in, scoped_refptr<ExtensionsService> frontend) {
+ frontend_ = frontend;
+
+ // Explicit UI loads are always noisy.
+ alert_on_error_ = true;
+
+ FilePath extension_path = path_in;
+ file_util::AbsolutePath(&extension_path);
+
+ LOG(INFO) << "Loading single extension from " <<
+ extension_path.BaseName().value();
+
+ std::string error;
+ Extension* extension = extension_file_util::LoadExtension(
+ extension_path,
+ false, // Don't require id
+ &error);
+
+ if (!extension) {
+ ReportExtensionLoadError(extension_path, error);
+ return;
+ }
+
+ extension->set_location(Extension::LOAD);
+
+ // Report this as an installed extension so that it gets remembered in the
+ // prefs.
+ ChromeThread::PostTask(
+ ChromeThread::UI, FROM_HERE,
+ NewRunnableMethod(frontend_, &ExtensionsService::OnExtensionInstalled,
+ extension, true));
+}
+
+void ExtensionsServiceBackend::ReportExtensionLoadError(
+ const FilePath& extension_path, const std::string &error) {
+ ChromeThread::PostTask(
+ ChromeThread::UI, FROM_HERE,
+ NewRunnableMethod(
+ frontend_,
+ &ExtensionsService::ReportExtensionLoadError, extension_path,
+ error, NotificationType::EXTENSION_INSTALL_ERROR, alert_on_error_));
+}
+
+bool ExtensionsServiceBackend::LookupExternalExtension(
+ const std::string& id, Version** version, Extension::Location* location) {
+ scoped_ptr<Version> extension_version;
+ for (ProviderMap::const_iterator i = external_extension_providers_.begin();
+ i != external_extension_providers_.end(); ++i) {
+ const ExternalExtensionProvider* provider = i->second.get();
+ 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
+// (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 ExtensionsServiceBackend::CheckForExternalUpdates(
+ std::set<std::string> ids_to_ignore,
+ scoped_refptr<ExtensionsService> frontend) {
+ // 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.
+
+ for (ProviderMap::const_iterator i = external_extension_providers_.begin();
+ i != external_extension_providers_.end(); ++i) {
+ ExternalExtensionProvider* provider = i->second.get();
+ provider->VisitRegisteredExtension(this, ids_to_ignore);
+ }
+
+ if (external_extension_added_ && frontend->updater()) {
+ ChromeThread::PostTask(
+ ChromeThread::UI, FROM_HERE,
+ NewRunnableMethod(
+ frontend->updater(), &ExtensionUpdater::CheckNow));
+ }
+}
+
+void ExtensionsServiceBackend::CheckExternalUninstall(
+ scoped_refptr<ExtensionsService> frontend, const std::string& id,
+ Extension::Location location) {
+ // Check if the providers know about this extension.
+ ProviderMap::const_iterator i = external_extension_providers_.find(location);
+ if (i == external_extension_providers_.end()) {
+ NOTREACHED() << "CheckExternalUninstall called for non-external extension "
+ << location;
+ return;
+ }
+
+ scoped_ptr<Version> version;
+ version.reset(i->second->RegisteredVersion(id, NULL));
+ if (version.get())
+ return; // Yup, known extension, don't uninstall.
+
+ // This is an external extension that we don't have registered. Uninstall.
+ ChromeThread::PostTask(
+ ChromeThread::UI, FROM_HERE,
+ NewRunnableMethod(
+ frontend.get(), &ExtensionsService::UninstallExtension, id, true));
+}
+
+void ExtensionsServiceBackend::ClearProvidersForTesting() {
+ external_extension_providers_.clear();
+}
+
+void ExtensionsServiceBackend::SetProviderForTesting(
+ Extension::Location location,
+ ExternalExtensionProvider* test_provider) {
+ DCHECK(test_provider);
+ external_extension_providers_[location] =
+ linked_ptr<ExternalExtensionProvider>(test_provider);
+}
+
+void ExtensionsServiceBackend::OnExternalExtensionFileFound(
+ const std::string& id, const Version* version, const FilePath& path,
+ Extension::Location location) {
+ DCHECK(version);
+ ChromeThread::PostTask(
+ ChromeThread::UI, FROM_HERE,
+ NewRunnableMethod(
+ frontend_, &ExtensionsService::OnExternalExtensionFileFound, id,
+ version->GetString(), path, location));
+}
+
+void ExtensionsServiceBackend::OnExternalExtensionUpdateUrlFound(
+ const std::string& id,
+ const GURL& update_url,
+ bool enable_incognito_on_install) {
+ if (frontend_->GetExtensionById(id, true)) {
+ // Already installed. Do not change the update URL that the extension set.
+ return;
+ }
+
+ frontend_->AddPendingExtensionFromExternalUpdateUrl(id, update_url,
+ enable_incognito_on_install);
+ external_extension_added_ |= true;
+}
+
+void ExtensionsServiceBackend::ReloadExtensionManifests(
+ ExtensionPrefs::ExtensionsInfo* extensions_to_reload,
+ base::TimeTicks start_time,
+ scoped_refptr<ExtensionsService> frontend) {
+ frontend_ = frontend;
+
+ for (size_t i = 0; i < extensions_to_reload->size(); ++i) {
+ ExtensionInfo* info = extensions_to_reload->at(i).get();
+ if (!ShouldReloadExtensionManifest(*info))
+ continue;
+
+ // We need to reload original manifest in order to localize properly.
+ std::string error;
+ scoped_ptr<Extension> extension(extension_file_util::LoadExtension(
+ info->extension_path, false, &error));
+
+ if (extension.get())
+ extensions_to_reload->at(i)->extension_manifest.reset(
+ static_cast<DictionaryValue*>(
+ extension->manifest_value()->DeepCopy()));
+ }
+
+ // Finish installing on UI thread.
+ ChromeThread::PostTask(
+ ChromeThread::UI, FROM_HERE,
+ NewRunnableMethod(
+ frontend_,
+ &ExtensionsService::ContinueLoadAllExtensions,
+ extensions_to_reload,
+ start_time,
+ true));
+}
+
// static
bool ExtensionsService::IsDownloadFromGallery(const GURL& download_url,
const GURL& referrer_url) {
@@ -1485,215 +1807,3 @@
return false;
}
-
-// ExtensionsServicesBackend
-
-ExtensionsServiceBackend::ExtensionsServiceBackend(
- 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_[Extension::EXTERNAL_PREF] =
- linked_ptr<ExternalExtensionProvider>(
- new ExternalPrefExtensionProvider());
-#if defined(OS_WIN)
- external_extension_providers_[Extension::EXTERNAL_REGISTRY] =
- linked_ptr<ExternalExtensionProvider>(
- new ExternalRegistryExtensionProvider());
-#endif
-}
-
-ExtensionsServiceBackend::~ExtensionsServiceBackend() {
-}
-
-void ExtensionsServiceBackend::LoadSingleExtension(
- const FilePath& path_in, scoped_refptr<ExtensionsService> frontend) {
- frontend_ = frontend;
-
- // Explicit UI loads are always noisy.
- alert_on_error_ = true;
-
- FilePath extension_path = path_in;
- file_util::AbsolutePath(&extension_path);
-
- LOG(INFO) << "Loading single extension from " <<
- extension_path.BaseName().value();
-
- std::string error;
- Extension* extension = extension_file_util::LoadExtension(
- extension_path,
- false, // Don't require id
- &error);
-
- if (!extension) {
- ReportExtensionLoadError(extension_path, error);
- return;
- }
-
- extension->set_location(Extension::LOAD);
-
- // Report this as an installed extension so that it gets remembered in the
- // prefs.
- ChromeThread::PostTask(
- ChromeThread::UI, FROM_HERE,
- NewRunnableMethod(frontend_, &ExtensionsService::OnExtensionInstalled,
- extension, true));
-}
-
-void ExtensionsServiceBackend::ReportExtensionLoadError(
- const FilePath& extension_path, const std::string &error) {
- ChromeThread::PostTask(
- ChromeThread::UI, FROM_HERE,
- NewRunnableMethod(
- frontend_,
- &ExtensionsService::ReportExtensionLoadError, extension_path,
- error, NotificationType::EXTENSION_INSTALL_ERROR, alert_on_error_));
-}
-
-bool ExtensionsServiceBackend::LookupExternalExtension(
- const std::string& id, Version** version, Extension::Location* location) {
- scoped_ptr<Version> extension_version;
- for (ProviderMap::const_iterator i = external_extension_providers_.begin();
- i != external_extension_providers_.end(); ++i) {
- const ExternalExtensionProvider* provider = i->second.get();
- 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
-// (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 ExtensionsServiceBackend::CheckForExternalUpdates(
- std::set<std::string> ids_to_ignore,
- scoped_refptr<ExtensionsService> frontend) {
- // 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.
-
- for (ProviderMap::const_iterator i = external_extension_providers_.begin();
- i != external_extension_providers_.end(); ++i) {
- ExternalExtensionProvider* provider = i->second.get();
- provider->VisitRegisteredExtension(this, ids_to_ignore);
- }
-
- if (external_extension_added_ && frontend->updater()) {
- ChromeThread::PostTask(
- ChromeThread::UI, FROM_HERE,
- NewRunnableMethod(
- frontend->updater(), &ExtensionUpdater::CheckNow));
- }
-}
-
-void ExtensionsServiceBackend::CheckExternalUninstall(
- scoped_refptr<ExtensionsService> frontend, const std::string& id,
- Extension::Location location) {
- // Check if the providers know about this extension.
- ProviderMap::const_iterator i = external_extension_providers_.find(location);
- if (i == external_extension_providers_.end()) {
- NOTREACHED() << "CheckExternalUninstall called for non-external extension "
- << location;
- return;
- }
-
- scoped_ptr<Version> version;
- version.reset(i->second->RegisteredVersion(id, NULL));
- if (version.get())
- return; // Yup, known extension, don't uninstall.
-
- // This is an external extension that we don't have registered. Uninstall.
- ChromeThread::PostTask(
- ChromeThread::UI, FROM_HERE,
- NewRunnableMethod(
- frontend.get(), &ExtensionsService::UninstallExtension, id, true));
-}
-
-void ExtensionsServiceBackend::ClearProvidersForTesting() {
- external_extension_providers_.clear();
-}
-
-void ExtensionsServiceBackend::SetProviderForTesting(
- Extension::Location location,
- ExternalExtensionProvider* test_provider) {
- DCHECK(test_provider);
- external_extension_providers_[location] =
- linked_ptr<ExternalExtensionProvider>(test_provider);
-}
-
-void ExtensionsServiceBackend::OnExternalExtensionFileFound(
- const std::string& id, const Version* version, const FilePath& path,
- Extension::Location location) {
- DCHECK(version);
- ChromeThread::PostTask(
- ChromeThread::UI, FROM_HERE,
- NewRunnableMethod(
- frontend_, &ExtensionsService::OnExternalExtensionFileFound, id,
- version->GetString(), path, location));
-}
-
-void ExtensionsServiceBackend::OnExternalExtensionUpdateUrlFound(
- const std::string& id,
- const GURL& update_url,
- bool enable_incognito_on_install) {
- if (frontend_->GetExtensionById(id, true)) {
- // Already installed. Do not change the update URL that the extension set.
- return;
- }
-
- frontend_->AddPendingExtensionFromExternalUpdateUrl(id, update_url,
- enable_incognito_on_install);
- external_extension_added_ |= true;
-}
-
-void ExtensionsServiceBackend::ReloadExtensionManifests(
- ExtensionPrefs::ExtensionsInfo* extensions_to_reload,
- base::TimeTicks start_time,
- scoped_refptr<ExtensionsService> frontend) {
- frontend_ = frontend;
-
- for (size_t i = 0; i < extensions_to_reload->size(); ++i) {
- ExtensionInfo* info = extensions_to_reload->at(i).get();
- if (!ShouldReloadExtensionManifest(*info))
- continue;
-
- // We need to reload original manifest in order to localize properly.
- std::string error;
- scoped_ptr<Extension> extension(extension_file_util::LoadExtension(
- info->extension_path, false, &error));
-
- if (extension.get())
- extensions_to_reload->at(i)->extension_manifest.reset(
- static_cast<DictionaryValue*>(
- extension->manifest_value()->DeepCopy()));
- }
-
- // Finish installing on UI thread.
- ChromeThread::PostTask(
- ChromeThread::UI, FROM_HERE,
- NewRunnableMethod(
- frontend_,
- &ExtensionsService::ContinueLoadAllExtensions,
- extensions_to_reload,
- start_time,
- true));
-}