summaryrefslogtreecommitdiffstats
path: root/chrome/installer
diff options
context:
space:
mode:
authorgrt@chromium.org <grt@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-11-11 13:28:34 +0000
committergrt@chromium.org <grt@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-11-11 13:28:34 +0000
commit2589396510cb9ec9a4e3520dcef3524e65fecd58 (patch)
tree54824cb5227354c24f04c7f34b5c104c78a14943 /chrome/installer
parentc7959c98c6625ad4e0758bd8e95e35be3442219a (diff)
downloadchromium_src-2589396510cb9ec9a4e3520dcef3524e65fecd58.zip
chromium_src-2589396510cb9ec9a4e3520dcef3524e65fecd58.tar.gz
chromium_src-2589396510cb9ec9a4e3520dcef3524e65fecd58.tar.bz2
Add support for --critical-update-version to installer.
The installer may now be given a --critical-update-version=W.X.Y.Z option on the command line. If this is present for an in-use update and the indicated version is newer than the in-use Chrome, a new "cpv" value is dropped in the registry alongside "opv" and "cmd" (the other state associated with an in-use update). Thanks to Finnur, Chrome will eventually notice that there's a pending critical update and do magical things to keep our users safe and secure. Go users! Other things I did while I was at it: - switched version string conversions from UTF8ToWide to ASCIIToWide since version numbers are always ASCII dotted numbers. - renamed the reg value from "CriticalUpdate" to "cpv" so it fits in nicely with the other cryptic values in the product's Clients key (a.k.a. Version key). BUG=103526,97665 TEST=Install version N, launch it with --check-for-update-interval=5, then install verison M>N with --critical-update-version=M. After a few seconds, Chrome should do something fantastic. Note that the alternate_version_generator can be used to create a newer versioned mini_installer from an existing one (just build it and run it). Review URL: http://codereview.chromium.org/8517012 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@109620 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/installer')
-rw-r--r--chrome/installer/setup/install_worker.cc56
-rw-r--r--chrome/installer/setup/setup_main.cc15
-rw-r--r--chrome/installer/util/google_update_constants.cc2
-rw-r--r--chrome/installer/util/google_update_constants.h2
-rw-r--r--chrome/installer/util/install_util.cc2
-rw-r--r--chrome/installer/util/installer_state.cc19
-rw-r--r--chrome/installer/util/installer_state.h10
-rw-r--r--chrome/installer/util/installer_state_unittest.cc158
-rw-r--r--chrome/installer/util/util_constants.cc4
-rw-r--r--chrome/installer/util/util_constants.h1
10 files changed, 239 insertions, 30 deletions
diff --git a/chrome/installer/setup/install_worker.cc b/chrome/installer/setup/install_worker.cc
index b771ac3..1200219 100644
--- a/chrome/installer/setup/install_worker.cc
+++ b/chrome/installer/setup/install_worker.cc
@@ -199,11 +199,11 @@ void AddUninstallShortcutWorkItems(const InstallerState& installer_state,
true);
install_list->AddSetRegValueWorkItem(reg_root, uninstall_reg,
L"Version",
- UTF8ToWide(new_version.GetString()),
+ ASCIIToWide(new_version.GetString()),
true);
install_list->AddSetRegValueWorkItem(reg_root, uninstall_reg,
L"DisplayVersion",
- UTF8ToWide(new_version.GetString()),
+ ASCIIToWide(new_version.GetString()),
true);
install_list->AddSetRegValueWorkItem(reg_root, uninstall_reg,
L"InstallDate",
@@ -254,7 +254,7 @@ void AddVersionKeyWorkItems(HKEY root,
false); // set during first install
list->AddSetRegValueWorkItem(root, version_key,
google_update::kRegVersionField,
- UTF8ToWide(new_version.GetString()),
+ ASCIIToWide(new_version.GetString()),
true); // overwrite version
}
@@ -547,14 +547,19 @@ bool AppendPostInstallTasks(const InstallerState& installer_state,
const Products& products = installer_state.products();
// Append work items that will only be executed if this was an update.
- // We update the 'opv' key with the current version that is active and 'cmd'
- // key with the rename command to run.
+ // We update the 'opv' value with the current version that is active,
+ // the 'cpv' value with the critical update version (if present), and the
+ // 'cmd' value with the rename command to run.
{
scoped_ptr<WorkItemList> in_use_update_work_items(
WorkItem::CreateConditionalWorkItemList(
new ConditionRunIfFileExists(new_chrome_exe)));
in_use_update_work_items->set_log_message("InUseUpdateWorkItemList");
+ // |critical_version| will be valid only if this in-use update includes a
+ // version considered critical relative to the version being updated.
+ Version critical_version(installer_state.DetermineCriticalVersion(
+ current_version, new_version));
FilePath installer_path(installer_state.GetInstallerDirectory(new_version)
.Append(setup_path.BaseName()));
@@ -574,7 +579,15 @@ bool AppendPostInstallTasks(const InstallerState& installer_state,
if (current_version != NULL) {
in_use_update_work_items->AddSetRegValueWorkItem(root, version_key,
google_update::kRegOldVersionField,
- UTF8ToWide(current_version->GetString()), true);
+ ASCIIToWide(current_version->GetString()), true);
+ }
+ if (critical_version.IsValid()) {
+ in_use_update_work_items->AddSetRegValueWorkItem(root, version_key,
+ google_update::kRegCriticalVersionField,
+ ASCIIToWide(critical_version.GetString()), true);
+ } else {
+ in_use_update_work_items->AddDeleteRegValueWorkItem(root, version_key,
+ google_update::kRegCriticalVersionField);
}
// Adding this registry entry for all products is overkill.
@@ -585,22 +598,25 @@ bool AppendPostInstallTasks(const InstallerState& installer_state,
CommandLine product_rename_cmd(rename);
products[i]->AppendRenameFlags(&product_rename_cmd);
in_use_update_work_items->AddSetRegValueWorkItem(
- root,
- version_key,
- google_update::kRegRenameCmdField,
- product_rename_cmd.GetCommandLineString(),
- true);
+ root, version_key, google_update::kRegRenameCmdField,
+ product_rename_cmd.GetCommandLineString(), true);
}
if (current_version != NULL && installer_state.is_multi_install()) {
BrowserDistribution* dist =
installer_state.multi_package_binaries_distribution();
+ version_key = dist->GetVersionKey();
in_use_update_work_items->AddSetRegValueWorkItem(
- root,
- dist->GetVersionKey(),
- google_update::kRegOldVersionField,
- UTF8ToWide(current_version->GetString()),
- true);
+ root, version_key, google_update::kRegOldVersionField,
+ ASCIIToWide(current_version->GetString()), true);
+ if (critical_version.IsValid()) {
+ in_use_update_work_items->AddSetRegValueWorkItem(
+ root, version_key, google_update::kRegCriticalVersionField,
+ ASCIIToWide(critical_version.GetString()), true);
+ } else {
+ in_use_update_work_items->AddDeleteRegValueWorkItem(
+ root, version_key, google_update::kRegCriticalVersionField);
+ }
// TODO(tommi): We should move the rename command here. We also need to
// update upgrade_utils::SwapNewChromeExeIfPresent.
}
@@ -620,14 +636,16 @@ bool AppendPostInstallTasks(const InstallerState& installer_state,
new Not(new ConditionRunIfFileExists(new_chrome_exe))));
regular_update_work_items->set_log_message("RegularUpdateWorkItemList");
- // Since this was not an in-use-update, delete 'opv' and 'cmd' keys.
+ // Since this was not an in-use-update, delete 'opv', 'cpv', and 'cmd' keys.
for (size_t i = 0; i < products.size(); ++i) {
BrowserDistribution* dist = products[i]->distribution();
std::wstring version_key(dist->GetVersionKey());
regular_update_work_items->AddDeleteRegValueWorkItem(root, version_key,
- google_update::kRegOldVersionField);
+ google_update::kRegOldVersionField);
+ regular_update_work_items->AddDeleteRegValueWorkItem(root, version_key,
+ google_update::kRegCriticalVersionField);
regular_update_work_items->AddDeleteRegValueWorkItem(root, version_key,
- google_update::kRegRenameCmdField);
+ google_update::kRegRenameCmdField);
}
if (installer_state.FindProduct(BrowserDistribution::CHROME_FRAME)) {
diff --git a/chrome/installer/setup/setup_main.cc b/chrome/installer/setup/setup_main.cc
index be33736..fa7103f 100644
--- a/chrome/installer/setup/setup_main.cc
+++ b/chrome/installer/setup/setup_main.cc
@@ -230,17 +230,18 @@ installer::InstallStatus RenameChromeExecutables(
dists[num_dists++] = products[i]->distribution();
}
- // Add work items to delete the "opv" and "cmd" values from all distributions.
+ // Add work items to delete the "opv", "cpv", and "cmd" values from all
+ // distributions.
HKEY reg_root = installer_state->root_key();
std::wstring version_key;
for (int i = 0; i < num_dists; ++i) {
version_key = dists[i]->GetVersionKey();
- install_list->AddDeleteRegValueWorkItem(reg_root,
- version_key,
- google_update::kRegOldVersionField);
- install_list->AddDeleteRegValueWorkItem(reg_root,
- version_key,
- google_update::kRegRenameCmdField);
+ install_list->AddDeleteRegValueWorkItem(
+ reg_root, version_key, google_update::kRegOldVersionField);
+ install_list->AddDeleteRegValueWorkItem(
+ reg_root, version_key, google_update::kRegCriticalVersionField);
+ install_list->AddDeleteRegValueWorkItem(
+ reg_root, version_key, google_update::kRegRenameCmdField);
}
installer::InstallStatus ret = installer::RENAME_SUCCESSFUL;
if (!install_list->Do()) {
diff --git a/chrome/installer/util/google_update_constants.cc b/chrome/installer/util/google_update_constants.cc
index bcc9e80..4e4126d 100644
--- a/chrome/installer/util/google_update_constants.cc
+++ b/chrome/installer/util/google_update_constants.cc
@@ -24,7 +24,7 @@ const wchar_t kRegCFOptOutCmdField[] = L"CFOptOutCmd";
const wchar_t kRegCFTempOptOutCmdField[] = L"CFTempOptOutCmd";
const wchar_t kRegClientField[] = L"client";
const wchar_t kRegCommandLineField[] = L"CommandLine";
-const wchar_t kRegCriticalUpdateField[] = L"CriticalUpdate";
+const wchar_t kRegCriticalVersionField[] = L"cpv";
const wchar_t kRegDidRunField[] = L"dr";
const wchar_t kRegEULAAceptedField[] = L"eulaaccepted";
const wchar_t kRegLangField[] = L"lang";
diff --git a/chrome/installer/util/google_update_constants.h b/chrome/installer/util/google_update_constants.h
index 27a7c0e..eb27910 100644
--- a/chrome/installer/util/google_update_constants.h
+++ b/chrome/installer/util/google_update_constants.h
@@ -34,7 +34,7 @@ extern const wchar_t kRegCFOptOutCmdField[];
extern const wchar_t kRegCFTempOptOutCmdField[];
extern const wchar_t kRegClientField[];
extern const wchar_t kRegCommandLineField[];
-extern const wchar_t kRegCriticalUpdateField[];
+extern const wchar_t kRegCriticalVersionField[];
extern const wchar_t kRegDidRunField[];
extern const wchar_t kRegEULAAceptedField[];
extern const wchar_t kRegLangField[];
diff --git a/chrome/installer/util/install_util.cc b/chrome/installer/util/install_util.cc
index 2d6d1d9..f14f372 100644
--- a/chrome/installer/util/install_util.cc
+++ b/chrome/installer/util/install_util.cc
@@ -203,7 +203,7 @@ Version* InstallUtil::GetCriticalUpdateVersion(BrowserDistribution* dist,
string16 version_str;
if (result == ERROR_SUCCESS)
- result = key.ReadValue(google_update::kRegCriticalUpdateField,
+ result = key.ReadValue(google_update::kRegCriticalVersionField,
&version_str);
Version* ret = NULL;
diff --git a/chrome/installer/util/installer_state.cc b/chrome/installer/util/installer_state.cc
index bc365de..5e88ad5 100644
--- a/chrome/installer/util/installer_state.cc
+++ b/chrome/installer/util/installer_state.cc
@@ -156,6 +156,11 @@ void InstallerState::Initialize(const CommandLine& command_line,
state_key_ = operand->GetStateKey();
state_type_ = operand->GetType();
+
+ // Parse --critical-update-version=W.X.Y.Z
+ std::string critical_version_value(
+ command_line.GetSwitchValueASCII(switches::kCriticalUpdateVersion));
+ critical_update_version_ = Version(critical_version_value);
}
void InstallerState::set_level(Level level) {
@@ -413,6 +418,20 @@ Version* InstallerState::GetCurrentVersion(
return current_version.release();
}
+Version InstallerState::DetermineCriticalVersion(
+ const Version* current_version,
+ const Version& new_version) const {
+ DCHECK(current_version == NULL || current_version->IsValid());
+ DCHECK(new_version.IsValid());
+ if (critical_update_version_.IsValid() &&
+ (current_version == NULL ||
+ (current_version->CompareTo(critical_update_version_) < 0)) &&
+ new_version.CompareTo(critical_update_version_) >= 0) {
+ return critical_update_version_;
+ }
+ return Version();
+}
+
bool InstallerState::IsChromeFrameRunning(
const InstallationState& machine_state) const {
// We check only for the current version (e.g. the version we are upgrading
diff --git a/chrome/installer/util/installer_state.h b/chrome/installer/util/installer_state.h
index 04417be..987bf1b 100644
--- a/chrome/installer/util/installer_state.h
+++ b/chrome/installer/util/installer_state.h
@@ -14,6 +14,7 @@
#include "base/logging.h"
#include "base/memory/scoped_ptr.h"
#include "base/memory/scoped_vector.h"
+#include "base/version.h"
#include "chrome/installer/util/browser_distribution.h"
#include "chrome/installer/util/product.h"
#include "chrome/installer/util/util_constants.h"
@@ -144,6 +145,14 @@ class InstallerState {
// products are installed. Ownership is passed to the caller.
Version* GetCurrentVersion(const InstallationState& machine_state) const;
+ // Returns the critical update version if all of the following are true:
+ // * --critical-update-version=CUV was specified on the command-line.
+ // * current_version == NULL or current_version < CUV.
+ // * new_version >= CUV.
+ // Otherwise, returns an invalid version.
+ Version DetermineCriticalVersion(const Version* current_version,
+ const Version& new_version) const;
+
// Returns whether or not there is currently a Chrome Frame instance running.
// Note that there isn't a mechanism to lock Chrome Frame in place, so Chrome
// Frame may either exit or start up after this is called.
@@ -211,6 +220,7 @@ class InstallerState {
BrowserDistribution::Type state_type_;
ScopedVector<Product> products_;
BrowserDistribution* multi_package_distribution_;
+ Version critical_update_version_;
Level level_;
PackageType package_type_;
#if defined(OS_WIN)
diff --git a/chrome/installer/util/installer_state_unittest.cc b/chrome/installer/util/installer_state_unittest.cc
index 14dec6d..5029699 100644
--- a/chrome/installer/util/installer_state_unittest.cc
+++ b/chrome/installer/util/installer_state_unittest.cc
@@ -42,7 +42,7 @@ class InstallerStateTest : public TestWithTempDirAndDeleteTempOverrideKeys {
protected:
};
-// An installer state on which we can tweak the target path.
+// An installer state on which we can access otherwise protected members.
class MockInstallerState : public InstallerState {
public:
MockInstallerState() : InstallerState() { }
@@ -52,6 +52,9 @@ class MockInstallerState : public InstallerState {
static bool IsFileInUse(const FilePath& file) {
return InstallerState::IsFileInUse(file);
}
+ const Version& critical_update_version() const {
+ return critical_update_version_;
+ }
};
// Simple function to dump some text into a new file.
@@ -491,3 +494,156 @@ TEST_F(InstallerStateTest, IsFileInUse) {
// And once the handle is gone, it should no longer be in use.
EXPECT_FALSE(MockInstallerState::IsFileInUse(temp_file));
}
+
+// A fixture for testing InstallerState::DetermineCriticalVersion. Individual
+// tests must invoke Initialize() with a critical version.
+class InstallerStateCriticalVersionTest : public ::testing::Test {
+ protected:
+ InstallerStateCriticalVersionTest() : cmd_line_(CommandLine::NO_PROGRAM) {}
+
+ // Creates a set of versions for use by all test runs.
+ static void SetUpTestCase() {
+ low_version_ = new Version("15.0.874.106");
+ opv_version_ = new Version("15.0.874.255");
+ middle_version_ = new Version("16.0.912.32");
+ pv_version_ = new Version("16.0.912.255");
+ high_version_ = new Version("17.0.932.0");
+ }
+
+ // Cleans up versions used by all test runs.
+ static void TearDownTestCase() {
+ delete low_version_;
+ delete opv_version_;
+ delete middle_version_;
+ delete pv_version_;
+ delete high_version_;
+ }
+
+ // Initializes the InstallerState to use for a test run. The returned
+ // instance's critical update version is set to |version|. |version| may be
+ // NULL, in which case the critical update version is unset.
+ MockInstallerState& Initialize(const Version* version) {
+ cmd_line_ = version == NULL ?
+ CommandLine::FromString(L"setup.exe") :
+ CommandLine::FromString(
+ L"setup.exe --critical-update-version=" +
+ ASCIIToWide(version->GetString()));
+ prefs_.reset(new MasterPreferences(cmd_line_));
+ machine_state_.Initialize();
+ installer_state_.Initialize(cmd_line_, *prefs_, machine_state_);
+ return installer_state_;
+ }
+
+ static Version* low_version_;
+ static Version* opv_version_;
+ static Version* middle_version_;
+ static Version* pv_version_;
+ static Version* high_version_;
+
+ CommandLine cmd_line_;
+ scoped_ptr<MasterPreferences> prefs_;
+ InstallationState machine_state_;
+ MockInstallerState installer_state_;
+};
+
+Version* InstallerStateCriticalVersionTest::low_version_ = NULL;
+Version* InstallerStateCriticalVersionTest::opv_version_ = NULL;
+Version* InstallerStateCriticalVersionTest::middle_version_ = NULL;
+Version* InstallerStateCriticalVersionTest::pv_version_ = NULL;
+Version* InstallerStateCriticalVersionTest::high_version_ = NULL;
+
+// Test the case where the critical version is less than the currently-running
+// Chrome. The critical version is ignored since it doesn't apply.
+TEST_F(InstallerStateCriticalVersionTest, CriticalBeforeOpv) {
+ MockInstallerState& installer_state(Initialize(low_version_));
+
+ EXPECT_TRUE(installer_state.critical_update_version().Equals(*low_version_));
+ // Unable to determine the installed version, so assume critical update.
+ EXPECT_TRUE(
+ installer_state.DetermineCriticalVersion(NULL, *pv_version_).IsValid());
+ // Installed version is past the critical update.
+ EXPECT_FALSE(
+ installer_state.DetermineCriticalVersion(opv_version_, *pv_version_)
+ .IsValid());
+ // Installed version is past the critical update.
+ EXPECT_FALSE(
+ installer_state.DetermineCriticalVersion(pv_version_, *pv_version_)
+ .IsValid());
+}
+
+// Test the case where the critical version is equal to the currently-running
+// Chrome. The critical version is ignored since it doesn't apply.
+TEST_F(InstallerStateCriticalVersionTest, CriticalEqualsOpv) {
+ MockInstallerState& installer_state(Initialize(opv_version_));
+
+ EXPECT_TRUE(installer_state.critical_update_version().Equals(*opv_version_));
+ // Unable to determine the installed version, so assume critical update.
+ EXPECT_TRUE(
+ installer_state.DetermineCriticalVersion(NULL, *pv_version_).IsValid());
+ // Installed version equals the critical update.
+ EXPECT_FALSE(
+ installer_state.DetermineCriticalVersion(opv_version_, *pv_version_)
+ .IsValid());
+ // Installed version equals the critical update.
+ EXPECT_FALSE(
+ installer_state.DetermineCriticalVersion(pv_version_, *pv_version_)
+ .IsValid());
+}
+
+// Test the case where the critical version is between the currently-running
+// Chrome and the to-be-installed Chrome.
+TEST_F(InstallerStateCriticalVersionTest, CriticalBetweenOpvAndPv) {
+ MockInstallerState& installer_state(Initialize(middle_version_));
+
+ EXPECT_TRUE(installer_state.critical_update_version().Equals(
+ *middle_version_));
+ // Unable to determine the installed version, so assume critical update.
+ EXPECT_TRUE(
+ installer_state.DetermineCriticalVersion(NULL, *pv_version_).IsValid());
+ // Installed version before the critical update.
+ EXPECT_TRUE(
+ installer_state.DetermineCriticalVersion(opv_version_, *pv_version_)
+ .IsValid());
+ // Installed version is past the critical update.
+ EXPECT_FALSE(
+ installer_state.DetermineCriticalVersion(pv_version_, *pv_version_)
+ .IsValid());
+}
+
+// Test the case where the critical version is the same as the to-be-installed
+// Chrome.
+TEST_F(InstallerStateCriticalVersionTest, CriticalEqualsPv) {
+ MockInstallerState& installer_state(Initialize(pv_version_));
+
+ EXPECT_TRUE(installer_state.critical_update_version().Equals(
+ *pv_version_));
+ // Unable to determine the installed version, so assume critical update.
+ EXPECT_TRUE(
+ installer_state.DetermineCriticalVersion(NULL, *pv_version_).IsValid());
+ // Installed version before the critical update.
+ EXPECT_TRUE(
+ installer_state.DetermineCriticalVersion(opv_version_, *pv_version_)
+ .IsValid());
+ // Installed version equals the critical update.
+ EXPECT_FALSE(
+ installer_state.DetermineCriticalVersion(pv_version_, *pv_version_)
+ .IsValid());
+}
+
+// Test the case where the critical version is greater than the to-be-installed
+// Chrome.
+TEST_F(InstallerStateCriticalVersionTest, CriticalAfterPv) {
+ MockInstallerState& installer_state(Initialize(high_version_));
+
+ EXPECT_TRUE(installer_state.critical_update_version().Equals(
+ *high_version_));
+ // Critical update newer than the new version.
+ EXPECT_FALSE(
+ installer_state.DetermineCriticalVersion(NULL, *pv_version_).IsValid());
+ EXPECT_FALSE(
+ installer_state.DetermineCriticalVersion(opv_version_, *pv_version_)
+ .IsValid());
+ EXPECT_FALSE(
+ installer_state.DetermineCriticalVersion(pv_version_, *pv_version_)
+ .IsValid());
+}
diff --git a/chrome/installer/util/util_constants.cc b/chrome/installer/util/util_constants.cc
index c470faf..72943a8 100644
--- a/chrome/installer/util/util_constants.cc
+++ b/chrome/installer/util/util_constants.cc
@@ -42,6 +42,10 @@ const char kChromeSxS[] = "chrome-sxs";
// Create Desktop and QuickLaunch shortcuts
const char kCreateAllShortcuts[] = "create-all-shortcuts";
+// The version number of an update containing critical fixes, for which an
+// in-use Chrome should be restarted ASAP.
+const char kCriticalUpdateVersion[] = "critical-update-version";
+
// Delete user profile data. This param is useful only when specified with
// kUninstall, otherwise it is silently ignored.
const char kDeleteProfile[] = "delete-profile";
diff --git a/chrome/installer/util/util_constants.h b/chrome/installer/util/util_constants.h
index 95d79df..5911701 100644
--- a/chrome/installer/util/util_constants.h
+++ b/chrome/installer/util/util_constants.h
@@ -128,6 +128,7 @@ extern const char kChromeFrameReadyModeTempOptOut[];
extern const char kChromeFrameReadyModeEndTempOptOut[];
extern const char kChromeSxS[];
extern const char kCreateAllShortcuts[];
+extern const char kCriticalUpdateVersion[];
extern const char kDeleteProfile[];
extern const char kDisableLogging[];
extern const char kDoNotCreateShortcuts[];