diff options
Diffstat (limited to 'chrome/installer/setup/setup_main.cc')
-rw-r--r-- | chrome/installer/setup/setup_main.cc | 466 |
1 files changed, 288 insertions, 178 deletions
diff --git a/chrome/installer/setup/setup_main.cc b/chrome/installer/setup/setup_main.cc index b385b8b..78d641c 100644 --- a/chrome/installer/setup/setup_main.cc +++ b/chrome/installer/setup/setup_main.cc @@ -20,6 +20,7 @@ #include "base/string_util.h" #include "base/utf_string_conversions.h" #include "base/values.h" +#include "base/win/registry.h" #include "base/win/scoped_handle.h" #include "base/win/win_util.h" #include "base/win/windows_version.h" @@ -31,6 +32,7 @@ #include "chrome/installer/setup/setup_util.h" #include "chrome/installer/setup/uninstall.h" #include "chrome/installer/util/browser_distribution.h" +#include "chrome/installer/util/channel_info.h" #include "chrome/installer/util/delete_after_reboot_helper.h" #include "chrome/installer/util/delete_tree_work_item.h" #include "chrome/installer/util/google_update_settings.h" @@ -45,7 +47,6 @@ #include "chrome/installer/util/lzma_util.h" #include "chrome/installer/util/master_preferences.h" #include "chrome/installer/util/master_preferences_constants.h" -#include "chrome/installer/util/package_properties.h" #include "chrome/installer/util/shell_util.h" #include "chrome/installer/util/util_constants.h" @@ -54,11 +55,8 @@ using installer::InstallerState; using installer::InstallationState; using installer::Product; -using installer::ProductPackageMapping; using installer::ProductState; using installer::Products; -using installer::Package; -using installer::Packages; using installer::MasterPreferences; const wchar_t kChromePipeName[] = L"\\\\.\\pipe\\ChromeCrashServices"; @@ -83,7 +81,7 @@ namespace { // present on the system already. As the final step the new archive file // is unpacked in the path specified by parameter "output_directory". DWORD UnPackArchive(const FilePath& archive, - const Package& installation, + const InstallerState& installer_state, const FilePath& temp_path, const FilePath& output_directory, bool& incremental_install) { @@ -98,7 +96,7 @@ DWORD UnPackArchive(const FilePath& archive, FilePath uncompressed_archive(temp_path.Append(installer::kChromeArchive)); scoped_ptr<Version> archive_version( - installer::GetVersionFromArchiveDir(installation.path())); + installer::GetVersionFromArchiveDir(installer_state.target_path())); // Check if this is differential update and if it is, patch it to the // installer archive that should already be on the machine. We assume @@ -112,7 +110,7 @@ DWORD UnPackArchive(const FilePath& archive, return installer::CHROME_NOT_INSTALLED; } - FilePath existing_archive(installation.path().Append( + FilePath existing_archive(installer_state.target_path().Append( UTF8ToWide(archive_version->GetString()))); existing_archive = existing_archive.Append(installer::kInstallerDir); existing_archive = existing_archive.Append(installer::kChromeArchive); @@ -136,12 +134,11 @@ DWORD UnPackArchive(const FilePath& archive, // system and a key called 'opv' in the registry. This function will move // new_chrome.exe to chrome.exe and delete 'opv' key in one atomic operation. installer::InstallStatus RenameChromeExecutables( - const Package& installation) { - FilePath chrome_exe(installation.path().Append(installer::kChromeExe)); - FilePath chrome_old_exe(installation.path().Append( - installer::kChromeOldExe)); - FilePath chrome_new_exe(installation.path().Append( - installer::kChromeNewExe)); + const InstallerState& installer_state) { + const FilePath &target_path = installer_state.target_path(); + FilePath chrome_exe(target_path.Append(installer::kChromeExe)); + FilePath chrome_old_exe(target_path.Append(installer::kChromeOldExe)); + FilePath chrome_new_exe(target_path.Append(installer::kChromeNewExe)); scoped_ptr<WorkItemList> install_list(WorkItem::CreateWorkItemList()); install_list->AddDeleteTreeWorkItem(chrome_old_exe); @@ -158,9 +155,8 @@ installer::InstallStatus RenameChromeExecutables( std::wstring()); install_list->AddDeleteTreeWorkItem(chrome_new_exe); - HKEY reg_root = installation.system_level() ? HKEY_LOCAL_MACHINE : - HKEY_CURRENT_USER; - const Products& products = installation.products(); + HKEY reg_root = installer_state.root_key(); + const Products& products = installer_state.products(); for (size_t i = 0; i < products.size(); ++i) { const Product* product = products[i]; BrowserDistribution* browser_dist = product->distribution(); @@ -182,44 +178,218 @@ installer::InstallStatus RenameChromeExecutables( return ret; } +// The supported multi-install modes are: +// --multi-install --chrome --chrome-frame --ready-mode +// - If a non-multi Chrome Frame installation is present, Chrome Frame is +// removed from |installer_state|'s list of products (thereby preserving +// the existing SxS install). +// - If a multi Chrome Frame installation is present, its options are +// preserved (i.e., the --ready-mode command-line option is ignored). +// --multi-install --chrome-frame +// - If a non-multi Chrome Frame installation is present, fail. +// - If a Chrome installation on a different channel is present, fail. +// - If --ready-mode and no Chrome installation is present, fail. +// - If a Chrome installation is present, add it to the set of products to +// install. +bool CheckMultiInstallConditions(const InstallationState& original_state, + InstallerState* installer_state, + installer::InstallStatus* status) { + const Products& products = installer_state->products(); + DCHECK(products.size()); + + bool is_first_install = true; + const bool system_level = installer_state->system_install(); + + if (installer_state->is_multi_install()) { + const Product* chrome = + installer_state->FindProduct(BrowserDistribution::CHROME_BROWSER); + const Product* chrome_frame = + installer_state->FindProduct(BrowserDistribution::CHROME_FRAME); + const ProductState* cf_state = + original_state.GetProductState(system_level, + BrowserDistribution::CHROME_FRAME); + if (chrome != NULL) { + if (chrome_frame != NULL && + chrome_frame->HasOption(installer::kOptionReadyMode)) { + // We're being asked to install Chrome with Chrome Frame in ready-mode. + // This is an optimistic operation: if a SxS install of Chrome Frame + // is already present, don't touch it; if a multi-install of Chrome + // Frame is present, preserve its settings (ready-mode, CEEE). + if (cf_state != NULL) { + installer_state->RemoveProduct(chrome_frame); + chrome_frame = NULL; + if (cf_state->is_multi_install()) { + chrome_frame = installer_state->AddProductFromState( + BrowserDistribution::CHROME_FRAME, *cf_state); + VLOG(1) << "Upgrading existing multi-install Chrome Frame rather " + "than installing in ready-mode."; + } else { + VLOG(1) << "Skipping upgrade of single-install Chrome Frame rather " + "than installing in ready-mode."; + } + } else { + VLOG(1) << "Performing initial install of Chrome Frame ready-mode."; + } + } + } else if (chrome_frame != NULL) { + // We're being asked to install or update Chrome Frame alone. + const ProductState* chrome_state = + original_state.GetProductState(system_level, + BrowserDistribution::CHROME_BROWSER); + if (chrome_state != NULL) { + base::win::RegKey key; + installer::ChannelInfo cf_channel; + // Chrome Frame may not yet be installed, so peek into the registry + // directly to see what channel Google Update has specified. There will + // be no value if we're not being managed by Google Update. + if (key.Open(installer_state->root_key(), + chrome_frame->distribution()->GetStateKey().c_str(), + KEY_QUERY_VALUE) == ERROR_SUCCESS) { + cf_channel.Initialize(key); + } + // Fail if Chrome is already installed but is on a different update + // channel. + if (!cf_channel.EqualsBaseOf(chrome_state->channel())) { + LOG(ERROR) << "Cannot install Chrome Frame because existing Chrome " + "install is on a different update channel."; + *status = installer::CONFLICTING_CHANNEL_EXISTS; + InstallUtil::WriteInstallerResult(system_level, + installer_state->state_key(), *status, + IDS_INSTALL_CONFLICTING_CHANNEL_EXISTS_BASE, NULL); + return false; + } + // Otherwise, add Chrome to the set of products (making it multi-install + // in the process) so that it is updated, too. + scoped_ptr<Product> multi_chrome(new Product( + BrowserDistribution::GetSpecificDistribution( + BrowserDistribution::CHROME_BROWSER))); + multi_chrome->SetOption(installer::kOptionMultiInstall, true); + chrome = installer_state->AddProduct(&multi_chrome); + VLOG(1) << "Upgrading existing multi-install Chrome browser along with " + << chrome_frame->distribution()->GetApplicationName(); + } else if (chrome_frame->HasOption(installer::kOptionReadyMode)) { + // Chrome Frame with ready-mode is to be installed, yet Chrome is + // neither installed nor being installed. Fail. + LOG(ERROR) << "Cannot install Chrome Frame in ready mode without " + "Chrome."; + *status = installer::READY_MODE_REQUIRES_CHROME; + InstallUtil::WriteInstallerResult(system_level, + installer_state->state_key(), *status, + IDS_INSTALL_READY_MODE_REQUIRES_CHROME_BASE, NULL); + return false; + } + } + + // Fail if we're installing Chrome Frame when a single-install of it is + // already installed. + // TODO(grt): Add support for migration of Chrome Frame from single- to + // multi-install. + if (chrome_frame != NULL && + cf_state != NULL && !cf_state->is_multi_install()) { + LOG(ERROR) << "Cannot migrate existing Chrome Frame installation to " + "multi-install."; + *status = installer::NON_MULTI_INSTALLATION_EXISTS; + InstallUtil::WriteInstallerResult(system_level, + installer_state->state_key(), *status, + IDS_INSTALL_NON_MULTI_INSTALLATION_EXISTS_BASE, NULL); + return false; + } + } else if (DCHECK_IS_ON()) { + // It isn't possible to stuff two products into a single-install + // InstallerState. Abort the process here in debug builds just in case + // someone finds a way. + DCHECK_EQ(1U, products.size()); + } + + return true; +} + +// In multi-install, adds all products to |installer_state| that are +// multi-installed and must be updated along with the products already present +// in |installer_state|. +void AddExistingMultiInstalls(const InstallationState& original_state, + InstallerState* installer_state) { + if (installer_state->is_multi_install()) { + BrowserDistribution::Type product_checks[] = { + BrowserDistribution::CHROME_BROWSER, + BrowserDistribution::CHROME_FRAME + }; + + for (size_t i = 0; i < arraysize(product_checks); ++i) { + BrowserDistribution::Type type = product_checks[i]; + if (!installer_state->FindProduct(type)) { + const ProductState* state = + original_state.GetProductState(installer_state->system_install(), + type); + if ((state != NULL) && state->is_multi_install()) { + installer_state->AddProductFromState(type, *state); + VLOG(1) << "Product already installed and must be included: " + << BrowserDistribution::GetSpecificDistribution( + type)->GetApplicationName(); + } + } + } + } +} + +// Checks for compatibility between the current state of the system and the +// desired operation. Also applies policy that mutates the desired operation; +// specifically, the |installer_state| object. +// Also blocks simultaneous user-level and system-level installs. In the case +// of trying to install user-level Chrome when system-level exists, the +// existing system-level Chrome is launched. bool CheckPreInstallConditions(const InstallationState& original_state, - const InstallerState& installer_state, - const Package& installation, - const MasterPreferences& prefs, + InstallerState* installer_state, installer::InstallStatus* status) { - const Products& products = installation.products(); + const Products& products = installer_state->products(); DCHECK(products.size()); + if (!CheckMultiInstallConditions(original_state, installer_state, status)) + return false; + bool is_first_install = true; - const bool system_level = installation.system_level(); + const bool system_level = installer_state->system_install(); for (size_t i = 0; i < products.size(); ++i) { const Product* product = products[i]; BrowserDistribution* browser_dist = product->distribution(); + + // Check for an existing installation of the product. const ProductState* product_state = original_state.GetProductState(system_level, browser_dist->GetType()); - if (product_state != NULL) + if (product_state != NULL) { is_first_install = false; + // Block downgrades from multi-install to single-install. + if (!installer_state->is_multi_install() && + product_state->is_multi_install()) { + LOG(ERROR) << "Multi-install " << browser_dist->GetApplicationName() + << " exists; aborting single install."; + *status = installer::MULTI_INSTALLATION_EXISTS; + InstallUtil::WriteInstallerResult(system_level, + installer_state->state_key(), *status, + IDS_INSTALL_MULTI_INSTALLATION_EXISTS_BASE, NULL); + return false; + } + } // Check to avoid simultaneous per-user and per-machine installs. const ProductState* other_state = original_state.GetProductState(!system_level, browser_dist->GetType()); - if (other_state != NULL) { LOG(ERROR) << "Already installed version " << other_state->version().GetString() << " conflicts with the current install mode."; if (!system_level && is_first_install && product->is_chrome()) { // This is user-level install and there is a system-level chrome - // installation. Instruct Omaha to launch the existing one. There - // should be no error dialog. + // installation. Instruct Google Update to launch the existing one. + // There should be no error dialog. FilePath chrome_exe(installer::GetChromeInstallPath(!system_level, browser_dist)); if (chrome_exe.empty()) { // If we failed to construct install path. Give up. *status = installer::OS_ERROR; InstallUtil::WriteInstallerResult(system_level, - installer_state.state_key(), *status, IDS_INSTALL_OS_ERROR_BASE, + installer_state->state_key(), *status, IDS_INSTALL_OS_ERROR_BASE, NULL); } else { *status = installer::EXISTING_VERSION_LAUNCHED; @@ -227,7 +397,7 @@ bool CheckPreInstallConditions(const InstallationState& original_state, CommandLine cmd(chrome_exe); cmd.AppendSwitch(switches::kFirstRun); InstallUtil::WriteInstallerResult(system_level, - installer_state.state_key(), *status, 0, NULL); + installer_state->state_key(), *status, 0, NULL); VLOG(1) << "Launching existing system-level chrome instead."; base::LaunchApp(cmd, false, false, NULL); } @@ -237,7 +407,7 @@ bool CheckPreInstallConditions(const InstallationState& original_state, // If the following compile assert fires it means that the InstallStatus // enumeration changed which will break the contract between the old // chrome installed and the new setup.exe that is trying to upgrade. - COMPILE_ASSERT(installer::SXS_OPTION_NOT_SUPPORTED == 33, + COMPILE_ASSERT(installer::CONFLICTING_CHANNEL_EXISTS == 39, dont_change_enum); // This is an update, not an install. Omaha should know the difference @@ -247,23 +417,28 @@ bool CheckPreInstallConditions(const InstallationState& original_state, int str_id = system_level ? IDS_INSTALL_USER_LEVEL_EXISTS_BASE : IDS_INSTALL_SYSTEM_LEVEL_EXISTS_BASE; InstallUtil::WriteInstallerResult(system_level, - installer_state.state_key(), *status, str_id, NULL); + installer_state->state_key(), *status, str_id, NULL); return false; } } + // See what products are already installed in multi mode. When we do multi + // installs, we must upgrade all installations since they share the binaries. + AddExistingMultiInstalls(original_state, installer_state); + // If no previous installation of Chrome, make sure installation directory // either does not exist or can be deleted (i.e. is not locked by some other // process). if (is_first_install) { - if (file_util::PathExists(installation.path()) && - !file_util::Delete(installation.path(), true)) { - LOG(ERROR) << "Installation directory " << installation.path().value() + if (file_util::PathExists(installer_state->target_path()) && + !file_util::Delete(installer_state->target_path(), true)) { + LOG(ERROR) << "Installation directory " + << installer_state->target_path().value() << " exists and can not be deleted."; *status = installer::INSTALL_DIR_IN_USE; int str_id = IDS_INSTALL_DIR_IN_USE_BASE; InstallUtil::WriteInstallerResult(system_level, - installer_state.state_key(), *status, str_id, NULL); + installer_state->state_key(), *status, str_id, NULL); return false; } } @@ -271,13 +446,15 @@ bool CheckPreInstallConditions(const InstallationState& original_state, return true; } -installer::InstallStatus InstallChrome(const InstallationState& original_state, - const InstallerState& installer_state, - const CommandLine& cmd_line, const Package& installation, - const MasterPreferences& prefs) { +installer::InstallStatus InstallProducts( + const InstallationState& original_state, + const CommandLine& cmd_line, + const MasterPreferences& prefs, + InstallerState* installer_state) { + const bool system_install = installer_state->system_install(); installer::InstallStatus install_status = installer::UNKNOWN_STATUS; - if (!CheckPreInstallConditions(original_state, installer_state, installation, - prefs, &install_status)) + if (!CheckPreInstallConditions(original_state, installer_state, + &install_status)) return install_status; // For install the default location for chrome.packed.7z is in current @@ -291,15 +468,15 @@ installer::InstallStatus InstallChrome(const InstallationState& original_state, installer::switches::kInstallArchive); } VLOG(1) << "Archive found to install Chrome " << archive.value(); - const Products& products = installation.products(); + const Products& products = installer_state->products(); // Create a temp folder where we will unpack Chrome archive. If it fails, // then we are doomed, so return immediately and no cleanup is required. FilePath temp_path; if (!file_util::CreateNewTempDirectory(L"chrome_", &temp_path)) { LOG(ERROR) << "Could not create temporary path."; - InstallUtil::WriteInstallerResult(installer_state.system_install(), - installer_state.state_key(), installer::TEMP_DIR_FAILED, + InstallUtil::WriteInstallerResult(system_install, + installer_state->state_key(), installer::TEMP_DIR_FAILED, IDS_INSTALL_TEMP_DIR_FAILED_BASE, NULL); return installer::TEMP_DIR_FAILED; } @@ -307,11 +484,11 @@ installer::InstallStatus InstallChrome(const InstallationState& original_state, FilePath unpack_path(temp_path.Append(installer::kInstallSourceDir)); bool incremental_install = false; - if (UnPackArchive(archive, installation, temp_path, unpack_path, + if (UnPackArchive(archive, *installer_state, temp_path, unpack_path, incremental_install)) { install_status = installer::UNCOMPRESSION_FAILED; - InstallUtil::WriteInstallerResult(installer_state.system_install(), - installer_state.state_key(), install_status, + InstallUtil::WriteInstallerResult(system_install, + installer_state->state_key(), install_status, IDS_INSTALL_UNCOMPRESSION_FAILED_BASE, NULL); } else { VLOG(1) << "unpacked to " << unpack_path.value(); @@ -321,8 +498,8 @@ installer::InstallStatus InstallChrome(const InstallationState& original_state, if (!installer_version.get()) { LOG(ERROR) << "Did not find any valid version in installer."; install_status = installer::INVALID_ARCHIVE; - InstallUtil::WriteInstallerResult(installer_state.system_install(), - installer_state.state_key(), install_status, + InstallUtil::WriteInstallerResult(system_install, + installer_state->state_key(), install_status, IDS_INSTALL_INVALID_ARCHIVE_BASE, NULL); } else { // TODO(tommi): Move towards having only a single version that is common @@ -332,10 +509,10 @@ installer::InstallStatus InstallChrome(const InstallationState& original_state, // (or rather must) be upgraded. VLOG(1) << "version to install: " << installer_version->GetString(); bool higher_version_installed = false; - for (size_t i = 0; i < installation.products().size(); ++i) { - const Product* product = installation.products()[i]; + for (size_t i = 0; i < installer_state->products().size(); ++i) { + const Product* product = installer_state->products()[i]; const ProductState* product_state = - original_state.GetProductState(installer_state.system_install(), + original_state.GetProductState(system_install, product->distribution()->GetType()); if (product_state != NULL && (product_state->version().CompareTo(*installer_version) > 0)) { @@ -346,12 +523,12 @@ installer::InstallStatus InstallChrome(const InstallationState& original_state, if (product->is_chrome()) { // TODO(robertshield): We should take the installer result text // strings from the Product. - InstallUtil::WriteInstallerResult(installer_state.system_install(), - installer_state.state_key(), install_status, + InstallUtil::WriteInstallerResult(system_install, + installer_state->state_key(), install_status, IDS_INSTALL_HIGHER_VERSION_BASE, NULL); } else { - InstallUtil::WriteInstallerResult(installer_state.system_install(), - installer_state.state_key(), install_status, + InstallUtil::WriteInstallerResult(system_install, + installer_state->state_key(), install_status, IDS_INSTALL_HIGHER_VERSION_CF_BASE, NULL); } } @@ -364,33 +541,37 @@ installer::InstallStatus InstallChrome(const InstallationState& original_state, FilePath prefs_source_path(cmd_line.GetSwitchValueNative( installer::switches::kInstallerData)); install_status = installer::InstallOrUpdateProduct(original_state, - installer_state, cmd_line.GetProgram(), archive_to_copy, temp_path, - prefs_source_path, prefs, *installer_version, installation); + *installer_state, cmd_line.GetProgram(), archive_to_copy, temp_path, + prefs_source_path, prefs, *installer_version); int install_msg_base = IDS_INSTALL_FAILED_BASE; std::wstring chrome_exe; if (install_status == installer::SAME_VERSION_REPAIR_FAILED) { - if (FindProduct(products, BrowserDistribution::CHROME_FRAME)) { + if (installer_state->FindProduct(BrowserDistribution::CHROME_FRAME)) { install_msg_base = IDS_SAME_VERSION_REPAIR_FAILED_CF_BASE; } else { install_msg_base = IDS_SAME_VERSION_REPAIR_FAILED_BASE; } } else if (install_status != installer::INSTALL_FAILED) { - if (installation.path().empty()) { + if (installer_state->target_path().empty()) { // If we failed to construct install path, it means the OS call to // get %ProgramFiles% or %AppData% failed. Report this as failure. install_msg_base = IDS_INSTALL_OS_ERROR_BASE; install_status = installer::OS_ERROR; } else { - chrome_exe = installation.path() + chrome_exe = installer_state->target_path() .Append(installer::kChromeExe).value(); chrome_exe = L"\"" + chrome_exe + L"\""; install_msg_base = 0; } } - const Product* chrome_install = - FindProduct(products, BrowserDistribution::CHROME_BROWSER); + // Only do Chrome-specific stuff (like launching the browser) if + // Chrome was specifically requested (rather than being upgraded as + // part of a multi-install). + const Product* chrome_install = prefs.install_chrome() ? + installer_state->FindProduct(BrowserDistribution::CHROME_BROWSER) : + NULL; bool value = false; if (chrome_install) { @@ -404,8 +585,8 @@ installer::InstallStatus InstallChrome(const InstallationState& original_state, bool write_chrome_launch_string = (!value) && (install_status != installer::IN_USE_UPDATED); - InstallUtil::WriteInstallerResult(installer_state.system_install(), - installer_state.state_key(), install_status, install_msg_base, + InstallUtil::WriteInstallerResult(system_install, + installer_state->state_key(), install_status, install_msg_base, write_chrome_launch_string ? &chrome_exe : NULL); if (install_status == installer::FIRST_INSTALL_SUCCESS) { @@ -416,8 +597,8 @@ installer::InstallStatus InstallChrome(const InstallationState& original_state, prefs.GetBool( installer::master_preferences::kDoNotLaunchChrome, &do_not_launch_chrome); - if (!installation.system_level() && !do_not_launch_chrome) - chrome_install->LaunchChrome(); + if (!system_install && !do_not_launch_chrome) + chrome_install->LaunchChrome(installer_state->target_path()); } } else if ((install_status == installer::NEW_VERSION_UPDATED) || (install_status == installer::IN_USE_UPDATED)) { @@ -438,7 +619,7 @@ installer::InstallStatus InstallChrome(const InstallationState& original_state, for (size_t i = 0; i < products.size(); ++i) { const Product* product = products[i]; product->distribution()->LaunchUserExperiment(install_status, - *installer_version, *product, installation.system_level()); + *installer_version, *product, system_install); } } @@ -472,14 +653,13 @@ installer::InstallStatus InstallChrome(const InstallationState& original_state, for (size_t i = 0; i < products.size(); ++i) { const Product* product = products[i]; product->distribution()->UpdateInstallStatus( - installer_state.system_install(), incremental_install, - prefs.is_multi_install(), install_status); - } - if (prefs.is_multi_install()) { - installation.properties()->UpdateInstallStatus( - installer_state.system_install(), incremental_install, true, + system_install, incremental_install, prefs.is_multi_install(), install_status); } + if (installer_state->is_multi_install()) { + installer_state->multi_package_binaries_distribution()->UpdateInstallStatus( + system_install, incremental_install, true, install_status); + } return install_status; } @@ -539,11 +719,10 @@ installer::InstallStatus ShowEULADialog(const std::wstring& inner_frame) { // various tasks other than installation (renaming chrome.exe, showing eula // among others). This function returns true if any such command line option // has been found and processed (so setup.exe should exit at that point). -bool HandleNonInstallCmdLineOptions(const InstallerState& installer_state, +bool HandleNonInstallCmdLineOptions(const InstallationState& original_state, const CommandLine& cmd_line, - const ProductPackageMapping& installs, + const InstallerState& installer_state, int* exit_code) { - DCHECK(installs.products().size()); bool handled = true; // TODO(tommi): Split these checks up into functions and use a data driven // map of switch->function. @@ -588,12 +767,11 @@ bool HandleNonInstallCmdLineOptions(const InstallerState& installer_state, cmd_line.GetSwitchValueNative(installer::switches::kShowEula); *exit_code = ShowEULADialog(inner_frame); if (installer::EULA_REJECTED != *exit_code) - GoogleUpdateSettings::SetEULAConsent(*installs.packages()[0].get(), true); + GoogleUpdateSettings::SetEULAConsent(installer_state, true); } else if (cmd_line.HasSwitch( installer::switches::kRegisterChromeBrowser)) { const Product* chrome_install = - FindProduct(installs.products(), BrowserDistribution::CHROME_BROWSER); - DCHECK(chrome_install); + installer_state.FindProduct(BrowserDistribution::CHROME_BROWSER); if (chrome_install) { // If --register-chrome-browser option is specified, register all // Chrome protocol/file associations as well as register it as a valid @@ -611,16 +789,13 @@ bool HandleNonInstallCmdLineOptions(const InstallerState& installer_state, *exit_code = ShellUtil::RegisterChromeBrowser( chrome_install->distribution(), chrome_exe, suffix, false); } else { - LOG(ERROR) << "Can't register browser - Chrome distribution not found"; + LOG(DFATAL) << "Can't register browser - Chrome distribution not found"; *exit_code = installer::UNKNOWN_STATUS; } } else if (cmd_line.HasSwitch(installer::switches::kRenameChromeExe)) { // If --rename-chrome-exe is specified, we want to rename the executables // and exit. - const Packages& packages = installs.packages(); - DCHECK_EQ(1U, packages.size()); - for (size_t i = 0; i < packages.size(); ++i) - *exit_code = RenameChromeExecutables(*packages[i].get()); + *exit_code = RenameChromeExecutables(installer_state); } else if (cmd_line.HasSwitch( installer::switches::kRemoveChromeRegistration)) { // This is almost reverse of --register-chrome-browser option above. @@ -635,7 +810,7 @@ bool HandleNonInstallCmdLineOptions(const InstallerState& installer_state, } installer::InstallStatus tmp = installer::UNKNOWN_STATUS; const Product* chrome_install = - FindProduct(installs.products(), BrowserDistribution::CHROME_BROWSER); + installer_state.FindProduct(BrowserDistribution::CHROME_BROWSER); DCHECK(chrome_install); if (chrome_install) { installer::DeleteChromeRegistrationKeys(chrome_install->distribution(), @@ -651,37 +826,41 @@ bool HandleNonInstallCmdLineOptions(const InstallerState& installer_state, if (flavor == -1) { *exit_code = installer::UNKNOWN_STATUS; } else { - const Products& products = installs.products(); + const Products& products = installer_state.products(); for (size_t i = 0; i < products.size(); ++i) { const Product* product = products[i]; BrowserDistribution* browser_dist = product->distribution(); - browser_dist->InactiveUserToastExperiment(flavor, *product); + browser_dist->InactiveUserToastExperiment(flavor, *product, + installer_state.target_path()); } } } else if (cmd_line.HasSwitch(installer::switches::kSystemLevelToast)) { - const Products& products = installs.products(); + const Products& products = installer_state.products(); for (size_t i = 0; i < products.size(); ++i) { const Product* product = products[i]; BrowserDistribution* browser_dist = product->distribution(); // We started as system-level and have been re-launched as user level // to continue with the toast experiment. scoped_ptr<Version> installed_version( - InstallUtil::GetChromeVersion(browser_dist, installs.system_level())); + InstallUtil::GetChromeVersion(browser_dist, + installer_state.system_install())); browser_dist->LaunchUserExperiment(installer::REENTRY_SYS_UPDATE, *installed_version, *product, true); } } else if (cmd_line.HasSwitch( installer::switches::kChromeFrameReadyModeOptIn)) { *exit_code = InstallUtil::GetInstallReturnCode( - installer::ChromeFrameReadyModeOptIn(installer_state, cmd_line)); + installer::ChromeFrameReadyModeOptIn(original_state, installer_state)); } else if (cmd_line.HasSwitch( installer::switches::kChromeFrameReadyModeTempOptOut)) { *exit_code = InstallUtil::GetInstallReturnCode( - installer::ChromeFrameReadyModeTempOptOut(cmd_line)); + installer::ChromeFrameReadyModeTempOptOut(original_state, + installer_state)); } else if (cmd_line.HasSwitch( installer::switches::kChromeFrameReadyModeEndTempOptOut)) { *exit_code = InstallUtil::GetInstallReturnCode( - installer::ChromeFrameReadyModeEndTempOptOut(cmd_line)); + installer::ChromeFrameReadyModeEndTempOptOut(original_state, + installer_state)); } else { handled = false; } @@ -743,54 +922,9 @@ class AutoCom { bool initialized_; }; -bool PopulateInstallations(bool for_uninstall, - const MasterPreferences& prefs, - ProductPackageMapping* installations) { - DCHECK(installations); - bool success = true; - - bool implicit_chrome_install = false; - bool implicit_gcf_install = false; - - // See what products are already installed in multi mode. - // When we do multi installs, we must upgrade all installations in sync since - // they share the binaries. Be careful to not do this when we're uninstalling - // a product. - if (prefs.is_multi_install() && !for_uninstall) { - struct CheckInstall { - bool* installed; - BrowserDistribution::Type type; - } product_checks[] = { - {&implicit_chrome_install, BrowserDistribution::CHROME_BROWSER}, - {&implicit_gcf_install, BrowserDistribution::CHROME_FRAME}, - }; - for (size_t i = 0; i < arraysize(product_checks); ++i) { - BrowserDistribution* dist = BrowserDistribution::GetSpecificDistribution( - product_checks[i].type, prefs); - *product_checks[i].installed = installer::IsInstalledAsMulti( - installations->system_level(), dist); - LOG_IF(INFO, *product_checks[i].installed) - << "Product already installed and must be included: " - << dist->GetApplicationName(); - } - } - if (prefs.install_chrome() || implicit_chrome_install) { - VLOG(1) << (for_uninstall ? "Uninstall" : "Install") - << " distribution: Chrome"; - success = installations->AddDistribution( - BrowserDistribution::CHROME_BROWSER, prefs); - } - if (success && (prefs.install_chrome_frame() || implicit_gcf_install)) { - VLOG(1) << (for_uninstall ? "Uninstall" : "Install") - << " distribution: Chrome Frame"; - success = installations->AddDistribution( - BrowserDistribution::CHROME_FRAME, prefs); - } - return success; -} // Returns the Custom information for the client identified by the exe path // passed in. This information is used for crash reporting. @@ -883,28 +1017,12 @@ int WINAPI wWinMain(HINSTANCE instance, HINSTANCE prev_instance, InitializeCrashReporting(system_install)); InstallationState original_state; - original_state.Initialize(prefs); + original_state.Initialize(); InstallerState installer_state; - installer_state.Initialize(prefs, original_state); + installer_state.Initialize(cmd_line, prefs, original_state); const bool is_uninstall = cmd_line.HasSwitch(installer::switches::kUninstall); - ProductPackageMapping installations(prefs.is_multi_install(), system_install); - if (!PopulateInstallations(is_uninstall, prefs, &installations)) { - // Currently this can only fail if one of the installations is a multi and - // a pre-existing single installation exists or vice versa. - installer::InstallStatus status = installer::NON_MULTI_INSTALLATION_EXISTS; - int string_id = IDS_INSTALL_NON_MULTI_INSTALLATION_EXISTS_BASE; - if (!prefs.is_multi_install()) { - status = installer::MULTI_INSTALLATION_EXISTS; - string_id = IDS_INSTALL_MULTI_INSTALLATION_EXISTS_BASE; - } - LOG(ERROR) << "Failed to populate installations: " << status; - InstallUtil::WriteInstallerResult(system_install, - installer_state.state_key(), status, string_id, NULL); - return status; - } - // Check to make sure current system is WinXP or later. If not, log // error message and get out. if (!InstallUtil::IsOSSupported()) { @@ -940,8 +1058,8 @@ int WINAPI wWinMain(HINSTANCE instance, HINSTANCE prev_instance, } int exit_code = 0; - if (HandleNonInstallCmdLineOptions(installer_state, cmd_line, installations, - &exit_code)) + if (HandleNonInstallCmdLineOptions(original_state, cmd_line, installer_state, + &exit_code)) return exit_code; if (system_install && !IsUserAnAdmin()) { @@ -965,24 +1083,22 @@ int WINAPI wWinMain(HINSTANCE instance, HINSTANCE prev_instance, } installer::InstallStatus install_status = installer::UNKNOWN_STATUS; - // If --uninstall option is given, uninstall chrome + // If --uninstall option is given, uninstall the identified product(s) if (is_uninstall) { - for (size_t i = 0; i < installations.products().size(); ++i) { + const Products& products = installer_state.products(); + for (size_t i = 0; i < products.size(); ++i) { install_status = UninstallProduct(original_state, installer_state, - cmd_line, *installations.products()[i]); + cmd_line, *products[i]); } } else { // If --uninstall option is not specified, we assume it is install case. - const Packages& packages = installations.packages(); - VLOG(1) << "Installing to " << packages.size() << " target paths"; - for (size_t i = 0; i < packages.size(); ++i) { - install_status = InstallChrome(original_state, installer_state, cmd_line, - *packages[i].get(), prefs); - } + VLOG(1) << "Installing to " << installer_state.target_path().value(); + install_status = InstallProducts(original_state, cmd_line, prefs, + &installer_state); } const Product* cf_install = - FindProduct(installations.products(), BrowserDistribution::CHROME_FRAME); + installer_state.FindProduct(BrowserDistribution::CHROME_FRAME); if (cf_install && !cmd_line.HasSwitch(installer::switches::kForceUninstall)) { @@ -991,7 +1107,7 @@ int WINAPI wWinMain(HINSTANCE instance, HINSTANCE prev_instance, } else if (is_uninstall) { // Only show the message box if Chrome Frame was the only product being // uninstalled. - if (installations.products().size() == 1U) { + if (installer_state.products().size() == 1U) { ::MessageBoxW(NULL, installer::GetLocalizedString( IDS_UNINSTALL_COMPLETE_BASE).c_str(), @@ -1005,17 +1121,11 @@ int WINAPI wWinMain(HINSTANCE instance, HINSTANCE prev_instance, // MSI demands that custom actions always return 0 (ERROR_SUCCESS) or it will // rollback the action. If we're uninstalling we want to avoid this, so always // report success, squashing any more informative return codes. - // TODO(tommi): Fix this loop when IsMsi has been moved out of the Product - // class. - for (size_t i = 0; i < installations.products().size(); ++i) { - const Product* product = installations.products()[i]; - if (!(product->IsMsi() && is_uninstall)) { - // Note that we allow the status installer::UNINSTALL_REQUIRES_REBOOT - // to pass through, since this is only returned on uninstall which is - // never invoked directly by Google Update. - return_code = InstallUtil::GetInstallReturnCode(install_status); - } - } + if (!(installer_state.is_msi() && is_uninstall)) + // Note that we allow the status installer::UNINSTALL_REQUIRES_REBOOT + // to pass through, since this is only returned on uninstall which is + // never invoked directly by Google Update. + return_code = InstallUtil::GetInstallReturnCode(install_status); VLOG(1) << "Installation complete, returning: " << return_code; |