summaryrefslogtreecommitdiffstats
path: root/chrome/installer
diff options
context:
space:
mode:
authorgrt <grt@chromium.org>2015-02-12 13:25:28 -0800
committerCommit bot <commit-bot@chromium.org>2015-02-12 21:26:35 +0000
commit06b99a6d026db87f962ef5ea19dc55cd48bdf965 (patch)
tree019a0928e3cee903c19ee44d27845320e095cce4 /chrome/installer
parent5df17877659c5ec9678ead07287d9ff09da0e75e (diff)
downloadchromium_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.cc116
-rw-r--r--chrome/installer/util/install_util.cc6
-rw-r--r--chrome/installer/util/install_util.h6
-rw-r--r--chrome/installer/util/install_util_unittest.cc4
-rw-r--r--chrome/installer/util/installation_state.cc4
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