diff options
author | grt <grt@chromium.org> | 2015-02-12 13:25:28 -0800 |
---|---|---|
committer | Commit bot <commit-bot@chromium.org> | 2015-02-12 21:26:35 +0000 |
commit | 06b99a6d026db87f962ef5ea19dc55cd48bdf965 (patch) | |
tree | 019a0928e3cee903c19ee44d27845320e095cce4 /chrome/installer | |
parent | 5df17877659c5ec9678ead07287d9ff09da0e75e (diff) | |
download | chromium_src-06b99a6d026db87f962ef5ea19dc55cd48bdf965.zip chromium_src-06b99a6d026db87f962ef5ea19dc55cd48bdf965.tar.gz chromium_src-06b99a6d026db87f962ef5ea19dc55cd48bdf965.tar.bz2 |
Repair per-user Chromes broken by a bad canary update.
Canaries 42.0.2293.0 through 42.0.2302.0 contained a bug that broke
updates for regular Chrome installed at user-level. This change
introduces short-term repair code into the canary installer that
launches the installed Chrome so it will self-heal. As per the TODO in
the code, it will be removed once clients have picked it up.
BUG=456602
R=robertshield@chromium.org
Review URL: https://codereview.chromium.org/918773002
Cr-Commit-Position: refs/heads/master@{#316052}
Diffstat (limited to 'chrome/installer')
-rw-r--r-- | chrome/installer/setup/setup_main.cc | 116 | ||||
-rw-r--r-- | chrome/installer/util/install_util.cc | 6 | ||||
-rw-r--r-- | chrome/installer/util/install_util.h | 6 | ||||
-rw-r--r-- | chrome/installer/util/install_util_unittest.cc | 4 | ||||
-rw-r--r-- | chrome/installer/util/installation_state.cc | 4 |
5 files changed, 126 insertions, 10 deletions
diff --git a/chrome/installer/setup/setup_main.cc b/chrome/installer/setup/setup_main.cc index 5454e8d..6be142b 100644 --- a/chrome/installer/setup/setup_main.cc +++ b/chrome/installer/setup/setup_main.cc @@ -67,6 +67,10 @@ #include "installer_util_strings.h" // NOLINT +#if defined(GOOGLE_CHROME_BUILD) +#include "chrome/installer/util/updating_app_registration_data.h" +#endif + using installer::InstallerState; using installer::InstallationState; using installer::InstallationValidator; @@ -677,6 +681,116 @@ void UninstallBinariesIfUnused( } } +// This function is a short-term repair for the damage documented in +// http://crbug.com/456602. Briefly: canaries from 42.0.2293.0 through +// 42.0.2302.0 (inclusive) contained a bug that broke normal Chrome installed at +// user-level. This function detects the broken state during a canary update and +// repairs it by calling on the existing Chrome's installer to fix itself. +// TODO(grt): Remove this once the majority of impacted canary clients have +// picked it up. +void RepairChromeIfBroken(const InstallationState& original_state, + const InstallerState& installer_state) { +#if !defined(GOOGLE_CHROME_BUILD) + // Chromium does not support SxS installation, so there is no work to be done. + return; +#else // GOOGLE_CHROME_BUILD + // Nothing to do if not a per-user SxS install/update. + if (!InstallUtil::IsChromeSxSProcess() || + installer_state.system_install() || + installer_state.is_multi_install()) { + return; + } + + // When running a side-by-side install, BrowserDistribution provides no way + // to create or access a GoogleChromeDistribution (by design). + static const base::char16 kChromeGuid[] = + L"{8A69D345-D564-463c-AFF1-A69D9E530F96}"; + static const base::char16 kChromeBinariesGuid[] = + L"{4DC8B4CA-1BDA-483e-B5FA-D3C12E15B62D}"; + + UpdatingAppRegistrationData chrome_reg_data(kChromeGuid); + UpdatingAppRegistrationData binaries_reg_data(kChromeBinariesGuid); + + // Nothing to do if the binaries are installed. + base::win::RegKey key; + base::string16 version_str; + if (key.Open(HKEY_CURRENT_USER, + binaries_reg_data.GetVersionKey().c_str(), + KEY_QUERY_VALUE | KEY_WOW64_32KEY) == ERROR_SUCCESS && + key.ReadValue(google_update::kRegVersionField, + &version_str) == ERROR_SUCCESS) { + return; + } + + // Nothing to do if Chrome is not installed. + if (key.Open(HKEY_CURRENT_USER, + chrome_reg_data.GetVersionKey().c_str(), + KEY_QUERY_VALUE | KEY_WOW64_32KEY) != ERROR_SUCCESS || + key.ReadValue(google_update::kRegVersionField, + &version_str) != ERROR_SUCCESS) { + return; + } + + // Nothing to do if Chrome is not multi-install. + base::string16 setup_args; + if (key.Open(HKEY_CURRENT_USER, + chrome_reg_data.GetStateKey().c_str(), + KEY_QUERY_VALUE | KEY_WOW64_32KEY) != ERROR_SUCCESS) { + LOG(ERROR) << "RepairChrome: Failed to open Chrome's ClientState key."; + return; + } + if (key.ReadValue(installer::kUninstallArgumentsField, + &setup_args) != ERROR_SUCCESS) { + LOG(ERROR) << "RepairChrome: Failed to read Chrome's UninstallArguments."; + return; + } + if (setup_args.find(base::UTF8ToUTF16(installer::switches::kMultiInstall)) == + base::string16::npos) { + LOG(INFO) << "RepairChrome: Not repairing single-install Chrome."; + return; + } + + // Generate a command line to run Chrome's installer. + base::string16 setup_path; + if (key.ReadValue(installer::kUninstallStringField, + &setup_path) != ERROR_SUCCESS) { + LOG(ERROR) << "RepairChrome: Failed to read Chrome's UninstallString."; + return; + } + + // Replace --uninstall with --do-not-launch-chrome to cause chrome to + // self-repair. + ReplaceFirstSubstringAfterOffset( + &setup_args, 0, base::UTF8ToUTF16(installer::switches::kUninstall), + base::UTF8ToUTF16(installer::switches::kDoNotLaunchChrome)); + base::CommandLine setup_command(base::CommandLine::NO_PROGRAM); + InstallUtil::ComposeCommandLine(setup_path, setup_args, &setup_command); + + // Run Chrome's installer so that it repairs itself. Break away from any job + // in which this operation is running so that Google Update doesn't wait + // around for the repair. Retry once without the attempt to break away in case + // this process doesn't have JOB_OBJECT_LIMIT_BREAKAWAY_OK. + base::LaunchOptions launch_options; + launch_options.force_breakaway_from_job_ = true; + while (true) { + if (base::LaunchProcess(setup_command, launch_options).IsValid()) { + LOG(INFO) << "RepairChrome: Launched repair command \"" + << setup_command.GetCommandLineString() << "\""; + break; + } else { + PLOG(ERROR) << "RepairChrome: Failed launching repair command \"" + << setup_command.GetCommandLineString() << "\""; + if (launch_options.force_breakaway_from_job_) { + LOG(ERROR) << "RepairChrome: Will retry without breakaway."; + launch_options.force_breakaway_from_job_ = false; + } else { + break; + } + } + } +#endif // GOOGLE_CHROME_BUILD +} + installer::InstallStatus InstallProducts( const InstallationState& original_state, const base::FilePath& setup_exe, @@ -733,6 +847,8 @@ installer::InstallStatus InstallProducts( UninstallBinariesIfUnused(original_state, *installer_state, &install_status); + RepairChromeIfBroken(original_state, *installer_state); + installer_state->UpdateStage(installer::NO_STAGE); return install_status; } diff --git a/chrome/installer/util/install_util.cc b/chrome/installer/util/install_util.cc index 7a11c81..a3861b8 100644 --- a/chrome/installer/util/install_util.cc +++ b/chrome/installer/util/install_util.cc @@ -564,9 +564,9 @@ int InstallUtil::GetInstallReturnCode(installer::InstallStatus status) { } // static -void InstallUtil::MakeUninstallCommand(const base::string16& program, - const base::string16& arguments, - base::CommandLine* command_line) { +void InstallUtil::ComposeCommandLine(const base::string16& program, + const base::string16& arguments, + base::CommandLine* command_line) { *command_line = base::CommandLine::FromString(L"\"" + program + L"\" " + arguments); } diff --git a/chrome/installer/util/install_util.h b/chrome/installer/util/install_util.h index 2d4e7d7..edc6e36 100644 --- a/chrome/installer/util/install_util.h +++ b/chrome/installer/util/install_util.h @@ -176,9 +176,9 @@ class InstallUtil { static int GetInstallReturnCode(installer::InstallStatus install_status); // Composes |program| and |arguments| into |command_line|. - static void MakeUninstallCommand(const base::string16& program, - const base::string16& arguments, - base::CommandLine* command_line); + static void ComposeCommandLine(const base::string16& program, + const base::string16& arguments, + base::CommandLine* command_line); // Returns a string in the form YYYYMMDD of the current date. static base::string16 GetCurrentDate(); diff --git a/chrome/installer/util/install_util_unittest.cc b/chrome/installer/util/install_util_unittest.cc index 22dea39..a891f8d 100644 --- a/chrome/installer/util/install_util_unittest.cc +++ b/chrome/installer/util/install_util_unittest.cc @@ -34,7 +34,7 @@ class InstallUtilTest : public TestWithTempDirAndDeleteTempOverrideKeys { protected: }; -TEST_F(InstallUtilTest, MakeUninstallCommand) { +TEST_F(InstallUtilTest, ComposeCommandLine) { base::CommandLine command_line(base::CommandLine::NO_PROGRAM); std::pair<std::wstring, std::wstring> params[] = { @@ -46,7 +46,7 @@ TEST_F(InstallUtilTest, MakeUninstallCommand) { }; for (int i = 0; i < arraysize(params); ++i) { std::pair<std::wstring, std::wstring>& param = params[i]; - InstallUtil::MakeUninstallCommand(param.first, param.second, &command_line); + InstallUtil::ComposeCommandLine(param.first, param.second, &command_line); EXPECT_EQ(param.first, command_line.GetProgram().value()); if (param.second.empty()) { EXPECT_TRUE(command_line.GetSwitches().empty()); diff --git a/chrome/installer/util/installation_state.cc b/chrome/installer/util/installation_state.cc index 645738d..5bf9e57 100644 --- a/chrome/installer/util/installation_state.cc +++ b/chrome/installer/util/installation_state.cc @@ -96,8 +96,8 @@ bool ProductState::Initialize(bool system_install, key.ReadValue(kUninstallStringField, &setup_path); // "UninstallArguments" will be absent for the multi-installer package. key.ReadValue(kUninstallArgumentsField, &uninstall_arguments); - InstallUtil::MakeUninstallCommand(setup_path, uninstall_arguments, - &uninstall_command_); + InstallUtil::ComposeCommandLine(setup_path, uninstall_arguments, + &uninstall_command_); // "usagestats" may be absent, 0 (false), or 1 (true). On the chance that // different values are permitted in the future, we'll simply hold whatever |