diff options
author | erikwright@chromium.org <erikwright@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-07-20 17:08:54 +0000 |
---|---|---|
committer | erikwright@chromium.org <erikwright@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-07-20 17:08:54 +0000 |
commit | a1cbc96e8f0bbdbefa209367c5633c7ad0f3e111 (patch) | |
tree | 2ab182fc502bde4990f42e9a913c434007d52c67 /chrome/installer/setup | |
parent | 912f06843fb90f6b50a9b6e270253d67f9be1d88 (diff) | |
download | chromium_src-a1cbc96e8f0bbdbefa209367c5633c7ad0f3e111.zip chromium_src-a1cbc96e8f0bbdbefa209367c5633c7ad0f3e111.tar.gz chromium_src-a1cbc96e8f0bbdbefa209367c5633c7ad0f3e111.tar.bz2 |
Revert 147650 - Implement installation of the Chrome App Host.
The Chrome App Host is a simple exe that delegates to a Chrome Binaries installation at user or system level. If no installation is available, it will trigger an installation.
The Chrome App Host prevents the Chrome Binaries from being uninstalled, except in the case of an upgrade to system-level.
The Chrome App Host is implemented in this uncommitted CL: http://codereview.chromium.org/10559090/ .
BUG=None
TEST=None
Review URL: https://chromiumcodereview.appspot.com/10665002
TBR=erikwright@chromium.org
Review URL: https://chromiumcodereview.appspot.com/10797047
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@147668 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/installer/setup')
-rw-r--r-- | chrome/installer/setup/chrome_frame_quick_enable.cc | 13 | ||||
-rw-r--r-- | chrome/installer/setup/install.cc | 2 | ||||
-rw-r--r-- | chrome/installer/setup/install_worker.cc | 374 | ||||
-rw-r--r-- | chrome/installer/setup/install_worker.h | 25 | ||||
-rw-r--r-- | chrome/installer/setup/setup_main.cc | 337 | ||||
-rw-r--r-- | chrome/installer/setup/uninstall.cc | 289 |
6 files changed, 391 insertions, 649 deletions
diff --git a/chrome/installer/setup/chrome_frame_quick_enable.cc b/chrome/installer/setup/chrome_frame_quick_enable.cc index f78038e..a2202ab 100644 --- a/chrome/installer/setup/chrome_frame_quick_enable.cc +++ b/chrome/installer/setup/chrome_frame_quick_enable.cc @@ -100,6 +100,8 @@ InstallStatus ChromeFrameQuickEnable(const InstallationState& machine_state, FilePath setup_path(chrome_state->GetSetupPath()); const Version& new_version = chrome_state->version(); + FilePath new_chrome_exe( + installer_state->target_path().Append(installer::kChromeNewExe)); // This creates the uninstallation entry for GCF. AddUninstallShortcutWorkItems(*installer_state, setup_path, new_version, @@ -112,7 +114,7 @@ InstallStatus ChromeFrameQuickEnable(const InstallationState& machine_state, new_version, *cf, item_list.get()); const Version* opv = chrome_state->old_version(); - AppendPostInstallTasks(*installer_state, setup_path, opv, + AppendPostInstallTasks(*installer_state, setup_path, new_chrome_exe, opv, new_version, temp_path.path(), item_list.get()); // Before updating the channel values, add Chrome back to the mix so that @@ -123,11 +125,10 @@ InstallStatus ChromeFrameQuickEnable(const InstallationState& machine_state, item_list.get()); // Add the items to remove the quick-enable-cf command from the registry. - AddQuickEnableChromeFrameWorkItems( - *installer_state, machine_state, - &chrome_state->uninstall_command().GetProgram(), - &chrome_state->version(), - item_list.get()); + AddQuickEnableWorkItems(*installer_state, machine_state, + &chrome_state->uninstall_command().GetProgram(), + &chrome_state->version(), + item_list.get()); if (!item_list->Do()) { item_list->Rollback(); diff --git a/chrome/installer/setup/install.cc b/chrome/installer/setup/install.cc index a3bb52f..5895090 100644 --- a/chrome/installer/setup/install.cc +++ b/chrome/installer/setup/install.cc @@ -427,8 +427,6 @@ InstallStatus InstallOrUpdateProduct( // TODO(robertshield): Removing the pending on-reboot moves should be done // elsewhere. - // TODO(erikwright): Understand why this is Chrome Frame only and whether - // it also applies to App Host. Shouldn't it apply to any multi-install too? const Products& products = installer_state.products(); DCHECK(products.size()); if (installer_state.FindProduct(BrowserDistribution::CHROME_FRAME)) { diff --git a/chrome/installer/setup/install_worker.cc b/chrome/installer/setup/install_worker.cc index e3c1fe3..f314fa0 100644 --- a/chrome/installer/setup/install_worker.cc +++ b/chrome/installer/setup/install_worker.cc @@ -25,7 +25,6 @@ #include "base/win/registry.h" #include "base/win/windows_version.h" #include "chrome/common/chrome_constants.h" -#include "chrome/common/chrome_switches.h" #include "chrome/installer/setup/install.h" #include "chrome/installer/setup/setup_constants.h" #include "chrome/installer/setup/setup_util.h" @@ -104,21 +103,16 @@ void AddInstallerCopyTasks(const InstallerState& installer_state, FilePath exe_dst(installer_dir.Append(setup_path.BaseName())); FilePath archive_dst(installer_dir.Append(archive_path.BaseName())); - if (exe_dst != setup_path) { - install_list->AddCopyTreeWorkItem(setup_path.value(), exe_dst.value(), - temp_path.value(), WorkItem::ALWAYS); - } + install_list->AddCopyTreeWorkItem(setup_path.value(), exe_dst.value(), + temp_path.value(), WorkItem::ALWAYS); - if (archive_path != archive_dst) { - // In the past, we copied rather than moved for system level installs so - // that the permissions of %ProgramFiles% would be picked up. Now that - // |temp_path| is in %ProgramFiles% for system level installs (and in - // %LOCALAPPDATA% otherwise), there is no need to do this for the archive. - // Setup.exe, on the other hand, is created elsewhere so it must always be - // copied. - install_list->AddMoveTreeWorkItem(archive_path.value(), archive_dst.value(), - temp_path.value(), WorkItem::ALWAYS_MOVE); - } + // In the past, we copied rather than moved for system level installs so that + // the permissions of %ProgramFiles% would be picked up. Now that |temp_path| + // is in %ProgramFiles% for system level installs (and in %LOCALAPPDATA% + // otherwise), there is no need to do this for the archive. Setup.exe, on + // the other hand, is created elsewhere so it must always be copied. + install_list->AddMoveTreeWorkItem(archive_path.value(), archive_dst.value(), + temp_path.value(), WorkItem::ALWAYS_MOVE); } // This method adds work items to create (or update) Chrome uninstall entry in @@ -149,16 +143,19 @@ void AddUninstallShortcutWorkItems(const InstallerState& installer_state, AppendUninstallCommandLineFlags(installer_state, product, &uninstall_arguments); - // If Chrome Frame is installed in Ready Mode, add --chrome-frame to Chrome's - // uninstall entry. We skip this processing in case of uninstall since this - // means that Chrome Frame is being uninstalled, so there's no need to do any - // looping. + // The Chrome uninstallation command serves as the master uninstall command + // for Chrome + all other products (i.e. Chrome Frame) that do not have an + // uninstall entry in the Add/Remove Programs dialog. We skip this processing + // in case of uninstall since this means that Chrome Frame is being + // uninstalled, so there's no need to do any looping. if (product.is_chrome() && installer_state.operation() != InstallerState::UNINSTALL) { - const Product* chrome_frame = - installer_state.FindProduct(BrowserDistribution::CHROME_FRAME); - if (chrome_frame && chrome_frame->HasOption(kOptionReadyMode)) - chrome_frame->AppendProductFlags(&uninstall_arguments); + const Products& products = installer_state.products(); + for (size_t i = 0; i < products.size(); ++i) { + const Product& p = *products[i]; + if (!p.is_chrome() && !p.ShouldCreateUninstallEntry()) + p.AppendProductFlags(&uninstall_arguments); + } } std::wstring update_state_key(browser_dist->GetStateKey()); @@ -231,6 +228,28 @@ void AddUninstallShortcutWorkItems(const InstallerState& installer_state, } } +// Add uninstall-related work items for multi-install scenarios. +void AddMultiUninstallWorkItems(const InstallerState& installer_state, + const FilePath& setup_path, + const Version& new_version, + WorkItemList* install_list) { + DCHECK(installer_state.is_multi_install()); + + // The mini_installer needs a reliable way to locate setup.exe for diff + // updates. For single-installs, the product's ClientState key is consulted + // (Chrome's or Chrome Frame's). For multi-installs, the binaries' key is + // used. + const HKEY reg_root = installer_state.root_key(); + std::wstring binaries_state_key( + installer_state.multi_package_binaries_distribution()->GetStateKey()); + FilePath installer_path( + installer_state.GetInstallerDirectory(new_version) + .Append(setup_path.BaseName())); + install_list->AddCreateRegKeyWorkItem(reg_root, binaries_state_key); + install_list->AddSetRegValueWorkItem(reg_root, binaries_state_key, + installer::kUninstallStringField, installer_path.value(), true); +} + // Create Version key for a product (if not already present) and sets the new // product version as the last step. void AddVersionKeyWorkItems(HKEY root, @@ -267,32 +286,6 @@ void AddVersionKeyWorkItems(HKEY root, true); // overwrite version } -void AddInstallAppCommandWorkItems(const InstallerState& installer_state, - const InstallationState& machine_state, - const FilePath* setup_path, - const Version* new_version, - const Product& product, - WorkItemList* work_item_list) { - DCHECK(product.is_chrome_app_host()); - - std::wstring cmd_key(product.distribution()->GetVersionKey()); - cmd_key.append(1, L'\\').append(google_update::kRegCommandsKey) - .append(1, L'\\').append(kCmdInstallApp); - - if (installer_state.operation() != InstallerState::UNINSTALL) { - FilePath target_path(installer_state.target_path()); - CommandLine cmd_line(target_path.Append(installer::kChromeAppHostExe)); - cmd_line.AppendSwitchASCII(::switches::kAppsInstallFromManifestURL, "%1"); - - AppCommand cmd(cmd_line.GetCommandLineString(), true, true); - cmd.AddWorkItems(installer_state.root_key(), cmd_key, work_item_list); - } else { - work_item_list->AddDeleteRegKeyWorkItem(installer_state.root_key(), - cmd_key)->set_log_message( - "removing install-application command"); - } -} - void AddProductSpecificWorkItems(const InstallationState& original_state, const InstallerState& installer_state, const FilePath& setup_path, @@ -305,10 +298,6 @@ void AddProductSpecificWorkItems(const InstallationState& original_state, AddChromeFrameWorkItems(original_state, installer_state, setup_path, new_version, p, list); } - if (p.is_chrome_app_host()) { - AddInstallAppCommandWorkItems(installer_state, original_state, - &setup_path, &new_version, p, list); - } } } @@ -577,6 +566,7 @@ void AddDeleteUninstallShortcutsForMSIWorkItems( // false. bool AppendPostInstallTasks(const InstallerState& installer_state, const FilePath& setup_path, + const FilePath& new_chrome_exe, const Version* current_version, const Version& new_version, const FilePath& temp_path, @@ -585,8 +575,6 @@ bool AppendPostInstallTasks(const InstallerState& installer_state, HKEY root = installer_state.root_key(); const Products& products = installer_state.products(); - FilePath new_chrome_exe( - installer_state.target_path().Append(installer::kChromeNewExe)); // Append work items that will only be executed if this was an update. // We update the 'opv' value with the current version that is active, @@ -727,29 +715,32 @@ bool AppendPostInstallTasks(const InstallerState& installer_state, return true; } -void AddChromeWorkItems(const InstallationState& original_state, - const InstallerState& installer_state, - const FilePath& setup_path, - const FilePath& archive_path, - const FilePath& src_path, - const FilePath& temp_path, - const Version& new_version, - scoped_ptr<Version>* current_version, - WorkItemList* install_list) { +void AddInstallWorkItems(const InstallationState& original_state, + const InstallerState& installer_state, + const FilePath& setup_path, + const FilePath& archive_path, + const FilePath& src_path, + const FilePath& temp_path, + const Version& new_version, + scoped_ptr<Version>* current_version, + WorkItemList* install_list) { + DCHECK(install_list); + const FilePath& target_path = installer_state.target_path(); + // A temp directory that work items need and the actual install directory. + install_list->AddCreateDirWorkItem(temp_path); + install_list->AddCreateDirWorkItem(target_path); + if (current_version != NULL && current_version->get() != NULL) { // Delete the archive from an existing install to save some disk space. We // make this an unconditional work item since there's no need to roll this // back; if installation fails we'll be moved to the "-full" channel anyway. FilePath old_installer_dir( installer_state.GetInstallerDirectory(**current_version)); - FilePath old_archive(old_installer_dir.Append(installer::kChromeArchive)); - // Don't delete the archive that we are actually installing from. - if (archive_path != old_archive) { - install_list->AddDeleteTreeWorkItem(old_archive, temp_path) - ->set_ignore_failure(true); - } + FilePath old_archive(old_installer_dir.Append(archive_path.BaseName())); + install_list->AddDeleteTreeWorkItem(old_archive, temp_path) + ->set_ignore_failure(true); } // Delete any new_chrome.exe if present (we will end up creating a new one @@ -852,48 +843,6 @@ void AddChromeWorkItems(const InstallationState& original_state, AddInstallerCopyTasks(installer_state, setup_path, archive_path, temp_path, new_version, install_list); -} - -void AddInstallWorkItems(const InstallationState& original_state, - const InstallerState& installer_state, - const FilePath& setup_path, - const FilePath& archive_path, - const FilePath& src_path, - const FilePath& temp_path, - const Version& new_version, - scoped_ptr<Version>* current_version, - WorkItemList* install_list) { - DCHECK(install_list); - - const FilePath& target_path = installer_state.target_path(); - - // A temp directory that work items need and the actual install directory. - install_list->AddCreateDirWorkItem(temp_path); - install_list->AddCreateDirWorkItem(target_path); - - if (installer_state.FindProduct(BrowserDistribution::CHROME_BROWSER) || - installer_state.FindProduct(BrowserDistribution::CHROME_FRAME) || - installer_state.FindProduct(BrowserDistribution::CHROME_BINARIES)) { - AddChromeWorkItems(original_state, - installer_state, - setup_path, - archive_path, - src_path, - temp_path, - new_version, - current_version, - install_list); - } - - if (installer_state.FindProduct(BrowserDistribution::CHROME_APP_HOST)) { - install_list->AddCopyTreeWorkItem( - src_path.Append(installer::kChromeAppHostExe).value(), - target_path.Append(installer::kChromeAppHostExe).value(), - temp_path.value(), - WorkItem::ALWAYS, - L""); - } - const HKEY root = installer_state.root_key(); // Only set "lang" for user-level installs since for system-level, the install // language may not be related to a given user's runtime language. @@ -916,6 +865,15 @@ void AddInstallWorkItems(const InstallationState& original_state, install_list); } + if (installer_state.is_multi_install()) { + AddMultiUninstallWorkItems(installer_state, setup_path, new_version, + install_list); + + AddVersionKeyWorkItems(root, + installer_state.multi_package_binaries_distribution(), new_version, + add_language_identifier, install_list); + } + // Add any remaining work items that involve special settings for // each product. AddProductSpecificWorkItems(original_state, installer_state, setup_path, @@ -924,16 +882,13 @@ void AddInstallWorkItems(const InstallationState& original_state, // Copy over brand, usagestats, and other values. AddGoogleUpdateWorkItems(original_state, installer_state, install_list); - AddQuickEnableApplicationHostWorkItems(installer_state, original_state, - &setup_path, &new_version, - install_list); - - AddQuickEnableChromeFrameWorkItems(installer_state, original_state, - &setup_path, &new_version, install_list); + AddQuickEnableWorkItems(installer_state, original_state, &setup_path, + &new_version, install_list); // Append the tasks that run after the installation. AppendPostInstallTasks(installer_state, setup_path, + new_chrome_exe, current_version->get(), new_version, temp_path, @@ -1391,14 +1346,11 @@ void RefreshElevationPolicy() { } } -void AddGenericQuickEnableWorkItems(const InstallerState& installer_state, - const InstallationState& machine_state, - const FilePath* setup_path, - const Version* new_version, - WorkItemList* work_item_list, - bool have_child_product, - const CommandLine& child_product_switches, - const std::wstring& command_id) { +void AddQuickEnableWorkItems(const InstallerState& installer_state, + const InstallationState& machine_state, + const FilePath* setup_path, + const Version* new_version, + WorkItemList* work_item_list) { DCHECK(setup_path || installer_state.operation() == InstallerState::UNINSTALL); DCHECK(new_version || @@ -1406,17 +1358,27 @@ void AddGenericQuickEnableWorkItems(const InstallerState& installer_state, DCHECK(work_item_list); const bool system_install = installer_state.system_install(); - bool have_chrome_binaries = false; + bool have_multi_chrome = false; + bool have_chrome_frame = false; // STEP 1: Figure out the state of the machine before the operation. const ProductState* product_state = NULL; - // Are the Chrome Binaries already on the machine? + // Is multi-install Chrome already on the machine? product_state = machine_state.GetProductState(system_install, - BrowserDistribution::CHROME_BINARIES); + BrowserDistribution::CHROME_BROWSER); if (product_state != NULL && product_state->is_multi_install()) - have_chrome_binaries = true; + have_multi_chrome = true; + + // Is Chrome Frame !ready-mode already on the machine? + product_state = + machine_state.GetProductState(system_install, + BrowserDistribution::CHROME_FRAME); + if (product_state != NULL && + !product_state->uninstall_command().HasSwitch( + switches::kChromeFrameReadyMode)) + have_chrome_frame = true; // STEP 2: Now take into account the current operation. const Product* product = NULL; @@ -1424,15 +1386,29 @@ void AddGenericQuickEnableWorkItems(const InstallerState& installer_state, if (installer_state.operation() == InstallerState::UNINSTALL) { // Forget about multi-install Chrome if it is being uninstalled. product = - installer_state.FindProduct(BrowserDistribution::CHROME_BINARIES); + installer_state.FindProduct(BrowserDistribution::CHROME_BROWSER); if (product != NULL && installer_state.is_multi_install()) - have_chrome_binaries = false; + have_multi_chrome = false; + + // Forget about Chrome Frame if it is being uninstalled. Note that we don't + // bother to check !HasOption(kOptionReadyMode) since have_chrome_frame + // should have been false for that case in the first place. It's odd if it + // wasn't, but the right thing to do in that case is to proceed with the + // thought that CF will not be installed in any sense when we reach the + // finish line. + if (installer_state.FindProduct(BrowserDistribution::CHROME_FRAME) != NULL) + have_chrome_frame = false; } else { - // Check if we're installing Chrome Binaries + // Check if we're installing multi-install Chrome. product = - installer_state.FindProduct(BrowserDistribution::CHROME_BINARIES); + installer_state.FindProduct(BrowserDistribution::CHROME_BROWSER); if (product != NULL && installer_state.is_multi_install()) - have_chrome_binaries = true; + have_multi_chrome = true; + + // Check if we're installing Chrome Frame !ready-mode. + product = installer_state.FindProduct(BrowserDistribution::CHROME_FRAME); + if (product != NULL && !product->HasOption(kOptionReadyMode)) + have_chrome_frame = true; } // STEP 3: Decide what to do based on the final state of things. @@ -1443,29 +1419,31 @@ void AddGenericQuickEnableWorkItems(const InstallerState& installer_state, } operation = DO_NOTHING; FilePath binaries_setup_path; - if (have_child_product) { - // Child product is being uninstalled. Unconditionally remove the Quick - // Enable command from the binaries. We do this even if multi-install Chrome - // isn't installed since we don't want them left behind in any case. + if (have_chrome_frame) { + // Chrome Frame !ready-mode is or will be installed. Unconditionally remove + // the quick-enable-cf command from the binaries. We do this even if + // multi-install Chrome isn't installed since we don't want them left + // behind in any case. operation = REMOVE_COMMAND; - } else if (have_chrome_binaries) { - // Child product isn't (to be) installed while multi-install Chrome is (to - // be) installed. Add the Quick Enable command to the binaries. + } else if (have_multi_chrome) { + // Chrome Frame isn't (to be) installed or is (to be) installed only in + // ready-mode, while multi-install Chrome is (to be) installed. Add the + // quick-enable-cf command to the binaries. operation = ADD_COMMAND; // The path to setup.exe contains the version of the Chrome binaries, so it // takes a little work to get it right. if (installer_state.operation() == InstallerState::UNINSTALL) { - // One or more products are being uninstalled, but not the binaries. Use - // the path to the currently installed Chrome setup.exe. + // Chrome Frame is being uninstalled. Use the path to the currently + // installed Chrome setup.exe. product_state = machine_state.GetProductState(system_install, - BrowserDistribution::CHROME_BINARIES); + BrowserDistribution::CHROME_BROWSER); DCHECK(product_state); binaries_setup_path = product_state->uninstall_command().GetProgram(); } else { - // Chrome Binaries are being installed, updated, or otherwise operated on. + // Chrome is being installed, updated, or otherwise being operated on. // Use the path to the given |setup_path| in the normal location of - // multi-install Chrome Binaries of the given |version|. + // multi-install Chrome of the given |version|. DCHECK(installer_state.is_multi_install()); binaries_setup_path = installer_state.GetInstallerDirectory(*new_version).Append( @@ -1481,116 +1459,26 @@ void AddGenericQuickEnableWorkItems(const InstallerState& installer_state, BrowserDistribution::CHROME_BINARIES); std::wstring cmd_key(binaries->GetVersionKey()); cmd_key.append(1, L'\\').append(google_update::kRegCommandsKey) - .append(1, L'\\').append(command_id); + .append(1, L'\\').append(kCmdQuickEnableCf); if (operation == ADD_COMMAND) { DCHECK(!binaries_setup_path.empty()); CommandLine cmd_line(binaries_setup_path); - cmd_line.AppendArguments(child_product_switches, - false); // include_program + cmd_line.AppendSwitch(switches::kMultiInstall); + if (installer_state.system_install()) + cmd_line.AppendSwitch(switches::kSystemLevel); if (installer_state.verbose_logging()) cmd_line.AppendSwitch(switches::kVerboseLogging); + cmd_line.AppendSwitch(switches::kChromeFrameQuickEnable); AppCommand cmd(cmd_line.GetCommandLineString(), true, true); cmd.AddWorkItems(installer_state.root_key(), cmd_key, work_item_list); } else { DCHECK(operation == REMOVE_COMMAND); work_item_list->AddDeleteRegKeyWorkItem(installer_state.root_key(), cmd_key)->set_log_message( - "removing " + WideToASCII(command_id) + " command"); + "removing quick-enable-cf command"); } } } -void AddQuickEnableChromeFrameWorkItems(const InstallerState& installer_state, - const InstallationState& machine_state, - const FilePath* setup_path, - const Version* new_version, - WorkItemList* work_item_list) { - DCHECK(setup_path || - installer_state.operation() == InstallerState::UNINSTALL); - DCHECK(new_version || - installer_state.operation() == InstallerState::UNINSTALL); - DCHECK(work_item_list); - - const bool system_install = installer_state.system_install(); - bool have_chrome_frame = false; - - // STEP 1: Figure out the state of the machine before the operation. - const ProductState* product_state = NULL; - - // Is Chrome Frame !ready-mode already on the machine? - product_state = - machine_state.GetProductState(system_install, - BrowserDistribution::CHROME_FRAME); - if (product_state != NULL && - !product_state->uninstall_command().HasSwitch( - switches::kChromeFrameReadyMode)) - have_chrome_frame = true; - - // STEP 2: Now take into account the current operation. - const Product* product = NULL; - - if (installer_state.operation() == InstallerState::UNINSTALL) { - // Forget about Chrome Frame if it is being uninstalled. Note that we don't - // bother to check !HasOption(kOptionReadyMode) since have_chrome_frame - // should have been false for that case in the first place. It's odd if it - // wasn't, but the right thing to do in that case is to proceed with the - // thought that CF will not be installed in any sense when we reach the - // finish line. - if (installer_state.FindProduct(BrowserDistribution::CHROME_FRAME) != NULL) - have_chrome_frame = false; - } else { - // Check if we're installing Chrome Frame !ready-mode. - product = installer_state.FindProduct(BrowserDistribution::CHROME_FRAME); - if (product != NULL && !product->HasOption(kOptionReadyMode)) - have_chrome_frame = true; - } - - CommandLine cmd_line(CommandLine::NO_PROGRAM); - cmd_line.AppendSwitch(switches::kMultiInstall); - if (installer_state.system_install()) - cmd_line.AppendSwitch(switches::kSystemLevel); - cmd_line.AppendSwitch(switches::kChromeFrameQuickEnable); - - AddGenericQuickEnableWorkItems(installer_state, - machine_state, - setup_path, - new_version, - work_item_list, - have_chrome_frame, - cmd_line, - kCmdQuickEnableCf); -} - -void AddQuickEnableApplicationHostWorkItems( - const InstallerState& installer_state, - const InstallationState& machine_state, - const FilePath* setup_path, - const Version* new_version, - WorkItemList* work_item_list) { - DCHECK(setup_path || - installer_state.operation() == InstallerState::UNINSTALL); - DCHECK(new_version || - installer_state.operation() == InstallerState::UNINSTALL); - DCHECK(work_item_list); - - CommandLine cmd_line(CommandLine::NO_PROGRAM); - cmd_line.AppendSwitch(switches::kMultiInstall); - cmd_line.AppendSwitch(switches::kChromeAppHost); - - // For system-level binaries there is no way to keep the command state in sync - // with the installation/uninstallation of the Application Host (which is - // always at user-level). - // So we pass false for 'have_child_product' to cause this command to always - // be installed if the Chrome Binaries are installed. - AddGenericQuickEnableWorkItems(installer_state, - machine_state, - setup_path, - new_version, - work_item_list, - false, // have_child_product - cmd_line, - kCmdQuickEnableApplicationHost); -} - } // namespace installer diff --git a/chrome/installer/setup/install_worker.h b/chrome/installer/setup/install_worker.h index c112f8c..3a32d72 100644 --- a/chrome/installer/setup/install_worker.h +++ b/chrome/installer/setup/install_worker.h @@ -63,6 +63,7 @@ void AddUsageStatsWorkItems(const InstallationState& original_state, // false. bool AppendPostInstallTasks(const InstallerState& installer_state, const FilePath& setup_path, + const FilePath& new_chrome_exe, const Version* current_version, const Version& new_version, const FilePath& temp_path, @@ -181,25 +182,11 @@ void RefreshElevationPolicy(); // run) and |new_version| (the version of the product(s) currently being // installed) are required when processing product installation; they are unused // (and may therefore be NULL) when uninstalling. -void AddQuickEnableChromeFrameWorkItems(const InstallerState& installer_state, - const InstallationState& machine_state, - const FilePath* setup_path, - const Version* new_version, - WorkItemList* work_item_list); - -// Add work items to add or remove the "quick-enable-application-host" command -// to the multi-installer binaries' version key on the basis of the current -// operation (represented in |installer_state|) and the pre-existing machine -// configuration (represented in |machine_state|). |setup_path| (the path to -// the executable currently being run) and |new_version| (the version of the -// product(s) currently being installed) are required when processing product -// installation; they are unused (and may therefore be NULL) when uninstalling. -void AddQuickEnableApplicationHostWorkItems( - const InstallerState& installer_state, - const InstallationState& machine_state, - const FilePath* setup_path, - const Version* new_version, - WorkItemList* work_item_list); +void AddQuickEnableWorkItems(const InstallerState& installer_state, + const InstallationState& machine_state, + const FilePath* setup_path, + const Version* new_version, + WorkItemList* work_item_list); } // namespace installer diff --git a/chrome/installer/setup/setup_main.cc b/chrome/installer/setup/setup_main.cc index eb59d17..9d9ff5a 100644 --- a/chrome/installer/setup/setup_main.cc +++ b/chrome/installer/setup/setup_main.cc @@ -148,10 +148,8 @@ 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::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 @@ bool CheckGroupPolicySettings(const InstallationState& original_state, #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 @@ 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); - 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,83 +384,51 @@ bool CheckMultiInstallConditions(const InstallationState& original_state, 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; @@ -511,11 +446,9 @@ bool CheckAppHostPreconditions(const InstallationState& original_state, bool CheckPreInstallConditions(const InstallationState& original_state, InstallerState* installer_state, installer::InstallStatus* status) { - if (!CheckAppHostPreconditions(original_state, installer_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); const Products& products = installer_state->products(); if (products.empty()) { @@ -528,47 +461,57 @@ bool CheckPreInstallConditions(const InstallationState& original_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; - 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,13 +519,31 @@ bool CheckPreInstallConditions(const InstallationState& original_state, 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; } } @@ -609,7 +570,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, @@ -625,48 +586,13 @@ installer::InstallStatus InstallProductsHelper( 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 @@ installer::InstallStatus InstallProductsHelper( } 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::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, @@ -955,20 +879,11 @@ installer::InstallStatus UninstallProducts( 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); diff --git a/chrome/installer/setup/uninstall.cc b/chrome/installer/setup/uninstall.cc index bd4f944..f767409 100644 --- a/chrome/installer/setup/uninstall.cc +++ b/chrome/installer/setup/uninstall.cc @@ -52,23 +52,6 @@ using installer::MasterPreferences; namespace { -// Avoid leaving behind a Temp dir. If one exists, ask SelfCleaningTempDir to -// clean it up for us. This may involve scheduling it for deletion after -// reboot. Don't report that a reboot is required in this case, however. -// TODO(erikwright): Shouldn't this still lead to -// ScheduleParentAndGrandparentForDeletion? -void DeleteInstallTempDir(const FilePath& target_path) { - FilePath temp_path(target_path.DirName().Append(installer::kInstallTempDir)); - if (file_util::DirectoryExists(temp_path)) { - installer::SelfCleaningTempDir temp_dir; - if (!temp_dir.Initialize(target_path.DirName(), - installer::kInstallTempDir) || - !temp_dir.Delete()) { - LOG(ERROR) << "Failed to delete temp dir " << temp_path.value(); - } - } -} - // Makes appropriate changes to the Google Update "ap" value in the registry. // Specifically, removes the flags associated with this product ("-chrome" or // "-chromeframe[-readymode]") from the "ap" values for all other @@ -92,15 +75,17 @@ void ProcessGoogleUpdateItems( // Apply the new channel value to all other products and to the multi package. if (modified) { + BrowserDistribution::Type other_dist_types[] = { + (distribution->GetType() == BrowserDistribution::CHROME_BROWSER) ? + BrowserDistribution::CHROME_FRAME : + BrowserDistribution::CHROME_BROWSER, + BrowserDistribution::CHROME_BINARIES + }; scoped_ptr<WorkItemList> update_list(WorkItem::CreateNoRollbackWorkItemList()); - for (size_t i = 0; i < BrowserDistribution::NUM_TYPES; ++i) { - BrowserDistribution::Type other_dist_type = - static_cast<BrowserDistribution::Type>(i); - if (distribution->GetType() == other_dist_type) - continue; - + for (int i = 0; i < arraysize(other_dist_types); ++i) { + BrowserDistribution::Type other_dist_type = other_dist_types[i]; product_state = original_state.GetProductState(system_level, other_dist_type); // Only modify other products if they're installed and multi. @@ -135,11 +120,8 @@ void ProcessQuickEnableWorkItems( scoped_ptr<WorkItemList> work_item_list( WorkItem::CreateNoRollbackWorkItemList()); - AddQuickEnableChromeFrameWorkItems(installer_state, machine_state, NULL, NULL, - work_item_list.get()); - - AddQuickEnableApplicationHostWorkItems(installer_state, machine_state, NULL, - NULL, work_item_list.get()); + AddQuickEnableWorkItems(installer_state, machine_state, NULL, NULL, + work_item_list.get()); if (!work_item_list->Do()) LOG(ERROR) << "Failed to update quick-enable-cf command."; } @@ -417,80 +399,44 @@ bool MoveSetupOutOfInstallFolder(const InstallerState& installer_state, return ret; } -DeleteResult DeleteAppHostFilesAndFolders(const InstallerState& installer_state, - const Version& installed_version) { +DeleteResult DeleteFilesAndFolders(const InstallerState& installer_state, + const Version& installed_version) { const FilePath& target_path = installer_state.target_path(); if (target_path.empty()) { - LOG(ERROR) << "DeleteAppHostFilesAndFolders: no installation destination " - << "path."; + LOG(ERROR) << "DeleteFilesAndFolders: no installation destination path."; return DELETE_FAILED; // Nothing else we can do to uninstall, so we return. } - DeleteInstallTempDir(target_path); - DeleteResult result = DELETE_SUCCEEDED; - FilePath app_host_exe(target_path.Append(installer::kChromeAppHostExe)); - if (!file_util::Delete(app_host_exe, false)) { - result = DELETE_FAILED; - LOG(ERROR) << "Failed to delete path: " << app_host_exe.value(); - } else { - DeleteEmptyParentDir(target_path); - } - - return result; -} - -DeleteResult DeleteChromeFilesAndFolders(const InstallerState& installer_state, - const Version& installed_version) { - const FilePath& target_path = installer_state.target_path(); - if (target_path.empty()) { - LOG(ERROR) << "DeleteChromeFilesAndFolders: no installation destination " - << "path."; - return DELETE_FAILED; // Nothing else we can do to uninstall, so we return. + // Avoid leaving behind a Temp dir. If one exists, ask SelfCleaningTempDir to + // clean it up for us. This may involve scheduling it for deletion after + // reboot. Don't report that a reboot is required in this case, however. + FilePath temp_path(target_path.DirName().Append(kInstallTempDir)); + if (file_util::DirectoryExists(temp_path)) { + installer::SelfCleaningTempDir temp_dir; + if (!temp_dir.Initialize(target_path.DirName(), kInstallTempDir) || + !temp_dir.Delete()) { + LOG(ERROR) << "Failed to delete temp dir " << temp_path.value(); + } } - DeleteInstallTempDir(target_path); - - DeleteResult result = DELETE_SUCCEEDED; - - using file_util::FileEnumerator; - FileEnumerator file_enumerator( - target_path, - false, - static_cast<FileEnumerator::FileType>(FileEnumerator::FILES | - FileEnumerator::DIRECTORIES)); - while (true) { - FilePath to_delete(file_enumerator.Next()); - if (to_delete.empty()) - break; - if (to_delete.BaseName().value() == installer::kChromeAppHostExe) - continue; - - VLOG(1) << "Deleting install path " << target_path.value(); - if (!file_util::Delete(to_delete, true)) { - LOG(ERROR) << "Failed to delete path (1st try): " << to_delete.value(); - if (installer_state.FindProduct(BrowserDistribution::CHROME_FRAME)) { - // We don't try killing Chrome processes for Chrome Frame builds since - // that is unlikely to help. Instead, schedule files for deletion and - // return a value that will trigger a reboot prompt. - FileEnumerator::FindInfo find_info; - file_enumerator.GetFindInfo(&find_info); - if (FileEnumerator::IsDirectory(find_info)) - ScheduleDirectoryForDeletion(to_delete.value().c_str()); - else - ScheduleFileSystemEntityForDeletion(to_delete.value().c_str()); - result = DELETE_REQUIRES_REBOOT; - } else { - // Try closing any running Chrome processes and deleting files once - // again. - CloseAllChromeProcesses(); - if (!file_util::Delete(to_delete, true)) { - LOG(ERROR) << "Failed to delete path (2nd try): " - << to_delete.value(); - result = DELETE_FAILED; - break; - } + VLOG(1) << "Deleting install path " << target_path.value(); + if (!file_util::Delete(target_path, true)) { + LOG(ERROR) << "Failed to delete folder (1st try): " << target_path.value(); + if (installer_state.FindProduct(BrowserDistribution::CHROME_FRAME)) { + // We don't try killing Chrome processes for Chrome Frame builds since + // that is unlikely to help. Instead, schedule files for deletion and + // return a value that will trigger a reboot prompt. + ScheduleDirectoryForDeletion(target_path.value().c_str()); + result = DELETE_REQUIRES_REBOOT; + } else { + // Try closing any running chrome processes and deleting files once again. + CloseAllChromeProcesses(); + if (!file_util::Delete(target_path, true)) { + LOG(ERROR) << "Failed to delete folder (2nd try): " + << target_path.value(); + result = DELETE_FAILED; } } } @@ -554,7 +500,7 @@ bool ShouldDeleteProfile(const InstallerState& installer_state, // UI to prompt otherwise and the profile stores no useful data anyway) // unless they are managed by MSI. MSI uninstalls will explicitly include // the --delete-profile flag to distinguish them from MSI upgrades. - if (product.is_chrome_frame() && !installer_state.is_msi()) { + if (!product.is_chrome() && !installer_state.is_msi()) { should_delete = true; } else { should_delete = @@ -943,11 +889,11 @@ InstallStatus UninstallProduct(const InstallationState& original_state, auto_launch_util::DisableAllAutoStartFeatures( ASCIIToUTF16(chrome::kInitialProfile)); - - // First delete shortcuts from Start->Programs, Desktop & Quick Launch. - DeleteChromeShortcuts(installer_state, product); } + // First delete shortcuts from Start->Programs, Desktop & Quick Launch. + DeleteChromeShortcuts(installer_state, product); + // Delete the registry keys (Uninstall key and Version key). HKEY reg_root = installer_state.root_key(); @@ -955,13 +901,8 @@ InstallStatus UninstallProduct(const InstallationState& original_state, // product.GetVersionKey(). string16 distribution_data(browser_dist->GetDistributionData(reg_root)); - // Remove Control Panel uninstall link. - if (product.ShouldCreateUninstallEntry()) { - InstallUtil::DeleteRegistryKey(reg_root, - browser_dist->GetUninstallRegPath()); - } - - // Remove Omaha product key. + // Remove Control Panel uninstall link and Omaha product key. + InstallUtil::DeleteRegistryKey(reg_root, browser_dist->GetUninstallRegPath()); InstallUtil::DeleteRegistryKey(reg_root, browser_dist->GetVersionKey()); // Also try to delete the MSI value in the ClientState key (it might not be @@ -970,67 +911,63 @@ InstallStatus UninstallProduct(const InstallationState& original_state, // being picked up on reinstall. product.SetMsiMarker(installer_state.system_install(), false); + // Remove all Chrome registration keys. + // Registration data is put in HKCU for both system level and user level + // installs. InstallStatus ret = installer::UNKNOWN_STATUS; - - if (is_chrome) { - // Remove all Chrome registration keys. - // Registration data is put in HKCU for both system level and user level - // installs. - DeleteChromeRegistrationKeys(browser_dist, HKEY_CURRENT_USER, suffix, + DeleteChromeRegistrationKeys(browser_dist, HKEY_CURRENT_USER, suffix, + installer_state.target_path(), &ret); + + // If the user's Chrome is registered with a suffix: it is possible that old + // unsuffixed registrations were left in HKCU (e.g. if this install was + // previously installed with no suffix in HKCU (old suffix rules if the user + // is not an admin (or declined UAC at first run)) and later had to be + // suffixed when fully registered in HKLM (e.g. when later making Chrome + // default through the UI)). + // Remove remaining HKCU entries with no suffix if any. + if (!suffix.empty()) { + DeleteChromeRegistrationKeys(browser_dist, HKEY_CURRENT_USER, string16(), installer_state.target_path(), &ret); - // If the user's Chrome is registered with a suffix: it is possible that old - // unsuffixed registrations were left in HKCU (e.g. if this install was - // previously installed with no suffix in HKCU (old suffix rules if the user - // is not an admin (or declined UAC at first run)) and later had to be - // suffixed when fully registered in HKLM (e.g. when later making Chrome - // default through the UI)). - // Remove remaining HKCU entries with no suffix if any. - if (!suffix.empty()) { - DeleteChromeRegistrationKeys(browser_dist, HKEY_CURRENT_USER, string16(), - installer_state.target_path(), &ret); - - // For similar reasons it is possible in very few installs (from - // 21.0.1180.0 and fixed shortly after) to be installed with the new-style - // suffix, but have some old-style suffix registrations left behind. - string16 old_style_suffix; - if (ShellUtil::GetOldUserSpecificRegistrySuffix(&old_style_suffix) && - suffix != old_style_suffix) { - DeleteChromeRegistrationKeys(browser_dist, HKEY_CURRENT_USER, - old_style_suffix, - installer_state.target_path(), &ret); - } - } - - // Chrome is registered in HKLM for all system-level installs and for - // user-level installs for which Chrome has been made the default browser. - // Always remove the HKLM registration for system-level installs. For - // user-level installs, only remove it if both: 1) this uninstall isn't a - // self destruct following the installation of a system-level Chrome - // (because the system-level Chrome owns the HKLM registration now), and 2) - // this user has made Chrome their default browser (i.e. has shell - // integration entries registered with |suffix| (note: |suffix| will be the - // empty string if required as it is obtained by - // GetCurrentInstallationSuffix() above)). - // TODO(gab): This can still leave parts of a suffixed install behind. To be - // able to remove them we would need to be able to remove only suffixed - // entries (as it is now some of the shell integration entries are - // unsuffixed; thus removing suffixed installs is prohibited in HKLM if - // !|remove_all| for now). - if (installer_state.system_install() || - (remove_all && - ShellUtil::QuickIsChromeRegisteredInHKLM( - browser_dist, chrome_exe, suffix))) { - DeleteChromeRegistrationKeys(browser_dist, HKEY_LOCAL_MACHINE, suffix, + // For similar reasons it is possible in very few installs (from 21.0.1180.0 + // and fixed shortly after) to be installed with the new-style suffix, but + // have some old-style suffix registrations left behind. + string16 old_style_suffix; + if (ShellUtil::GetOldUserSpecificRegistrySuffix(&old_style_suffix) && + suffix != old_style_suffix) { + DeleteChromeRegistrationKeys(browser_dist, HKEY_CURRENT_USER, + old_style_suffix, installer_state.target_path(), &ret); } + } - ProcessDelegateExecuteWorkItems(installer_state, product); + // Chrome is registered in HKLM for all system-level installs and for + // user-level installs for which Chrome has been made the default browser. + // Always remove the HKLM registration for system-level installs. For + // user-level installs, only remove it if both: 1) this uninstall isn't a self + // destruct following the installation of a system-level Chrome (because the + // system-level Chrome owns the HKLM registration now), and 2) this user has + // made Chrome their default browser (i.e. has shell integration entries + // registered with |suffix| (note: |suffix| will be the empty string if + // required as it is obtained by GetCurrentInstallationSuffix() above)). + // TODO(gab): This can still leave parts of a suffixed install behind. To be + // able to remove them we would need to be able to remove only suffixed + // entries (as it is now some of the shell integration entries are unsuffixed; + // thus removing suffixed installs is prohibited in HKLM if !|remove_all| for + // now). + if (installer_state.system_install() || + (remove_all && + ShellUtil::QuickIsChromeRegisteredInHKLM( + browser_dist, chrome_exe, suffix))) { + DeleteChromeRegistrationKeys(browser_dist, HKEY_LOCAL_MACHINE, suffix, + installer_state.target_path(), &ret); UninstallActiveSetupEntries(installer_state, product); } - if (product.is_chrome_frame()) { + ProcessDelegateExecuteWorkItems(installer_state, product); + + if (!is_chrome) { ProcessChromeFrameWorkItems(original_state, installer_state, setup_path, product); } @@ -1078,7 +1015,7 @@ InstallStatus UninstallProduct(const InstallationState& original_state, unreg_work_item_list->Do(); } - if (product.is_chrome_frame()) + if (!is_chrome) ProcessIELowRightsPolicyWorkItems(installer_state); } @@ -1098,25 +1035,41 @@ InstallStatus UninstallProduct(const InstallationState& original_state, ret = installer::UNINSTALL_SUCCESSFUL; // When deleting files, we must make sure that we're either a "single" - // (aka non-multi) installation or we are the Chrome Binaries. + // (aka non-multi) installation or, in the case of multi, that no other + // "multi" products share the binaries we are about to delete. + + bool can_delete_files = true; + if (installer_state.is_multi_install()) { + ProductState prod_state; + for (size_t i = 0; i < BrowserDistribution::kNumProductTypes; ++i) { + if (prod_state.Initialize(installer_state.system_install(), + BrowserDistribution::kProductTypes[i]) && + prod_state.is_multi_install()) { + can_delete_files = false; + break; + } + } + LOG(INFO) << (can_delete_files ? "Shared binaries will be deleted." : + "Shared binaries still in use."); + if (can_delete_files) { + BrowserDistribution* multi_dist = + installer_state.multi_package_binaries_distribution(); + InstallUtil::DeleteRegistryKey(reg_root, multi_dist->GetVersionKey()); + } + } - FilePath backup_state_file( - BackupLocalStateFile(GetLocalStateFolder(product))); + FilePath backup_state_file(BackupLocalStateFile( + GetLocalStateFolder(product))); DeleteResult delete_result = DELETE_SUCCEEDED; - - if (product.is_chrome_app_host()) { - DeleteAppHostFilesAndFolders(installer_state, product_state->version()); - } else if (!installer_state.is_multi_install() || - product.is_chrome_binaries()) { - + if (can_delete_files) { // In order to be able to remove the folder in which we're running, we // need to move setup.exe out of the install folder. // TODO(tommi): What if the temp folder is on a different volume? MoveSetupOutOfInstallFolder(installer_state, setup_path, product_state->version()); - delete_result = DeleteChromeFilesAndFolders(installer_state, - product_state->version()); + delete_result = DeleteFilesAndFolders(installer_state, + product_state->version()); } if (delete_profile) @@ -1129,7 +1082,7 @@ InstallStatus UninstallProduct(const InstallationState& original_state, } if (!force_uninstall) { - VLOG(1) << "Uninstallation complete. Launching post-uninstall operations."; + VLOG(1) << "Uninstallation complete. Launching Uninstall survey."; browser_dist->DoPostUninstallOperations(product_state->version(), backup_state_file, distribution_data); } |