summaryrefslogtreecommitdiffstats
path: root/chrome
diff options
context:
space:
mode:
authoryoz@chromium.org <yoz@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-11-02 18:18:01 +0000
committeryoz@chromium.org <yoz@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-11-02 18:18:01 +0000
commitd8c8f25f706a2f565ced667ddd90ff3f1c831a6d (patch)
tree7e4b28786c5613136de1f713fde269bd5195e65e /chrome
parent8d93603116c5be19665c84340c5c12b61b62b5f1 (diff)
downloadchromium_src-d8c8f25f706a2f565ced667ddd90ff3f1c831a6d.zip
chromium_src-d8c8f25f706a2f565ced667ddd90ff3f1c831a6d.tar.gz
chromium_src-d8c8f25f706a2f565ced667ddd90ff3f1c831a6d.tar.bz2
Refactor loading out of ExtensionService.
- Make ExtensionServiceBackend go away, as it's only used for installing unpacked extensions. Tear this out into UnpackedInstaller task. - Pull out LoadAllExtensions / LoadInstalledExtension into InstalledExtensionLoader task. - Break out component extensions to be handled by ComponentLoader. Coming soon: a unit test for InstalledExtensionLoader. BUG=97883 TEST=existing tests + InstalledExtensionLoaderUnittest Review URL: http://codereview.chromium.org/8417012 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@108319 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome')
-rw-r--r--chrome/browser/autocomplete/autocomplete_browsertest.cc9
-rw-r--r--chrome/browser/automation/automation_provider.cc9
-rw-r--r--chrome/browser/chromeos/accessibility_util.cc8
-rw-r--r--chrome/browser/debugger/devtools_sanity_unittest.cc3
-rw-r--r--chrome/browser/download/download_crx_util.cc2
-rw-r--r--chrome/browser/extensions/component_loader.cc224
-rw-r--r--chrome/browser/extensions/component_loader.h83
-rw-r--r--chrome/browser/extensions/crx_installer.cc7
-rw-r--r--chrome/browser/extensions/crx_installer.h22
-rw-r--r--chrome/browser/extensions/crx_installer_browsertest.cc3
-rw-r--r--chrome/browser/extensions/extension_browsertest.cc12
-rw-r--r--chrome/browser/extensions/extension_service.cc619
-rw-r--r--chrome/browser/extensions/extension_service.h95
-rw-r--r--chrome/browser/extensions/extension_service_unittest.cc43
-rw-r--r--chrome/browser/extensions/extension_updater_unittest.cc4
-rw-r--r--chrome/browser/extensions/installed_loader.cc282
-rw-r--r--chrome/browser/extensions/installed_loader.h40
-rw-r--r--chrome/browser/extensions/network_delay_listener_unittest.cc3
-rw-r--r--chrome/browser/extensions/unpacked_installer.cc215
-rw-r--r--chrome/browser/extensions/unpacked_installer.h82
-rw-r--r--chrome/browser/extensions/user_script_listener_unittest.cc5
-rw-r--r--chrome/browser/profiles/profile_impl.cc133
-rw-r--r--chrome/browser/profiles/profile_impl.h2
-rw-r--r--chrome/browser/ui/browser.cc3
-rw-r--r--chrome/browser/ui/panels/base_panel_browser_test.cc4
-rw-r--r--chrome/browser/ui/webui/ntp/app_launcher_handler.cc2
-rw-r--r--chrome/browser/ui/webui/options/extension_settings_handler.cc4
-rw-r--r--chrome/chrome_browser.gypi14
28 files changed, 1065 insertions, 867 deletions
diff --git a/chrome/browser/autocomplete/autocomplete_browsertest.cc b/chrome/browser/autocomplete/autocomplete_browsertest.cc
index 6348a82..a52aadc 100644
--- a/chrome/browser/autocomplete/autocomplete_browsertest.cc
+++ b/chrome/browser/autocomplete/autocomplete_browsertest.cc
@@ -12,6 +12,7 @@
#include "chrome/browser/autocomplete/autocomplete_popup_model.h"
#include "chrome/browser/extensions/extension_browsertest.h"
#include "chrome/browser/extensions/extension_service.h"
+#include "chrome/browser/extensions/unpacked_installer.h"
#include "chrome/browser/history/history.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/tabs/tab_strip_model.h"
@@ -264,12 +265,12 @@ IN_PROC_BROWSER_TEST_F(AutocompleteBrowserTest, ExtensionAppProvider) {
FilePath test_dir;
ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &test_dir));
// Load a packaged app.
- service->LoadExtension(test_dir.AppendASCII("extensions")
- .AppendASCII("packaged_app"));
+ extensions::UnpackedInstaller::Create(service)->Load(
+ test_dir.AppendASCII("extensions").AppendASCII("packaged_app"));
WaitForExtensionLoad();
// Load a hosted app.
- service->LoadExtension(test_dir.AppendASCII("extensions")
- .AppendASCII("app"));
+ extensions::UnpackedInstaller::Create(service)->Load(
+ test_dir.AppendASCII("extensions").AppendASCII("app"));
WaitForExtensionLoad();
ASSERT_EQ(extension_count + 2U, service->extensions()->size());
diff --git a/chrome/browser/automation/automation_provider.cc b/chrome/browser/automation/automation_provider.cc
index ce93a20..01b4377 100644
--- a/chrome/browser/automation/automation_provider.cc
+++ b/chrome/browser/automation/automation_provider.cc
@@ -50,6 +50,7 @@
#include "chrome/browser/extensions/extension_service.h"
#include "chrome/browser/extensions/extension_tab_util.h"
#include "chrome/browser/extensions/extension_toolbar_model.h"
+#include "chrome/browser/extensions/unpacked_installer.h"
#include "chrome/browser/extensions/user_script_master.h"
#include "chrome/browser/net/url_request_mock_util.h"
#include "chrome/browser/prefs/pref_service.h"
@@ -858,13 +859,17 @@ void AutomationProvider::InstallExtension(
if (extension_path.MatchesExtension(FILE_PATH_LITERAL(".crx"))) {
ExtensionInstallUI* client =
(with_ui ? new ExtensionInstallUI(profile_) : NULL);
- scoped_refptr<CrxInstaller> installer(service->MakeCrxInstaller(client));
+ scoped_refptr<CrxInstaller> installer(
+ CrxInstaller::Create(service, client));
if (!with_ui)
installer->set_allow_silent_install(true);
installer->set_install_cause(extension_misc::INSTALL_CAUSE_AUTOMATION);
installer->InstallCrx(extension_path);
} else {
- service->LoadExtension(extension_path, with_ui);
+ scoped_refptr<extensions::UnpackedInstaller> installer(
+ extensions::UnpackedInstaller::Create(service));
+ installer->set_prompt_for_plugins(with_ui);
+ installer->Load(extension_path);
}
} else {
AutomationMsg_InstallExtension::WriteReplyParams(reply_message, 0);
diff --git a/chrome/browser/chromeos/accessibility_util.cc b/chrome/browser/chromeos/accessibility_util.cc
index 22d13e3..cee420c 100644
--- a/chrome/browser/chromeos/accessibility_util.cc
+++ b/chrome/browser/chromeos/accessibility_util.cc
@@ -10,6 +10,7 @@
#include "chrome/browser/chromeos/dbus/dbus_thread_manager.h"
#include "chrome/browser/chromeos/dbus/speech_synthesizer_client.h"
#include "chrome/browser/extensions/extension_accessibility_api.h"
+#include "chrome/browser/extensions/component_loader.h"
#include "chrome/browser/extensions/extension_service.h"
#include "chrome/browser/extensions/file_reader.h"
#include "chrome/browser/profiles/profile.h"
@@ -110,11 +111,9 @@ void EnableAccessibility(bool enabled, WebUI* login_web_ui) {
GetRawDataResource(IDR_CHROMEVOX_MANIFEST).as_string();
FilePath path = FilePath(extension_misc::kAccessExtensionPath)
.AppendASCII(extension_misc::kChromeVoxDirectoryName);
- ExtensionService::ComponentExtensionInfo info(manifest, path);
if (enabled) { // Load ChromeVox
- extension_service->register_component_extension(info);
const Extension* extension =
- extension_service->LoadComponentExtension(info);
+ extension_service->component_loader()->Add(manifest, path);
if (login_web_ui) {
RenderViewHost* render_view_host =
@@ -136,8 +135,7 @@ void EnableAccessibility(bool enabled, WebUI* login_web_ui) {
LOG(INFO) << "ChromeVox was Loaded.";
} else { // Unload ChromeVox
- extension_service->UnloadComponentExtension(info);
- extension_service->UnregisterComponentExtension(info);
+ extension_service->component_loader()->Remove(manifest);
LOG(INFO) << "ChromeVox was Unloaded.";
}
}
diff --git a/chrome/browser/debugger/devtools_sanity_unittest.cc b/chrome/browser/debugger/devtools_sanity_unittest.cc
index 87dca28..9bf6ade 100644
--- a/chrome/browser/debugger/devtools_sanity_unittest.cc
+++ b/chrome/browser/debugger/devtools_sanity_unittest.cc
@@ -12,6 +12,7 @@
#include "chrome/browser/debugger/devtools_window.h"
#include "chrome/browser/extensions/extension_host.h"
#include "chrome/browser/extensions/extension_service.h"
+#include "chrome/browser/extensions/unpacked_installer.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/common/chrome_notification_types.h"
@@ -211,7 +212,7 @@ class DevToolsExtensionDebugTest : public DevToolsSanityTest,
new CancelableQuitTask("Extension load timed out.");
MessageLoop::current()->PostDelayedTask(FROM_HERE, delayed_quit,
4*1000);
- service->LoadExtension(path);
+ extensions::UnpackedInstaller::Create(service)->Load(path);
ui_test_utils::RunMessageLoop();
delayed_quit->cancel();
}
diff --git a/chrome/browser/download/download_crx_util.cc b/chrome/browser/download/download_crx_util.cc
index 23f54ca..f709f9c 100644
--- a/chrome/browser/download/download_crx_util.cc
+++ b/chrome/browser/download/download_crx_util.cc
@@ -57,7 +57,7 @@ scoped_refptr<CrxInstaller> OpenChromeExtension(
CHECK(service);
scoped_refptr<CrxInstaller> installer(
- service->MakeCrxInstaller(CreateExtensionInstallUI(profile)));
+ CrxInstaller::Create(service, CreateExtensionInstallUI(profile)));
installer->set_delete_source(true);
if (UserScript::IsURLUserScript(download_item.GetURL(),
diff --git a/chrome/browser/extensions/component_loader.cc b/chrome/browser/extensions/component_loader.cc
new file mode 100644
index 0000000..6cf7f55
--- /dev/null
+++ b/chrome/browser/extensions/component_loader.cc
@@ -0,0 +1,224 @@
+// 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/component_loader.h"
+
+#include "base/command_line.h"
+#include "base/path_service.h"
+#include "base/json/json_value_serializer.h"
+#include "chrome/browser/browser_process.h"
+#include "chrome/browser/extensions/extension_service.h"
+#include "chrome/common/chrome_paths.h"
+#include "chrome/common/chrome_switches.h"
+#include "chrome/common/extensions/extension.h"
+#include "chrome/common/pref_names.h"
+#include "grit/browser_resources.h"
+#include "ui/base/resource/resource_bundle.h"
+
+namespace {
+
+typedef std::list<std::pair<FilePath::StringType, int> >
+ ComponentExtensionList;
+
+#if defined(FILE_MANAGER_EXTENSION)
+void AddFileManagerExtension(ComponentExtensionList* component_extensions) {
+#ifndef NDEBUG
+ const CommandLine* command_line = CommandLine::ForCurrentProcess();
+ if (command_line->HasSwitch(switches::kFileManagerExtensionPath)) {
+ FilePath filemgr_extension_path =
+ command_line->GetSwitchValuePath(switches::kFileManagerExtensionPath);
+ component_extensions->push_back(std::make_pair(
+ filemgr_extension_path.value(),
+ IDR_FILEMANAGER_MANIFEST));
+ return;
+ }
+#endif // NDEBUG
+ component_extensions->push_back(std::make_pair(
+ FILE_PATH_LITERAL("file_manager"),
+ IDR_FILEMANAGER_MANIFEST));
+}
+#endif // defined(FILE_MANAGER_EXTENSION)
+
+} // namespace
+
+namespace extensions {
+
+bool ComponentLoader::ComponentExtensionInfo::Equals(
+ const ComponentExtensionInfo& other) const {
+ return other.manifest == manifest && other.root_directory == root_directory;
+}
+
+ComponentLoader::ComponentLoader(ExtensionService* extension_service)
+ : extension_service_(extension_service) {
+}
+
+ComponentLoader::~ComponentLoader() {
+}
+
+void ComponentLoader::LoadAll() {
+ for (RegisteredComponentExtensions::iterator it =
+ component_extensions_.begin();
+ it != component_extensions_.end(); ++it) {
+ Load(*it);
+ }
+}
+
+const Extension* ComponentLoader::Add(
+ const std::string& manifest, const FilePath& root_directory) {
+ ComponentExtensionInfo info(manifest, root_directory);
+ Register(info);
+ if (extension_service_->is_ready())
+ return Load(info);
+ return NULL;
+}
+
+const Extension* ComponentLoader::Load(const ComponentExtensionInfo& info) {
+ JSONStringValueSerializer serializer(info.manifest);
+ scoped_ptr<Value> manifest(serializer.Deserialize(NULL, NULL));
+ if (!manifest.get()) {
+ LOG(ERROR) << "Failed to parse manifest for extension";
+ return NULL;
+ }
+
+ int flags = Extension::REQUIRE_KEY;
+ if (Extension::ShouldDoStrictErrorChecking(Extension::COMPONENT))
+ flags |= Extension::STRICT_ERROR_CHECKS;
+ std::string error;
+ scoped_refptr<const Extension> extension(Extension::Create(
+ info.root_directory,
+ Extension::COMPONENT,
+ *static_cast<DictionaryValue*>(manifest.get()),
+ flags,
+ &error));
+ if (!extension.get()) {
+ LOG(ERROR) << error;
+ return NULL;
+ }
+ extension_service_->AddExtension(extension);
+ return extension;
+}
+
+void ComponentLoader::Remove(const std::string& manifest_str) {
+ // Unload the extension.
+ JSONStringValueSerializer serializer(manifest_str);
+ scoped_ptr<Value> manifest(serializer.Deserialize(NULL, NULL));
+ if (!manifest.get()) {
+ LOG(ERROR) << "Failed to parse manifest for extension";
+ return;
+ }
+ std::string public_key;
+ std::string public_key_bytes;
+ std::string id;
+ if (!static_cast<DictionaryValue*>(manifest.get())->
+ GetString(extension_manifest_keys::kPublicKey, &public_key) ||
+ !Extension::ParsePEMKeyBytes(public_key, &public_key_bytes) ||
+ !Extension::GenerateId(public_key_bytes, &id)) {
+ LOG(ERROR) << "Failed to get extension id";
+ return;
+ }
+ extension_service_->
+ UnloadExtension(id, extension_misc::UNLOAD_REASON_DISABLE);
+
+ // Unregister the extension.
+ RegisteredComponentExtensions new_component_extensions;
+ for (RegisteredComponentExtensions::iterator it =
+ component_extensions_.begin();
+ it != component_extensions_.end(); ++it) {
+ if (it->manifest != manifest_str)
+ new_component_extensions.push_back(*it);
+ }
+ component_extensions_.swap(new_component_extensions);
+}
+
+// We take ComponentExtensionList:
+// path, manifest ID => full manifest, absolute path
+void ComponentLoader::AddDefaultComponentExtensions() {
+ ComponentExtensionList component_extensions;
+
+ // Bookmark manager.
+ component_extensions.push_back(std::make_pair(
+ FILE_PATH_LITERAL("bookmark_manager"),
+ IDR_BOOKMARKS_MANIFEST));
+
+#if defined(FILE_MANAGER_EXTENSION)
+ AddFileManagerExtension(&component_extensions);
+#endif
+
+#if defined(TOUCH_UI)
+ component_extensions.push_back(std::make_pair(
+ FILE_PATH_LITERAL("keyboard"),
+ IDR_KEYBOARD_MANIFEST));
+#endif
+
+#if defined(OS_CHROMEOS)
+ component_extensions.push_back(std::make_pair(
+ FILE_PATH_LITERAL("/usr/share/chromeos-assets/mobile"),
+ IDR_MOBILE_MANIFEST));
+
+ const CommandLine* command_line = CommandLine::ForCurrentProcess();
+ if (command_line->HasSwitch(switches::kAuthExtensionPath)) {
+ FilePath auth_extension_path =
+ command_line->GetSwitchValuePath(switches::kAuthExtensionPath);
+ component_extensions.push_back(std::make_pair(
+ auth_extension_path.value(),
+ IDR_GAIA_TEST_AUTH_MANIFEST));
+ } else {
+ component_extensions.push_back(std::make_pair(
+ FILE_PATH_LITERAL("/usr/share/chromeos-assets/gaia_auth"),
+ IDR_GAIA_AUTH_MANIFEST));
+ }
+
+#if defined(OFFICIAL_BUILD)
+ if (browser_defaults::enable_help_app) {
+ component_extensions.push_back(std::make_pair(
+ FILE_PATH_LITERAL("/usr/share/chromeos-assets/helpapp"),
+ IDR_HELP_MANIFEST));
+ }
+#endif
+#endif
+
+ // Web Store.
+ component_extensions.push_back(std::make_pair(
+ FILE_PATH_LITERAL("web_store"),
+ IDR_WEBSTORE_MANIFEST));
+
+#if !defined(OS_CHROMEOS)
+ // Cloud Print component app. Not required on Chrome OS.
+ component_extensions.push_back(std::make_pair(
+ FILE_PATH_LITERAL("cloud_print"),
+ IDR_CLOUDPRINT_MANIFEST));
+#endif // !defined(OS_CHROMEOS)
+
+ for (ComponentExtensionList::iterator iter = component_extensions.begin();
+ iter != component_extensions.end(); ++iter) {
+ FilePath path(iter->first);
+ if (!path.IsAbsolute()) {
+ if (PathService::Get(chrome::DIR_RESOURCES, &path)) {
+ path = path.Append(iter->first);
+ } else {
+ NOTREACHED();
+ }
+ }
+
+ std::string manifest =
+ ResourceBundle::GetSharedInstance().GetRawDataResource(
+ iter->second).as_string();
+ Add(manifest, path);
+ }
+
+#if defined(OS_CHROMEOS)
+ // Register access extensions only if accessibility is enabled.
+ if (g_browser_process->local_state()->
+ GetBoolean(prefs::kAccessibilityEnabled)) {
+ FilePath path = FilePath(extension_misc::kAccessExtensionPath)
+ .AppendASCII(extension_misc::kChromeVoxDirectoryName);
+ std::string manifest =
+ ResourceBundle::GetSharedInstance().GetRawDataResource(
+ IDR_CHROMEVOX_MANIFEST).as_string();
+ Add(manifest, path);
+ }
+#endif
+}
+
+} // namespace extensions
diff --git a/chrome/browser/extensions/component_loader.h b/chrome/browser/extensions/component_loader.h
new file mode 100644
index 0000000..6961098
--- /dev/null
+++ b/chrome/browser/extensions/component_loader.h
@@ -0,0 +1,83 @@
+// 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_COMPONENT_LOADER_H_
+#define CHROME_BROWSER_EXTENSIONS_COMPONENT_LOADER_H_
+#pragma once
+
+#include <string>
+
+#include "base/file_path.h"
+
+class Extension;
+class ExtensionService;
+
+namespace extensions {
+
+// For registering, loading, and unloading component extensions.
+class ComponentLoader {
+ public:
+ explicit ComponentLoader(ExtensionService* extension_service);
+ virtual ~ComponentLoader();
+
+ // Loads any registered component extensions.
+ void LoadAll();
+
+ // Loads and registers a component extension. If ExtensionService has been
+ // initialized, the extension is loaded; otherwise, the load is deferred
+ // until LoadAll is called.
+ const Extension* Add(const std::string& manifest,
+ const FilePath& root_directory);
+
+ // Unloads a component extension and removes it from the list of component
+ // extensions to be loaded.
+ void Remove(const std::string& manifest_str);
+
+ // Adds the default component extensions.
+ //
+ // Component extension manifests must contain a 'key' property with a unique
+ // public key, serialized in base64. You can create a suitable value with the
+ // following commands on a unixy system:
+ //
+ // ssh-keygen -t rsa -b 1024 -N '' -f /tmp/key.pem
+ // openssl rsa -pubout -outform DER < /tmp/key.pem 2>/dev/null | base64 -w 0
+ void AddDefaultComponentExtensions();
+
+ private:
+ // Information about a registered component extension.
+ struct ComponentExtensionInfo {
+ ComponentExtensionInfo(const std::string& manifest,
+ const FilePath& root_directory)
+ : manifest(manifest),
+ root_directory(root_directory) {
+ }
+
+ bool Equals(const ComponentExtensionInfo& other) const;
+
+ // The extension's manifest. This is required for component extensions so
+ // that ExtensionService doesn't need to go to disk to load them.
+ std::string manifest;
+
+ // Directory where the extension is stored.
+ FilePath root_directory;
+ };
+
+ // Loads a registered component extension.
+ const Extension* Load(const ComponentExtensionInfo& info);
+
+ // Registers an extension to be loaded as a component extension.
+ void Register(const ComponentExtensionInfo& info) {
+ component_extensions_.push_back(info);
+ }
+
+ // List of registered component extensions (see Extension::Location).
+ typedef std::vector<ComponentExtensionInfo> RegisteredComponentExtensions;
+ RegisteredComponentExtensions component_extensions_;
+
+ ExtensionService* extension_service_;
+};
+
+} // namespace extensions
+
+#endif // CHROME_BROWSER_EXTENSIONS_COMPONENT_LOADER_H_
diff --git a/chrome/browser/extensions/crx_installer.cc b/chrome/browser/extensions/crx_installer.cc
index 2700002..a8b39ca 100644
--- a/chrome/browser/extensions/crx_installer.cc
+++ b/chrome/browser/extensions/crx_installer.cc
@@ -62,6 +62,13 @@ CrxInstaller::WhitelistEntry::WhitelistEntry()
CrxInstaller::WhitelistEntry::~WhitelistEntry() {}
// static
+scoped_refptr<CrxInstaller> CrxInstaller::Create(
+ ExtensionService* frontend,
+ ExtensionInstallUI* client) {
+ return new CrxInstaller(frontend->AsWeakPtr(), client);
+}
+
+// static
void CrxInstaller::SetWhitelistedInstallId(const std::string& id) {
CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
g_whitelisted_install_data.Get().ids.insert(id);
diff --git a/chrome/browser/extensions/crx_installer.h b/chrome/browser/extensions/crx_installer.h
index 4e0474e..d2955ae 100644
--- a/chrome/browser/extensions/crx_installer.h
+++ b/chrome/browser/extensions/crx_installer.h
@@ -48,6 +48,13 @@ class CrxInstaller
: public SandboxedExtensionUnpackerClient,
public ExtensionInstallUI::Delegate {
public:
+ // Extensions will be installed into frontend->install_directory(),
+ // then registered with |frontend|. Any install UI will be displayed
+ // using |client|. Pass NULL for |client| for silent install.
+ static scoped_refptr<CrxInstaller> Create(
+ ExtensionService* frontend,
+ ExtensionInstallUI* client);
+
// This is pretty lame, but given the difficulty of connecting a particular
// ExtensionFunction to a resulting download in the download manager, it's
// currently necessary. This is the |id| of an extension to be installed
@@ -92,13 +99,6 @@ class CrxInstaller
// only be called on the UI thread.
static bool ClearWhitelistedInstallId(const std::string& id);
- // Constructor. Extensions will be installed into
- // frontend_weak->install_directory() then registered with
- // |frontend_weak|. Any install UI will be displayed using
- // |client|. Pass NULL for |client| for silent install.
- CrxInstaller(base::WeakPtr<ExtensionService> frontend_weak,
- ExtensionInstallUI* client);
-
// Install the crx in |source_file|.
void InstallCrx(const FilePath& source_file);
@@ -141,8 +141,10 @@ class CrxInstaller
return (creation_flags_ & Extension::FROM_WEBSTORE) > 0;
}
void set_is_gallery_install(bool val) {
- if (val) creation_flags_ |= Extension::FROM_WEBSTORE;
- else creation_flags_ &= ~Extension::FROM_WEBSTORE;
+ if (val)
+ creation_flags_ |= Extension::FROM_WEBSTORE;
+ else
+ creation_flags_ &= ~Extension::FROM_WEBSTORE;
}
// The original download URL should be set when the WebstoreInstaller is
@@ -181,6 +183,8 @@ class CrxInstaller
private:
friend class ExtensionUpdaterTest;
+ CrxInstaller(base::WeakPtr<ExtensionService> frontend_weak,
+ ExtensionInstallUI* client);
virtual ~CrxInstaller();
// Converts the source user script to an extension.
diff --git a/chrome/browser/extensions/crx_installer_browsertest.cc b/chrome/browser/extensions/crx_installer_browsertest.cc
index d108c56..14153b1 100644
--- a/chrome/browser/extensions/crx_installer_browsertest.cc
+++ b/chrome/browser/extensions/crx_installer_browsertest.cc
@@ -52,7 +52,8 @@ class ExtensionCrxInstallerTest : public ExtensionBrowserTest {
MockInstallUI* mock_install_ui = new MockInstallUI(browser()->profile());
scoped_refptr<CrxInstaller> installer(
- service->MakeCrxInstaller(mock_install_ui /* ownership transferred */));
+ CrxInstaller::Create(service,
+ mock_install_ui /* ownership transferred */));
installer->set_allow_silent_install(true);
installer->set_is_gallery_install(true);
diff --git a/chrome/browser/extensions/extension_browsertest.cc b/chrome/browser/extensions/extension_browsertest.cc
index 3c8a214..771b1ad 100644
--- a/chrome/browser/extensions/extension_browsertest.cc
+++ b/chrome/browser/extensions/extension_browsertest.cc
@@ -12,12 +12,14 @@
#include "base/path_service.h"
#include "base/scoped_temp_dir.h"
#include "base/string_number_conversions.h"
+#include "chrome/browser/extensions/component_loader.h"
#include "chrome/browser/extensions/crx_installer.h"
#include "chrome/browser/extensions/extension_creator.h"
#include "chrome/browser/extensions/extension_error_reporter.h"
#include "chrome/browser/extensions/extension_host.h"
#include "chrome/browser/extensions/extension_install_ui.h"
#include "chrome/browser/extensions/extension_service.h"
+#include "chrome/browser/extensions/unpacked_installer.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/browser_window.h"
@@ -66,7 +68,10 @@ const Extension* ExtensionBrowserTest::LoadExtensionWithOptions(
content::NotificationRegistrar registrar;
registrar.Add(this, chrome::NOTIFICATION_EXTENSION_LOADED,
content::NotificationService::AllSources());
- service->LoadExtension(path, false);
+ scoped_refptr<extensions::UnpackedInstaller> installer(
+ extensions::UnpackedInstaller::Create(service));
+ installer->set_prompt_for_plugins(false);
+ installer->Load(path);
ui_test_utils::RunMessageLoop();
}
@@ -147,8 +152,7 @@ bool ExtensionBrowserTest::LoadExtensionAsComponent(const FilePath& path) {
&manifest))
return false;
- service->LoadComponentExtension(
- ExtensionService::ComponentExtensionInfo(manifest, path));
+ service->component_loader()->Add(manifest, path);
return true;
}
@@ -269,7 +273,7 @@ bool ExtensionBrowserTest::InstallOrUpdateExtension(const std::string& id,
return false;
scoped_refptr<CrxInstaller> installer(
- service->MakeCrxInstaller(install_ui));
+ CrxInstaller::Create(service, install_ui));
installer->set_expected_id(id);
installer->set_is_gallery_install(from_webstore);
installer->InstallCrx(crx_path);
diff --git a/chrome/browser/extensions/extension_service.cc b/chrome/browser/extensions/extension_service.cc
index 49b33e7..14275d1 100644
--- a/chrome/browser/extensions/extension_service.cc
+++ b/chrome/browser/extensions/extension_service.cc
@@ -12,11 +12,9 @@
#include "base/callback.h"
#include "base/command_line.h"
#include "base/file_util.h"
-#include "base/json/json_value_serializer.h"
#include "base/logging.h"
#include "base/metrics/field_trial.h"
#include "base/metrics/histogram.h"
-#include "base/path_service.h"
#include "base/stl_util.h"
#include "base/string16.h"
#include "base/string_number_conversions.h"
@@ -32,6 +30,7 @@
#include "chrome/browser/chrome_plugin_service_filter.h"
#include "chrome/browser/extensions/app_notification_manager.h"
#include "chrome/browser/extensions/apps_promo.h"
+#include "chrome/browser/extensions/component_loader.h"
#include "chrome/browser/extensions/crx_installer.h"
#include "chrome/browser/extensions/default_apps_trial.h"
#include "chrome/browser/extensions/extension_accessibility_api.h"
@@ -43,7 +42,6 @@
#include "chrome/browser/extensions/extension_global_error.h"
#include "chrome/browser/extensions/extension_host.h"
#include "chrome/browser/extensions/extension_input_ime_api.h"
-#include "chrome/browser/extensions/extension_install_ui.h"
#include "chrome/browser/extensions/extension_management_api.h"
#include "chrome/browser/extensions/extension_preference_api.h"
#include "chrome/browser/extensions/extension_process_manager.h"
@@ -55,7 +53,9 @@
#include "chrome/browser/extensions/extension_webnavigation_api.h"
#include "chrome/browser/extensions/external_extension_provider_impl.h"
#include "chrome/browser/extensions/external_extension_provider_interface.h"
+#include "chrome/browser/extensions/installed_loader.h"
#include "chrome/browser/extensions/pending_extension_manager.h"
+#include "chrome/browser/extensions/unpacked_installer.h"
#include "chrome/browser/history/history_extension_api.h"
#include "chrome/browser/net/chrome_url_request_context.h"
#include "chrome/browser/prefs/pref_service.h"
@@ -75,13 +75,11 @@
#include "chrome/browser/ui/webui/ntp/thumbnail_source.h"
#include "chrome/common/child_process_logging.h"
#include "chrome/common/chrome_notification_types.h"
-#include "chrome/common/chrome_paths.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/extensions/extension.h"
#include "chrome/common/extensions/extension_constants.h"
#include "chrome/common/extensions/extension_error_utils.h"
#include "chrome/common/extensions/extension_file_util.h"
-#include "chrome/common/extensions/extension_l10n_util.h"
#include "chrome/common/extensions/extension_messages.h"
#include "chrome/common/extensions/extension_resource.h"
#include "chrome/common/pref_names.h"
@@ -137,29 +135,6 @@ static const int kOmniboxIconPaddingRight = 0;
const char* kNaClPluginMimeType = "application/x-nacl";
-// The following enumeration is used in histograms matching
-// Extensions.ManifestReload* . Values may be added, as long
-// as existing values are not changed.
-enum ManifestReloadReason {
- NOT_NEEDED = 0, // Reload not needed.
- UNPACKED_DIR, // Unpacked directory
- NEEDS_RELOCALIZATION, // The local has changed since we read this extension.
- NUM_MANIFEST_RELOAD_REASONS
-};
-
-ManifestReloadReason ShouldReloadExtensionManifest(const ExtensionInfo& info) {
- // Always reload manifests of unpacked extensions, because they can change
- // on disk independent of the manifest in our prefs.
- if (info.extension_location == Extension::LOAD)
- return UNPACKED_DIR;
-
- // Reload the manifest if it needs to be relocalized.
- if (extension_l10n_util::ShouldRelocalizeManifest(info))
- return NEEDS_RELOCALIZATION;
-
- return NOT_NEEDED;
-}
-
static void ForceShutdownPlugin(const FilePath& plugin_path) {
PluginProcessHost* plugin =
PluginService::GetInstance()->FindNpapiPluginProcess(plugin_path);
@@ -175,60 +150,8 @@ static bool IsSyncableApp(const Extension& extension) {
return extension.GetSyncType() == Extension::SYNC_TYPE_APP;
}
-// Manages an ExtensionInstallUI for a particular extension.
-class SimpleExtensionLoadPrompt : public ExtensionInstallUI::Delegate {
- public:
- SimpleExtensionLoadPrompt(Profile* profile,
- base::WeakPtr<ExtensionService> extension_service,
- const Extension* extension);
- ~SimpleExtensionLoadPrompt();
-
- void ShowPrompt();
-
- // ExtensionInstallUI::Delegate
- virtual void InstallUIProceed();
- virtual void InstallUIAbort(bool user_initiated);
-
- private:
- base::WeakPtr<ExtensionService> extension_service_;
- scoped_ptr<ExtensionInstallUI> install_ui_;
- scoped_refptr<const Extension> extension_;
-};
-
-SimpleExtensionLoadPrompt::SimpleExtensionLoadPrompt(
- Profile* profile,
- base::WeakPtr<ExtensionService> extension_service,
- const Extension* extension)
- : extension_service_(extension_service),
- install_ui_(new ExtensionInstallUI(profile)),
- extension_(extension) {
-}
-
-SimpleExtensionLoadPrompt::~SimpleExtensionLoadPrompt() {
-}
-
-void SimpleExtensionLoadPrompt::ShowPrompt() {
- install_ui_->ConfirmInstall(this, extension_);
-}
-
-void SimpleExtensionLoadPrompt::InstallUIProceed() {
- if (extension_service_.get())
- extension_service_->OnExtensionInstalled(
- extension_, false, -1); // Not from web store.
- delete this;
-}
-
-void SimpleExtensionLoadPrompt::InstallUIAbort(bool user_initiated) {
- delete this;
-}
-
} // namespace
-bool ExtensionService::ComponentExtensionInfo::Equals(
- const ComponentExtensionInfo& other) const {
- return other.manifest == manifest && other.root_directory == root_directory;
-}
-
ExtensionService::ExtensionRuntimeData::ExtensionRuntimeData()
: background_page_ready(false),
being_upgraded(false),
@@ -251,146 +174,6 @@ const char* ExtensionService::kExtensionSettingsDirectoryName =
"Extension Settings";
const char* ExtensionService::kAppSettingsDirectoryName = "App Settings";
-// Implements IO for the ExtensionService.
-
-class ExtensionServiceBackend
- : public base::RefCountedThreadSafe<ExtensionServiceBackend> {
- public:
- // |install_directory| is a path where to look for extensions to load.
- ExtensionServiceBackend(
- base::WeakPtr<ExtensionService> frontend,
- 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. If |prompt_for_plugins|
- // is true and the extension contains plugins, we prompt the user before
- // loading.
- // Errors are reported through ExtensionErrorReporter. On success,
- // AddExtension() 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, bool prompt_for_plugins);
-
- private:
- friend class base::RefCountedThreadSafe<ExtensionServiceBackend>;
-
- virtual ~ExtensionServiceBackend();
-
- // LoadSingleExtension needs to check the file access preference, which needs
- // to happen back on the UI thread, so it posts CheckExtensionFileAccess on
- // the UI thread. In turn, once that gets the pref, it goes back to the
- // file thread with LoadSingleExtensionWithFileAccess.
- void CheckExtensionFileAccess(const FilePath& extension_path,
- bool prompt_for_plugins);
- void LoadSingleExtensionWithFileAccess(
- const FilePath &path, bool allow_file_access, bool prompt_for_plugins);
-
- // Notify the frontend that there was an error loading an extension.
- void ReportExtensionLoadError(const FilePath& extension_path,
- const std::string& error);
-
- // Notify the frontend that an extension was installed.
- void OnLoadSingleExtension(const scoped_refptr<const Extension>& extension,
- bool prompt_for_plugins);
-
- base::WeakPtr<ExtensionService> frontend_;
-
- // The top-level extensions directory being installed to.
- FilePath install_directory_;
-
- DISALLOW_COPY_AND_ASSIGN(ExtensionServiceBackend);
-};
-
-ExtensionServiceBackend::ExtensionServiceBackend(
- base::WeakPtr<ExtensionService> frontend,
- const FilePath& install_directory)
- : frontend_(frontend),
- install_directory_(install_directory) {
- CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
-}
-
-ExtensionServiceBackend::~ExtensionServiceBackend() {
- CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI) ||
- BrowserThread::CurrentlyOn(BrowserThread::FILE));
-}
-
-void ExtensionServiceBackend::LoadSingleExtension(const FilePath& path_in,
- bool prompt_for_plugins) {
- CHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
-
- FilePath extension_path = path_in;
- file_util::AbsolutePath(&extension_path);
-
- BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
- base::Bind(&ExtensionServiceBackend::CheckExtensionFileAccess,
- this, extension_path, prompt_for_plugins));
-}
-
-void ExtensionServiceBackend::CheckExtensionFileAccess(
- const FilePath& extension_path, bool prompt_for_plugins) {
- CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
- std::string id = Extension::GenerateIdForPath(extension_path);
- // Unpacked extensions default to allowing file access, but if that has been
- // overridden, don't reset the value.
- bool allow_file_access =
- Extension::ShouldAlwaysAllowFileAccess(Extension::LOAD);
- if (frontend_->extension_prefs()->HasAllowFileAccessSetting(id))
- allow_file_access = frontend_->extension_prefs()->AllowFileAccess(id);
-
- BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE,
- base::Bind(
- &ExtensionServiceBackend::LoadSingleExtensionWithFileAccess,
- this, extension_path, allow_file_access, prompt_for_plugins));
-}
-
-void ExtensionServiceBackend::LoadSingleExtensionWithFileAccess(
- const FilePath& extension_path,
- bool allow_file_access,
- bool prompt_for_plugins) {
- CHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
- int flags = allow_file_access ?
- Extension::ALLOW_FILE_ACCESS : Extension::NO_FLAGS;
- if (Extension::ShouldDoStrictErrorChecking(Extension::LOAD))
- flags |= Extension::STRICT_ERROR_CHECKS;
- std::string error;
- scoped_refptr<const Extension> extension(extension_file_util::LoadExtension(
- extension_path,
- Extension::LOAD,
- flags,
- &error));
-
- if (!extension) {
- BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
- base::Bind(
- &ExtensionServiceBackend::ReportExtensionLoadError,
- this,
- extension_path, error));
- return;
- }
-
- // Report this as an installed extension so that it gets remembered in the
- // prefs.
- BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
- base::Bind(
- &ExtensionServiceBackend::OnLoadSingleExtension,
- this, extension, prompt_for_plugins));
-}
-
-void ExtensionServiceBackend::ReportExtensionLoadError(
- const FilePath& extension_path, const std::string &error) {
- CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
- if (frontend_.get())
- frontend_->ReportExtensionLoadError(
- extension_path, error, true /* alert_on_error */);
-}
-
-void ExtensionServiceBackend::OnLoadSingleExtension(
- const scoped_refptr<const Extension>& extension, bool prompt_for_plugins) {
- CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
- if (frontend_.get())
- frontend_->OnLoadSingleExtension(extension, prompt_for_plugins);
-}
-
void ExtensionService::CheckExternalUninstall(const std::string& id) {
CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
@@ -579,8 +362,7 @@ ExtensionService::ExtensionService(Profile* profile,
ExtensionPrefs* extension_prefs,
bool autoupdate_enabled,
bool extensions_enabled)
- : weak_ptr_factory_(ALLOW_THIS_IN_INITIALIZER_LIST(this)),
- profile_(profile),
+ : profile_(profile),
extension_prefs_(extension_prefs),
extension_settings_frontend_(profile),
pending_extension_manager_(*ALLOW_THIS_IN_INITIALIZER_LIST(this)),
@@ -629,9 +411,7 @@ ExtensionService::ExtensionService(Profile* profile,
update_frequency));
}
- backend_ =
- new ExtensionServiceBackend(weak_ptr_factory_.GetWeakPtr(),
- install_directory_);
+ component_loader_.reset(new extensions::ComponentLoader(this));
app_notification_manager_->Init();
@@ -667,18 +447,6 @@ PendingExtensionManager* ExtensionService::pending_extension_manager() {
return &pending_extension_manager_;
}
-void ExtensionService::UnregisterComponentExtension(
- const ComponentExtensionInfo& info) {
- RegisteredComponentExtensions new_component_extension_manifests;
- for (RegisteredComponentExtensions::iterator it =
- component_extension_manifests_.begin();
- it != component_extension_manifests_.end(); ++it) {
- if (!it->Equals(info))
- new_component_extension_manifests.push_back(*it);
- }
- component_extension_manifests_.swap(new_component_extension_manifests);
-}
-
ExtensionService::~ExtensionService() {
// No need to unload extensions here because they are profile-scoped, and the
// profile is in the process of being deleted.
@@ -752,7 +520,8 @@ void ExtensionService::Init() {
// the first extension, because its members listen for loaded notifications.
g_browser_process->resource_dispatcher_host();
- LoadAllExtensions();
+ component_loader_->LoadAll();
+ extensions::InstalledLoader(this).LoadAllExtensions();
// TODO(erikkay) this should probably be deferred to a future point
// rather than running immediately at startup.
@@ -795,7 +564,7 @@ bool ExtensionService::UpdateExtension(
(!is_pending_extension || pending_extension_info.install_silently()) ?
NULL : new ExtensionInstallUI(profile_);
- scoped_refptr<CrxInstaller> installer(MakeCrxInstaller(client));
+ scoped_refptr<CrxInstaller> installer(CrxInstaller::Create(this, client));
installer->set_expected_id(id);
if (is_pending_extension)
installer->set_install_source(pending_extension_info.install_source());
@@ -849,12 +618,13 @@ void ExtensionService::ReloadExtension(const std::string& extension_id) {
extension_prefs_->GetInstalledExtensionInfo(extension_id));
if (installed_extension.get() &&
installed_extension->extension_manifest.get()) {
- LoadInstalledExtension(*installed_extension, false);
+ extensions::InstalledLoader(this).Load(*installed_extension, false);
} else {
+ // Otherwise, the extension is unpacked (location LOAD).
// We should always be able to remember the extension's path. If it's not in
// the map, someone failed to update |unloaded_extension_paths_|.
CHECK(!path.empty());
- LoadExtension(path);
+ extensions::UnpackedInstaller::Create(this)->Load(path);
}
}
@@ -1108,275 +878,6 @@ void ExtensionService::UpdateActivePermissions(
extension->SetActivePermissions(permissions);
}
-void ExtensionService::LoadExtension(const FilePath& extension_path) {
- LoadExtension(extension_path, true);
-}
-
-void ExtensionService::LoadExtension(const FilePath& extension_path,
- bool prompt_for_plugins) {
- BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE,
- base::Bind(&ExtensionServiceBackend::LoadSingleExtension, backend_.get(),
- extension_path, prompt_for_plugins));
-}
-
-void ExtensionService::LoadExtensionFromCommandLine(
- const FilePath& path_in) {
-
- // Load extensions from the command line synchronously to avoid a race
- // between extension loading and loading an URL from the command line.
- base::ThreadRestrictions::ScopedAllowIO allow_io;
-
- FilePath extension_path = path_in;
- file_util::AbsolutePath(&extension_path);
-
- std::string id = Extension::GenerateIdForPath(extension_path);
- bool allow_file_access =
- Extension::ShouldAlwaysAllowFileAccess(Extension::LOAD);
- if (extension_prefs()->HasAllowFileAccessSetting(id))
- allow_file_access = extension_prefs()->AllowFileAccess(id);
-
- int flags = Extension::NO_FLAGS;
- if (allow_file_access)
- flags |= Extension::ALLOW_FILE_ACCESS;
- if (Extension::ShouldDoStrictErrorChecking(Extension::LOAD))
- flags |= Extension::STRICT_ERROR_CHECKS;
-
- std::string error;
- scoped_refptr<const Extension> extension(extension_file_util::LoadExtension(
- extension_path,
- Extension::LOAD,
- flags,
- &error));
-
- if (!extension) {
- ReportExtensionLoadError(extension_path, error, true);
- return;
- }
-
- OnLoadSingleExtension(extension, false);
-}
-
-void ExtensionService::LoadComponentExtensions() {
- for (RegisteredComponentExtensions::iterator it =
- component_extension_manifests_.begin();
- it != component_extension_manifests_.end(); ++it) {
- LoadComponentExtension(*it);
- }
-}
-
-const Extension* ExtensionService::LoadComponentExtension(
- const ComponentExtensionInfo &info) {
- JSONStringValueSerializer serializer(info.manifest);
- scoped_ptr<Value> manifest(serializer.Deserialize(NULL, NULL));
- if (!manifest.get()) {
- LOG(ERROR) << "Failed to parse manifest for extension";
- return NULL;
- }
-
- int flags = Extension::REQUIRE_KEY;
- if (Extension::ShouldDoStrictErrorChecking(Extension::COMPONENT))
- flags |= Extension::STRICT_ERROR_CHECKS;
- std::string error;
- scoped_refptr<const Extension> extension(Extension::Create(
- info.root_directory,
- Extension::COMPONENT,
- *static_cast<DictionaryValue*>(manifest.get()),
- flags,
- &error));
- if (!extension.get()) {
- LOG(ERROR) << error;
- return NULL;
- }
- AddExtension(extension);
- return extension;
-}
-
-void ExtensionService::UnloadComponentExtension(
- const ComponentExtensionInfo& info) {
- JSONStringValueSerializer serializer(info.manifest);
- scoped_ptr<Value> manifest(serializer.Deserialize(NULL, NULL));
- if (!manifest.get()) {
- LOG(ERROR) << "Failed to parse manifest for extension";
- return;
- }
- std::string public_key;
- std::string public_key_bytes;
- std::string id;
- if (!static_cast<DictionaryValue*>(manifest.get())->
- GetString(extension_manifest_keys::kPublicKey, &public_key) ||
- !Extension::ParsePEMKeyBytes(public_key, &public_key_bytes) ||
- !Extension::GenerateId(public_key_bytes, &id)) {
- LOG(ERROR) << "Failed to get extension id";
- return;
- }
- UnloadExtension(id, extension_misc::UNLOAD_REASON_DISABLE);
-}
-
-void ExtensionService::LoadAllExtensions() {
- CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
-
- base::TimeTicks start_time = base::TimeTicks::Now();
-
- // Load any component extensions.
- LoadComponentExtensions();
-
- // Load the previously installed extensions.
- scoped_ptr<ExtensionPrefs::ExtensionsInfo> extensions_info(
- extension_prefs_->GetInstalledExtensionsInfo());
-
- std::vector<int> reload_reason_counts(NUM_MANIFEST_RELOAD_REASONS, 0);
- bool should_write_prefs = false;
-
- for (size_t i = 0; i < extensions_info->size(); ++i) {
- ExtensionInfo* info = extensions_info->at(i).get();
-
- ManifestReloadReason reload_reason = ShouldReloadExtensionManifest(*info);
- ++reload_reason_counts[reload_reason];
- UMA_HISTOGRAM_ENUMERATION("Extensions.ManifestReloadEnumValue",
- reload_reason, 100);
-
- if (reload_reason != NOT_NEEDED) {
- // Reloading and extension reads files from disk. We do this on the
- // UI thread because reloads should be very rare, and the complexity
- // added by delaying the time when the extensions service knows about
- // all extensions is significant. See crbug.com/37548 for details.
- // |allow_io| disables tests that file operations run on the file
- // thread.
- base::ThreadRestrictions::ScopedAllowIO allow_io;
-
- std::string error;
- scoped_refptr<const Extension> extension(
- extension_file_util::LoadExtension(
- info->extension_path,
- info->extension_location,
- GetExtensionCreateFlagsForInstalledExtension(info),
- &error));
-
- if (extension.get()) {
- extensions_info->at(i)->extension_manifest.reset(
- static_cast<DictionaryValue*>(
- extension->manifest_value()->DeepCopy()));
- should_write_prefs = true;
- }
- }
- }
-
- for (size_t i = 0; i < extensions_info->size(); ++i) {
- LoadInstalledExtension(*extensions_info->at(i), should_write_prefs);
- }
-
- OnLoadedInstalledExtensions();
-
- // The histograms Extensions.ManifestReload* allow us to validate
- // the assumption that reloading manifest is a rare event.
- UMA_HISTOGRAM_COUNTS_100("Extensions.ManifestReloadNotNeeded",
- reload_reason_counts[NOT_NEEDED]);
- UMA_HISTOGRAM_COUNTS_100("Extensions.ManifestReloadUnpackedDir",
- reload_reason_counts[UNPACKED_DIR]);
- UMA_HISTOGRAM_COUNTS_100("Extensions.ManifestReloadNeedsRelocalization",
- reload_reason_counts[NEEDS_RELOCALIZATION]);
-
- UMA_HISTOGRAM_COUNTS_100("Extensions.LoadAll", extensions_.size());
- UMA_HISTOGRAM_COUNTS_100("Extensions.Disabled", disabled_extensions_.size());
-
- UMA_HISTOGRAM_TIMES("Extensions.LoadAllTime",
- base::TimeTicks::Now() - start_time);
-
- int app_user_count = 0;
- int app_external_count = 0;
- int hosted_app_count = 0;
- int packaged_app_count = 0;
- int user_script_count = 0;
- int extension_user_count = 0;
- int extension_external_count = 0;
- int theme_count = 0;
- int page_action_count = 0;
- int browser_action_count = 0;
- ExtensionList::iterator ex;
- for (ex = extensions_.begin(); ex != extensions_.end(); ++ex) {
- Extension::Location location = (*ex)->location();
- Extension::Type type = (*ex)->GetType();
- if ((*ex)->is_app()) {
- UMA_HISTOGRAM_ENUMERATION("Extensions.AppLocation",
- location, 100);
- } else if (type == Extension::TYPE_EXTENSION) {
- UMA_HISTOGRAM_ENUMERATION("Extensions.ExtensionLocation",
- location, 100);
- }
-
- // Don't count component extensions, since they are only extensions as an
- // implementation detail.
- if (location == Extension::COMPONENT)
- continue;
-
- // Don't count unpacked extensions, since they're a developer-specific
- // feature.
- if (location == Extension::LOAD)
- continue;
-
- // Using an enumeration shows us the total installed ratio across all users.
- // Using the totals per user at each startup tells us the distribution of
- // usage for each user (e.g. 40% of users have at least one app installed).
- UMA_HISTOGRAM_ENUMERATION("Extensions.LoadType", type, 100);
- switch (type) {
- case Extension::TYPE_THEME:
- ++theme_count;
- break;
- case Extension::TYPE_USER_SCRIPT:
- ++user_script_count;
- break;
- case Extension::TYPE_HOSTED_APP:
- ++hosted_app_count;
- if (Extension::IsExternalLocation(location)) {
- ++app_external_count;
- } else {
- ++app_user_count;
- }
- break;
- case Extension::TYPE_PACKAGED_APP:
- ++packaged_app_count;
- if (Extension::IsExternalLocation(location)) {
- ++app_external_count;
- } else {
- ++app_user_count;
- }
- break;
- case Extension::TYPE_EXTENSION:
- default:
- if (Extension::IsExternalLocation(location)) {
- ++extension_external_count;
- } else {
- ++extension_user_count;
- }
- break;
- }
- if ((*ex)->page_action() != NULL)
- ++page_action_count;
- if ((*ex)->browser_action() != NULL)
- ++browser_action_count;
-
- RecordPermissionMessagesHistogram(
- ex->get(), "Extensions.Permissions_Load");
- }
- UMA_HISTOGRAM_COUNTS_100("Extensions.LoadApp",
- app_user_count + app_external_count);
- UMA_HISTOGRAM_COUNTS_100("Extensions.LoadAppUser", app_user_count);
- UMA_HISTOGRAM_COUNTS_100("Extensions.LoadAppExternal", app_external_count);
- UMA_HISTOGRAM_COUNTS_100("Extensions.LoadHostedApp", hosted_app_count);
- UMA_HISTOGRAM_COUNTS_100("Extensions.LoadPackagedApp", packaged_app_count);
- UMA_HISTOGRAM_COUNTS_100("Extensions.LoadExtension",
- extension_user_count + extension_external_count);
- UMA_HISTOGRAM_COUNTS_100("Extensions.LoadExtensionUser",
- extension_user_count);
- UMA_HISTOGRAM_COUNTS_100("Extensions.LoadExtensionExternal",
- extension_external_count);
- UMA_HISTOGRAM_COUNTS_100("Extensions.LoadUserScript", user_script_count);
- UMA_HISTOGRAM_COUNTS_100("Extensions.LoadTheme", theme_count);
- UMA_HISTOGRAM_COUNTS_100("Extensions.LoadPageAction", page_action_count);
- UMA_HISTOGRAM_COUNTS_100("Extensions.LoadBrowserAction",
- browser_action_count);
-}
-
// static
void ExtensionService::RecordPermissionMessagesHistogram(
const Extension* e, const char* histogram) {
@@ -1399,65 +900,6 @@ void ExtensionService::RecordPermissionMessagesHistogram(
}
}
-void ExtensionService::LoadInstalledExtension(const ExtensionInfo& info,
- bool write_to_prefs) {
- std::string error;
- scoped_refptr<const Extension> extension(NULL);
-
- // An explicit check against policy is required to behave correctly during
- // startup. This is because extensions that were previously OK might have
- // been blacklisted in policy while Chrome was not running.
- if (!extension_prefs_->IsExtensionAllowedByPolicy(info.extension_id,
- info.extension_location)) {
- error = errors::kDisabledByPolicy;
- } else if (info.extension_manifest.get()) {
- extension = Extension::Create(
- info.extension_path,
- info.extension_location,
- *info.extension_manifest,
- GetExtensionCreateFlagsForInstalledExtension(&info),
- &error);
- } else {
- error = errors::kManifestUnreadable;
- }
-
- // Once installed, non-unpacked extensions cannot change their IDs (e.g., by
- // updating the 'key' field in their manifest).
- if (extension &&
- extension->location() != Extension::LOAD &&
- info.extension_id != extension->id()) {
- error = errors::kCannotChangeExtensionID;
- extension = NULL;
- UserMetrics::RecordAction(UserMetricsAction("Extensions.IDChangedError"));
- }
-
- if (!extension) {
- ReportExtensionLoadError(info.extension_path, error, false);
- return;
- }
-
- if (write_to_prefs)
- extension_prefs_->UpdateManifest(extension);
-
- AddExtension(extension);
-}
-
-int ExtensionService::GetExtensionCreateFlagsForInstalledExtension(
- const ExtensionInfo* info) {
- int flags = Extension::NO_FLAGS;
- if (info->extension_location != Extension::LOAD)
- flags |= Extension::REQUIRE_KEY;
- if (Extension::ShouldDoStrictErrorChecking(info->extension_location))
- flags |= Extension::STRICT_ERROR_CHECKS;
- if (extension_prefs_->AllowFileAccess(info->extension_id))
- flags |= Extension::ALLOW_FILE_ACCESS;
- if (extension_prefs_->IsFromWebStore(info->extension_id))
- flags |= Extension::FROM_WEBSTORE;
- if (extension_prefs_->IsFromBookmark(info->extension_id))
- flags |= Extension::FROM_BOOKMARK;
- return flags;
-}
-
void ExtensionService::NotifyExtensionLoaded(const Extension* extension) {
// The ChromeURLRequestContexts need to be first to know that the extension
// was loaded, otherwise a race can arise where a renderer that is created
@@ -2206,7 +1648,7 @@ void ExtensionService::IdentifyAlertableExtensions() {
// If this is the first time, grandfather extensions that would have
// caused notification.
scoped_ptr<ExtensionGlobalError> global_error(
- new ExtensionGlobalError(weak_ptr_factory_.GetWeakPtr()));
+ new ExtensionGlobalError(AsWeakPtr()));
bool needs_alert = false;
for (ExtensionList::const_iterator iter = extensions_.begin();
iter != extensions_.end(); ++iter) {
@@ -2356,7 +1798,8 @@ void ExtensionService::UnloadAllExtensions() {
void ExtensionService::ReloadExtensions() {
UnloadAllExtensions();
- LoadAllExtensions();
+ component_loader_->LoadAll();
+ extensions::InstalledLoader(this).LoadAllExtensions();
}
void ExtensionService::GarbageCollectExtensions() {
@@ -2562,22 +2005,6 @@ void ExtensionService::UpdateActiveExtensionsInCrashReporter() {
child_process_logging::SetActiveExtensions(extension_ids);
}
-void ExtensionService::OnLoadSingleExtension(const Extension* extension,
- bool prompt_for_plugins) {
- // If this is a new install of an extension with plugins, prompt the user
- // first.
- if (show_extensions_prompts_ && prompt_for_plugins &&
- !extension->plugins().empty() &&
- disabled_extension_paths_.find(extension->id()) ==
- disabled_extension_paths_.end()) {
- SimpleExtensionLoadPrompt* prompt = new SimpleExtensionLoadPrompt(
- profile_, weak_ptr_factory_.GetWeakPtr(), extension);
- prompt->ShowPrompt();
- return; // continues in SimpleExtensionLoadPrompt::InstallUI*
- }
- OnExtensionInstalled(extension, false, -1); // Not from web store.
-}
-
void ExtensionService::OnExtensionInstalled(
const Extension* extension, bool from_webstore, int page_index) {
CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
@@ -2815,7 +2242,7 @@ void ExtensionService::OnExternalExtensionFileFound(
pending_extension_manager()->AddFromExternalFile(id, location);
// no client (silent install)
- scoped_refptr<CrxInstaller> installer(MakeCrxInstaller(NULL));
+ scoped_refptr<CrxInstaller> installer(CrxInstaller::Create(this, NULL));
installer->set_install_source(location);
installer->set_expected_id(id);
installer->set_expected_version(*version);
@@ -2828,11 +2255,10 @@ void ExtensionService::ReportExtensionLoadError(
const FilePath& extension_path,
const std::string &error,
bool be_noisy) {
- content::NotificationService* service =
- content::NotificationService::current();
- service->Notify(chrome::NOTIFICATION_EXTENSION_LOAD_ERROR,
- content::Source<Profile>(profile_),
- content::Details<const std::string>(&error));
+ content::NotificationService::current()->Notify(
+ chrome::NOTIFICATION_EXTENSION_LOAD_ERROR,
+ content::Source<Profile>(profile_),
+ content::Details<const std::string>(&error));
std::string path_str = UTF16ToUTF8(extension_path.LossyDisplayName());
std::string message = base::StringPrintf(
@@ -2874,7 +2300,7 @@ void ExtensionService::Observe(int type,
FROM_HERE,
base::Bind(
&ExtensionService::TrackTerminatedExtension,
- weak_ptr_factory_.GetWeakPtr(),
+ AsWeakPtr(),
host->extension()));
break;
}
@@ -2951,11 +2377,6 @@ ExtensionIdSet ExtensionService::GetAppIds() const {
return result;
}
-scoped_refptr<CrxInstaller> ExtensionService::MakeCrxInstaller(
- ExtensionInstallUI* client) {
- return new CrxInstaller(weak_ptr_factory_.GetWeakPtr(), client);
-}
-
bool ExtensionService::IsBackgroundPageReady(const Extension* extension) {
return (extension->background_url().is_empty() ||
extension_runtime_data_[extension->id()].background_page_ready);
diff --git a/chrome/browser/extensions/extension_service.h b/chrome/browser/extensions/extension_service.h
index 52cfa2f..47cc52d 100644
--- a/chrome/browser/extensions/extension_service.h
+++ b/chrome/browser/extensions/extension_service.h
@@ -53,15 +53,14 @@ class ExtensionCookiesEventRouter;
class ExtensionDownloadsEventRouter;
class ExtensionFileBrowserEventRouter;
class ExtensionGlobalError;
-class HistoryExtensionEventRouter;
class ExtensionInstallUI;
class ExtensionManagementEventRouter;
class ExtensionPreferenceEventRouter;
-class ExtensionServiceBackend;
class ExtensionSyncData;
class ExtensionToolbarModel;
class ExtensionUpdater;
class ExtensionWebNavigationEventRouter;
+class HistoryExtensionEventRouter;
class GURL;
class PendingExtensionManager;
class Profile;
@@ -70,7 +69,11 @@ class Version;
namespace chromeos {
class ExtensionInputMethodEventRouter;
-} // namespace chromeos
+}
+
+namespace extensions {
+class ComponentLoader;
+}
// This is an interface class to encapsulate the dependencies that
// various classes have on ExtensionService. This allows easy mocking.
@@ -116,25 +119,10 @@ class ExtensionServiceInterface : public SyncableService {
class ExtensionService
: public ExtensionServiceInterface,
public ExternalExtensionProviderInterface::VisitorInterface,
+ public base::SupportsWeakPtr<ExtensionService>,
public content::NotificationObserver {
public:
- // Information about a registered component extension.
- struct ComponentExtensionInfo {
- ComponentExtensionInfo(const std::string& manifest,
- const FilePath& root_directory)
- : manifest(manifest),
- root_directory(root_directory) {
- }
-
- bool Equals(const ComponentExtensionInfo& other) const;
-
- // The extension's manifest. This is required for component extensions so
- // that ExtensionService doesn't need to go to disk to load them.
- std::string manifest;
-
- // Directory where the extension is stored.
- FilePath root_directory;
- };
+ using base::SupportsWeakPtr<ExtensionService>::AsWeakPtr;
// The name of the directory inside the profile where extensions are
// installed to.
@@ -194,14 +182,6 @@ class ExtensionService
// Gets the object managing the set of pending extensions.
virtual PendingExtensionManager* pending_extension_manager() OVERRIDE;
- // Registers an extension to be loaded as a component extension.
- void register_component_extension(const ComponentExtensionInfo& info) {
- component_extension_manifests_.push_back(info);
- }
-
- // Unregisters a component extension from the list of extensions to be loaded
- void UnregisterComponentExtension(const ComponentExtensionInfo& info);
-
const FilePath& install_directory() const { return install_directory_; }
AppsPromo* apps_promo() { return &apps_promo_; }
@@ -325,28 +305,6 @@ class ExtensionService
void UpdateActivePermissions(const Extension* extension,
const ExtensionPermissionSet* permissions);
- // Loads the extension from the directory |extension_path|.
- void LoadExtension(const FilePath& extension_path);
-
- // Loads the extension from the directory |extension_path|.
- // This version of this method is intended for testing only.
- void LoadExtension(const FilePath& extension_path, bool prompt_for_plugins);
-
- // Same as above, but for use with command line switch --load-extension=path.
- void LoadExtensionFromCommandLine(const FilePath& extension_path);
-
- // Loads any component extensions.
- void LoadComponentExtensions();
-
- // Loads particular component extension.
- const Extension* LoadComponentExtension(const ComponentExtensionInfo& info);
-
- // Unloads particular component extension.
- void UnloadComponentExtension(const ComponentExtensionInfo& info);
-
- // Loads all known extensions (used by startup and testing code).
- void LoadAllExtensions();
-
// Check for updates (or potentially new extensions from external providers)
void CheckForExternalUpdates();
@@ -401,10 +359,6 @@ class ExtensionService
// been loaded from a file and installed.
void AddExtension(const Extension* extension);
- // Called by the backend when an unpacked extension has been loaded.
- void OnLoadSingleExtension(const Extension* extension,
- bool prompt_for_plugins);
-
// Called by the backend when an extension has been installed.
void OnExtensionInstalled(
const Extension* extension, bool from_webstore, int page_index);
@@ -458,9 +412,12 @@ class ExtensionService
ExtensionContentSettingsStore* GetExtensionContentSettingsStore();
// Whether the extension service is ready.
- // TODO(skerner): Get rid of this method. crbug.com/63756
bool is_ready() { return ready_; }
+ extensions::ComponentLoader* component_loader() {
+ return component_loader_.get();
+ }
+
// Note that this may return NULL if autoupdate is not turned on.
ExtensionUpdater* updater();
@@ -492,7 +449,10 @@ class ExtensionService
#endif
// Notify the frontend that there was an error loading an extension.
- // This method is public because ExtensionServiceBackend can post to here.
+ // This method is public because UnpackedInstaller and InstalledLoader
+ // can post to here.
+ // TODO(aa): Remove this. It doesn't do enough to be worth the dependency
+ // of these classes on ExtensionService.
void ReportExtensionLoadError(const FilePath& extension_path,
const std::string& error,
bool be_noisy);
@@ -565,9 +525,6 @@ class ExtensionService
static void RecordPermissionMessagesHistogram(
const Extension* e, const char* histogram);
- // |client| can be NULL for a silent install.
- scoped_refptr<CrxInstaller> MakeCrxInstaller(ExtensionInstallUI* client);
-
#if defined(UNIT_TEST)
void TrackTerminatedExtensionForTest(const Extension* extension) {
TrackTerminatedExtension(extension);
@@ -679,9 +636,6 @@ class ExtensionService
// Helper that updates the active extension list used for crash reporting.
void UpdateActiveExtensionsInCrashReporter();
- // Helper method. Loads extension from prefs.
- void LoadInstalledExtension(const ExtensionInfo& info, bool write_to_prefs);
-
// We implement some Pepper plug-ins using NaCl to take advantage of NaCl's
// strong sandbox. Typically, these NaCl modules are stored in extensions
// and registered here. Not all NaCl modules need to register for a MIME
@@ -697,13 +651,6 @@ class ExtensionService
NaClModuleInfoList::iterator FindNaClModule(const GURL& url);
- // Returns the flags that should be used with Extension::Create() for an
- // extension that is already installed.
- int GetExtensionCreateFlagsForInstalledExtension(
- const ExtensionInfo* info);
-
- base::WeakPtrFactory<ExtensionService> weak_ptr_factory_;
-
// The profile this ExtensionService is part of.
Profile* profile_;
@@ -746,9 +693,6 @@ class ExtensionService
// Whether to notify users when they attempt to install an extension.
bool show_extensions_prompts_;
- // The backend that will do IO on behalf of this instance.
- scoped_refptr<ExtensionServiceBackend> backend_;
-
// Used by dispatchers to limit API quota for individual extensions.
ExtensionsQuotaService quota_service_;
@@ -782,6 +726,9 @@ class ExtensionService
content::NotificationRegistrar registrar_;
PrefChangeRegistrar pref_change_registrar_;
+ // Keeps track of loading and unloading component extensions.
+ scoped_ptr<extensions::ComponentLoader> component_loader_;
+
// Keeps track of menu items added by extensions.
ExtensionMenuManager menu_manager_;
@@ -795,10 +742,6 @@ class ExtensionService
ExtensionIconManager omnibox_icon_manager_;
ExtensionIconManager omnibox_popup_icon_manager_;
- // List of registered component extensions (see Extension::Location).
- typedef std::vector<ComponentExtensionInfo> RegisteredComponentExtensions;
- RegisteredComponentExtensions component_extension_manifests_;
-
// Manages the promotion of the web store.
AppsPromo apps_promo_;
diff --git a/chrome/browser/extensions/extension_service_unittest.cc b/chrome/browser/extensions/extension_service_unittest.cc
index f7c66dc..70bddf2 100644
--- a/chrome/browser/extensions/extension_service_unittest.cc
+++ b/chrome/browser/extensions/extension_service_unittest.cc
@@ -26,6 +26,7 @@
#include "base/version.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/extensions/crx_installer.h"
+#include "chrome/browser/extensions/component_loader.h"
#include "chrome/browser/extensions/extension_creator.h"
#include "chrome/browser/extensions/extension_error_reporter.h"
#include "chrome/browser/extensions/extension_service.h"
@@ -35,9 +36,11 @@
#include "chrome/browser/extensions/external_extension_provider_impl.h"
#include "chrome/browser/extensions/external_extension_provider_interface.h"
#include "chrome/browser/extensions/external_pref_extension_loader.h"
+#include "chrome/browser/extensions/installed_loader.h"
#include "chrome/browser/extensions/pack_extension_job.cc"
#include "chrome/browser/extensions/pending_extension_info.h"
#include "chrome/browser/extensions/pending_extension_manager.h"
+#include "chrome/browser/extensions/unpacked_installer.h"
#include "chrome/browser/prefs/browser_prefs.h"
#include "chrome/browser/prefs/pref_service_mock_builder.h"
#include "chrome/browser/prefs/scoped_user_pref_update.h"
@@ -590,8 +593,7 @@ class ExtensionServiceTest
void StartCrxInstall(const FilePath& crx_path, bool from_webstore) {
ASSERT_TRUE(file_util::PathExists(crx_path))
<< "Path does not exist: "<< crx_path.value().c_str();
- scoped_refptr<CrxInstaller> installer(
- service_->MakeCrxInstaller(NULL));
+ scoped_refptr<CrxInstaller> installer(CrxInstaller::Create(service_, NULL));
installer->set_allow_silent_install(true);
installer->set_is_gallery_install(from_webstore);
installer->InstallCrx(crx_path);
@@ -609,7 +611,7 @@ class ExtensionServiceTest
ASSERT_TRUE(file_util::PathExists(crx_path))
<< "Path does not exist: "<< crx_path.value().c_str();
// no client (silent install)
- scoped_refptr<CrxInstaller> installer(service_->MakeCrxInstaller(NULL));
+ scoped_refptr<CrxInstaller> installer(CrxInstaller::Create(service_, NULL));
installer->set_install_source(install_location);
installer->InstallCrx(crx_path);
@@ -1374,8 +1376,7 @@ TEST_F(ExtensionServiceTest, InstallUserScript) {
.AppendASCII("user_script_basic.user.js");
ASSERT_TRUE(file_util::PathExists(path));
- scoped_refptr<CrxInstaller> installer(
- service_->MakeCrxInstaller(NULL));
+ scoped_refptr<CrxInstaller> installer(CrxInstaller::Create(service_, NULL));
installer->set_allow_silent_install(true);
installer->InstallUserScript(
path,
@@ -1763,7 +1764,7 @@ TEST_F(ExtensionServiceTest, LoadLocalizedTheme) {
FilePath extension_path = data_dir_
.AppendASCII("theme_i18n");
- service_->LoadExtension(extension_path);
+ extensions::UnpackedInstaller::Create(service_)->Load(extension_path);
loop_.RunAllPending();
EXPECT_EQ(0u, GetErrors().size());
ASSERT_EQ(1u, loaded_.size());
@@ -2179,7 +2180,7 @@ TEST_F(ExtensionServiceTest, LoadExtensionsCanDowngrade) {
JSONFileValueSerializer serializer(manifest_path);
ASSERT_TRUE(serializer.Serialize(manifest));
- service_->LoadExtension(extension_path);
+ extensions::UnpackedInstaller::Create(service_)->Load(extension_path);
loop_.RunAllPending();
EXPECT_EQ(0u, GetErrors().size());
@@ -2193,7 +2194,7 @@ TEST_F(ExtensionServiceTest, LoadExtensionsCanDowngrade) {
manifest.SetString("version", "1.0");
ASSERT_TRUE(serializer.Serialize(manifest));
- service_->LoadExtension(extension_path);
+ extensions::UnpackedInstaller::Create(service_)->Load(extension_path);
loop_.RunAllPending();
EXPECT_EQ(0u, GetErrors().size());
@@ -2622,8 +2623,7 @@ TEST_F(ExtensionServiceTest, ComponentExtensionWhitelisted) {
std::string manifest;
ASSERT_TRUE(file_util::ReadFileToString(
path.Append(Extension::kManifestFilename), &manifest));
- service_->register_component_extension(
- ExtensionService::ComponentExtensionInfo(manifest, path));
+ service_->component_loader()->Add(manifest, path);
service_->Init();
// Extension should be installed despite blacklist.
@@ -3074,7 +3074,7 @@ TEST_F(ExtensionServiceTest, LoadExtension) {
.AppendASCII("Extensions")
.AppendASCII("behllobkkfkfnphdnhnkndlbkcpglgmj")
.AppendASCII("1.0.0.0");
- service_->LoadExtension(ext1);
+ extensions::UnpackedInstaller::Create(service_)->Load(ext1);
loop_.RunAllPending();
EXPECT_EQ(0u, GetErrors().size());
ASSERT_EQ(1u, loaded_.size());
@@ -3088,7 +3088,7 @@ TEST_F(ExtensionServiceTest, LoadExtension) {
// .AppendASCII("Extensions")
.AppendASCII("cccccccccccccccccccccccccccccccc")
.AppendASCII("1");
- service_->LoadExtension(no_manifest);
+ extensions::UnpackedInstaller::Create(service_)->Load(no_manifest);
loop_.RunAllPending();
EXPECT_EQ(1u, GetErrors().size());
ASSERT_EQ(1u, loaded_.size());
@@ -3111,7 +3111,7 @@ TEST_F(ExtensionServiceTest, GenerateID) {
FilePath no_id_ext = data_dir_.AppendASCII("no_id");
- service_->LoadExtension(no_id_ext);
+ extensions::UnpackedInstaller::Create(service_)->Load(no_id_ext);
loop_.RunAllPending();
EXPECT_EQ(0u, GetErrors().size());
ASSERT_EQ(1u, loaded_.size());
@@ -3123,7 +3123,7 @@ TEST_F(ExtensionServiceTest, GenerateID) {
std::string previous_id = loaded_[0]->id();
// If we reload the same path, we should get the same extension ID.
- service_->LoadExtension(no_id_ext);
+ extensions::UnpackedInstaller::Create(service_)->Load(no_id_ext);
loop_.RunAllPending();
ASSERT_EQ(1u, loaded_.size());
ASSERT_EQ(previous_id, loaded_[0]->id());
@@ -3252,7 +3252,7 @@ void ExtensionServiceTest::TestExternalProvider(
// Should still be at 0.
loaded_.clear();
- service_->LoadAllExtensions();
+ extensions::InstalledLoader(service_).LoadAllExtensions();
loop_.RunAllPending();
ASSERT_EQ(0u, loaded_.size());
ValidatePrefKeyCount(1);
@@ -3703,9 +3703,9 @@ TEST_F(ExtensionServiceTest, StorageQuota) {
FilePath unlimited_quota_ext2 =
extensions_path.AppendASCII("unlimited_quota")
.AppendASCII("2.0");
- service_->LoadExtension(limited_quota_ext);
- service_->LoadExtension(unlimited_quota_ext);
- service_->LoadExtension(unlimited_quota_ext2);
+ extensions::UnpackedInstaller::Create(service_)->Load(limited_quota_ext);
+ extensions::UnpackedInstaller::Create(service_)->Load(unlimited_quota_ext);
+ extensions::UnpackedInstaller::Create(service_)->Load(unlimited_quota_ext2);
loop_.RunAllPending();
ASSERT_EQ(3u, loaded_.size());
@@ -3719,7 +3719,7 @@ TEST_F(ExtensionServiceTest, StorageQuota) {
loaded_[2]->url()));
}
-// Tests ExtensionService::register_component_extension().
+// Tests ComponentLoader::Add().
TEST_F(ExtensionServiceTest, ComponentExtensions) {
InitializeEmptyExtensionService();
@@ -3736,8 +3736,7 @@ TEST_F(ExtensionServiceTest, ComponentExtensions) {
ASSERT_TRUE(file_util::ReadFileToString(
path.Append(Extension::kManifestFilename), &manifest));
- service_->register_component_extension(
- ExtensionService::ComponentExtensionInfo(manifest, path));
+ service_->component_loader()->Add(manifest, path);
service_->Init();
// Note that we do not pump messages -- the extension should be loaded
@@ -3748,7 +3747,7 @@ TEST_F(ExtensionServiceTest, ComponentExtensions) {
EXPECT_EQ(Extension::COMPONENT, loaded_[0]->location());
EXPECT_EQ(1u, service_->extensions()->size());
- // Component extensions shouldn't get recourded in the prefs.
+ // Component extensions shouldn't get recorded in the prefs.
ValidatePrefKeyCount(0);
// Reload all extensions, and make sure it comes back.
diff --git a/chrome/browser/extensions/extension_updater_unittest.cc b/chrome/browser/extensions/extension_updater_unittest.cc
index 7f916d6..79134fd 100644
--- a/chrome/browser/extensions/extension_updater_unittest.cc
+++ b/chrome/browser/extensions/extension_updater_unittest.cc
@@ -818,9 +818,9 @@ class ExtensionUpdaterTest : public testing::Test {
profile.GetExtensionService()->set_show_extensions_prompts(false);
scoped_refptr<CrxInstaller> fake_crx1(
- profile.GetExtensionService()->MakeCrxInstaller(NULL));
+ CrxInstaller::Create(profile.GetExtensionService(), NULL));
scoped_refptr<CrxInstaller> fake_crx2(
- profile.GetExtensionService()->MakeCrxInstaller(NULL));
+ CrxInstaller::Create(profile.GetExtensionService(), NULL));
if (updates_start_running) {
// Add fake CrxInstaller to be returned by service.UpdateExtension().
diff --git a/chrome/browser/extensions/installed_loader.cc b/chrome/browser/extensions/installed_loader.cc
new file mode 100644
index 0000000..20bd824
--- /dev/null
+++ b/chrome/browser/extensions/installed_loader.cc
@@ -0,0 +1,282 @@
+// 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/installed_loader.h"
+
+#include "base/file_path.h"
+#include "base/metrics/histogram.h"
+#include "base/stringprintf.h"
+#include "base/utf_string_conversions.h"
+#include "base/values.h"
+#include "chrome/browser/extensions/extension_prefs.h"
+#include "chrome/browser/extensions/extension_service.h"
+#include "chrome/common/chrome_switches.h"
+#include "chrome/common/extensions/extension.h"
+#include "chrome/common/extensions/extension_file_util.h"
+#include "chrome/common/extensions/extension_l10n_util.h"
+#include "chrome/common/pref_names.h"
+#include "content/public/browser/notification_service.h"
+#include "content/browser/user_metrics.h"
+
+namespace errors = extension_manifest_errors;
+
+namespace {
+
+// The following enumeration is used in histograms matching
+// Extensions.ManifestReload* . Values may be added, as long as existing
+// values are not changed.
+enum ManifestReloadReason {
+ NOT_NEEDED = 0, // Reload not needed.
+ UNPACKED_DIR, // Unpacked directory.
+ NEEDS_RELOCALIZATION, // The locale has changed since we read this extension.
+ NUM_MANIFEST_RELOAD_REASONS
+};
+
+ManifestReloadReason ShouldReloadExtensionManifest(const ExtensionInfo& info) {
+ // Always reload manifests of unpacked extensions, because they can change
+ // on disk independent of the manifest in our prefs.
+ if (info.extension_location == Extension::LOAD)
+ return UNPACKED_DIR;
+
+ // Reload the manifest if it needs to be relocalized.
+ if (extension_l10n_util::ShouldRelocalizeManifest(info))
+ return NEEDS_RELOCALIZATION;
+
+ return NOT_NEEDED;
+}
+
+} // namespace
+
+namespace extensions {
+
+InstalledLoader::InstalledLoader(ExtensionService* extension_service)
+ : extension_service_(extension_service),
+ extension_prefs_(extension_service->extension_prefs()) {
+}
+
+InstalledLoader::~InstalledLoader() {
+}
+
+void InstalledLoader::Load(const ExtensionInfo& info, bool write_to_prefs) {
+ std::string error;
+ scoped_refptr<const Extension> extension(NULL);
+ // An explicit check against policy is required to behave correctly during
+ // startup. This is because extensions that were previously OK might have
+ // been blacklisted in policy while Chrome was not running.
+ if (!extension_prefs_->IsExtensionAllowedByPolicy(info.extension_id,
+ info.extension_location)) {
+ error = errors::kDisabledByPolicy;
+ } else if (info.extension_manifest.get()) {
+ extension = Extension::Create(
+ info.extension_path,
+ info.extension_location,
+ *info.extension_manifest,
+ GetCreationFlags(&info),
+ &error);
+ } else {
+ error = errors::kManifestUnreadable;
+ }
+
+ // Once installed, non-unpacked extensions cannot change their IDs (e.g., by
+ // updating the 'key' field in their manifest).
+ if (extension &&
+ extension->location() != Extension::LOAD &&
+ info.extension_id != extension->id()) {
+ error = errors::kCannotChangeExtensionID;
+ extension = NULL;
+ UserMetrics::RecordAction(UserMetricsAction("Extensions.IDChangedError"));
+ }
+
+ if (!extension) {
+ extension_service_->
+ ReportExtensionLoadError(info.extension_path, error, false);
+ return;
+ }
+
+ if (write_to_prefs)
+ extension_prefs_->UpdateManifest(extension);
+
+ extension_service_->AddExtension(extension);
+}
+
+void InstalledLoader::LoadAllExtensions() {
+ CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+
+ base::TimeTicks start_time = base::TimeTicks::Now();
+
+ scoped_ptr<ExtensionPrefs::ExtensionsInfo> extensions_info(
+ extension_prefs_->GetInstalledExtensionsInfo());
+
+ std::vector<int> reload_reason_counts(NUM_MANIFEST_RELOAD_REASONS, 0);
+ bool should_write_prefs = false;
+
+ for (size_t i = 0; i < extensions_info->size(); ++i) {
+ ExtensionInfo* info = extensions_info->at(i).get();
+
+ ManifestReloadReason reload_reason = ShouldReloadExtensionManifest(*info);
+ ++reload_reason_counts[reload_reason];
+ UMA_HISTOGRAM_ENUMERATION("Extensions.ManifestReloadEnumValue",
+ reload_reason, 100);
+
+ if (reload_reason != NOT_NEEDED) {
+ // Reloading an extension reads files from disk. We do this on the
+ // UI thread because reloads should be very rare, and the complexity
+ // added by delaying the time when the extensions service knows about
+ // all extensions is significant. See crbug.com/37548 for details.
+ // |allow_io| disables tests that file operations run on the file
+ // thread.
+ base::ThreadRestrictions::ScopedAllowIO allow_io;
+
+ std::string error;
+ scoped_refptr<const Extension> extension(
+ extension_file_util::LoadExtension(
+ info->extension_path,
+ info->extension_location,
+ GetCreationFlags(info),
+ &error));
+
+ if (extension.get()) {
+ extensions_info->at(i)->extension_manifest.reset(
+ static_cast<DictionaryValue*>(
+ extension->manifest_value()->DeepCopy()));
+ should_write_prefs = true;
+ }
+ }
+ }
+
+ for (size_t i = 0; i < extensions_info->size(); ++i) {
+ Load(*extensions_info->at(i), should_write_prefs);
+ }
+
+ extension_service_->OnLoadedInstalledExtensions();
+
+ // The histograms Extensions.ManifestReload* allow us to validate
+ // the assumption that reloading manifest is a rare event.
+ UMA_HISTOGRAM_COUNTS_100("Extensions.ManifestReloadNotNeeded",
+ reload_reason_counts[NOT_NEEDED]);
+ UMA_HISTOGRAM_COUNTS_100("Extensions.ManifestReloadUnpackedDir",
+ reload_reason_counts[UNPACKED_DIR]);
+ UMA_HISTOGRAM_COUNTS_100("Extensions.ManifestReloadNeedsRelocalization",
+ reload_reason_counts[NEEDS_RELOCALIZATION]);
+
+ UMA_HISTOGRAM_COUNTS_100("Extensions.LoadAll",
+ extension_service_->extensions()->size());
+ UMA_HISTOGRAM_COUNTS_100("Extensions.Disabled",
+ extension_service_->disabled_extensions()->size());
+
+ UMA_HISTOGRAM_TIMES("Extensions.LoadAllTime",
+ base::TimeTicks::Now() - start_time);
+
+ int app_user_count = 0;
+ int app_external_count = 0;
+ int hosted_app_count = 0;
+ int packaged_app_count = 0;
+ int user_script_count = 0;
+ int extension_user_count = 0;
+ int extension_external_count = 0;
+ int theme_count = 0;
+ int page_action_count = 0;
+ int browser_action_count = 0;
+ const ExtensionList* extensions = extension_service_->extensions();
+ ExtensionList::const_iterator ex;
+ for (ex = extensions->begin(); ex != extensions->end(); ++ex) {
+ Extension::Location location = (*ex)->location();
+ Extension::Type type = (*ex)->GetType();
+ if ((*ex)->is_app()) {
+ UMA_HISTOGRAM_ENUMERATION("Extensions.AppLocation",
+ location, 100);
+ } else if (type == Extension::TYPE_EXTENSION) {
+ UMA_HISTOGRAM_ENUMERATION("Extensions.ExtensionLocation",
+ location, 100);
+ }
+
+ // Don't count component extensions, since they are only extensions as an
+ // implementation detail.
+ if (location == Extension::COMPONENT)
+ continue;
+
+ // Don't count unpacked extensions, since they're a developer-specific
+ // feature.
+ if (location == Extension::LOAD)
+ continue;
+
+ // Using an enumeration shows us the total installed ratio across all users.
+ // Using the totals per user at each startup tells us the distribution of
+ // usage for each user (e.g. 40% of users have at least one app installed).
+ UMA_HISTOGRAM_ENUMERATION("Extensions.LoadType", type, 100);
+ switch (type) {
+ case Extension::TYPE_THEME:
+ ++theme_count;
+ break;
+ case Extension::TYPE_USER_SCRIPT:
+ ++user_script_count;
+ break;
+ case Extension::TYPE_HOSTED_APP:
+ ++hosted_app_count;
+ if (Extension::IsExternalLocation(location)) {
+ ++app_external_count;
+ } else {
+ ++app_user_count;
+ }
+ break;
+ case Extension::TYPE_PACKAGED_APP:
+ ++packaged_app_count;
+ if (Extension::IsExternalLocation(location)) {
+ ++app_external_count;
+ } else {
+ ++app_user_count;
+ }
+ break;
+ case Extension::TYPE_EXTENSION:
+ default:
+ if (Extension::IsExternalLocation(location)) {
+ ++extension_external_count;
+ } else {
+ ++extension_user_count;
+ }
+ break;
+ }
+ if ((*ex)->page_action() != NULL)
+ ++page_action_count;
+ if ((*ex)->browser_action() != NULL)
+ ++browser_action_count;
+
+ extension_service_->RecordPermissionMessagesHistogram(
+ ex->get(), "Extensions.Permissions_Load");
+ }
+ UMA_HISTOGRAM_COUNTS_100("Extensions.LoadApp",
+ app_user_count + app_external_count);
+ UMA_HISTOGRAM_COUNTS_100("Extensions.LoadAppUser", app_user_count);
+ UMA_HISTOGRAM_COUNTS_100("Extensions.LoadAppExternal", app_external_count);
+ UMA_HISTOGRAM_COUNTS_100("Extensions.LoadHostedApp", hosted_app_count);
+ UMA_HISTOGRAM_COUNTS_100("Extensions.LoadPackagedApp", packaged_app_count);
+ UMA_HISTOGRAM_COUNTS_100("Extensions.LoadExtension",
+ extension_user_count + extension_external_count);
+ UMA_HISTOGRAM_COUNTS_100("Extensions.LoadExtensionUser",
+ extension_user_count);
+ UMA_HISTOGRAM_COUNTS_100("Extensions.LoadExtensionExternal",
+ extension_external_count);
+ UMA_HISTOGRAM_COUNTS_100("Extensions.LoadUserScript", user_script_count);
+ UMA_HISTOGRAM_COUNTS_100("Extensions.LoadTheme", theme_count);
+ UMA_HISTOGRAM_COUNTS_100("Extensions.LoadPageAction", page_action_count);
+ UMA_HISTOGRAM_COUNTS_100("Extensions.LoadBrowserAction",
+ browser_action_count);
+}
+
+int InstalledLoader::GetCreationFlags(const ExtensionInfo* info) {
+ int flags = Extension::NO_FLAGS;
+ if (info->extension_location != Extension::LOAD)
+ flags |= Extension::REQUIRE_KEY;
+ if (Extension::ShouldDoStrictErrorChecking(info->extension_location))
+ flags |= Extension::STRICT_ERROR_CHECKS;
+ if (extension_prefs_->AllowFileAccess(info->extension_id))
+ flags |= Extension::ALLOW_FILE_ACCESS;
+ if (extension_prefs_->IsFromWebStore(info->extension_id))
+ flags |= Extension::FROM_WEBSTORE;
+ if (extension_prefs_->IsFromBookmark(info->extension_id))
+ flags |= Extension::FROM_BOOKMARK;
+ return flags;
+}
+
+} // namespace extensions
diff --git a/chrome/browser/extensions/installed_loader.h b/chrome/browser/extensions/installed_loader.h
new file mode 100644
index 0000000..774f10c
--- /dev/null
+++ b/chrome/browser/extensions/installed_loader.h
@@ -0,0 +1,40 @@
+// 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_INSTALLED_LOADER_H_
+#define CHROME_BROWSER_EXTENSIONS_INSTALLED_LOADER_H_
+#pragma once
+
+class Extension;
+class ExtensionPrefs;
+class ExtensionService;
+struct ExtensionInfo;
+
+namespace extensions {
+
+// Loads installed extensions from the prefs.
+class InstalledLoader {
+ public:
+ explicit InstalledLoader(ExtensionService* extension_service);
+ virtual ~InstalledLoader();
+
+ // Loads extension from prefs.
+ void Load(const ExtensionInfo& info, bool write_to_prefs);
+
+ // Loads all installed extensions (used by startup and testing code).
+ void LoadAllExtensions();
+
+ private:
+ // Returns the flags that should be used with Extension::Create() for an
+ // extension that is already installed.
+ int GetCreationFlags(const ExtensionInfo* info);
+
+ ExtensionService* extension_service_;
+
+ ExtensionPrefs* extension_prefs_;
+};
+
+} // namespace extensions
+
+#endif // CHROME_BROWSER_EXTENSIONS_INSTALLED_LOADER_H_
diff --git a/chrome/browser/extensions/network_delay_listener_unittest.cc b/chrome/browser/extensions/network_delay_listener_unittest.cc
index 1223804..e550851 100644
--- a/chrome/browser/extensions/network_delay_listener_unittest.cc
+++ b/chrome/browser/extensions/network_delay_listener_unittest.cc
@@ -5,6 +5,7 @@
#include "base/message_loop.h"
#include "chrome/browser/extensions/extension_host.h"
#include "chrome/browser/extensions/extension_service_unittest.h"
+#include "chrome/browser/extensions/unpacked_installer.h"
#include "chrome/browser/extensions/network_delay_listener.h"
#include "chrome/common/chrome_notification_types.h"
#include "chrome/common/chrome_paths.h"
@@ -119,7 +120,7 @@ class NetworkDelayListenerTest
.AppendASCII(id)
.AppendASCII("1.0");
- service_->LoadExtension(extension_path);
+ extensions::UnpackedInstaller::Create(service_)->Load(extension_path);
MessageLoop::current()->RunAllPending();
}
diff --git a/chrome/browser/extensions/unpacked_installer.cc b/chrome/browser/extensions/unpacked_installer.cc
new file mode 100644
index 0000000..b747035
--- /dev/null
+++ b/chrome/browser/extensions/unpacked_installer.cc
@@ -0,0 +1,215 @@
+// 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/unpacked_installer.h"
+
+#include "base/bind.h"
+#include "base/callback.h"
+#include "base/file_util.h"
+#include "chrome/browser/extensions/extension_install_ui.h"
+#include "chrome/browser/extensions/extension_prefs.h"
+#include "chrome/browser/extensions/extension_service.h"
+#include "chrome/common/extensions/extension.h"
+#include "chrome/common/extensions/extension_file_util.h"
+
+namespace {
+
+// Manages an ExtensionInstallUI for a particular extension.
+class SimpleExtensionLoadPrompt : public ExtensionInstallUI::Delegate {
+ public:
+ SimpleExtensionLoadPrompt(Profile* profile,
+ base::WeakPtr<ExtensionService> extension_service,
+ const Extension* extension);
+ ~SimpleExtensionLoadPrompt();
+
+ void ShowPrompt();
+
+ // ExtensionInstallUI::Delegate
+ virtual void InstallUIProceed();
+ virtual void InstallUIAbort(bool user_initiated);
+
+ private:
+ base::WeakPtr<ExtensionService> service_weak_;
+ scoped_ptr<ExtensionInstallUI> install_ui_;
+ scoped_refptr<const Extension> extension_;
+};
+
+SimpleExtensionLoadPrompt::SimpleExtensionLoadPrompt(
+ Profile* profile,
+ base::WeakPtr<ExtensionService> extension_service,
+ const Extension* extension)
+ : service_weak_(extension_service),
+ install_ui_(new ExtensionInstallUI(profile)),
+ extension_(extension) {
+}
+
+SimpleExtensionLoadPrompt::~SimpleExtensionLoadPrompt() {
+}
+
+void SimpleExtensionLoadPrompt::ShowPrompt() {
+ install_ui_->ConfirmInstall(this, extension_);
+}
+
+void SimpleExtensionLoadPrompt::InstallUIProceed() {
+ if (service_weak_.get())
+ service_weak_->OnExtensionInstalled(
+ extension_, false, -1); // Not from web store.
+ delete this;
+}
+
+void SimpleExtensionLoadPrompt::InstallUIAbort(bool user_initiated) {
+ delete this;
+}
+
+} // namespace
+
+namespace extensions {
+
+// static
+scoped_refptr<UnpackedInstaller> UnpackedInstaller::Create(
+ ExtensionService* extension_service) {
+ return scoped_refptr<UnpackedInstaller>(
+ new UnpackedInstaller(extension_service));
+}
+
+UnpackedInstaller::UnpackedInstaller(ExtensionService* extension_service)
+ : service_weak_(extension_service->AsWeakPtr()),
+ prompt_for_plugins_(true) {
+ CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+}
+
+UnpackedInstaller::~UnpackedInstaller() {
+ CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI) ||
+ BrowserThread::CurrentlyOn(BrowserThread::FILE));
+}
+
+void UnpackedInstaller::Load(const FilePath& path_in) {
+ extension_path_ = path_in;
+ BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE,
+ base::Bind(&UnpackedInstaller::GetAbsolutePath, this));
+}
+
+void UnpackedInstaller::LoadFromCommandLine(const FilePath& path_in) {
+ if (!service_weak_.get())
+ return;
+ // Load extensions from the command line synchronously to avoid a race
+ // between extension loading and loading an URL from the command line.
+ base::ThreadRestrictions::ScopedAllowIO allow_io;
+
+ extension_path_ = path_in;
+ file_util::AbsolutePath(&extension_path_);
+
+ std::string id = Extension::GenerateIdForPath(extension_path_);
+ bool allow_file_access =
+ Extension::ShouldAlwaysAllowFileAccess(Extension::LOAD);
+ if (service_weak_->extension_prefs()->HasAllowFileAccessSetting(id))
+ allow_file_access = service_weak_->extension_prefs()->AllowFileAccess(id);
+
+ int flags = Extension::NO_FLAGS;
+ if (allow_file_access)
+ flags |= Extension::ALLOW_FILE_ACCESS;
+ if (Extension::ShouldDoStrictErrorChecking(Extension::LOAD))
+ flags |= Extension::STRICT_ERROR_CHECKS;
+
+ std::string error;
+ scoped_refptr<const Extension> extension(extension_file_util::LoadExtension(
+ extension_path_,
+ Extension::LOAD,
+ flags,
+ &error));
+
+ if (!extension) {
+ service_weak_->ReportExtensionLoadError(extension_path_, error, true);
+ return;
+ }
+
+ OnLoaded(extension);
+}
+
+void UnpackedInstaller::GetAbsolutePath() {
+ CHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
+
+ file_util::AbsolutePath(&extension_path_);
+
+ BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
+ base::Bind(&UnpackedInstaller::CheckExtensionFileAccess, this));
+}
+
+void UnpackedInstaller::CheckExtensionFileAccess() {
+ CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ std::string id = Extension::GenerateIdForPath(extension_path_);
+ // Unpacked extensions default to allowing file access, but if that has been
+ // overridden, don't reset the value.
+ bool allow_file_access =
+ Extension::ShouldAlwaysAllowFileAccess(Extension::LOAD);
+ if (service_weak_->extension_prefs()->HasAllowFileAccessSetting(id))
+ allow_file_access = service_weak_->extension_prefs()->AllowFileAccess(id);
+
+ BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE,
+ base::Bind(
+ &UnpackedInstaller::LoadWithFileAccess,
+ this, allow_file_access));
+}
+
+void UnpackedInstaller::LoadWithFileAccess(bool allow_file_access) {
+ CHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
+ int flags = allow_file_access ?
+ Extension::ALLOW_FILE_ACCESS : Extension::NO_FLAGS;
+ if (Extension::ShouldDoStrictErrorChecking(Extension::LOAD))
+ flags |= Extension::STRICT_ERROR_CHECKS;
+ std::string error;
+ scoped_refptr<const Extension> extension(extension_file_util::LoadExtension(
+ extension_path_,
+ Extension::LOAD,
+ flags,
+ &error));
+
+ if (!extension) {
+ BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
+ base::Bind(
+ &UnpackedInstaller::ReportExtensionLoadError,
+ this, error));
+ return;
+ }
+
+ BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
+ base::Bind(
+ &UnpackedInstaller::OnLoaded,
+ this, extension));
+}
+
+void UnpackedInstaller::ReportExtensionLoadError(const std::string &error) {
+ CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ if (!service_weak_.get())
+ return;
+ service_weak_->ReportExtensionLoadError(extension_path_, error, true);
+}
+
+void UnpackedInstaller::OnLoaded(
+ const scoped_refptr<const Extension>& extension) {
+ CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ if (!service_weak_.get())
+ return;
+ const ExtensionList* disabled_extensions =
+ service_weak_->disabled_extensions();
+ if (service_weak_->show_extensions_prompts() &&
+ prompt_for_plugins_ &&
+ !extension->plugins().empty() &&
+ std::find(disabled_extensions->begin(),
+ disabled_extensions->end(),
+ extension) !=
+ disabled_extensions->end()) {
+ SimpleExtensionLoadPrompt* prompt = new SimpleExtensionLoadPrompt(
+ service_weak_->profile(),
+ service_weak_,
+ extension);
+ prompt->ShowPrompt();
+ return; // continues in SimpleExtensionLoadPrompt::InstallUI*
+ }
+ service_weak_->OnExtensionInstalled(extension,
+ false, // Not from web store.
+ -1);
+}
+
+} // namespace extensions
diff --git a/chrome/browser/extensions/unpacked_installer.h b/chrome/browser/extensions/unpacked_installer.h
new file mode 100644
index 0000000..f73d57a
--- /dev/null
+++ b/chrome/browser/extensions/unpacked_installer.h
@@ -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.
+
+#ifndef CHROME_BROWSER_EXTENSIONS_UNPACKED_INSTALLER_H_
+#define CHROME_BROWSER_EXTENSIONS_UNPACKED_INSTALLER_H_
+#pragma once
+
+#include <string>
+
+#include "base/file_path.h"
+#include "base/memory/ref_counted.h"
+#include "base/memory/weak_ptr.h"
+
+class Extension;
+class ExtensionService;
+
+namespace extensions {
+
+// Installs and loads an unpacked extension.
+// TODO(erikkay): It might be useful to be able to load a packed extension
+// (presumably into memory) without installing it.
+class UnpackedInstaller
+ : public base::RefCountedThreadSafe<UnpackedInstaller> {
+ public:
+ static scoped_refptr<UnpackedInstaller> Create(
+ ExtensionService* extension_service);
+
+ // Loads the extension from the directory |extension_path|, which is
+ // the top directory of a specific extension where its manifest file lives.
+ // Errors are reported through ExtensionErrorReporter. On success,
+ // ExtensionService::AddExtension() is called.
+ void Load(const FilePath& extension_path);
+
+ // Loads the extension from the directory |extension_path|;
+ // for use with command line switch --load-extension=path.
+ // This is equivalent to Load, except that it runs synchronously.
+ void LoadFromCommandLine(const FilePath& extension_path);
+
+ // Allows prompting for plugins to be disabled; intended for testing only.
+ bool prompt_for_plugins() { return prompt_for_plugins_; }
+ void set_prompt_for_plugins(bool val) { prompt_for_plugins_ = val; }
+
+ private:
+ friend class base::RefCountedThreadSafe<UnpackedInstaller>;
+
+ explicit UnpackedInstaller(ExtensionService* extension_service);
+ virtual ~UnpackedInstaller();
+
+ // We change the input extension path to an absolute path, on the file thread.
+ // Then we need to check the file access preference, which needs
+ // to happen back on the UI thread, so it posts CheckExtensionFileAccess on
+ // the UI thread. In turn, once that gets the pref, it goes back to the
+ // file thread with LoadWithFileAccess.
+ // TODO(yoz): It would be nice to remove this ping-pong, but we need to know
+ // what file access flags to pass to extension_file_util::LoadExtension.
+ void GetAbsolutePath();
+ void CheckExtensionFileAccess();
+ void LoadWithFileAccess(bool allow_file_access);
+
+ // Notify the frontend that there was an error loading an extension.
+ void ReportExtensionLoadError(const std::string& error);
+
+ // Called when an unpacked extension has been loaded and installed.
+ void OnLoaded(const scoped_refptr<const Extension>& extension);
+
+ base::WeakPtr<ExtensionService> service_weak_;
+
+ // The pathname of the directory to load from, which is an absolute path
+ // after GetAbsolutePath has been called.
+ FilePath extension_path_;
+
+ // If true and the extension contains plugins, we prompt the user before
+ // loading.
+ bool prompt_for_plugins_;
+
+ DISALLOW_COPY_AND_ASSIGN(UnpackedInstaller);
+};
+
+} // namespace extensions
+
+#endif // CHROME_BROWSER_EXTENSIONS_UNPACKED_INSTALLER_H_
diff --git a/chrome/browser/extensions/user_script_listener_unittest.cc b/chrome/browser/extensions/user_script_listener_unittest.cc
index 3d88cc6..d046bdf 100644
--- a/chrome/browser/extensions/user_script_listener_unittest.cc
+++ b/chrome/browser/extensions/user_script_listener_unittest.cc
@@ -2,11 +2,12 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#include "base/file_util.h"
#include "base/message_loop.h"
#include "base/threading/thread.h"
#include "base/json/json_value_serializer.h"
-#include "base/file_util.h"
#include "chrome/browser/extensions/extension_service_unittest.h"
+#include "chrome/browser/extensions/unpacked_installer.h"
#include "chrome/browser/extensions/user_script_listener.h"
#include "chrome/common/chrome_notification_types.h"
#include "chrome/common/chrome_paths.h"
@@ -132,7 +133,7 @@ class UserScriptListenerTest
.AppendASCII("Extensions")
.AppendASCII("behllobkkfkfnphdnhnkndlbkcpglgmj")
.AppendASCII("1.0.0.0");
- service_->LoadExtension(extension_path);
+ extensions::UnpackedInstaller::Create(service_)->Load(extension_path);
}
void UnloadTestExtension() {
diff --git a/chrome/browser/profiles/profile_impl.cc b/chrome/browser/profiles/profile_impl.cc
index 8c886cf..aa2d69a 100644
--- a/chrome/browser/profiles/profile_impl.cc
+++ b/chrome/browser/profiles/profile_impl.cc
@@ -29,6 +29,7 @@
#include "chrome/browser/defaults.h"
#include "chrome/browser/download/download_service.h"
#include "chrome/browser/download/download_service_factory.h"
+#include "chrome/browser/extensions/component_loader.h"
#include "chrome/browser/extensions/extension_devtools_manager.h"
#include "chrome/browser/extensions/extension_error_reporter.h"
#include "chrome/browser/extensions/extension_event_router.h"
@@ -40,6 +41,7 @@
#include "chrome/browser/extensions/extension_service.h"
#include "chrome/browser/extensions/extension_settings_backend.h"
#include "chrome/browser/extensions/extension_special_storage_policy.h"
+#include "chrome/browser/extensions/unpacked_installer.h"
#include "chrome/browser/extensions/user_script_master.h"
#include "chrome/browser/favicon/favicon_service.h"
#include "chrome/browser/geolocation/chrome_geolocation_permission_context.h"
@@ -86,7 +88,6 @@
#include "chrome/browser/webdata/web_data_service.h"
#include "chrome/common/chrome_constants.h"
#include "chrome/common/chrome_notification_types.h"
-#include "chrome/common/chrome_paths.h"
#include "chrome/common/chrome_paths_internal.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/extensions/extension_permission_set.h"
@@ -106,11 +107,9 @@
#include "content/browser/user_metrics.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/notification_service.h"
-#include "grit/browser_resources.h"
#include "grit/locale_settings.h"
#include "net/base/transport_security_state.h"
#include "net/http/http_server_properties.h"
-#include "ui/base/resource/resource_bundle.h"
#include "webkit/database/database_tracker.h"
#include "webkit/quota/quota_manager.h"
@@ -158,9 +157,6 @@ enum ContextType {
kMediaContext
};
-typedef std::list<std::pair<FilePath::StringType, int> >
- ComponentExtensionList;
-
// Helper method needed because PostTask cannot currently take a Callback
// function with non-void return type.
// TODO(jhawkins): Remove once IgnoreReturn is fixed.
@@ -168,25 +164,6 @@ void CreateDirectoryNoResult(const FilePath& path) {
file_util::CreateDirectory(path);
}
-#if defined(FILE_MANAGER_EXTENSION)
-void AddFileManagerExtension(ComponentExtensionList* component_extensions) {
-#ifndef NDEBUG
- const CommandLine* command_line = CommandLine::ForCurrentProcess();
- if (command_line->HasSwitch(switches::kFileManagerExtensionPath)) {
- FilePath filemgr_extension_path =
- command_line->GetSwitchValuePath(switches::kFileManagerExtensionPath);
- component_extensions->push_back(std::make_pair(
- filemgr_extension_path.value(),
- IDR_FILEMANAGER_MANIFEST));
- return;
- }
-#endif // NDEBUG
- component_extensions->push_back(std::make_pair(
- FILE_PATH_LITERAL("file_manager"),
- IDR_FILEMANAGER_MANIFEST));
-}
-#endif // defined(FILE_MANAGER_EXTENSION)
-
// Gets the cache parameters from the command line. |type| is the type of
// request context that we need, |cache_path| will be set to the user provided
// path, or will not be touched if there is not an argument. |max_size| will
@@ -479,15 +456,17 @@ void ProfileImpl::InitExtensions(bool extensions_enabled) {
autoupdate_enabled,
extensions_enabled));
- RegisterComponentExtensions();
+ extension_service_->component_loader()->AddDefaultComponentExtensions();
extension_service_->Init();
if (extensions_enabled) {
// Load any extensions specified with --load-extension.
+ // TODO(yoz): Seems like this should move into ExtensionService::Init.
if (command_line->HasSwitch(switches::kLoadExtension)) {
FilePath path = command_line->GetSwitchValuePath(
switches::kLoadExtension);
- extension_service_->LoadExtensionFromCommandLine(path);
+ extensions::UnpackedInstaller::Create(extension_service_.get())->
+ LoadFromCommandLine(path);
}
}
@@ -516,106 +495,6 @@ void ProfileImpl::InitExtensions(bool extensions_enabled) {
}
}
-void ProfileImpl::RegisterComponentExtensions() {
- // Register the component extensions.
- //
- // Component extension manifest must contain a 'key' property with a unique
- // public key, serialized in base64. You can create a suitable value with the
- // following commands on a unixy system:
- //
- // ssh-keygen -t rsa -b 1024 -N '' -f /tmp/key.pem
- // openssl rsa -pubout -outform DER < /tmp/key.pem 2>/dev/null | base64 -w 0
- typedef std::list<std::pair<FilePath::StringType, int> >
- ComponentExtensionList;
- ComponentExtensionList component_extensions;
-
- // Bookmark manager.
- component_extensions.push_back(std::make_pair(
- FILE_PATH_LITERAL("bookmark_manager"),
- IDR_BOOKMARKS_MANIFEST));
-
-#if defined(FILE_MANAGER_EXTENSION)
- AddFileManagerExtension(&component_extensions);
-#endif
-
-#if defined(USE_VIRTUAL_KEYBOARD)
- component_extensions.push_back(std::make_pair(
- FILE_PATH_LITERAL("keyboard"),
- IDR_KEYBOARD_MANIFEST));
-#endif
-
-#if defined(OS_CHROMEOS)
- component_extensions.push_back(std::make_pair(
- FILE_PATH_LITERAL("/usr/share/chromeos-assets/mobile"),
- IDR_MOBILE_MANIFEST));
-
- const CommandLine* command_line = CommandLine::ForCurrentProcess();
- if (command_line->HasSwitch(switches::kAuthExtensionPath)) {
- FilePath auth_extension_path =
- command_line->GetSwitchValuePath(switches::kAuthExtensionPath);
- component_extensions.push_back(std::make_pair(
- auth_extension_path.value(),
- IDR_GAIA_TEST_AUTH_MANIFEST));
- } else {
- component_extensions.push_back(std::make_pair(
- FILE_PATH_LITERAL("/usr/share/chromeos-assets/gaia_auth"),
- IDR_GAIA_AUTH_MANIFEST));
- }
-
-#if defined(OFFICIAL_BUILD)
- if (browser_defaults::enable_help_app) {
- component_extensions.push_back(std::make_pair(
- FILE_PATH_LITERAL("/usr/share/chromeos-assets/helpapp"),
- IDR_HELP_MANIFEST));
- }
-#endif
-#endif
-
- // Web Store.
- component_extensions.push_back(std::make_pair(
- FILE_PATH_LITERAL("web_store"),
- IDR_WEBSTORE_MANIFEST));
-
-#if !defined(OS_CHROMEOS)
- // Cloud Print component app. Not required on Chrome OS.
- component_extensions.push_back(std::make_pair(
- FILE_PATH_LITERAL("cloud_print"),
- IDR_CLOUDPRINT_MANIFEST));
-#endif // !defined(OS_CHROMEOS)
-
- for (ComponentExtensionList::iterator iter = component_extensions.begin();
- iter != component_extensions.end(); ++iter) {
- FilePath path(iter->first);
- if (!path.IsAbsolute()) {
- if (PathService::Get(chrome::DIR_RESOURCES, &path)) {
- path = path.Append(iter->first);
- } else {
- NOTREACHED();
- }
- }
-
- std::string manifest =
- ResourceBundle::GetSharedInstance().GetRawDataResource(
- iter->second).as_string();
- extension_service_->register_component_extension(
- ExtensionService::ComponentExtensionInfo(manifest, path));
- }
-
-#if defined(OS_CHROMEOS)
- // Register access extensions only if accessibility is enabled.
- if (g_browser_process->local_state()->
- GetBoolean(prefs::kAccessibilityEnabled)) {
- FilePath path = FilePath(extension_misc::kAccessExtensionPath)
- .AppendASCII(extension_misc::kChromeVoxDirectoryName);
- std::string manifest =
- ResourceBundle::GetSharedInstance().GetRawDataResource(
- IDR_CHROMEVOX_MANIFEST).as_string();
- extension_service_->register_component_extension(
- ExtensionService::ComponentExtensionInfo(manifest, path));
- }
-#endif
-}
-
void ProfileImpl::InitPromoResources() {
if (promo_resource_service_)
return;
diff --git a/chrome/browser/profiles/profile_impl.h b/chrome/browser/profiles/profile_impl.h
index d7929e8..10ec531d 100644
--- a/chrome/browser/profiles/profile_impl.h
+++ b/chrome/browser/profiles/profile_impl.h
@@ -175,8 +175,6 @@ class ProfileImpl : public Profile,
void EnsureSessionServiceCreated();
- void RegisterComponentExtensions();
-
ExtensionPrefValueMap* GetExtensionPrefValueMap();
void CreateQuotaManagerAndClients();
diff --git a/chrome/browser/ui/browser.cc b/chrome/browser/ui/browser.cc
index e5aa2dc..9a8948c 100644
--- a/chrome/browser/ui/browser.cc
+++ b/chrome/browser/ui/browser.cc
@@ -4148,7 +4148,8 @@ void Browser::OnInstallApplication(TabContentsWrapper* source,
if (!extension_service)
return;
- scoped_refptr<CrxInstaller> installer(extension_service->MakeCrxInstaller(
+ scoped_refptr<CrxInstaller> installer(CrxInstaller::Create(
+ extension_service,
extension_service->show_extensions_prompts() ?
new ExtensionInstallUI(profile()) : NULL));
installer->InstallWebApp(web_app);
diff --git a/chrome/browser/ui/panels/base_panel_browser_test.cc b/chrome/browser/ui/panels/base_panel_browser_test.cc
index 8dc0809..651d5c6 100644
--- a/chrome/browser/ui/panels/base_panel_browser_test.cc
+++ b/chrome/browser/ui/panels/base_panel_browser_test.cc
@@ -330,7 +330,7 @@ scoped_refptr<Extension> BasePanelBrowserTest::CreateExtension(
Extension::STRICT_ERROR_CHECKS, &error);
EXPECT_TRUE(extension.get());
EXPECT_STREQ("", error.c_str());
- browser()->GetProfile()->GetExtensionService()->OnLoadSingleExtension(
- extension.get(), false);
+ browser()->GetProfile()->GetExtensionService()->
+ OnExtensionInstalled(extension.get(), false, -1);
return extension;
}
diff --git a/chrome/browser/ui/webui/ntp/app_launcher_handler.cc b/chrome/browser/ui/webui/ntp/app_launcher_handler.cc
index 36efd10..466911e 100644
--- a/chrome/browser/ui/webui/ntp/app_launcher_handler.cc
+++ b/chrome/browser/ui/webui/ntp/app_launcher_handler.cc
@@ -877,7 +877,7 @@ void AppLauncherHandler::OnFaviconForApp(FaviconService::Handle handle,
}
scoped_refptr<CrxInstaller> installer(
- extension_service_->MakeCrxInstaller(NULL));
+ CrxInstaller::Create(extension_service_, NULL));
installer->set_page_index(install_info->page_index);
installer->InstallWebApp(*web_app);
attempted_bookmark_app_install_ = true;
diff --git a/chrome/browser/ui/webui/options/extension_settings_handler.cc b/chrome/browser/ui/webui/options/extension_settings_handler.cc
index f8c3fc5..cc8607c 100644
--- a/chrome/browser/ui/webui/options/extension_settings_handler.cc
+++ b/chrome/browser/ui/webui/options/extension_settings_handler.cc
@@ -20,6 +20,7 @@
#include "chrome/browser/extensions/extension_service.h"
#include "chrome/browser/extensions/extension_updater.h"
#include "chrome/browser/extensions/extension_warning_set.h"
+#include "chrome/browser/extensions/unpacked_installer.h"
#include "chrome/browser/google/google_util.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/tab_contents/background_contents.h"
@@ -427,7 +428,8 @@ void ExtensionSettingsHandler::HandleLoadMessage(const ListValue* args) {
FilePath::StringType string_path;
CHECK_EQ(1U, args->GetSize()) << args->GetSize();
CHECK(args->GetString(0, &string_path));
- extension_service_->LoadExtension(FilePath(string_path));
+ extensions::UnpackedInstaller::Create(extension_service_)->
+ Load(FilePath(string_path));
}
void ExtensionSettingsHandler::ShowAlert(const std::string& message) {
diff --git a/chrome/chrome_browser.gypi b/chrome/chrome_browser.gypi
index 28c03f9..d29cee5 100644
--- a/chrome/chrome_browser.gypi
+++ b/chrome/chrome_browser.gypi
@@ -952,16 +952,18 @@
'browser/extensions/app_notification_storage.h',
'browser/extensions/apps_promo.cc',
'browser/extensions/apps_promo.h',
- 'browser/extensions/default_apps.cc',
- 'browser/extensions/default_apps.h',
- 'browser/extensions/default_apps_trial.cc',
- 'browser/extensions/default_apps_trial.h',
+ 'browser/extensions/component_loader.cc',
+ 'browser/extensions/component_loader.h',
'browser/extensions/convert_user_script.cc',
'browser/extensions/convert_user_script.h',
'browser/extensions/convert_web_app.cc',
'browser/extensions/convert_web_app.h',
'browser/extensions/crx_installer.cc',
'browser/extensions/crx_installer.h',
+ 'browser/extensions/default_apps.cc',
+ 'browser/extensions/default_apps.h',
+ 'browser/extensions/default_apps_trial.cc',
+ 'browser/extensions/default_apps_trial.h',
'browser/extensions/execute_code_in_tab_function.cc',
'browser/extensions/execute_code_in_tab_function.h',
'browser/extensions/extension_accessibility_api.cc',
@@ -1230,6 +1232,8 @@
'browser/extensions/image_loading_tracker.h',
'browser/extensions/in_memory_extension_settings_storage.cc',
'browser/extensions/in_memory_extension_settings_storage.h',
+ 'browser/extensions/installed_loader.cc',
+ 'browser/extensions/installed_loader.h',
'browser/extensions/key_identifier_conversion_views.cc',
'browser/extensions/key_identifier_conversion_views.h',
'browser/extensions/network_delay_listener.cc',
@@ -1252,6 +1256,8 @@
'browser/extensions/syncable_extension_settings_storage.h',
'browser/extensions/theme_installed_infobar_delegate.cc',
'browser/extensions/theme_installed_infobar_delegate.h',
+ 'browser/extensions/unpacked_installer.cc',
+ 'browser/extensions/unpacked_installer.h',
'browser/extensions/user_script_listener.cc',
'browser/extensions/user_script_listener.h',
'browser/extensions/user_script_master.cc',