diff options
author | grt@chromium.org <grt@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-03-15 12:00:30 +0000 |
---|---|---|
committer | grt@chromium.org <grt@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-03-15 12:00:30 +0000 |
commit | 2614ed923300f66bd8f9bd2d109f0be5eed69a0d (patch) | |
tree | ef38fcb7c9765d886b97d9c13e2eef7e54d7f8eb /chrome/installer | |
parent | 1b3f6b7b95f4534eab79c01cb46c209003a3a890 (diff) | |
download | chromium_src-2614ed923300f66bd8f9bd2d109f0be5eed69a0d.zip chromium_src-2614ed923300f66bd8f9bd2d109f0be5eed69a0d.tar.gz chromium_src-2614ed923300f66bd8f9bd2d109f0be5eed69a0d.tar.bz2 |
Launch Google Update on uninstall.
So it can self-destruct if Chrome (or Chrome Frame) was the last Omaha-managed product on the system.
BUG=114786
TEST=Install Google Update 1.3.21.105 or later and Chrome w/ --verbose-logging. Uninstall Chrome and see that Google Update vanishes immediately. Take a look at chrome_installer.log and look for messages related to Launching Google Update's uninstaller.
Review URL: http://codereview.chromium.org/9693055
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@126888 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/installer')
-rw-r--r-- | chrome/installer/setup/setup_main.cc | 38 | ||||
-rw-r--r-- | chrome/installer/util/google_update_constants.cc | 4 | ||||
-rw-r--r-- | chrome/installer/util/google_update_constants.h | 10 | ||||
-rw-r--r-- | chrome/installer/util/google_update_settings.cc | 13 | ||||
-rw-r--r-- | chrome/installer/util/google_update_settings.h | 4 | ||||
-rw-r--r-- | chrome/installer/util/google_update_settings_unittest.cc | 101 |
6 files changed, 128 insertions, 42 deletions
diff --git a/chrome/installer/setup/setup_main.cc b/chrome/installer/setup/setup_main.cc index 4d0c845..c99d3e6 100644 --- a/chrome/installer/setup/setup_main.cc +++ b/chrome/installer/setup/setup_main.cc @@ -68,6 +68,7 @@ using installer::MasterPreferences; const wchar_t kChromePipeName[] = L"\\\\.\\pipe\\ChromeCrashServices"; const wchar_t kGoogleUpdatePipeName[] = L"\\\\.\\pipe\\GoogleCrashServices\\"; const wchar_t kSystemPrincipalSid[] = L"S-1-5-18"; +const int kGoogleUpdateTimeoutMs = 20 * 1000; const MINIDUMP_TYPE kLargerDumpType = static_cast<MINIDUMP_TYPE>( MiniDumpWithProcessThreadData | // Get PEB and TEB. @@ -834,6 +835,41 @@ installer::InstallStatus UninstallProduct( cmd_line.GetProgram(), product, remove_all, force_uninstall, cmd_line); } +// Tell Google Update that an uninstall has taken place. This gives it a chance +// to uninstall itself straight away if no more products are installed on the +// system rather than waiting for the next time the scheduled task runs. +// Success or failure of Google Update has no bearing on the success or failure +// of Chrome's uninstallation. +void UninstallGoogleUpdate(bool system_install) { + string16 uninstall_cmd( + GoogleUpdateSettings::GetUninstallCommandLine(system_install)); + if (!uninstall_cmd.empty()) { + base::win::ScopedHandle process; + LOG(INFO) << "Launching Google Update's uninstaller: " << uninstall_cmd; + if (base::LaunchProcess(uninstall_cmd, base::LaunchOptions(), + process.Receive())) { + int exit_code = 0; + if (base::WaitForExitCodeWithTimeout(process, &exit_code, + kGoogleUpdateTimeoutMs)) { + if (exit_code == 0) { + LOG(INFO) << " normal exit."; + } else { + LOG(ERROR) << "Google Update uninstaller (" << uninstall_cmd + << ") exited with code " << exit_code << "."; + } + } else { + // The process didn't finish in time, or GetExitCodeProcess failed. + LOG(ERROR) << "Google Update uninstaller (" << uninstall_cmd + << ") is taking more than " << kGoogleUpdateTimeoutMs + << " milliseconds to complete."; + } + } else { + PLOG(ERROR) << "Failed to launch Google Update uninstaller (" + << uninstall_cmd << ")"; + } + } +} + installer::InstallStatus UninstallProducts( const InstallationState& original_state, const InstallerState& installer_state, @@ -860,6 +896,8 @@ installer::InstallStatus UninstallProducts( install_status = prod_status; } + UninstallGoogleUpdate(installer_state.system_install()); + return install_status; } diff --git a/chrome/installer/util/google_update_constants.cc b/chrome/installer/util/google_update_constants.cc index 4e4126d..761cb61 100644 --- a/chrome/installer/util/google_update_constants.cc +++ b/chrome/installer/util/google_update_constants.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Copyright (c) 2012 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. @@ -12,6 +12,7 @@ const wchar_t kRegPathClients[] = L"Software\\Google\\Update\\Clients"; const wchar_t kRegPathClientState[] = L"Software\\Google\\Update\\ClientState"; const wchar_t kRegPathClientStateMedium[] = L"Software\\Google\\Update\\ClientStateMedium"; +const wchar_t kRegPathGoogleUpdate[] = L"Software\\Google\\Update"; const wchar_t kRegCommandsKey[] = L"Commands"; @@ -41,6 +42,7 @@ const wchar_t kRegRLZReactivationBrandField[] = L"reactivationbrand"; const wchar_t kRegReferralField[] = L"referral"; const wchar_t kRegRenameCmdField[] = L"cmd"; const wchar_t kRegSendsPingsField[] = L"SendsPings"; +const wchar_t kRegUninstallCmdLine[] = L"UninstallCmdLine"; const wchar_t kRegUsageStatsField[] = L"usagestats"; const wchar_t kRegVersionField[] = L"pv"; const wchar_t kRegWebAccessibleField[] = L"WebAccessible"; diff --git a/chrome/installer/util/google_update_constants.h b/chrome/installer/util/google_update_constants.h index eb27910..e7fc369 100644 --- a/chrome/installer/util/google_update_constants.h +++ b/chrome/installer/util/google_update_constants.h @@ -1,4 +1,4 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Copyright (c) 2012 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. @@ -16,11 +16,14 @@ extern const wchar_t kChromeUpgradeCode[]; extern const wchar_t kRegPathClients[]; // The difference between ClientState and ClientStateMedium is that the former -// lives on HKCU or HKLM and the later always lives in HKLM. The only use of -// the ClientStateMedium is for the EULA consent. See bug 1594565. +// lives on HKCU or HKLM and the later always lives in HKLM. ClientStateMedium +// is primarily used for consent of the EULA and stats collection. See bug +// 1594565. extern const wchar_t kRegPathClientState[]; extern const wchar_t kRegPathClientStateMedium[]; +extern const wchar_t kRegPathGoogleUpdate[]; + // The name of the "Commands" key that lives in an app's Clients key // (a.k.a. "Version" key). extern const wchar_t kRegCommandsKey[]; @@ -50,6 +53,7 @@ extern const wchar_t kRegRLZReactivationBrandField[]; extern const wchar_t kRegReferralField[]; extern const wchar_t kRegRenameCmdField[]; extern const wchar_t kRegSendsPingsField[]; +extern const wchar_t kRegUninstallCmdLine[]; extern const wchar_t kRegUsageStatsField[]; extern const wchar_t kRegVersionField[]; extern const wchar_t kRegWebAccessibleField[]; diff --git a/chrome/installer/util/google_update_settings.cc b/chrome/installer/util/google_update_settings.cc index 13d6185..1278c76 100644 --- a/chrome/installer/util/google_update_settings.cc +++ b/chrome/installer/util/google_update_settings.cc @@ -531,3 +531,16 @@ GoogleUpdateSettings::UpdatePolicy GoogleUpdateSettings::GetAppUpdatePolicy( return update_policy; } + +string16 GoogleUpdateSettings::GetUninstallCommandLine(bool system_install) { + const HKEY root_key = system_install ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER; + string16 cmd_line; + RegKey update_key; + + if (update_key.Open(root_key, google_update::kRegPathGoogleUpdate, + KEY_QUERY_VALUE) == ERROR_SUCCESS) { + update_key.ReadValue(google_update::kRegUninstallCmdLine, &cmd_line); + } + + return cmd_line; +} diff --git a/chrome/installer/util/google_update_settings.h b/chrome/installer/util/google_update_settings.h index a21e81c..2485502 100644 --- a/chrome/installer/util/google_update_settings.h +++ b/chrome/installer/util/google_update_settings.h @@ -196,6 +196,10 @@ class GoogleUpdateSettings { static UpdatePolicy GetAppUpdatePolicy(const std::wstring& app_guid, bool* is_overridden); + // Returns Google Update's uninstall command line, or an empty string if none + // is found. + static string16 GetUninstallCommandLine(bool system_install); + private: DISALLOW_IMPLICIT_CONSTRUCTORS(GoogleUpdateSettings); }; diff --git a/chrome/installer/util/google_update_settings_unittest.cc b/chrome/installer/util/google_update_settings_unittest.cc index 59c414c..4eb5d11 100644 --- a/chrome/installer/util/google_update_settings_unittest.cc +++ b/chrome/installer/util/google_update_settings_unittest.cc @@ -23,10 +23,6 @@ using installer::ChannelInfo; namespace { -const wchar_t kHKCUReplacement[] = - L"Software\\Google\\InstallUtilUnittest\\HKCU"; -const wchar_t kHKLMReplacement[] = - L"Software\\Google\\InstallUtilUnittest\\HKLM"; const wchar_t kGoogleUpdatePoliciesKey[] = L"SOFTWARE\\Policies\\Google\\Update"; const wchar_t kGoogleUpdateUpdateDefault[] = L"UpdateDefault"; @@ -45,38 +41,9 @@ const wchar_t kTestProductGuid[] = L"{89F1B351-B15D-48D4-8F10-1298721CF13D}"; // and user settings. class GoogleUpdateSettingsTest: public testing::Test { protected: - virtual void SetUp() { - // Wipe the keys we redirect to. - // This gives us a stable run, even in the presence of previous - // crashes or failures. - LSTATUS err = SHDeleteKey(HKEY_CURRENT_USER, kHKCUReplacement); - EXPECT_TRUE(err == ERROR_SUCCESS || err == ERROR_FILE_NOT_FOUND); - err = SHDeleteKey(HKEY_CURRENT_USER, kHKLMReplacement); - EXPECT_TRUE(err == ERROR_SUCCESS || err == ERROR_FILE_NOT_FOUND); - - // Create the keys we're redirecting HKCU and HKLM to. - ASSERT_EQ(ERROR_SUCCESS, - hkcu_.Create(HKEY_CURRENT_USER, kHKCUReplacement, KEY_READ)); - ASSERT_EQ(ERROR_SUCCESS, - hklm_.Create(HKEY_CURRENT_USER, kHKLMReplacement, KEY_READ)); - - // And do the switcharoo. - ASSERT_EQ(ERROR_SUCCESS, - ::RegOverridePredefKey(HKEY_CURRENT_USER, hkcu_.Handle())); - ASSERT_EQ(ERROR_SUCCESS, - ::RegOverridePredefKey(HKEY_LOCAL_MACHINE, hklm_.Handle())); - } - - virtual void TearDown() { - // Undo the redirection. - EXPECT_EQ(ERROR_SUCCESS, ::RegOverridePredefKey(HKEY_CURRENT_USER, NULL)); - EXPECT_EQ(ERROR_SUCCESS, ::RegOverridePredefKey(HKEY_LOCAL_MACHINE, NULL)); - - // Close our handles and delete the temp keys we redirected to. - hkcu_.Close(); - hklm_.Close(); - EXPECT_EQ(ERROR_SUCCESS, SHDeleteKey(HKEY_CURRENT_USER, kHKCUReplacement)); - EXPECT_EQ(ERROR_SUCCESS, SHDeleteKey(HKEY_CURRENT_USER, kHKLMReplacement)); + virtual void SetUp() OVERRIDE { + registry_overrides_.OverrideRegistry(HKEY_LOCAL_MACHINE, L"HKLM_pit"); + registry_overrides_.OverrideRegistry(HKEY_CURRENT_USER, L"HKCU_pit"); } enum SystemUserInstall { @@ -181,8 +148,7 @@ class GoogleUpdateSettingsTest: public testing::Test { return ap_key_value; } - RegKey hkcu_; - RegKey hklm_; + registry_util::RegistryOverrideManager registry_overrides_; }; } // namespace @@ -590,6 +556,65 @@ TEST_F(GoogleUpdateSettingsTest, GetAppUpdatePolicyAppOverride) { #endif // defined(GOOGLE_CHROME_BUILD) +// Test GoogleUpdateSettings::GetUninstallCommandLine at system- or user-level, +// according to the param. +class GetUninstallCommandLine : public GoogleUpdateSettingsTest, + public testing::WithParamInterface<bool> { + protected: + static const wchar_t kDummyCommand[]; + + virtual void SetUp() OVERRIDE { + GoogleUpdateSettingsTest::SetUp(); + system_install_ = GetParam(); + root_key_ = system_install_ ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER; + } + + HKEY root_key_; + bool system_install_; +}; + +const wchar_t GetUninstallCommandLine::kDummyCommand[] = + L"\"goopdate.exe\" /spam"; + +// Tests that GetUninstallCommandLine returns an empty string if there's no +// Software\Google\Update key. +TEST_P(GetUninstallCommandLine, TestNoKey) { + EXPECT_EQ(string16(), + GoogleUpdateSettings::GetUninstallCommandLine(system_install_)); +} + +// Tests that GetUninstallCommandLine returns an empty string if there's no +// UninstallCmdLine value in the Software\Google\Update key. +TEST_P(GetUninstallCommandLine, TestNoValue) { + RegKey(root_key_, google_update::kRegPathGoogleUpdate, KEY_SET_VALUE); + EXPECT_EQ(string16(), + GoogleUpdateSettings::GetUninstallCommandLine(system_install_)); +} + +// Tests that GetUninstallCommandLine returns an empty string if there's an +// empty UninstallCmdLine value in the Software\Google\Update key. +TEST_P(GetUninstallCommandLine, TestEmptyValue) { + RegKey(root_key_, google_update::kRegPathGoogleUpdate, KEY_SET_VALUE) + .WriteValue(google_update::kRegUninstallCmdLine, L""); + EXPECT_EQ(string16(), + GoogleUpdateSettings::GetUninstallCommandLine(system_install_)); +} + +// Tests that GetUninstallCommandLine returns the correct string if there's an +// UninstallCmdLine value in the Software\Google\Update key. +TEST_P(GetUninstallCommandLine, TestRealValue) { + RegKey(root_key_, google_update::kRegPathGoogleUpdate, KEY_SET_VALUE) + .WriteValue(google_update::kRegUninstallCmdLine, kDummyCommand); + EXPECT_EQ(string16(kDummyCommand), + GoogleUpdateSettings::GetUninstallCommandLine(system_install_)); + // Make sure that there's no value in the other level (user or system). + EXPECT_EQ(string16(), + GoogleUpdateSettings::GetUninstallCommandLine(!system_install_)); +} + +INSTANTIATE_TEST_CASE_P(GetUninstallCommandLineAtLevel, GetUninstallCommandLine, + testing::Bool()); + // Test values for use by the CollectStatsConsent test fixture. class StatsState { public: |