| Index: chrome/browser/extensions/crx_installer.cc
|
| diff --git a/chrome/browser/extensions/crx_installer.cc b/chrome/browser/extensions/crx_installer.cc
|
| index 6b6c732ad05eb7010a77e3ba3f49c369836c9546..60fe23ec18de71030b3322e7a597014f3f1c1189 100644
|
| --- a/chrome/browser/extensions/crx_installer.cc
|
| +++ b/chrome/browser/extensions/crx_installer.cc
|
| @@ -14,38 +14,48 @@
|
| #include "chrome/common/extensions/extension_error_reporter.h"
|
| #include "grit/chromium_strings.h"
|
|
|
| -#if defined(OS_WIN)
|
| -#include "app/win_util.h"
|
| -#elif defined(OS_MACOSX)
|
| -#include "base/scoped_cftyperef.h"
|
| -#include "base/sys_string_conversions.h"
|
| -#include <CoreFoundation/CFUserNotification.h>
|
| -#endif
|
| +namespace {
|
| + // Helper function to delete files. This is used to avoid ugly casts which
|
| + // would be necessary with PostMessage since file_util::Delete is overloaded.
|
| + static void DeleteFileHelper(const FilePath& path, bool recursive) {
|
| + file_util::Delete(path, recursive);
|
| + }
|
| +}
|
| +
|
| +void CrxInstaller::Start(const FilePath& crx_path,
|
| + const FilePath& install_directory,
|
| + Extension::Location install_source,
|
| + const std::string& expected_id,
|
| + bool delete_crx,
|
| + MessageLoop* file_loop,
|
| + ExtensionsService* frontend,
|
| + CrxInstallerClient* client) {
|
| + // Note: We don't keep a reference because this object manages its own
|
| + // lifetime.
|
| + new CrxInstaller(crx_path, install_directory, install_source, expected_id,
|
| + delete_crx, file_loop, frontend, client);
|
| +}
|
|
|
| CrxInstaller::CrxInstaller(const FilePath& crx_path,
|
| const FilePath& install_directory,
|
| Extension::Location install_source,
|
| const std::string& expected_id,
|
| - bool extensions_enabled,
|
| - bool is_from_gallery,
|
| - bool show_prompts,
|
| bool delete_crx,
|
| MessageLoop* file_loop,
|
| - ExtensionsService* frontend)
|
| + ExtensionsService* frontend,
|
| + CrxInstallerClient* client)
|
| : crx_path_(crx_path),
|
| install_directory_(install_directory),
|
| install_source_(install_source),
|
| expected_id_(expected_id),
|
| - extensions_enabled_(extensions_enabled),
|
| - is_from_gallery_(is_from_gallery),
|
| - show_prompts_(show_prompts),
|
| delete_crx_(delete_crx),
|
| file_loop_(file_loop),
|
| - ui_loop_(MessageLoop::current()) {
|
| + ui_loop_(MessageLoop::current()),
|
| + frontend_(frontend),
|
| + client_(client) {
|
| +
|
| + extensions_enabled_ = frontend_->extensions_enabled();
|
|
|
| - // Note: this is a refptr so that we keep the frontend alive long enough to
|
| - // get our response.
|
| - frontend_ = frontend;
|
| unpacker_ = new SandboxedExtensionUnpacker(
|
| crx_path, g_browser_process->resource_dispatcher_host(), this);
|
|
|
| @@ -53,31 +63,40 @@ CrxInstaller::CrxInstaller(const FilePath& crx_path,
|
| &SandboxedExtensionUnpacker::Start));
|
| }
|
|
|
| +CrxInstaller::~CrxInstaller() {
|
| + // Delete the temp directory and crx file as necessary. Note that the
|
| + // destructor might be called on any thread, so we post a task to the file
|
| + // thread to make sure the delete happens there.
|
| + if (!temp_dir_.value().empty()) {
|
| + file_loop_->PostTask(FROM_HERE, NewRunnableFunction(&DeleteFileHelper,
|
| + temp_dir_, true)); // recursive delete
|
| + }
|
| +
|
| + if (delete_crx_) {
|
| + file_loop_->PostTask(FROM_HERE, NewRunnableFunction(&DeleteFileHelper,
|
| + crx_path_, false)); // non-recursive delete
|
| + }
|
| +}
|
| +
|
| void CrxInstaller::OnUnpackFailure(const std::string& error_message) {
|
| + DCHECK(MessageLoop::current() == file_loop_);
|
| ReportFailureFromFileThread(error_message);
|
| }
|
|
|
| void CrxInstaller::OnUnpackSuccess(const FilePath& temp_dir,
|
| const FilePath& extension_dir,
|
| Extension* extension) {
|
| + DCHECK(MessageLoop::current() == file_loop_);
|
| +
|
| // Note: We take ownership of |extension| and |temp_dir|.
|
| extension_.reset(extension);
|
| temp_dir_ = temp_dir;
|
|
|
| - // temp_dir_deleter is stack allocated instead of a member of CrxInstaller, so
|
| - // that delete always happens on the file thread.
|
| - ScopedTempDir temp_dir_deleter;
|
| - temp_dir_deleter.Set(temp_dir);
|
| -
|
| // The unpack dir we don't have to delete explicity since it is a child of
|
| // the temp dir.
|
| unpacked_extension_root_ = extension_dir;
|
| DCHECK(file_util::ContainsPath(temp_dir_, unpacked_extension_root_));
|
|
|
| - // If we were supposed to delete the source file, we can do that now.
|
| - if (delete_crx_)
|
| - file_util::Delete(crx_path_, false); // non-recursive
|
| -
|
| // Determine whether to allow installation. We always allow themes and
|
| // external installs.
|
| if (!extensions_enabled_ && !extension->IsTheme() &&
|
| @@ -89,59 +108,36 @@ void CrxInstaller::OnUnpackSuccess(const FilePath& temp_dir,
|
| // Make sure the expected id matches.
|
| // TODO(aa): Also support expected version?
|
| if (!expected_id_.empty() && expected_id_ != extension->id()) {
|
| - ReportFailureFromFileThread(
|
| - StringPrintf("ID in new extension manifest (%s) does not match "
|
| - "expected id (%s)",
|
| - extension->id().c_str(),
|
| - expected_id_.c_str()));
|
| + ReportFailureFromFileThread(StringPrintf(
|
| + "ID in new extension manifest (%s) does not match expected id (%s)",
|
| + extension->id().c_str(),
|
| + expected_id_.c_str()));
|
| return;
|
| }
|
|
|
| - // Show the confirm UI if necessary.
|
| - // NOTE: We also special case themes to not have a dialog, because we show
|
| - // a special infobar UI for them instead.
|
| - if (show_prompts_ && !extension->IsTheme()) {
|
| - if (!ConfirmInstall())
|
| - return; // error reported by ConfirmInstall()
|
| + if (client_.get()) {
|
| + ui_loop_->PostTask(FROM_HERE, NewRunnableMethod(this,
|
| + &CrxInstaller::ConfirmInstall));
|
| + } else {
|
| + CompleteInstall();
|
| }
|
| -
|
| - CompleteInstall();
|
| }
|
|
|
| -bool CrxInstaller::ConfirmInstall() {
|
| -#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) {
|
| - ReportFailureFromFileThread("User did not allow extension to be "
|
| - "installed.");
|
| - return false;
|
| - }
|
| -#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;
|
| - if (kCFUserNotificationAlternateResponse == 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)) {
|
| - ReportFailureFromFileThread("User did not allow extension to be "
|
| - "installed.");
|
| - return false;
|
| +void CrxInstaller::ConfirmInstall() {
|
| + if (!client_->ConfirmInstall(extension_.get())) {
|
| + // We're done. Since we don't post any more tasks to ourselves, our ref
|
| + // count should go to zero and we die. The destructor will clean up the temp
|
| + // dir.
|
| + return;
|
| }
|
| -#endif // OS_*
|
|
|
| - return true;
|
| + file_loop_->PostTask(FROM_HERE, NewRunnableMethod(this,
|
| + &CrxInstaller::CompleteInstall));
|
| }
|
|
|
| void CrxInstaller::CompleteInstall() {
|
| + DCHECK(MessageLoop::current() == file_loop_);
|
| +
|
| FilePath version_dir;
|
| Extension::InstallType install_type = Extension::INSTALL_ERROR;
|
| std::string error_msg;
|
| @@ -173,22 +169,57 @@ void CrxInstaller::CompleteInstall() {
|
| }
|
|
|
| void CrxInstaller::ReportFailureFromFileThread(const std::string& error) {
|
| + DCHECK(MessageLoop::current() == file_loop_);
|
| ui_loop_->PostTask(FROM_HERE, NewRunnableMethod(this,
|
| &CrxInstaller::ReportFailureFromUIThread, error));
|
| }
|
|
|
| void CrxInstaller::ReportFailureFromUIThread(const std::string& error) {
|
| - ExtensionErrorReporter::GetInstance()->ReportError(error, show_prompts_);
|
| + DCHECK(MessageLoop::current() == ui_loop_);
|
| +
|
| + // This isn't really necessary, it is only used because unit tests expect to
|
| + // see errors get reported via this interface.
|
| + //
|
| + // TODO(aa): Need to go through unit tests and clean them up too, probably get
|
| + // rid of this line.
|
| + ExtensionErrorReporter::GetInstance()->ReportError(error, false); // quiet
|
| +
|
| + if (client_)
|
| + client_->OnInstallFailure(error);
|
| }
|
|
|
| void CrxInstaller::ReportOverinstallFromFileThread() {
|
| - ui_loop_->PostTask(FROM_HERE, NewRunnableMethod(frontend_.get(),
|
| - &ExtensionsService::OnExtensionOverinstallAttempted, extension_->id()));
|
| + DCHECK(MessageLoop::current() == file_loop_);
|
| + ui_loop_->PostTask(FROM_HERE, NewRunnableMethod(this,
|
| + &CrxInstaller::ReportOverinstallFromUIThread));
|
| +}
|
| +
|
| +void CrxInstaller::ReportOverinstallFromUIThread() {
|
| + DCHECK(MessageLoop::current() == ui_loop_);
|
| +
|
| + if (client_.get())
|
| + client_->OnOverinstallAttempted(extension_.get());
|
| +
|
| + frontend_->OnExtensionOverinstallAttempted(extension_->id());
|
| }
|
|
|
| void CrxInstaller::ReportSuccessFromFileThread() {
|
| + DCHECK(MessageLoop::current() == file_loop_);
|
| + ui_loop_->PostTask(FROM_HERE, NewRunnableMethod(this,
|
| + &CrxInstaller::ReportSuccessFromUIThread));
|
| +}
|
| +
|
| +void CrxInstaller::ReportSuccessFromUIThread() {
|
| + DCHECK(MessageLoop::current() == ui_loop_);
|
| +
|
| + // If there is a client, tell the client about installation.
|
| + if (client_.get())
|
| + client_->OnInstallSuccess(extension_.get());
|
| +
|
| // Tell the frontend about the installation and hand off ownership of
|
| // extension_ to it.
|
| - ui_loop_->PostTask(FROM_HERE, NewRunnableMethod(frontend_.get(),
|
| - &ExtensionsService::OnExtensionInstalled, extension_.release()));
|
| + frontend_->OnExtensionInstalled(extension_.release());
|
| +
|
| + // We're done. We don't post any more tasks to ourselves so we are deleted
|
| + // soon.
|
| }
|
|
|