| Index: chrome/installer/setup/setup_main.cc
|
| diff --git a/chrome/installer/setup/setup_main.cc b/chrome/installer/setup/setup_main.cc
|
| index 9d9ff5a5ec26f08bc53748e4c5c1a19e5ee2d6f1..eb59d175a630b57a8153b5bbdcb399353f9375f4 100644
|
| --- a/chrome/installer/setup/setup_main.cc
|
| +++ b/chrome/installer/setup/setup_main.cc
|
| @@ -148,8 +148,10 @@ DWORD UnPackArchive(const FilePath& archive,
|
| void AddExistingMultiInstalls(const InstallationState& original_state,
|
| InstallerState* installer_state) {
|
| if (installer_state->is_multi_install()) {
|
| - for (size_t i = 0; i < BrowserDistribution::kNumProductTypes; ++i) {
|
| - BrowserDistribution::Type type = BrowserDistribution::kProductTypes[i];
|
| + for (size_t i = 0; i < BrowserDistribution::NUM_TYPES; ++i) {
|
| + BrowserDistribution::Type type =
|
| + static_cast<BrowserDistribution::Type>(i);
|
| +
|
| if (!installer_state->FindProduct(type)) {
|
| const ProductState* state =
|
| original_state.GetProductState(installer_state->system_install(),
|
| @@ -333,18 +335,20 @@ bool CheckGroupPolicySettings(const InstallationState& original_state,
|
| #endif // defined(GOOGLE_CHROME_BUILD)
|
| }
|
|
|
| -// The supported multi-install modes are:
|
| -// --multi-install --chrome --chrome-frame --ready-mode
|
| +// If Chrome Frame is being installed by itself in multi-mode, non-ready-mode:
|
| +// - If a non-multi Chrome Frame installation is present, fail.
|
| +// If Chrome Frame is being installed by itself in multi-mode, ready-mode:
|
| +// - If no Chrome installation is present, fail.
|
| +// - If a Chrome installation is present, add it to the set of products to
|
| +// install.
|
| +// If Chrome Frame is being installed with Chrome in multi-mode, 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 --ready-mode and no Chrome installation is present, fail.
|
| -// - If a Chrome installation is present, add it to the set of products to
|
| -// install.
|
| +// If any product is being installed in single-mode that already exists in
|
| +// multi-mode, fail.
|
| bool CheckMultiInstallConditions(const InstallationState& original_state,
|
| InstallerState* installer_state,
|
| installer::InstallStatus* status) {
|
| @@ -356,13 +360,42 @@ bool CheckMultiInstallConditions(const InstallationState& original_state,
|
| if (installer_state->is_multi_install()) {
|
| const Product* chrome =
|
| installer_state->FindProduct(BrowserDistribution::CHROME_BROWSER);
|
| + const Product* app_host =
|
| + installer_state->FindProduct(BrowserDistribution::CHROME_APP_HOST);
|
| + const Product* binaries =
|
| + installer_state->FindProduct(BrowserDistribution::CHROME_BINARIES);
|
| 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 &&
|
| + const ProductState* chrome_state =
|
| + original_state.GetProductState(system_level,
|
| + BrowserDistribution::CHROME_BROWSER);
|
| +
|
| + if (!binaries) {
|
| + if (app_host && !chrome && !chrome_frame && !cf_state && !chrome_state) {
|
| + DCHECK(!system_level);
|
| + // App Host may use Chrome/Chrome binaries at system-level.
|
| + if (original_state.GetProductState(
|
| + true, // system
|
| + BrowserDistribution::CHROME_BROWSER) ||
|
| + original_state.GetProductState(
|
| + true, // system
|
| + BrowserDistribution::CHROME_BINARIES)) {
|
| + return true;
|
| + } else {
|
| + return false;
|
| + }
|
| + } else {
|
| + // Every other scenario requires the binaries to be installed/updated
|
| + // simultaneous to the main product.
|
| + return false;
|
| + }
|
| + }
|
| +
|
| + if (chrome) {
|
| + if (chrome_frame &&
|
| 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
|
| @@ -384,51 +417,83 @@ bool CheckMultiInstallConditions(const InstallationState& original_state,
|
| 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) {
|
| - // 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()->GetAppShortCutName();
|
| - } 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;
|
| - installer_state->WriteInstallerResult(*status,
|
| - IDS_INSTALL_READY_MODE_REQUIRES_CHROME_BASE, NULL);
|
| - return false;
|
| - }
|
| + } else if (chrome_state != NULL) {
|
| + // Chrome Frame is being installed in multi-install mode, and Chrome is
|
| + // already present. 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 Chrome browser in multi-install mode.";
|
| + } else if (chrome_frame &&
|
| + 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;
|
| + installer_state->WriteInstallerResult(
|
| + *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()) {
|
| + if (chrome_frame && cf_state && !cf_state->is_multi_install()) {
|
| LOG(ERROR) << "Cannot migrate existing Chrome Frame installation to "
|
| - "multi-install.";
|
| + << "multi-install.";
|
| *status = installer::NON_MULTI_INSTALLATION_EXISTS;
|
| installer_state->WriteInstallerResult(*status,
|
| IDS_INSTALL_NON_MULTI_INSTALLATION_EXISTS_BASE, NULL);
|
| return false;
|
| }
|
| - } else if (DCHECK_IS_ON()) {
|
| + } else {
|
| + // This is a non-multi installation.
|
| +
|
| // 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());
|
| + if (products.size() != 1)
|
| + return false;
|
| +
|
| + // Check for an existing installation of the product.
|
| + const ProductState* product_state = original_state.GetProductState(
|
| + system_level, products[0]->distribution()->GetType());
|
| + if (product_state != NULL) {
|
| + // Block downgrades from multi-install to single-install.
|
| + if (product_state->is_multi_install()) {
|
| + LOG(ERROR) << "Multi-install "
|
| + << products[0]->distribution()->GetAppShortCutName()
|
| + << " exists; aborting single install.";
|
| + *status = installer::MULTI_INSTALLATION_EXISTS;
|
| + installer_state->WriteInstallerResult(*status,
|
| + IDS_INSTALL_MULTI_INSTALLATION_EXISTS_BASE, NULL);
|
| + return false;
|
| + }
|
| + }
|
| +
|
| + }
|
| +
|
| + return true;
|
| +}
|
| +
|
| +bool CheckAppHostPreconditions(const InstallationState& original_state,
|
| + InstallerState* installer_state) {
|
| + if (!installer_state->FindProduct(BrowserDistribution::CHROME_APP_HOST))
|
| + return true;
|
| +
|
| + if (!installer_state->is_multi_install()) {
|
| + VLOG(1) << "Application Host may only be installed in multi-install mode.";
|
| + return false;
|
| + }
|
| +
|
| + if (installer_state->system_install()) {
|
| + VLOG(1) << "Application Host may only be installed at user-level.";
|
| + return false;
|
| }
|
|
|
| return true;
|
| @@ -446,9 +511,11 @@ bool CheckMultiInstallConditions(const InstallationState& original_state,
|
| bool CheckPreInstallConditions(const InstallationState& original_state,
|
| InstallerState* installer_state,
|
| installer::InstallStatus* status) {
|
| - // 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 (!CheckAppHostPreconditions(original_state, installer_state))
|
| + return false;
|
| +
|
| + if (!CheckMultiInstallConditions(original_state, installer_state, status))
|
| + return false;
|
|
|
| const Products& products = installer_state->products();
|
| if (products.empty()) {
|
| @@ -461,57 +528,47 @@ bool CheckPreInstallConditions(const InstallationState& original_state,
|
| return false;
|
| }
|
|
|
| - if (!CheckMultiInstallConditions(original_state, installer_state, status))
|
| - 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);
|
|
|
| - bool is_first_install = true;
|
| - const bool system_level = installer_state->system_install();
|
| + if (!installer_state->system_install()) {
|
| + // This is a user-level installation. Make sure that we are not installing
|
| + // on top of an existing system-level installation.
|
| + for (size_t i = 0; i < products.size(); ++i) {
|
| + const Product* product = products[i];
|
| + BrowserDistribution* browser_dist = product->distribution();
|
| + const ProductState* user_level_product_state =
|
| + original_state.GetProductState(false, browser_dist->GetType());
|
| + const ProductState* system_level_product_state =
|
| + original_state.GetProductState(true, browser_dist->GetType());
|
|
|
| - for (size_t i = 0; i < products.size(); ++i) {
|
| - const Product* product = products[i];
|
| - BrowserDistribution* browser_dist = product->distribution();
|
| + // Allow upgrades to proceed so that out-of-date versions are not left
|
| + // around.
|
| + if (user_level_product_state)
|
| + continue;
|
|
|
| - // Check for an existing installation of the product.
|
| - const ProductState* product_state =
|
| - original_state.GetProductState(system_level, browser_dist->GetType());
|
| - 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->GetAppShortCutName()
|
| - << " exists; aborting single install.";
|
| - *status = installer::MULTI_INSTALLATION_EXISTS;
|
| - installer_state->WriteInstallerResult(*status,
|
| - IDS_INSTALL_MULTI_INSTALLATION_EXISTS_BASE, NULL);
|
| - return false;
|
| - }
|
| - }
|
| + // This is a new user-level install...
|
|
|
| - // Check to avoid attempting to lay down a user-level installation on top
|
| - // of a system-level one.
|
| - const ProductState* other_state =
|
| - original_state.GetProductState(!system_level, browser_dist->GetType());
|
| - if (other_state != NULL && !system_level) {
|
| - if (is_first_install) {
|
| - // This is a user-level install and there is a system-level install of
|
| - // the product.
|
| + if (system_level_product_state) {
|
| + // ... and the product already exists at system-level.
|
| LOG(ERROR) << "Already installed version "
|
| - << other_state->version().GetString()
|
| + << system_level_product_state->version().GetString()
|
| << " at system-level conflicts with this one at user-level.";
|
| if (product->is_chrome()) {
|
| // Instruct Google Update to launch the existing system-level Chrome.
|
| // 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.
|
| + FilePath install_path(installer::GetChromeInstallPath(true, // system
|
| + browser_dist));
|
| + if (install_path.empty()) {
|
| + // Give up if we failed to construct the install path.
|
| *status = installer::OS_ERROR;
|
| installer_state->WriteInstallerResult(*status,
|
| - IDS_INSTALL_OS_ERROR_BASE, NULL);
|
| + IDS_INSTALL_OS_ERROR_BASE,
|
| + NULL);
|
| } else {
|
| *status = installer::EXISTING_VERSION_LAUNCHED;
|
| - chrome_exe = chrome_exe.Append(installer::kChromeExe);
|
| + FilePath chrome_exe = install_path.Append(installer::kChromeExe);
|
| CommandLine cmd(chrome_exe);
|
| cmd.AppendSwitch(switches::kFirstRun);
|
| installer_state->WriteInstallerResult(*status, 0, NULL);
|
| @@ -519,31 +576,13 @@ bool CheckPreInstallConditions(const InstallationState& original_state,
|
| base::LaunchProcess(cmd, base::LaunchOptions(), NULL);
|
| }
|
| } else {
|
| - // Display an error message for Chrome Frame.
|
| + // Display an error message for other products.
|
| *status = installer::SYSTEM_LEVEL_INSTALL_EXISTS;
|
| - installer_state->WriteInstallerResult(*status,
|
| - IDS_INSTALL_SYSTEM_LEVEL_EXISTS_BASE, NULL);
|
| + installer_state->WriteInstallerResult(
|
| + *status, IDS_INSTALL_SYSTEM_LEVEL_EXISTS_BASE, NULL);
|
| }
|
| return false;
|
| }
|
| - // This is an update, not a new install. Allow it to take place so that
|
| - // out-of-date versions are not left around.
|
| - }
|
| - }
|
| -
|
| - // 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(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;
|
| - installer_state->WriteInstallerResult(*status, str_id, NULL);
|
| - return false;
|
| }
|
| }
|
|
|
| @@ -570,7 +609,7 @@ installer::InstallStatus InstallProductsHelper(
|
| archive = cmd_line.GetSwitchValuePath(
|
| installer::switches::kInstallArchive);
|
| }
|
| - VLOG(1) << "Archive found to install Chrome " << archive.value();
|
| +
|
| const Products& products = installer_state.products();
|
|
|
| // Create a temp folder where we will unpack Chrome archive. If it fails,
|
| @@ -586,13 +625,48 @@ installer::InstallStatus InstallProductsHelper(
|
| VLOG(1) << "created path " << temp_path.path().value();
|
|
|
| FilePath unpack_path(temp_path.path().Append(installer::kInstallSourceDir));
|
| - if (UnPackArchive(archive, installer_state, temp_path.path(), unpack_path,
|
| - archive_type)) {
|
| - install_status = (*archive_type) == installer::INCREMENTAL_ARCHIVE_TYPE ?
|
| - installer::APPLY_DIFF_PATCH_FAILED : installer::UNCOMPRESSION_FAILED;
|
| - installer_state.WriteInstallerResult(install_status,
|
| - IDS_INSTALL_UNCOMPRESSION_FAILED_BASE, NULL);
|
| +
|
| + bool unpacked = false;
|
| +
|
| + // We want to keep uncompressed archive (chrome.7z) that we get after
|
| + // uncompressing and binary patching. Get the location for this file.
|
| + FilePath archive_to_copy;
|
| + if (file_util::PathExists(archive)) {
|
| + VLOG(1) << "Archive found to install Chrome " << archive.value();
|
| + if (UnPackArchive(archive, installer_state, temp_path.path(), unpack_path,
|
| + archive_type)) {
|
| + install_status = (*archive_type) == installer::INCREMENTAL_ARCHIVE_TYPE ?
|
| + installer::APPLY_DIFF_PATCH_FAILED : installer::UNCOMPRESSION_FAILED;
|
| + installer_state.WriteInstallerResult(
|
| + install_status,
|
| + IDS_INSTALL_UNCOMPRESSION_FAILED_BASE,
|
| + NULL);
|
| + } else {
|
| + unpacked = true;
|
| + archive_to_copy = temp_path.path().Append(installer::kChromeArchive);
|
| + }
|
| } else {
|
| + FilePath uncompressed_archive(cmd_line.GetProgram().DirName().Append(
|
| + installer::kChromeArchive));
|
| +
|
| + if (file_util::PathExists(uncompressed_archive)) {
|
| + VLOG(1) << "Uncompressed archive found to install Chrome "
|
| + << uncompressed_archive.value();
|
| + *archive_type = installer::FULL_ARCHIVE_TYPE;
|
| + string16 unpacked_file;
|
| + if (LzmaUtil::UnPackArchive(uncompressed_archive.value(),
|
| + unpack_path.value(), &unpacked_file)) {
|
| + installer_state.WriteInstallerResult(
|
| + installer::UNCOMPRESSION_FAILED,
|
| + IDS_INSTALL_UNCOMPRESSION_FAILED_BASE,
|
| + NULL);
|
| + } else {
|
| + unpacked = true;
|
| + archive_to_copy = uncompressed_archive;
|
| + }
|
| + }
|
| + }
|
| + if (unpacked) {
|
| VLOG(1) << "unpacked to " << unpack_path.value();
|
| FilePath src_path(unpack_path.Append(installer::kInstallSourceChromeDir));
|
| scoped_ptr<Version>
|
| @@ -624,22 +698,28 @@ installer::InstallStatus InstallProductsHelper(
|
| }
|
|
|
| if (higher_products != 0) {
|
| - COMPILE_ASSERT(BrowserDistribution::NUM_TYPES == 3,
|
| + COMPILE_ASSERT(BrowserDistribution::NUM_TYPES == 4,
|
| add_support_for_new_products_here_);
|
| const uint32 kBrowserBit = 1 << BrowserDistribution::CHROME_BROWSER;
|
| const uint32 kGCFBit = 1 << BrowserDistribution::CHROME_FRAME;
|
| + const uint32 kAppHostBit = 1 << BrowserDistribution::CHROME_APP_HOST;
|
| int message_id = 0;
|
|
|
| proceed_with_installation = false;
|
| install_status = installer::HIGHER_VERSION_EXISTS;
|
| - if ((higher_products & kBrowserBit) != 0) {
|
| - if ((higher_products & kGCFBit) != 0)
|
| - message_id = IDS_INSTALL_HIGHER_VERSION_CB_CF_BASE;
|
| - else
|
| + switch (higher_products) {
|
| + case kBrowserBit:
|
| message_id = IDS_INSTALL_HIGHER_VERSION_BASE;
|
| - } else {
|
| - DCHECK(higher_products == kGCFBit);
|
| - message_id = IDS_INSTALL_HIGHER_VERSION_CF_BASE;
|
| + break;
|
| + case kGCFBit:
|
| + message_id = IDS_INSTALL_HIGHER_VERSION_CF_BASE;
|
| + break;
|
| + case kGCFBit | kBrowserBit:
|
| + message_id = IDS_INSTALL_HIGHER_VERSION_CB_CF_BASE;
|
| + break;
|
| + default:
|
| + message_id = IDS_INSTALL_HIGHER_VERSION_APP_HOST_BASE;
|
| + break;
|
| }
|
|
|
| installer_state.WriteInstallerResult(install_status, message_id, NULL);
|
| @@ -651,10 +731,6 @@ installer::InstallStatus InstallProductsHelper(
|
| *installer_version, &install_status);
|
|
|
| if (proceed_with_installation) {
|
| - // We want to keep uncompressed archive (chrome.7z) that we get after
|
| - // uncompressing and binary patching. Get the location for this file.
|
| - FilePath archive_to_copy(
|
| - temp_path.path().Append(installer::kChromeArchive));
|
| FilePath prefs_source_path(cmd_line.GetSwitchValueNative(
|
| installer::switches::kInstallerData));
|
| install_status = installer::InstallOrUpdateProduct(original_state,
|
| @@ -879,11 +955,20 @@ installer::InstallStatus UninstallProducts(
|
| const InstallerState& installer_state,
|
| const CommandLine& cmd_line) {
|
| const Products& products = installer_state.products();
|
| - // InstallerState::Initialize always puts Chrome first, and we rely on that
|
| - // here for this reason: if Chrome is in-use, the user will be prompted to
|
| - // confirm uninstallation. Upon cancel, we should not continue with the
|
| - // other products.
|
| - DCHECK(products.size() < 2 || products[0]->is_chrome());
|
| +
|
| + if (installer_state.FindProduct(BrowserDistribution::CHROME_BROWSER)) {
|
| + // InstallerState::Initialize always puts Chrome first, and we rely on that
|
| + // here for this reason: if Chrome is in-use, the user will be prompted to
|
| + // confirm uninstallation. Upon cancel, we should not continue with the
|
| + // other products.
|
| + DCHECK(products[0]->is_chrome());
|
| + }
|
| + if (installer_state.FindProduct(BrowserDistribution::CHROME_BINARIES)) {
|
| + // Chrome Binaries should be last; if something else is cancelled, they
|
| + // should stay.
|
| + DCHECK(products[products.size() - 1]->is_chrome_binaries());
|
| + }
|
| +
|
| installer::InstallStatus install_status = installer::UNINSTALL_SUCCESSFUL;
|
| installer::InstallStatus prod_status = installer::UNKNOWN_STATUS;
|
| const bool force = cmd_line.HasSwitch(installer::switches::kForceUninstall);
|
|
|