Index: chrome/installer/setup/setup_main.cc |
=================================================================== |
--- chrome/installer/setup/setup_main.cc (revision 148045) |
+++ chrome/installer/setup/setup_main.cc (working copy) |
@@ -148,10 +148,8 @@ |
void AddExistingMultiInstalls(const InstallationState& original_state, |
InstallerState* installer_state) { |
if (installer_state->is_multi_install()) { |
- for (size_t i = 0; i < BrowserDistribution::NUM_TYPES; ++i) { |
- BrowserDistribution::Type type = |
- static_cast<BrowserDistribution::Type>(i); |
- |
+ for (size_t i = 0; i < BrowserDistribution::kNumProductTypes; ++i) { |
+ BrowserDistribution::Type type = BrowserDistribution::kProductTypes[i]; |
if (!installer_state->FindProduct(type)) { |
const ProductState* state = |
original_state.GetProductState(installer_state->system_install(), |
@@ -335,20 +333,18 @@ |
#endif // defined(GOOGLE_CHROME_BUILD) |
} |
-// 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: |
+// 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). |
-// If any product is being installed in single-mode that already exists in |
-// multi-mode, fail. |
+// --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. |
bool CheckMultiInstallConditions(const InstallationState& original_state, |
InstallerState* installer_state, |
installer::InstallStatus* status) { |
@@ -360,42 +356,13 @@ |
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); |
- 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 && |
+ 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 |
@@ -417,88 +384,56 @@ |
VLOG(1) << "Performing initial install of Chrome Frame ready-mode."; |
} |
} |
- } 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; |
+ } 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; |
+ } |
} |
// 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 && cf_state && !cf_state->is_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."; |
+ "multi-install."; |
*status = installer::NON_MULTI_INSTALLATION_EXISTS; |
installer_state->WriteInstallerResult(*status, |
IDS_INSTALL_NON_MULTI_INSTALLATION_EXISTS_BASE, NULL); |
return false; |
} |
- } else { |
- // This is a non-multi installation. |
- |
+ } 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()); |
- 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; |
-} |
- |
// 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. |
@@ -511,12 +446,10 @@ |
bool CheckPreInstallConditions(const InstallationState& original_state, |
InstallerState* installer_state, |
installer::InstallStatus* status) { |
- if (!CheckAppHostPreconditions(original_state, installer_state)) |
- 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 (!CheckMultiInstallConditions(original_state, installer_state, status)) |
- return false; |
- |
const Products& products = installer_state->products(); |
if (products.empty()) { |
// We haven't been given any products on which to operate. |
@@ -528,47 +461,57 @@ |
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 (!CheckMultiInstallConditions(original_state, installer_state, status)) |
+ return false; |
- 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()); |
+ bool is_first_install = true; |
+ const bool system_level = installer_state->system_install(); |
- // Allow upgrades to proceed so that out-of-date versions are not left |
- // around. |
- if (user_level_product_state) |
- continue; |
+ for (size_t i = 0; i < products.size(); ++i) { |
+ const Product* product = products[i]; |
+ BrowserDistribution* browser_dist = product->distribution(); |
- // This is a new user-level install... |
+ // 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; |
+ } |
+ } |
- if (system_level_product_state) { |
- // ... and the product already exists at system-level. |
+ // 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. |
LOG(ERROR) << "Already installed version " |
- << system_level_product_state->version().GetString() |
+ << other_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 install_path(installer::GetChromeInstallPath(true, // system |
- browser_dist)); |
- if (install_path.empty()) { |
- // Give up if we failed to construct the install path. |
+ 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; |
installer_state->WriteInstallerResult(*status, |
- IDS_INSTALL_OS_ERROR_BASE, |
- NULL); |
+ IDS_INSTALL_OS_ERROR_BASE, NULL); |
} else { |
*status = installer::EXISTING_VERSION_LAUNCHED; |
- FilePath chrome_exe = install_path.Append(installer::kChromeExe); |
+ chrome_exe = chrome_exe.Append(installer::kChromeExe); |
CommandLine cmd(chrome_exe); |
cmd.AppendSwitch(switches::kFirstRun); |
installer_state->WriteInstallerResult(*status, 0, NULL); |
@@ -576,16 +519,34 @@ |
base::LaunchProcess(cmd, base::LaunchOptions(), NULL); |
} |
} else { |
- // Display an error message for other products. |
+ // Display an error message for Chrome Frame. |
*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; |
+ } |
+ } |
+ |
return true; |
} |
@@ -609,7 +570,7 @@ |
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, |
@@ -625,48 +586,13 @@ |
VLOG(1) << "created path " << temp_path.path().value(); |
FilePath unpack_path(temp_path.path().Append(installer::kInstallSourceDir)); |
- |
- 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); |
- } |
+ 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 { |
- 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> |
@@ -698,28 +624,22 @@ |
} |
if (higher_products != 0) { |
- COMPILE_ASSERT(BrowserDistribution::NUM_TYPES == 4, |
+ COMPILE_ASSERT(BrowserDistribution::NUM_TYPES == 3, |
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; |
- switch (higher_products) { |
- case kBrowserBit: |
- message_id = IDS_INSTALL_HIGHER_VERSION_BASE; |
- break; |
- case kGCFBit: |
- message_id = IDS_INSTALL_HIGHER_VERSION_CF_BASE; |
- break; |
- case kGCFBit | kBrowserBit: |
+ if ((higher_products & kBrowserBit) != 0) { |
+ if ((higher_products & kGCFBit) != 0) |
message_id = IDS_INSTALL_HIGHER_VERSION_CB_CF_BASE; |
- break; |
- default: |
- message_id = IDS_INSTALL_HIGHER_VERSION_APP_HOST_BASE; |
- break; |
+ else |
+ message_id = IDS_INSTALL_HIGHER_VERSION_BASE; |
+ } else { |
+ DCHECK(higher_products == kGCFBit); |
+ message_id = IDS_INSTALL_HIGHER_VERSION_CF_BASE; |
} |
installer_state.WriteInstallerResult(install_status, message_id, NULL); |
@@ -731,6 +651,10 @@ |
*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, |
@@ -955,20 +879,11 @@ |
const InstallerState& installer_state, |
const CommandLine& cmd_line) { |
const Products& products = installer_state.products(); |
- |
- 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()); |
- } |
- |
+ // 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()); |
installer::InstallStatus install_status = installer::UNINSTALL_SUCCESSFUL; |
installer::InstallStatus prod_status = installer::UNKNOWN_STATUS; |
const bool force = cmd_line.HasSwitch(installer::switches::kForceUninstall); |