Chromium Code Reviews| Index: chrome/installer/setup/setup_main.cc |
| diff --git a/chrome/installer/setup/setup_main.cc b/chrome/installer/setup/setup_main.cc |
| index 9ffc986279f0534a5ddc63e3bc7b722a7ee72ca3..2d67de2f2ba09fec43f16e4658fdc99d13a03735 100644 |
| --- a/chrome/installer/setup/setup_main.cc |
| +++ b/chrome/installer/setup/setup_main.cc |
| @@ -701,63 +701,6 @@ bool CreateTemporaryAndUnpackDirectories( |
| return true; |
| } |
| -installer::InstallStatus InstallProducts( |
| - const InstallationState& original_state, |
| - const CommandLine& cmd_line, |
| - const MasterPreferences& prefs, |
| - InstallerState* installer_state, |
| - base::FilePath* installer_directory) { |
| - DCHECK(installer_state); |
| - const bool system_install = installer_state->system_install(); |
| - installer::InstallStatus install_status = installer::UNKNOWN_STATUS; |
| - installer::ArchiveType archive_type = installer::UNKNOWN_ARCHIVE_TYPE; |
| - bool delegated_to_existing = false; |
| - installer_state->UpdateStage(installer::PRECONDITIONS); |
| - // The stage provides more fine-grained information than -multifail, so remove |
| - // the -multifail suffix from the Google Update "ap" value. |
| - BrowserDistribution::GetSpecificDistribution(installer_state->state_type())-> |
| - UpdateInstallStatus(system_install, archive_type, install_status); |
| - if (CheckPreInstallConditions(original_state, installer_state, |
| - &install_status)) { |
| - VLOG(1) << "Installing to " << installer_state->target_path().value(); |
| - install_status = InstallProductsHelper( |
| - original_state, cmd_line, prefs, *installer_state, |
| - installer_directory, &archive_type, &delegated_to_existing); |
| - } else { |
| - // CheckPreInstallConditions must set the status on failure. |
| - DCHECK_NE(install_status, installer::UNKNOWN_STATUS); |
| - } |
| - |
| - // Delete the master preferences file if present. Note that we do not care |
| - // about rollback here and we schedule for deletion on reboot if the delete |
| - // fails. As such, we do not use DeleteTreeWorkItem. |
| - if (cmd_line.HasSwitch(installer::switches::kInstallerData)) { |
| - base::FilePath prefs_path(cmd_line.GetSwitchValuePath( |
| - installer::switches::kInstallerData)); |
| - if (!base::DeleteFile(prefs_path, false)) { |
| - LOG(ERROR) << "Failed deleting master preferences file " |
| - << prefs_path.value() |
| - << ", scheduling for deletion after reboot."; |
| - ScheduleFileSystemEntityForDeletion(prefs_path); |
| - } |
| - } |
| - |
| - // Early exit if this setup.exe delegated to another, since that one would |
| - // have taken care of UpdateInstallStatus and UpdateStage. |
| - if (delegated_to_existing) |
| - return install_status; |
| - |
| - const Products& products = installer_state->products(); |
| - for (Products::const_iterator it = products.begin(); it < products.end(); |
| - ++it) { |
| - (*it)->distribution()->UpdateInstallStatus( |
| - system_install, archive_type, install_status); |
| - } |
| - |
| - installer_state->UpdateStage(installer::NO_STAGE); |
| - return install_status; |
| -} |
| - |
| installer::InstallStatus UninstallProduct( |
| const InstallationState& original_state, |
| const InstallerState& installer_state, |
| @@ -868,6 +811,100 @@ installer::InstallStatus UninstallProducts( |
| return install_status; |
| } |
| +// Uninstall the binaries if they are the only product present and they're not |
| +// in-use. |
| +void UninstallBinariesIfUnused( |
| + const InstallationState& original_state, |
| + const InstallerState& installer_state, |
| + installer::InstallStatus* install_status) { |
| + // Early exit if the binaries are still in use. |
| + if (*install_status != installer::UNUSED_BINARIES || |
| + installer_state.AreBinariesInUse(original_state)) { |
| + return; |
| + } |
| + |
| + LOG(INFO) << "Uninstalling unused binaries"; |
|
robertshield
2013/12/03 02:20:05
VLOG(1) instead?
grt (UTC plus 2)
2013/12/03 13:37:51
I thought this would be useful to have in the inst
|
| + installer_state.UpdateStage(installer::UNINSTALLING_BINARIES); |
| + |
| + // Simulate the uninstall as coming from the installed version. |
| + const ProductState* binaries_state = |
| + original_state.GetProductState(installer_state.system_install(), |
| + BrowserDistribution::CHROME_BINARIES); |
| + const CommandLine& uninstall_cmd(binaries_state->uninstall_command()); |
| + MasterPreferences uninstall_prefs(uninstall_cmd); |
| + InstallerState uninstall_state; |
| + uninstall_state.Initialize(uninstall_cmd, uninstall_prefs, original_state); |
| + |
| + *install_status = |
| + UninstallProducts(original_state, uninstall_state, uninstall_cmd); |
| + |
| + // Report that the binaries were uninstalled if they were. This translates |
| + // into a successful install return code. |
| + if (IsUninstallSuccess(*install_status)) { |
| + *install_status = installer::UNUSED_BINARIES_UNINSTALLED; |
| + installer_state.WriteInstallerResult(*install_status, 0, NULL); |
| + } |
| +} |
| + |
| +installer::InstallStatus InstallProducts( |
| + const InstallationState& original_state, |
| + const CommandLine& cmd_line, |
| + const MasterPreferences& prefs, |
| + InstallerState* installer_state, |
| + base::FilePath* installer_directory) { |
| + DCHECK(installer_state); |
| + const bool system_install = installer_state->system_install(); |
| + installer::InstallStatus install_status = installer::UNKNOWN_STATUS; |
| + installer::ArchiveType archive_type = installer::UNKNOWN_ARCHIVE_TYPE; |
| + bool delegated_to_existing = false; |
| + installer_state->UpdateStage(installer::PRECONDITIONS); |
| + // The stage provides more fine-grained information than -multifail, so remove |
| + // the -multifail suffix from the Google Update "ap" value. |
| + BrowserDistribution::GetSpecificDistribution(installer_state->state_type())-> |
| + UpdateInstallStatus(system_install, archive_type, install_status); |
| + if (CheckPreInstallConditions(original_state, installer_state, |
| + &install_status)) { |
| + VLOG(1) << "Installing to " << installer_state->target_path().value(); |
| + install_status = InstallProductsHelper( |
| + original_state, cmd_line, prefs, *installer_state, |
| + installer_directory, &archive_type, &delegated_to_existing); |
| + } else { |
| + // CheckPreInstallConditions must set the status on failure. |
| + DCHECK_NE(install_status, installer::UNKNOWN_STATUS); |
| + } |
| + |
| + // Delete the master preferences file if present. Note that we do not care |
| + // about rollback here and we schedule for deletion on reboot if the delete |
| + // fails. As such, we do not use DeleteTreeWorkItem. |
| + if (cmd_line.HasSwitch(installer::switches::kInstallerData)) { |
| + base::FilePath prefs_path(cmd_line.GetSwitchValuePath( |
| + installer::switches::kInstallerData)); |
| + if (!base::DeleteFile(prefs_path, false)) { |
| + LOG(ERROR) << "Failed deleting master preferences file " |
| + << prefs_path.value() |
| + << ", scheduling for deletion after reboot."; |
| + ScheduleFileSystemEntityForDeletion(prefs_path); |
| + } |
| + } |
| + |
| + // Early exit if this setup.exe delegated to another, since that one would |
| + // have taken care of UpdateInstallStatus and UpdateStage. |
| + if (delegated_to_existing) |
| + return install_status; |
| + |
| + const Products& products = installer_state->products(); |
| + for (Products::const_iterator it = products.begin(); it < products.end(); |
| + ++it) { |
| + (*it)->distribution()->UpdateInstallStatus( |
| + system_install, archive_type, install_status); |
| + } |
| + |
| + UninstallBinariesIfUnused(original_state, *installer_state, &install_status); |
| + |
| + installer_state->UpdateStage(installer::NO_STAGE); |
| + return install_status; |
| +} |
| + |
| installer::InstallStatus ShowEULADialog(const string16& inner_frame) { |
| VLOG(1) << "About to show EULA"; |
| string16 eula_path = installer::GetLocalizedEulaResource(); |
| @@ -1367,6 +1404,63 @@ google_breakpad::ExceptionHandler* InitializeCrashReporting( |
| return breakpad; |
| } |
| +// Uninstalls multi-install Chrome Frame if the current operation is a |
| +// multi-install install or update. The operation is performed directly rather |
| +// than delegated to the existing install since there is no facility in older |
| +// versions of setup.exe to uninstall GCF without touching the binaries. The |
| +// binaries will be uninstalled during later processing if they are not in-use |
| +// (see UninstallBinariesIfUnused). |original_state| and |installer_state| are |
| +// updated to reflect the state of the world following the operation. |
| +void UninstallMultiChromeFrameIfPresent(const CommandLine& cmd_line, |
| + const MasterPreferences& prefs, |
| + InstallationState* original_state, |
| + InstallerState* installer_state) { |
| + // Early exit if not installing or updating multi-install product(s). |
| + if (installer_state->operation() != InstallerState::MULTI_INSTALL && |
| + installer_state->operation() != InstallerState::MULTI_UPDATE) { |
| + return; |
| + } |
| + |
| + // Early exit if Chrome Frame is not present as multi-install. |
| + const ProductState* chrome_frame_state = |
| + original_state->GetProductState(installer_state->system_install(), |
| + BrowserDistribution::CHROME_FRAME); |
| + if (!chrome_frame_state || !chrome_frame_state->is_multi_install()) |
| + return; |
| + |
| + LOG(INFO) << "Uninstalling multi-install Chrome Frame."; |
| + installer_state->UpdateStage(installer::UNINSTALLING_CHROME_FRAME); |
| + |
| + // Uninstall Chrome Frame without touching the multi-install binaries. |
| + // Simulate the uninstall as coming from the installed version. |
| + const CommandLine& uninstall_cmd(chrome_frame_state->uninstall_command()); |
| + MasterPreferences uninstall_prefs(uninstall_cmd); |
| + InstallerState uninstall_state; |
| + uninstall_state.Initialize(uninstall_cmd, uninstall_prefs, *original_state); |
| + const Product* chrome_frame_product = uninstall_state.FindProduct( |
| + BrowserDistribution::CHROME_FRAME); |
| + if (chrome_frame_product) { |
| + // No shared state should be left behind. |
| + const bool remove_all = true; |
| + // Don't accept no for an answer. |
| + const bool force_uninstall = true; |
| + installer::InstallStatus uninstall_status = |
| + installer::UninstallProduct(*original_state, uninstall_state, |
| + uninstall_cmd.GetProgram(), |
| + *chrome_frame_product, remove_all, |
| + force_uninstall, cmd_line); |
| + |
| + VLOG(1) << "Uninstallation of Chrome Frame returned status " |
| + << uninstall_status; |
| + } else { |
| + LOG(ERROR) << "Chrome Frame not found for uninstall."; |
| + } |
| + |
| + // Refresh state for the continuation of the original install/update. |
| + original_state->Initialize(); |
| + installer_state->Initialize(cmd_line, prefs, *original_state); |
| +} |
| + |
| } // namespace |
| namespace installer { |
| @@ -1775,27 +1869,21 @@ int WINAPI wWinMain(HINSTANCE instance, HINSTANCE prev_instance, |
| } |
| } |
| + UninstallMultiChromeFrameIfPresent(cmd_line, prefs, |
| + &original_state, &installer_state); |
| + |
| base::FilePath installer_directory; |
| installer::InstallStatus install_status = installer::UNKNOWN_STATUS; |
| - // If --uninstall option is not specified, we assume it is install case. |
| - if (!is_uninstall) { |
| + // If --uninstall option is given, uninstall the identified product(s) |
| + if (is_uninstall) { |
| + install_status = |
| + UninstallProducts(original_state, installer_state, cmd_line); |
| + } else { |
| + // If --uninstall option is not specified, we assume it is install case. |
| install_status = |
| InstallProducts(original_state, cmd_line, prefs, &installer_state, |
| &installer_directory); |
| } |
| - // If --uninstall option is given or only the binaries are present and they're |
| - // not in-use, uninstall the identified product(s). |
| - if (is_uninstall || (install_status == installer::UNUSED_BINARIES && |
| - !installer_state.AreBinariesInUse(original_state))) { |
| - install_status = |
| - UninstallProducts(original_state, installer_state, cmd_line); |
| - // Report that the binaries were uninstalled if they were. This translates |
| - // into a successful install return code. |
| - if (!is_uninstall && IsUninstallSuccess(install_status)) { |
| - install_status = installer::UNUSED_BINARIES_UNINSTALLED; |
| - installer_state.WriteInstallerResult(install_status, 0, NULL); |
| - } |
| - } |
| // Validate that the machine is now in a good state following the operation. |
| // TODO(grt): change this to log at DFATAL once we're convinced that the |