Index: chrome/browser/extensions/extensions_service.cc |
diff --git a/chrome/browser/extensions/extensions_service.cc b/chrome/browser/extensions/extensions_service.cc |
index 71f519b68564b1a6c7417e6eb58e8576ecfe9d4e..4257de04bdb880f74efa29205b171066214429ec 100644 |
--- a/chrome/browser/extensions/extensions_service.cc |
+++ b/chrome/browser/extensions/extensions_service.cc |
@@ -4,18 +4,13 @@ |
#include "chrome/browser/extensions/extensions_service.h" |
-#include "app/l10n_util.h" |
#include "base/command_line.h" |
#include "base/file_util.h" |
#include "base/string_util.h" |
#include "base/values.h" |
-#include "chrome/browser/browser.h" |
-#include "chrome/browser/browser_list.h" |
-#include "chrome/browser/browser_process.h" |
-#include "chrome/browser/chrome_thread.h" |
+#include "chrome/browser/extensions/crx_installer.h" |
#include "chrome/browser/extensions/extension_browser_event_router.h" |
#include "chrome/browser/extensions/extension_file_util.h" |
-#include "chrome/browser/extensions/extension_process_manager.h" |
#include "chrome/browser/extensions/extension_updater.h" |
#include "chrome/browser/extensions/external_extension_provider.h" |
#include "chrome/browser/extensions/external_pref_extension_provider.h" |
@@ -29,16 +24,9 @@ |
#include "chrome/common/pref_names.h" |
#include "chrome/common/pref_service.h" |
#include "chrome/common/url_constants.h" |
-#include "grit/chromium_strings.h" |
-#include "grit/generated_resources.h" |
#if defined(OS_WIN) |
-#include "app/win_util.h" |
#include "chrome/browser/extensions/external_registry_extension_provider_win.h" |
-#elif defined(OS_MACOSX) |
-#include "base/scoped_cftyperef.h" |
-#include "base/sys_string_conversions.h" |
-#include <CoreFoundation/CFUserNotification.h> |
#endif |
// ExtensionsService. |
@@ -62,61 +50,6 @@ bool ExtensionsService::IsDownloadFromGallery(const GURL& download_url, |
} |
} |
-// This class hosts a SandboxedExtensionUnpacker task and routes the results |
-// back to ExtensionsService. The unpack process is started immediately on |
-// construction of this object. |
-class ExtensionsServiceBackend::UnpackerClient |
- : public SandboxedExtensionUnpackerClient { |
- public: |
- UnpackerClient(ExtensionsServiceBackend* backend, |
- const FilePath& extension_path, |
- const std::string& expected_id, |
- bool silent, bool from_gallery) |
- : backend_(backend), extension_path_(extension_path), |
- expected_id_(expected_id), silent_(silent), from_gallery_(from_gallery) { |
- unpacker_ = new SandboxedExtensionUnpacker(extension_path, |
- backend->resource_dispatcher_host_, this); |
- unpacker_->Start(); |
- } |
- |
- private: |
- // SandboxedExtensionUnpackerClient |
- virtual void OnUnpackSuccess(const FilePath& temp_dir, |
- const FilePath& extension_dir, |
- Extension* extension) { |
- backend_->OnExtensionUnpacked(extension_path_, extension_dir, extension, |
- expected_id_, silent_, from_gallery_); |
- file_util::Delete(temp_dir, true); |
- delete this; |
- } |
- |
- virtual void OnUnpackFailure(const std::string& error_message) { |
- backend_->ReportExtensionInstallError(extension_path_, error_message); |
- delete this; |
- } |
- |
- scoped_refptr<SandboxedExtensionUnpacker> unpacker_; |
- |
- scoped_refptr<ExtensionsServiceBackend> backend_; |
- |
- // The path to the crx file that we're installing. |
- FilePath extension_path_; |
- |
- // The path to the copy of the crx file in the temporary directory where we're |
- // unpacking it. |
- FilePath temp_extension_path_; |
- |
- // The ID we expect this extension to have, if any. |
- std::string expected_id_; |
- |
- // True if the install should be done with no confirmation dialog. |
- bool silent_; |
- |
- // True if the install is from the gallery (and therefore should not get an |
- // alert UI if it turns out to also be a theme). |
- bool from_gallery_; |
-}; |
- |
ExtensionsService::ExtensionsService(Profile* profile, |
const CommandLine* command_line, |
PrefService* prefs, |
@@ -147,9 +80,7 @@ ExtensionsService::ExtensionsService(Profile* profile, |
updater_ = new ExtensionUpdater(this, update_frequency, backend_loop_); |
} |
- backend_ = new ExtensionsServiceBackend( |
- install_directory_, g_browser_process->resource_dispatcher_host(), |
- frontend_loop, extensions_enabled()); |
+ backend_ = new ExtensionsServiceBackend(install_directory_, frontend_loop); |
} |
ExtensionsService::~ExtensionsService() { |
@@ -159,12 +90,6 @@ ExtensionsService::~ExtensionsService() { |
} |
} |
-void ExtensionsService::SetExtensionsEnabled(bool enabled) { |
- extensions_enabled_ = true; |
- backend_loop_->PostTask(FROM_HERE, NewRunnableMethod(backend_.get(), |
- &ExtensionsServiceBackend::set_extensions_enabled, enabled)); |
-} |
- |
void ExtensionsService::Init() { |
DCHECK(!ready_); |
DCHECK_EQ(extensions_.size(), 0u); |
@@ -189,41 +114,32 @@ void ExtensionsService::InstallExtension(const FilePath& extension_path) { |
void ExtensionsService::InstallExtension(const FilePath& extension_path, |
const GURL& download_url, |
const GURL& referrer_url) { |
- backend_loop_->PostTask(FROM_HERE, NewRunnableMethod(backend_.get(), |
- &ExtensionsServiceBackend::InstallExtension, extension_path, |
- IsDownloadFromGallery(download_url, referrer_url), |
- scoped_refptr<ExtensionsService>(this))); |
- |
+ new CrxInstaller(extension_path, install_directory_, Extension::INTERNAL, |
+ "", // no expected id |
+ extensions_enabled_, |
+ IsDownloadFromGallery(download_url, referrer_url), |
+ show_extensions_prompts(), |
+ false, // don't delete crx when complete |
+ backend_loop_, |
+ this); |
} |
void ExtensionsService::UpdateExtension(const std::string& id, |
- const FilePath& extension_path, |
- bool alert_on_error, |
- ExtensionInstallCallback* callback) { |
- if (callback) { |
- if (install_callbacks_.find(extension_path) != install_callbacks_.end()) { |
- // We can't have multiple outstanding install requests for the same |
- // path, so immediately indicate error via the callback here. |
- LOG(WARNING) << "Dropping update request for '" << |
- extension_path.value() << "' (already in progress)'"; |
- callback->Run(extension_path, static_cast<Extension*>(NULL)); |
- delete callback; |
- return; |
- } |
- install_callbacks_[extension_path] = |
- linked_ptr<ExtensionInstallCallback>(callback); |
- } |
+ const FilePath& extension_path) { |
- if (!GetExtensionById(id)) { |
- LOG(WARNING) << "Will not update extension " << id << " because it is not " |
- << "installed"; |
- FireInstallCallback(extension_path, NULL); |
- return; |
+ if (!GetExtensionById(id)) { |
+ LOG(WARNING) << "Will not update extension " << id << " because it is not " |
+ << "installed"; |
+ return; |
} |
- backend_loop_->PostTask(FROM_HERE, NewRunnableMethod(backend_.get(), |
- &ExtensionsServiceBackend::UpdateExtension, id, extension_path, |
- alert_on_error, scoped_refptr<ExtensionsService>(this))); |
+ new CrxInstaller(extension_path, install_directory_, Extension::INTERNAL, |
+ id, extensions_enabled_, |
+ false, // not from gallery |
+ show_extensions_prompts(), |
+ true, // delete crx when complete |
+ backend_loop_, |
+ this); |
} |
void ExtensionsService::UninstallExtension(const std::string& extension_id, |
@@ -261,6 +177,8 @@ void ExtensionsService::LoadAllExtensions() { |
void ExtensionsService::CheckForExternalUpdates() { |
// This installs or updates externally provided extensions. |
+ // TODO(aa): Why pass this list into the provider, why not just filter it |
+ // later? |
std::set<std::string> killed_extensions; |
extension_prefs_->GetKilledExtensionIds(&killed_extensions); |
backend_loop_->PostTask(FROM_HERE, NewRunnableMethod(backend_.get(), |
@@ -380,9 +298,7 @@ void ExtensionsService::OnExtensionsLoaded(ExtensionList* new_extensions) { |
} |
} |
-void ExtensionsService::OnExtensionInstalled(const FilePath& path, |
- Extension* extension, Extension::InstallType install_type) { |
- FireInstallCallback(path, extension); |
+void ExtensionsService::OnExtensionInstalled(Extension* extension) { |
extension_prefs_->OnExtensionInstalled(extension); |
// If the extension is a theme, tell the profile (and therefore ThemeProvider) |
@@ -399,25 +315,15 @@ void ExtensionsService::OnExtensionInstalled(const FilePath& path, |
Source<ExtensionsService>(this), |
Details<Extension>(extension)); |
} |
-} |
- |
-void ExtensionsService::OnExtenionInstallError(const FilePath& path) { |
- FireInstallCallback(path, NULL); |
+ // Also load the extension. |
+ ExtensionList* list = new ExtensionList; |
+ list->push_back(extension); |
+ OnExtensionsLoaded(list); |
} |
-void ExtensionsService::FireInstallCallback(const FilePath& path, |
- Extension* extension) { |
- CallbackMap::iterator iter = install_callbacks_.find(path); |
- if (iter != install_callbacks_.end()) { |
- iter->second->Run(path, extension); |
- install_callbacks_.erase(iter); |
- } |
-} |
-void ExtensionsService::OnExtensionOverinstallAttempted(const std::string& id, |
- const FilePath& path) { |
- FireInstallCallback(path, NULL); |
+void ExtensionsService::OnExtensionOverinstallAttempted(const std::string& id) { |
Extension* extension = GetExtensionById(id); |
if (extension && extension->IsTheme()) { |
ShowThemePreviewInfobar(extension); |
@@ -472,17 +378,50 @@ bool ExtensionsService::ShowThemePreviewInfobar(Extension* extension) { |
return true; |
} |
+void ExtensionsService::OnExternalExtensionFound(const std::string& id, |
+ const std::string& version, |
+ const FilePath& path, |
+ Extension::Location location) { |
+ // Before even bothering to unpack, check and see if we already have this |
+ // version. This is important because these extensions are going to get |
+ // installed on every startup. |
+ Extension* existing = GetExtensionById(id); |
+ if (existing) { |
+ switch (existing->version()->CompareTo( |
+ *Version::GetVersionFromString(version))) { |
+ case -1: // existing version is older, we should upgrade |
+ break; |
+ case 0: // existing version is same, do nothing |
+ return; |
+ case 1: // existing version is newer, uh-oh |
+ LOG(WARNING) << "Found external version of extension " << id |
+ << "that is older than current version. Current version " |
+ << "is: " << existing->VersionString() << ". New version " |
+ << "is: " << version << ". Keeping current version."; |
+ return; |
+ } |
+ } |
+ |
+ new CrxInstaller(path, install_directory_, location, id, extensions_enabled_, |
+ false, // not from gallery |
+ show_extensions_prompts(), |
+ false, // don't delete crx when complete |
+ backend_loop_, |
+ this); |
+} |
+ |
+ |
// ExtensionsServicesBackend |
ExtensionsServiceBackend::ExtensionsServiceBackend( |
- const FilePath& install_directory, ResourceDispatcherHost* rdh, |
- MessageLoop* frontend_loop, bool extensions_enabled) |
+ const FilePath& install_directory, MessageLoop* frontend_loop) |
: frontend_(NULL), |
install_directory_(install_directory), |
- resource_dispatcher_host_(rdh), |
alert_on_error_(false), |
- frontend_loop_(frontend_loop), |
- extensions_enabled_(extensions_enabled) { |
+ frontend_loop_(frontend_loop) { |
+ // TODO(aa): This ends up doing blocking IO on the UI thread because it reads |
+ // pref data in the ctor and that is called on the UI thread. Would be better |
+ // to re-read data each time we list external extensions, anyway. |
external_extension_providers_[Extension::EXTERNAL_PREF] = |
linked_ptr<ExternalExtensionProvider>( |
new ExternalPrefExtensionProvider()); |
@@ -589,180 +528,6 @@ void ExtensionsServiceBackend::ReportExtensionsLoaded( |
frontend_, &ExtensionsService::OnExtensionsLoaded, extensions)); |
} |
-void ExtensionsServiceBackend::InstallExtension( |
- const FilePath& extension_path, bool from_gallery, |
- scoped_refptr<ExtensionsService> frontend) { |
- LOG(INFO) << "Installing extension " << extension_path.value(); |
- |
- frontend_ = frontend; |
- alert_on_error_ = true; |
- |
- InstallOrUpdateExtension(extension_path, from_gallery, std::string(), false); |
-} |
- |
-void ExtensionsServiceBackend::UpdateExtension(const std::string& id, |
- const FilePath& extension_path, bool alert_on_error, |
- scoped_refptr<ExtensionsService> frontend) { |
- LOG(INFO) << "Updating extension " << id << " " << extension_path.value(); |
- |
- frontend_ = frontend; |
- alert_on_error_ = alert_on_error; |
- |
- InstallOrUpdateExtension(extension_path, false, id, true); |
-} |
- |
-void ExtensionsServiceBackend::InstallOrUpdateExtension( |
- const FilePath& extension_path, bool from_gallery, |
- const std::string& expected_id, bool silent) { |
- UnpackerClient* client = new UnpackerClient( |
- this, extension_path, expected_id, silent, from_gallery); |
-} |
- |
-void ExtensionsServiceBackend::OnExtensionUnpacked( |
- const FilePath& crx_path, const FilePath& unpacked_path, |
- Extension* extension, const std::string expected_id, bool silent, |
- bool from_gallery) { |
- // Take ownership of the extension object. |
- scoped_ptr<Extension> extension_deleter(extension); |
- |
- Extension::Location location = Extension::INTERNAL; |
- LookupExternalExtension(extension->id(), NULL, &location); |
- extension->set_location(location); |
- |
- bool allow_install = false; |
- if (extensions_enabled_) |
- allow_install = true; |
- |
- // Always allow themes. |
- if (extension->IsTheme()) |
- allow_install = true; |
- |
- // Always allow externally installed extensions (partners use this). |
- if (Extension::IsExternalLocation(location)) |
- allow_install = true; |
- |
- if (!allow_install) { |
- ReportExtensionInstallError(crx_path, "Extensions are not enabled."); |
- return; |
- } |
- |
- // TODO(extensions): Make better extensions UI. http://crbug.com/12116 |
- |
- // We also skip the dialog for a few special cases: |
- // - themes (because we show the preview infobar for them) |
- // - externally registered extensions |
- // - during tests (!frontend->show_extension_prompts()) |
- // - autoupdate (silent). |
- bool show_dialog = true; |
- if (extension->IsTheme()) |
- show_dialog = false; |
- |
- if (Extension::IsExternalLocation(location)) |
- show_dialog = false; |
- |
- if (silent || !frontend_->show_extensions_prompts()) |
- show_dialog = false; |
- |
- if (show_dialog) { |
-#if defined(OS_WIN) |
- if (win_util::MessageBox(GetForegroundWindow(), |
- L"Are you sure you want to install this extension?\n\n" |
- L"You should only install extensions from sources you trust.", |
- l10n_util::GetString(IDS_PRODUCT_NAME).c_str(), |
- MB_OKCANCEL) != IDOK) { |
- return; |
- } |
-#elif defined(OS_MACOSX) |
- // Using CoreFoundation to do this dialog is unimaginably lame but will do |
- // until the UI is redone. |
- scoped_cftyperef<CFStringRef> product_name( |
- base::SysWideToCFStringRef(l10n_util::GetString(IDS_PRODUCT_NAME))); |
- CFOptionFlags response; |
- CFUserNotificationDisplayAlert( |
- 0, kCFUserNotificationCautionAlertLevel, NULL, NULL, NULL, |
- product_name, |
- CFSTR("Are you sure you want to install this extension?\n\n" |
- "This is a temporary message and it will be removed when " |
- "extensions UI is finalized."), |
- NULL, CFSTR("Cancel"), NULL, &response); |
- |
- if (response == kCFUserNotificationAlternateResponse) { |
- ReportExtensionInstallError(extension_path, |
- "User did not allow extension to be installed."); |
- return; |
- } |
-#endif // OS_* |
- } |
- |
- // If an expected id was provided, make sure it matches. |
- if (!expected_id.empty() && expected_id != extension->id()) { |
- ReportExtensionInstallError(crx_path, |
- StringPrintf("ID in new extension manifest (%s) does not match " |
- "expected id (%s)", extension->id(), expected_id)); |
- return; |
- } |
- |
- FilePath version_dir; |
- Extension::InstallType install_type = Extension::INSTALL_ERROR; |
- std::string error_msg; |
- if (!extension_file_util::InstallExtension(unpacked_path, install_directory_, |
- extension->id(), |
- extension->VersionString(), |
- &version_dir, |
- &install_type, &error_msg)) { |
- ReportExtensionInstallError(crx_path, error_msg); |
- return; |
- } |
- |
- if (install_type == Extension::DOWNGRADE) { |
- ReportExtensionInstallError(crx_path, "Attempted to downgrade extension."); |
- return; |
- } |
- |
- extension->set_path(version_dir); |
- |
- if (install_type == Extension::REINSTALL) { |
- // The client may use this as a signal (to switch themes, for instance). |
- ReportExtensionOverinstallAttempted(extension->id(), crx_path); |
- return; |
- } |
- |
- frontend_loop_->PostTask(FROM_HERE, NewRunnableMethod( |
- frontend_, &ExtensionsService::OnExtensionInstalled, crx_path, |
- extension, install_type)); |
- |
- // Only one extension, but ReportExtensionsLoaded can handle multiple, |
- // so we need to construct a list. |
- ExtensionList* extensions = new ExtensionList; |
- |
- // Hand off ownership of the extension to the frontend. |
- extensions->push_back(extension_deleter.release()); |
- ReportExtensionsLoaded(extensions); |
-} |
- |
-void ExtensionsServiceBackend::ReportExtensionInstallError( |
- const FilePath& extension_path, const std::string &error) { |
- |
- // TODO(erikkay): note that this isn't guaranteed to work properly on Linux. |
- std::string path_str = WideToASCII(extension_path.ToWStringHack()); |
- std::string message = |
- StringPrintf("Could not install extension from '%s'. %s", |
- path_str.c_str(), error.c_str()); |
- ExtensionErrorReporter::GetInstance()->ReportError(message, alert_on_error_); |
- |
- frontend_loop_->PostTask(FROM_HERE, NewRunnableMethod( |
- frontend_, |
- &ExtensionsService::OnExtenionInstallError, |
- extension_path)); |
-} |
- |
-void ExtensionsServiceBackend::ReportExtensionOverinstallAttempted( |
- const std::string& id, const FilePath& path) { |
- frontend_loop_->PostTask(FROM_HERE, NewRunnableMethod( |
- frontend_, &ExtensionsService::OnExtensionOverinstallAttempted, id, |
- path)); |
-} |
- |
bool ExtensionsServiceBackend::LookupExternalExtension( |
const std::string& id, Version** version, Extension::Location* location) { |
scoped_ptr<Version> extension_version; |
@@ -835,9 +600,9 @@ void ExtensionsServiceBackend::SetProviderForTesting( |
} |
void ExtensionsServiceBackend::OnExternalExtensionFound( |
- const std::string& id, const Version* version, const FilePath& path) { |
- InstallOrUpdateExtension(path, |
- false, // not from gallery |
- id, // expected id |
- true); // silent |
+ const std::string& id, const Version* version, const FilePath& path, |
+ Extension::Location location) { |
+ frontend_loop_->PostTask(FROM_HERE, NewRunnableMethod(frontend_, |
+ &ExtensionsService::OnExternalExtensionFound, id, version->GetString(), |
+ path, location)); |
} |