diff options
-rw-r--r-- | chrome/browser/browser_init.cc | 76 | ||||
-rw-r--r-- | chrome/browser/browser_main.cc | 20 | ||||
-rw-r--r-- | chrome/browser/extensions/extensions_service.cc | 19 | ||||
-rw-r--r-- | chrome/browser/extensions/extensions_service.h | 5 | ||||
-rw-r--r-- | chrome/browser/extensions/extensions_service_unittest.cc | 41 | ||||
-rw-r--r-- | chrome/browser/extensions/extensions_startup.cc | 123 | ||||
-rw-r--r-- | chrome/browser/extensions/extensions_startup.h | 24 | ||||
-rw-r--r-- | chrome/browser/process_singleton_win.cc | 11 | ||||
-rw-r--r-- | chrome/chrome_browser.gypi | 2 | ||||
-rw-r--r-- | chrome/common/chrome_switches.cc | 3 | ||||
-rw-r--r-- | chrome/common/chrome_switches.h | 1 | ||||
-rw-r--r-- | chrome/common/result_codes.h | 2 |
12 files changed, 251 insertions, 76 deletions
diff --git a/chrome/browser/browser_init.cc b/chrome/browser/browser_init.cc index f7f01a4..3e7e440 100644 --- a/chrome/browser/browser_init.cc +++ b/chrome/browser/browser_init.cc @@ -909,54 +909,6 @@ void BrowserInit::LaunchWithProfile::CheckDefaultBrowser(Profile* profile) { ChromeThread::FILE, FROM_HERE, new CheckDefaultBrowserTask()); } -class PackExtensionLogger : public PackExtensionJob::Client { - public: - PackExtensionLogger() {} - virtual void OnPackSuccess(const FilePath& crx_path, - const FilePath& output_private_key_path); - virtual void OnPackFailure(const std::string& error_message); - - private: - void ShowPackExtensionMessage(const std::wstring& caption, - const std::wstring& message); - - DISALLOW_COPY_AND_ASSIGN(PackExtensionLogger); -}; - -void PackExtensionLogger::OnPackSuccess(const FilePath& crx_path, - const FilePath& output_private_key_path) -{ - ShowPackExtensionMessage(L"Extension Packaging Success", - PackExtensionJob::StandardSuccessMessage( - crx_path, output_private_key_path)); -} - -void PackExtensionLogger::OnPackFailure(const std::string& error_message) { - ShowPackExtensionMessage(L"Extension Packaging Error", - UTF8ToWide(error_message)); -} - -void PackExtensionLogger::ShowPackExtensionMessage(const std::wstring& caption, - const std::wstring& message) -{ -#if defined(OS_WIN) - win_util::MessageBox(NULL, message, caption, MB_OK | MB_SETFOREGROUND); -#else - // Just send caption & text to stdout on mac & linux. - std::string out_text = WideToASCII(caption); - out_text.append("\n\n"); - out_text.append(WideToASCII(message)); - out_text.append("\n"); - printf("%s", out_text.c_str()); -#endif - - // We got the notification and processed it; we don't expect any further tasks - // to be posted to the current thread, so we should stop blocking and exit. - // This call to |Quit()| matches the call to |Run()| in - // |ProcessCmdLineImpl()|. - MessageLoop::current()->Quit(); -} - bool BrowserInit::ProcessCmdLineImpl(const CommandLine& command_line, const FilePath& cur_dir, bool process_startup, @@ -992,34 +944,6 @@ bool BrowserInit::ProcessCmdLineImpl(const CommandLine& command_line, profile, static_cast<size_t>(expected_tab_count)); } - - if (command_line.HasSwitch(switches::kPackExtension)) { - // Input Paths. - FilePath src_dir = command_line.GetSwitchValuePath( - switches::kPackExtension); - FilePath private_key_path; - if (command_line.HasSwitch(switches::kPackExtensionKey)) { - private_key_path = command_line.GetSwitchValuePath( - switches::kPackExtensionKey); - } - - // Launch a job to perform the packing on the file thread. - PackExtensionLogger pack_client; - scoped_refptr<PackExtensionJob> pack_job = - new PackExtensionJob(&pack_client, src_dir, private_key_path); - pack_job->Start(); - - // The job will post a notification task to the current thread's message - // loop when it is finished. We manually run the loop here so that we - // block and catch the notification. Otherwise, the process would exit; - // in particular, this would mean that |pack_client| would be destroyed - // and we wouldn't be able to report success or failure back to the user. - // This call to |Run()| is matched by a call to |Quit()| in the - // |PackExtensionLogger|'s notification handling code. - MessageLoop::current()->Run(); - - return false; - } } bool silent_launch = false; diff --git a/chrome/browser/browser_main.cc b/chrome/browser/browser_main.cc index d711778..4b3c4c1 100644 --- a/chrome/browser/browser_main.cc +++ b/chrome/browser/browser_main.cc @@ -43,6 +43,7 @@ #include "chrome/browser/dom_ui/chrome_url_data_manager.h" #include "chrome/browser/extensions/extension_protocols.h" #include "chrome/browser/extensions/extensions_service.h" +#include "chrome/browser/extensions/extensions_startup.h" #include "chrome/browser/first_run/first_run.h" #include "chrome/browser/jankometer.h" #include "chrome/browser/labs.h" @@ -1095,6 +1096,13 @@ int BrowserMain(const MainFunctionParams& parameters) { ResultCodes::NORMAL_EXIT : ResultCodes::SHELL_INTEGRATION_FAILED; } + // If the command line specifies --pack-extension, attempt the pack extension + // startup action and exit. + if (parsed_command_line.HasSwitch(switches::kPackExtension)) { + extensions_startup::HandlePackExtension(parsed_command_line); + return ResultCodes::NORMAL_EXIT; + } + #if !defined(OS_MACOSX) // In environments other than Mac OS X we support import of settings // from other browsers. In case this process is a short-lived "import" @@ -1384,6 +1392,18 @@ int BrowserMain(const MainFunctionParams& parameters) { profile->GetExtensionsService()->InitEventRouters(); } + // The extension service may be available at this point. If the command line + // specifies --uninstall-extension, attempt the uninstall extension startup + // action. + if (parsed_command_line.HasSwitch(switches::kUninstallExtension)) { + if (extensions_startup::HandleUninstallExtension(parsed_command_line, + profile)) { + return ResultCodes::NORMAL_EXIT; + } else { + return ResultCodes::UNINSTALL_EXTENSION_ERROR; + } + } + #if defined(OS_WIN) // We check this here because if the profile is OTR (chromeos possibility) // it won't still be accessible after browser is destroyed. diff --git a/chrome/browser/extensions/extensions_service.cc b/chrome/browser/extensions/extensions_service.cc index 0a0b980..bffb732 100644 --- a/chrome/browser/extensions/extensions_service.cc +++ b/chrome/browser/extensions/extensions_service.cc @@ -532,6 +532,25 @@ bool ExtensionsService::IsDownloadFromMiniGallery(const GURL& download_url) { false); // case_sensitive } +// static +bool ExtensionsService::UninstallExtensionHelper( + ExtensionsService* extensions_service, + const std::string& extension_id) { + DCHECK(extensions_service); + + // We can't call UninstallExtension with an invalid extension ID, so check it + // first. + if (extensions_service->GetExtensionById(extension_id, true)) { + extensions_service->UninstallExtension(extension_id, false); + } else { + LOG(WARNING) << "Attempted uninstallation of non-existent extension with " + << "extension with id: " << extension_id; + return false; + } + + return true; +} + ExtensionsService::ExtensionsService(Profile* profile, const CommandLine* command_line, const FilePath& install_directory, diff --git a/chrome/browser/extensions/extensions_service.h b/chrome/browser/extensions/extensions_service.h index 7d5ad97..18ef1f3 100644 --- a/chrome/browser/extensions/extensions_service.h +++ b/chrome/browser/extensions/extensions_service.h @@ -139,6 +139,11 @@ class ExtensionsService // Used to test if we need to show the "Loading" dialog for themes. static bool IsDownloadFromMiniGallery(const GURL& download_url); + // Attempts to uninstall an extension from a given ExtensionService. Returns + // true iff the target extension exists. + static bool UninstallExtensionHelper(ExtensionsService* extensions_service, + const std::string& extension_id); + ExtensionsService(Profile* profile, const CommandLine* command_line, const FilePath& install_directory, diff --git a/chrome/browser/extensions/extensions_service_unittest.cc b/chrome/browser/extensions/extensions_service_unittest.cc index 3240287..7d6733d 100644 --- a/chrome/browser/extensions/extensions_service_unittest.cc +++ b/chrome/browser/extensions/extensions_service_unittest.cc @@ -2034,6 +2034,47 @@ TEST_F(ExtensionsServiceTest, UninstallExtension) { EXPECT_FALSE(file_util::PathExists(extension_path)); } +// Tests the uninstaller helper. +TEST_F(ExtensionsServiceTest, UninstallExtensionHelper) { + InitializeEmptyExtensionsService(); + FilePath extensions_path; + ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &extensions_path)); + extensions_path = extensions_path.AppendASCII("extensions"); + + // A simple extension that should install without error. + FilePath path = extensions_path.AppendASCII("good.crx"); + InstallExtension(path, true); + + // The directory should be there now. + const char* extension_id = good_crx; + FilePath extension_path = extensions_install_dir_.AppendASCII(extension_id); + EXPECT_TRUE(file_util::PathExists(extension_path)); + + bool result = ExtensionsService::UninstallExtensionHelper(service_, + extension_id); + total_successes_ = 0; + + EXPECT_TRUE(result); + + // We should get an unload notification. + ASSERT_TRUE(unloaded_id_.length()); + EXPECT_EQ(extension_id, unloaded_id_); + + ValidatePrefKeyCount(0); + + // The extension should not be in the service anymore. + ASSERT_FALSE(service_->GetExtensionById(extension_id, false)); + loop_.RunAllPending(); + + // The directory should be gone. + EXPECT_FALSE(file_util::PathExists(extension_path)); + + // Attempt to uninstall again. This should fail as we just removed the + // extension. + result = ExtensionsService::UninstallExtensionHelper(service_, extension_id); + EXPECT_FALSE(result); +} + // Verifies extension state is removed upon uninstall TEST_F(ExtensionsServiceTest, ClearExtensionData) { InitializeEmptyExtensionsService(); diff --git a/chrome/browser/extensions/extensions_startup.cc b/chrome/browser/extensions/extensions_startup.cc new file mode 100644 index 0000000..90b0372 --- /dev/null +++ b/chrome/browser/extensions/extensions_startup.cc @@ -0,0 +1,123 @@ +// Copyright (c) 2010 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/extensions_startup.h" + +#include "base/string_util.h" +#include "base/stringprintf.h" +#include "base/utf_string_conversions.h" +#include "chrome/browser/extensions/extensions_service.h" +#include "chrome/browser/extensions/pack_extension_job.h" +#include "chrome/browser/profile.h" +#include "chrome/common/chrome_switches.h" + +#if defined(OS_WIN) +#include "app/win_util.h" +#endif + +namespace extensions_startup { + +class PackExtensionLogger : public PackExtensionJob::Client { + public: + PackExtensionLogger() {} + virtual void OnPackSuccess(const FilePath& crx_path, + const FilePath& output_private_key_path); + virtual void OnPackFailure(const std::string& error_message); + + private: + // We need to track if this extension packing job was created on process + // startup or not so we know if we should Quit() the message loop after + // packaging the extension. + bool process_startup_; + void ShowPackExtensionMessage(const std::wstring& caption, + const std::wstring& message); + + DISALLOW_COPY_AND_ASSIGN(PackExtensionLogger); +}; + +void PackExtensionLogger::OnPackSuccess( + const FilePath& crx_path, + const FilePath& output_private_key_path) { + ShowPackExtensionMessage(L"Extension Packaging Success", + PackExtensionJob::StandardSuccessMessage( + crx_path, output_private_key_path)); +} + +void PackExtensionLogger::OnPackFailure(const std::string& error_message) { + ShowPackExtensionMessage(L"Extension Packaging Error", + UTF8ToWide(error_message)); +} + +void PackExtensionLogger::ShowPackExtensionMessage( + const std::wstring& caption, + const std::wstring& message) { +#if defined(OS_WIN) + win_util::MessageBox(NULL, message, caption, MB_OK | MB_SETFOREGROUND); +#else + // Just send caption & text to stdout on mac & linux. + std::string out_text = WideToASCII(caption); + out_text.append("\n\n"); + out_text.append(WideToASCII(message)); + out_text.append("\n"); + base::StringPrintf("%s", out_text.c_str()); +#endif + + // We got the notification and processed it; we don't expect any further tasks + // to be posted to the current thread, so we should stop blocking and exit. + // This call to |Quit()| matches the call to |Run()| in + // |ProcessCmdLineImpl()|. + MessageLoop::current()->Quit(); +} + +bool HandlePackExtension(const CommandLine& cmd_line) { + if (cmd_line.HasSwitch(switches::kPackExtension)) { + // Input Paths. + FilePath src_dir = cmd_line.GetSwitchValuePath( + switches::kPackExtension); + FilePath private_key_path; + if (cmd_line.HasSwitch(switches::kPackExtensionKey)) { + private_key_path = cmd_line.GetSwitchValuePath( + switches::kPackExtensionKey); + } + + // Launch a job to perform the packing on the file thread. + PackExtensionLogger pack_client; + scoped_refptr<PackExtensionJob> pack_job = + new PackExtensionJob(&pack_client, src_dir, private_key_path); + pack_job->Start(); + + // The job will post a notification task to the current thread's message + // loop when it is finished. We manually run the loop here so that we + // block and catch the notification. Otherwise, the process would exit; + // in particular, this would mean that |pack_client| would be destroyed + // and we wouldn't be able to report success or failure back to the user. + // This call to |Run()| is matched by a call to |Quit()| in the + // |PackExtensionLogger|'s notification handling code. + MessageLoop::current()->Run(); + + return true; + } + + return false; +} + +bool HandleUninstallExtension(const CommandLine& cmd_line, Profile* profile) { + DCHECK(profile); + + if (cmd_line.HasSwitch(switches::kUninstallExtension)) { + ExtensionsService* extensions_service = profile->GetExtensionsService(); + if (extensions_service) { + std::string extension_id = cmd_line.GetSwitchValueASCII( + switches::kUninstallExtension); + if (ExtensionsService::UninstallExtensionHelper(extensions_service, + extension_id)) { + return true; + } + } + } + + return false; +} + +} // namespace extensions_startup diff --git a/chrome/browser/extensions/extensions_startup.h b/chrome/browser/extensions/extensions_startup.h new file mode 100644 index 0000000..85622de --- /dev/null +++ b/chrome/browser/extensions/extensions_startup.h @@ -0,0 +1,24 @@ +// Copyright (c) 2010 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_EXTENSIONS_STARTUP_H_ +#define CHROME_BROWSER_EXTENSIONS_EXTENSIONS_STARTUP_H_ +#pragma once + +class CommandLine; +class Profile; + +// Initialization helpers for various Extension startup actions. +namespace extensions_startup { +// Handle --pack-extension flag from the |cmd_line| by packing the specified +// extension. Returns false if the pack job could not be started. +bool HandlePackExtension(const CommandLine& cmd_line); + +// Handle --uninstall-extension flag from the |cmd_line| by uninstalling the +// specified extension from |profile|. Returns false if the uninstall job +// could not be started. +bool HandleUninstallExtension(const CommandLine& cmd_line, Profile* profile); +} // namespace extensions_startup + +#endif // CHROME_BROWSER_EXTENSIONS_EXTENSIONS_STARTUP_H_ diff --git a/chrome/browser/process_singleton_win.cc b/chrome/browser/process_singleton_win.cc index 52c7a96..5cbf2a5 100644 --- a/chrome/browser/process_singleton_win.cc +++ b/chrome/browser/process_singleton_win.cc @@ -15,11 +15,13 @@ #include "base/win_util.h" #include "chrome/browser/browser_init.h" #include "chrome/browser/browser_process.h" +#include "chrome/browser/extensions/extensions_startup.h" #include "chrome/browser/platform_util.h" #include "chrome/browser/profile.h" #include "chrome/browser/profile_manager.h" #include "chrome/common/chrome_constants.h" #include "chrome/common/chrome_paths.h" +#include "chrome/common/chrome_switches.h" #include "chrome/common/result_codes.h" #include "chrome/installer/util/browser_distribution.h" #include "grit/chromium_strings.h" @@ -279,6 +281,15 @@ LRESULT ProcessSingleton::OnCopyData(HWND hwnd, const COPYDATASTRUCT* cds) { return TRUE; } + // Handle the --uninstall-extension startup action. This needs to done here + // in the process that is running with the target profile, otherwise the + // uninstall will fail to unload and remove all components. + if (parsed_command_line.HasSwitch(switches::kUninstallExtension)) { + extensions_startup::HandleUninstallExtension(parsed_command_line, + profile); + return TRUE; + } + // Run the browser startup sequence again, with the command line of the // signalling process. BrowserInit::ProcessCommandLine(parsed_command_line, cur_dir, false, diff --git a/chrome/chrome_browser.gypi b/chrome/chrome_browser.gypi index ae97345..0f3ed35 100644 --- a/chrome/chrome_browser.gypi +++ b/chrome/chrome_browser.gypi @@ -1523,6 +1523,8 @@ 'browser/extensions/extensions_quota_service.h', 'browser/extensions/extensions_service.cc', 'browser/extensions/extensions_service.h', + 'browser/extensions/extensions_startup.cc', + 'browser/extensions/extensions_startup.h', 'browser/extensions/extensions_ui.cc', 'browser/extensions/extensions_ui.h', 'browser/extensions/external_extension_provider.h', diff --git a/chrome/common/chrome_switches.cc b/chrome/common/chrome_switches.cc index ad0f613..ef77ba2 100644 --- a/chrome/common/chrome_switches.cc +++ b/chrome/common/chrome_switches.cc @@ -694,6 +694,9 @@ const char kKeepAliveForTest[] = "keep-alive-for-test"; // Load an extension from the specified directory. const char kLoadExtension[] = "load-extension"; +// Uninstall an extension with the specified extension id. +const char kUninstallExtension[] = "uninstall-extension"; + // Load an NPAPI plugin from the specified path. const char kLoadPlugin[] = "load-plugin"; diff --git a/chrome/common/chrome_switches.h b/chrome/common/chrome_switches.h index 2fd5b1e..c62241d 100644 --- a/chrome/common/chrome_switches.h +++ b/chrome/common/chrome_switches.h @@ -202,6 +202,7 @@ extern const char kInternalPepper[]; extern const char kJavaScriptFlags[]; extern const char kKeepAliveForTest[]; extern const char kLoadExtension[]; +extern const char kUninstallExtension[]; extern const char kLoadPlugin[]; extern const char kExtraPluginDir[]; extern const char kLogNetLog[]; diff --git a/chrome/common/result_codes.h b/chrome/common/result_codes.h index 0b4bc3c..6625cb0 100644 --- a/chrome/common/result_codes.h +++ b/chrome/common/result_codes.h @@ -57,6 +57,8 @@ class ResultCodes { PROFILE_IN_USE, // The profile was in use on another host. + UNINSTALL_EXTENSION_ERROR, // Failed to silently uninstall an extension. + EXIT_LAST_CODE // Last return code (keep it last). }; }; |