summaryrefslogtreecommitdiffstats
path: root/chrome/installer
diff options
context:
space:
mode:
authorgrt@chromium.org <grt@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-07-26 12:42:39 +0000
committergrt@chromium.org <grt@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-07-26 12:42:39 +0000
commit09da4510e06b45a9d6b33195de03edd74e555514 (patch)
treed17a252d3ce286d457f7a3bb9004385e65899c40 /chrome/installer
parente4a8124decacfab7d88bd02b3ed4ae1fbc78cefd (diff)
downloadchromium_src-09da4510e06b45a9d6b33195de03edd74e555514.zip
chromium_src-09da4510e06b45a9d6b33195de03edd74e555514.tar.gz
chromium_src-09da4510e06b45a9d6b33195de03edd74e555514.tar.bz2
Add support for --migrate-chrome-frame.
This is a new non-install mode for the installer that will transform a multi-install Chrome Frame into single-install. The binaries are not removed from the system if no other multi-install products remain. A subsequent change will put this new mode to use. BUG=none Review URL: https://chromiumcodereview.appspot.com/20069003 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@213868 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/installer')
-rw-r--r--chrome/installer/setup/setup_main.cc51
-rw-r--r--chrome/installer/setup/setup_util.cc72
-rw-r--r--chrome/installer/setup/setup_util.h8
-rw-r--r--chrome/installer/setup/setup_util_unittest.cc90
-rw-r--r--chrome/installer/util/channel_info.cc11
-rw-r--r--chrome/installer/util/channel_info.h4
-rw-r--r--chrome/installer/util/channel_info_unittest.cc12
-rw-r--r--chrome/installer/util/util_constants.cc4
-rw-r--r--chrome/installer/util/util_constants.h1
9 files changed, 252 insertions, 1 deletions
diff --git a/chrome/installer/setup/setup_main.cc b/chrome/installer/setup/setup_main.cc
index 5135c51..dc96a5b 100644
--- a/chrome/installer/setup/setup_main.cc
+++ b/chrome/installer/setup/setup_main.cc
@@ -1285,6 +1285,55 @@ installer::InstallStatus RegisterDevChrome(
return status;
}
+// Migrates multi-install Chrome Frame to single-install at the current
+// level. Does not remove the multi-install binaries if no other products are
+// using them. --uncompressed-archive=chrome.7z is expected to be given on the
+// command line to point this setup.exe at the (possibly patched) archive from
+// the calling instance.
+installer::InstallStatus MigrateChromeFrame(
+ const InstallationState& original_state,
+ InstallerState* installer_state) {
+ const bool system_level = installer_state->system_install();
+
+ // Nothing to do if multi-install Chrome Frame is not installed.
+ const ProductState* multi_chrome_frame = original_state.GetProductState(
+ system_level, BrowserDistribution::CHROME_FRAME);
+ if (!multi_chrome_frame || !multi_chrome_frame->is_multi_install())
+ return installer::INVALID_STATE_FOR_OPTION;
+
+ // Install SxS Chrome Frame.
+ InstallerState install_gcf(installer_state->level());
+ {
+ scoped_ptr<Product> chrome_frame(
+ new Product(BrowserDistribution::GetSpecificDistribution(
+ BrowserDistribution::CHROME_FRAME)));
+ install_gcf.AddProduct(&chrome_frame);
+ }
+ DCHECK(!install_gcf.is_multi_install());
+
+ installer::ArchiveType archive_type = installer::UNKNOWN_ARCHIVE_TYPE;
+ bool delegated_to_existing = false;
+ installer::InstallStatus install_status = InstallProductsHelper(
+ original_state, *CommandLine::ForCurrentProcess(),
+ MasterPreferences::ForCurrentProcess(), install_gcf,
+ &archive_type, &delegated_to_existing);
+
+ if (!InstallUtil::GetInstallReturnCode(install_status)) {
+ // Migration was successful. There's no turning back now. The multi-install
+ // npchrome_frame.dll and/or chrome.exe may still be in use at this point,
+ // although the user-level helper will not be. It is not safe to delete the
+ // multi-install binaries until npchrome_frame.dll and chrome.exe are no
+ // longer in use. The remaining tasks here are best-effort. Failure does not
+ // do any harm.
+ installer::MigrateGoogleUpdateStateMultiToSingle(
+ system_level,
+ BrowserDistribution::CHROME_FRAME,
+ original_state);
+ }
+
+ return install_status;
+}
+
// This method processes any command line options that make setup.exe do
// various tasks other than installation (renaming chrome.exe, showing eula
// among others). This function returns true if any such command line option
@@ -1541,6 +1590,8 @@ bool HandleNonInstallCmdLineOptions(const InstallationState& original_state,
} else {
*exit_code = installer::PATCH_INVALID_ARGUMENTS;
}
+ } else if (cmd_line.HasSwitch(installer::switches::kMigrateChromeFrame)) {
+ *exit_code = MigrateChromeFrame(original_state, installer_state);
} else {
handled = false;
}
diff --git a/chrome/installer/setup/setup_util.cc b/chrome/installer/setup/setup_util.cc
index 2ca0e88..92358f2 100644
--- a/chrome/installer/setup/setup_util.cc
+++ b/chrome/installer/setup/setup_util.cc
@@ -18,9 +18,11 @@
#include "base/process/process_handle.h"
#include "base/strings/string_util.h"
#include "base/version.h"
+#include "base/win/registry.h"
#include "base/win/windows_version.h"
#include "chrome/installer/setup/setup_constants.h"
#include "chrome/installer/util/copy_tree_work_item.h"
+#include "chrome/installer/util/google_update_constants.h"
#include "chrome/installer/util/installation_state.h"
#include "chrome/installer/util/installer_state.h"
#include "chrome/installer/util/master_preferences.h"
@@ -370,6 +372,76 @@ bool AdjustProcessPriority() {
return false;
}
+void MigrateGoogleUpdateStateMultiToSingle(
+ bool system_level,
+ BrowserDistribution::Type to_migrate,
+ const installer::InstallationState& machine_state) {
+ const HKEY root = system_level ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER;
+ const ProductState* product = NULL;
+ BrowserDistribution* dist = NULL;
+ LONG result = ERROR_SUCCESS;
+ base::win::RegKey state_key;
+
+ Product product_to_migrate(
+ BrowserDistribution::GetSpecificDistribution(to_migrate));
+
+ // Copy usagestats from the binaries to the product's ClientState key.
+ product = machine_state.GetProductState(system_level,
+ BrowserDistribution::CHROME_BINARIES);
+ DWORD usagestats = 0;
+ if (product && product->GetUsageStats(&usagestats)) {
+ dist = product_to_migrate.distribution();
+ result = state_key.Open(root, dist->GetStateKey().c_str(),
+ KEY_SET_VALUE);
+ if (result != ERROR_SUCCESS) {
+ LOG(ERROR) << "Failed opening ClientState key for "
+ << dist->GetAppShortCutName() << " to migrate usagestats.";
+ } else {
+ state_key.WriteValue(google_update::kRegUsageStatsField, usagestats);
+ }
+ }
+
+ // Remove the migrating product from the "ap" value of other multi-install
+ // products.
+ for (int i = 0; i < BrowserDistribution::NUM_TYPES; ++i) {
+ BrowserDistribution::Type type =
+ static_cast<BrowserDistribution::Type>(i);
+ if (type == to_migrate)
+ continue;
+ product = machine_state.GetProductState(system_level, type);
+ if (product && product->is_multi_install()) {
+ installer::ChannelInfo channel_info;
+ dist = BrowserDistribution::GetSpecificDistribution(type);
+ result = state_key.Open(root, dist->GetStateKey().c_str(),
+ KEY_QUERY_VALUE | KEY_SET_VALUE);
+ if (result == ERROR_SUCCESS &&
+ channel_info.Initialize(state_key) &&
+ product_to_migrate.SetChannelFlags(false, &channel_info)) {
+ VLOG(1) << "Moving " << dist->GetAppShortCutName()
+ << " to channel: " << channel_info.value();
+ channel_info.Write(&state_key);
+ }
+ }
+ }
+
+ // Remove -multi, all product modifiers, and everything else but the channel
+ // name from the "ap" value of the product to migrate.
+ dist = product_to_migrate.distribution();
+ result = state_key.Open(root, dist->GetStateKey().c_str(),
+ KEY_QUERY_VALUE | KEY_SET_VALUE);
+ if (result == ERROR_SUCCESS) {
+ installer::ChannelInfo channel_info;
+ if (!channel_info.Initialize(state_key)) {
+ LOG(ERROR) << "Failed reading " << dist->GetAppShortCutName()
+ << " channel info.";
+ } else if (channel_info.RemoveAllModifiersAndSuffixes()) {
+ VLOG(1) << "Moving " << dist->GetAppShortCutName()
+ << " to channel: " << channel_info.value();
+ channel_info.Write(&state_key);
+ }
+ }
+}
+
ScopedTokenPrivilege::ScopedTokenPrivilege(const wchar_t* privilege_name)
: is_enabled_(false) {
if (!::OpenProcessToken(::GetCurrentProcess(),
diff --git a/chrome/installer/setup/setup_util.h b/chrome/installer/setup/setup_util.h
index 031b1cb..2ddfd5f 100644
--- a/chrome/installer/setup/setup_util.h
+++ b/chrome/installer/setup/setup_util.h
@@ -99,6 +99,14 @@ bool WillProductBePresentAfterSetup(
// procesing mode is entered.
bool AdjustProcessPriority();
+// Makes registry adjustments to migrate the Google Update state of |to_migrate|
+// from multi-install to single-install. This includes copying the usagestats
+// value and adjusting the ap values of all multi-install products.
+void MigrateGoogleUpdateStateMultiToSingle(
+ bool system_level,
+ BrowserDistribution::Type to_migrate,
+ const installer::InstallationState& machine_state);
+
// This class will enable the privilege defined by |privilege_name| on the
// current process' token. The privilege will be disabled upon the
// ScopedTokenPrivilege's destruction (unless it was already enabled when the
diff --git a/chrome/installer/setup/setup_util_unittest.cc b/chrome/installer/setup/setup_util_unittest.cc
index 17105fc..0391e3a 100644
--- a/chrome/installer/setup/setup_util_unittest.cc
+++ b/chrome/installer/setup/setup_util_unittest.cc
@@ -12,10 +12,10 @@
#include "base/file_util.h"
#include "base/files/scoped_temp_dir.h"
#include "base/memory/scoped_ptr.h"
-#include "base/path_service.h"
#include "base/process/kill.h"
#include "base/process/launch.h"
#include "base/process/process_handle.h"
+#include "base/test/test_reg_util_win.h"
#include "base/threading/platform_thread.h"
#include "base/time/time.h"
#include "base/version.h"
@@ -23,6 +23,7 @@
#include "base/win/windows_version.h"
#include "chrome/installer/setup/setup_util.h"
#include "chrome/installer/setup/setup_constants.h"
+#include "chrome/installer/util/google_update_constants.h"
#include "chrome/installer/util/installation_state.h"
#include "chrome/installer/util/installer_state.h"
#include "chrome/installer/util/util_constants.h"
@@ -399,3 +400,90 @@ TEST_F(FindArchiveToPatchTest, NoVersionFound) {
*original_state_, *installer_state_));
EXPECT_EQ(base::FilePath::StringType(), patch_source.value());
}
+
+namespace {
+
+class MigrateMultiToSingleTest : public testing::Test {
+ protected:
+ virtual void SetUp() OVERRIDE {
+ registry_override_manager_.OverrideRegistry(kRootKey,
+ L"MigrateMultiToSingleTest");
+ }
+
+ virtual void TearDown() OVERRIDE {
+ registry_override_manager_.RemoveAllOverrides();
+ }
+
+ static const bool kSystemLevel = false;
+ static const HKEY kRootKey;
+ static const wchar_t kVersionString[];
+ static const wchar_t kMultiChannel[];
+ registry_util::RegistryOverrideManager registry_override_manager_;
+};
+
+const bool MigrateMultiToSingleTest::kSystemLevel;
+const HKEY MigrateMultiToSingleTest::kRootKey =
+ kSystemLevel ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER;
+const wchar_t MigrateMultiToSingleTest::kVersionString[] = L"30.0.1574.0";
+const wchar_t MigrateMultiToSingleTest::kMultiChannel[] =
+ L"2.0-dev-multi-chromeframe";
+
+} // namespace
+
+// Test migrating Chrome Frame from multi to single.
+TEST_F(MigrateMultiToSingleTest, ChromeFrame) {
+ installer::ProductState chrome_frame;
+ installer::ProductState binaries;
+ DWORD usagestats = 0;
+
+ // Set up a config with dev-channel multi-install GCF.
+ base::win::RegKey key;
+
+ BrowserDistribution* dist = BrowserDistribution::GetSpecificDistribution(
+ BrowserDistribution::CHROME_BINARIES);
+ ASSERT_EQ(ERROR_SUCCESS,
+ base::win::RegKey(kRootKey, dist->GetVersionKey().c_str(),
+ KEY_SET_VALUE)
+ .WriteValue(google_update::kRegVersionField, kVersionString));
+ ASSERT_EQ(ERROR_SUCCESS,
+ base::win::RegKey(kRootKey, dist->GetStateKey().c_str(),
+ KEY_SET_VALUE)
+ .WriteValue(google_update::kRegApField, kMultiChannel));
+ ASSERT_EQ(ERROR_SUCCESS,
+ base::win::RegKey(kRootKey, dist->GetStateKey().c_str(),
+ KEY_SET_VALUE)
+ .WriteValue(google_update::kRegUsageStatsField, 1U));
+
+ dist = BrowserDistribution::GetSpecificDistribution(
+ BrowserDistribution::CHROME_FRAME);
+ ASSERT_EQ(ERROR_SUCCESS,
+ base::win::RegKey(kRootKey, dist->GetVersionKey().c_str(),
+ KEY_SET_VALUE)
+ .WriteValue(google_update::kRegVersionField, kVersionString));
+ ASSERT_EQ(ERROR_SUCCESS,
+ base::win::RegKey(kRootKey, dist->GetStateKey().c_str(),
+ KEY_SET_VALUE)
+ .WriteValue(google_update::kRegApField, kMultiChannel));
+
+ // Do the registry migration.
+ installer::InstallationState machine_state;
+ machine_state.Initialize();
+
+ installer::MigrateGoogleUpdateStateMultiToSingle(
+ kSystemLevel,
+ BrowserDistribution::CHROME_FRAME,
+ machine_state);
+
+ // Confirm that usagestats were copied to CF and that its channel was
+ // stripped.
+ ASSERT_TRUE(chrome_frame.Initialize(kSystemLevel,
+ BrowserDistribution::CHROME_FRAME));
+ EXPECT_TRUE(chrome_frame.GetUsageStats(&usagestats));
+ EXPECT_EQ(1U, usagestats);
+ EXPECT_EQ(L"2.0-dev", chrome_frame.channel().value());
+
+ // Confirm that the binaries' channel no longer contains GCF.
+ ASSERT_TRUE(binaries.Initialize(kSystemLevel,
+ BrowserDistribution::CHROME_BINARIES));
+ EXPECT_EQ(L"2.0-dev-multi", binaries.channel().value());
+}
diff --git a/chrome/installer/util/channel_info.cc b/chrome/installer/util/channel_info.cc
index 613ab81..e52ae77 100644
--- a/chrome/installer/util/channel_info.cc
+++ b/chrome/installer/util/channel_info.cc
@@ -281,4 +281,15 @@ bool ChannelInfo::SetMultiFailSuffix(bool value) {
return SetModifier(SFX_MULTI_FAIL, value, &value_);
}
+bool ChannelInfo::RemoveAllModifiersAndSuffixes() {
+ bool modified = false;
+
+ for (int scan = 0; scan < NUM_MODIFIERS; ++scan) {
+ ModifierIndex index = static_cast<ModifierIndex>(scan);
+ modified = SetModifier(index, false, &value_) || modified;
+ }
+
+ return modified;
+}
+
} // namespace installer
diff --git a/chrome/installer/util/channel_info.h b/chrome/installer/util/channel_info.h
index fd116af..438966f 100644
--- a/chrome/installer/util/channel_info.h
+++ b/chrome/installer/util/channel_info.h
@@ -101,6 +101,10 @@ class ChannelInfo {
// modified.
bool SetMultiFailSuffix(bool value);
+ // Removes all modifiers and suffixes. For example, 2.0-dev-multi-chrome-full
+ // becomes 2.0-dev. Returns true if the value is modified.
+ bool RemoveAllModifiersAndSuffixes();
+
private:
std::wstring value_;
}; // class ChannelInfo
diff --git a/chrome/installer/util/channel_info_unittest.cc b/chrome/installer/util/channel_info_unittest.cc
index efc6ef1..1aacb24 100644
--- a/chrome/installer/util/channel_info_unittest.cc
+++ b/chrome/installer/util/channel_info_unittest.cc
@@ -204,3 +204,15 @@ TEST(ChannelInfoTest, SetStage) {
EXPECT_TRUE(ci.SetStage(NULL));
EXPECT_EQ(L"2.0-beta-multi", ci.value());
}
+
+TEST(ChannelInfoTest, RemoveAllModifiersAndSuffixes) {
+ ChannelInfo ci;
+
+ ci.set_value(L"");
+ EXPECT_FALSE(ci.RemoveAllModifiersAndSuffixes());
+ EXPECT_EQ(L"", ci.value());
+
+ ci.set_value(L"2.0-dev-multi-chrome-chromeframe");
+ EXPECT_TRUE(ci.RemoveAllModifiersAndSuffixes());
+ EXPECT_EQ(L"2.0-dev", ci.value());
+}
diff --git a/chrome/installer/util/util_constants.cc b/chrome/installer/util/util_constants.cc
index 962012a..3d6baba 100644
--- a/chrome/installer/util/util_constants.cc
+++ b/chrome/installer/util/util_constants.cc
@@ -112,6 +112,10 @@ const char kLogFile[] = "log-file";
// register as default browser only for the current user.
const char kMakeChromeDefault[] = "make-chrome-default";
+// Migrate multi-install Chrome Frame to single-install. Use in conjunction with
+// --uncompressed-archive.
+const char kMigrateChromeFrame[] = "migrate-chrome-frame";
+
// Tells installer to expect to be run as a subsidiary to an MSI.
const char kMsi[] = "msi";
diff --git a/chrome/installer/util/util_constants.h b/chrome/installer/util/util_constants.h
index b651a61..b77c4c0 100644
--- a/chrome/installer/util/util_constants.h
+++ b/chrome/installer/util/util_constants.h
@@ -159,6 +159,7 @@ extern const char kInstallArchive[];
extern const char kInstallerData[];
extern const char kLogFile[];
extern const char kMakeChromeDefault[];
+extern const char kMigrateChromeFrame[];
extern const char kMsi[];
extern const char kMultiInstall[];
extern const char kNewSetupExe[];