diff options
author | grt@chromium.org <grt@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-07-26 12:42:39 +0000 |
---|---|---|
committer | grt@chromium.org <grt@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-07-26 12:42:39 +0000 |
commit | 09da4510e06b45a9d6b33195de03edd74e555514 (patch) | |
tree | d17a252d3ce286d457f7a3bb9004385e65899c40 /chrome/installer | |
parent | e4a8124decacfab7d88bd02b3ed4ae1fbc78cefd (diff) | |
download | chromium_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.cc | 51 | ||||
-rw-r--r-- | chrome/installer/setup/setup_util.cc | 72 | ||||
-rw-r--r-- | chrome/installer/setup/setup_util.h | 8 | ||||
-rw-r--r-- | chrome/installer/setup/setup_util_unittest.cc | 90 | ||||
-rw-r--r-- | chrome/installer/util/channel_info.cc | 11 | ||||
-rw-r--r-- | chrome/installer/util/channel_info.h | 4 | ||||
-rw-r--r-- | chrome/installer/util/channel_info_unittest.cc | 12 | ||||
-rw-r--r-- | chrome/installer/util/util_constants.cc | 4 | ||||
-rw-r--r-- | chrome/installer/util/util_constants.h | 1 |
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[]; |