diff options
49 files changed, 1788 insertions, 552 deletions
diff --git a/chrome/app/chromium_strings.grd b/chrome/app/chromium_strings.grd index da5ccf8..0d815a6 100644 --- a/chrome/app/chromium_strings.grd +++ b/chrome/app/chromium_strings.grd @@ -223,6 +223,12 @@ be available for now. --> <message name="IDS_PRODUCT_FRAME_NAME" desc="The Chrome Frame application name"> Chromium Frame </message> + <message name="IDS_PRODUCT_APP_HOST_NAME" desc="The Chrome App Host application name"> + Chromium App Host + </message> + <message name="IDS_PRODUCT_BINARIES_NAME" desc="The Chrome Binaries application name"> + Chromium Binaries + </message> <message name="IDS_VERSIONMISMATCH_HEADER"> Chromium Frame Update. </message> @@ -446,6 +452,9 @@ Chromium is unable to recover your settings. <message name="IDS_INSTALL_HIGHER_VERSION" desc="Error displayed when higher version already exists."> This computer already has a more recent version of Chromium. If the software is not working, please uninstall Chromium and try again. </message> + <message name="IDS_INSTALL_HIGHER_VERSION_APP_HOST" desc="Error displayed when higher version of the Chromium App Host already exists."> + This computer already has a more recent version of the Chromium components. Please use a more recent installer. + </message> <message name="IDS_INSTALL_HIGHER_VERSION_CF" desc="Error displayed when higher version already exists."> This computer already has a more recent version of Chromium Frame. If the software is not working, please uninstall Chromium Frame and try again. </message> diff --git a/chrome/app/google_chrome_strings.grd b/chrome/app/google_chrome_strings.grd index 92f0585..3b8f7ab 100644 --- a/chrome/app/google_chrome_strings.grd +++ b/chrome/app/google_chrome_strings.grd @@ -146,6 +146,12 @@ Chrome supports. --> <message name="IDS_PRODUCT_FRAME_NAME" desc="The Chrome Frame application name"> Google Chrome Frame </message> + <message name="IDS_PRODUCT_APP_HOST_NAME" desc="The Chrome App Host application name"> + Google Chrome App Host + </message> + <message name="IDS_PRODUCT_BINARIES_NAME" desc="The Chrome Binaries application name"> + Google Chrome Binaries + </message> <message name="IDS_VERSIONMISMATCH_HEADER"> Chrome Frame Update. </message> @@ -369,6 +375,9 @@ Google Chrome is unable to recover your settings. <message name="IDS_INSTALL_HIGHER_VERSION" desc="Error displayed when higher version already exists."> This computer already has a more recent version of Google Chrome. If the software is not working, please uninstall Google Chrome and try again. </message> + <message name="IDS_INSTALL_HIGHER_VERSION_APP_HOST" desc="Error displayed when higher version of the Chrome App Host already exists."> + This computer already has a more recent version of the Google Chrome components. Please use a more recent installer. + </message> <message name="IDS_INSTALL_HIGHER_VERSION_CF" desc="Error displayed when higher version of Chrome Frame already exists"> This computer already has a more recent version of Google Chrome Frame. If the software is not working, please uninstall Google Chrome Frame and try again. </message> diff --git a/chrome/chrome_installer.gypi b/chrome/chrome_installer.gypi index 8d32b84..b21fd76 100644 --- a/chrome/chrome_installer.gypi +++ b/chrome/chrome_installer.gypi @@ -88,7 +88,6 @@ 'sources': [ 'installer/setup/compat_checks_unittest.cc', 'installer/setup/setup_constants.cc', - 'installer/util/browser_distribution_unittest.cc', 'installer/util/channel_info_unittest.cc', 'installer/util/copy_reg_key_work_item_unittest.cc', 'installer/util/copy_tree_work_item_unittest.cc', @@ -262,6 +261,7 @@ 'installer_util_strings', '../base/base.gyp:base', '../build/temp_gyp/googleurl.gyp:googleurl', + '../chrome/chrome.gyp:common_constants', '../chrome_frame/chrome_frame.gyp:chrome_tab_idl', '../chrome_frame/chrome_frame.gyp:npchrome_frame', '../breakpad/breakpad.gyp:breakpad_handler', @@ -980,12 +980,12 @@ ['branding=="Chrome" and buildtype=="Official"', { 'actions': [ { - # copy_keychain_reauthorize.sh explains why this isn't in a - # 'copies' block, but briefly: this is a prebuilt signed - # binary component that relies on a correct signature to - # function properly, and a normal 'copies' block sadly makes - # a trivial modification to the file such that its signature - # is no longer valid. + # copy_keychain_reauthorize.sh explains why this isn't in a + # 'copies' block, but briefly: this is a prebuilt signed + # binary component that relies on a correct signature to + # function properly, and a normal 'copies' block sadly makes + # a trivial modification to the file such that its signature + # is no longer valid. 'action_name': 'Copy keychain_reauthorize', 'variables': { 'keychain_reauthorize_path': 'tools/build/mac/copy_keychain_reauthorize.sh', diff --git a/chrome/chrome_installer_util.gypi b/chrome/chrome_installer_util.gypi index c6ea69c..0d75575 100644 --- a/chrome/chrome_installer_util.gypi +++ b/chrome/chrome_installer_util.gypi @@ -1,4 +1,4 @@ -# Copyright (c) 2011 The Chromium Authors. All rights reserved. +# Copyright (c) 2012 The Chromium Authors. All rights reserved. # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. @@ -21,6 +21,8 @@ 'installer/util/browser_distribution.h', 'installer/util/channel_info.cc', 'installer/util/channel_info.h', + 'installer/util/chrome_app_host_distribution.cc', + 'installer/util/chrome_app_host_distribution.h', 'installer/util/chrome_frame_distribution.cc', 'installer/util/chrome_frame_distribution.h', 'installer/util/chromium_binaries_distribution.cc', @@ -114,6 +116,10 @@ '<(DEPTH)/third_party/lzma_sdk/lzma_sdk.gyp:lzma_sdk', ], 'sources': [ + 'installer/util/chrome_app_host_operations.cc', + 'installer/util/chrome_app_host_operations.h', + 'installer/util/chrome_binaries_operations.cc', + 'installer/util/chrome_binaries_operations.h', 'installer/util/chrome_browser_operations.cc', 'installer/util/chrome_browser_operations.h', 'installer/util/chrome_browser_sxs_operations.cc', diff --git a/chrome/common/chrome_switches.cc b/chrome/common/chrome_switches.cc index f7ab364..9e5e06b 100644 --- a/chrome/common/chrome_switches.cc +++ b/chrome/common/chrome_switches.cc @@ -91,6 +91,10 @@ const char kAppsGalleryURL[] = "apps-gallery-url"; // The update url used by gallery/webstore extensions. const char kAppsGalleryUpdateURL[] = "apps-gallery-update-url"; +// Specifies the URL of an application manifest to retrieve. The user will be +// prompted for consent and the application retrieved/installed if consented. +const char kAppsInstallFromManifestURL[] = "apps-install-from-manifest-url"; + // Whether to always use the new app install bubble when installing an app. const char kAppsNewInstallBubble[] = "apps-new-install-bubble"; diff --git a/chrome/common/chrome_switches.h b/chrome/common/chrome_switches.h index e80f71c..911b2f6 100644 --- a/chrome/common/chrome_switches.h +++ b/chrome/common/chrome_switches.h @@ -41,6 +41,7 @@ extern const char kAppsGalleryInstallAutoConfirmForTests[]; extern const char kAppsGalleryReturnTokens[]; extern const char kAppsGalleryURL[]; extern const char kAppsGalleryUpdateURL[]; +extern const char kAppsInstallFromManifestURL[]; extern const char kAppsNewInstallBubble[]; extern const char kAppsNoThrob[]; extern const char kAuthNegotiateDelegateWhitelist[]; diff --git a/chrome/installer/mini_installer.gyp b/chrome/installer/mini_installer.gyp index 0748ceb..9256eca 100644 --- a/chrome/installer/mini_installer.gyp +++ b/chrome/installer/mini_installer.gyp @@ -16,6 +16,7 @@ ['OS=="win"', { 'target_defaults': { 'dependencies': [ + '../chrome.gyp:app_host', '../chrome.gyp:chrome', '../chrome.gyp:chrome_nacl_win64', '../chrome.gyp:chrome_dll', @@ -234,6 +235,7 @@ ], 'inputs': [ '<(create_installer_archive_py_path)', + '<(PRODUCT_DIR)/app_host.exe', '<(PRODUCT_DIR)/chrome.exe', '<(PRODUCT_DIR)/chrome.dll', '<(PRODUCT_DIR)/nacl64.exe', diff --git a/chrome/installer/mini_installer.gypi b/chrome/installer/mini_installer.gypi index 8b5d5d0..ef92ab9 100644 --- a/chrome/installer/mini_installer.gypi +++ b/chrome/installer/mini_installer.gypi @@ -4,6 +4,7 @@ { 'dependencies': [ '<(chrome_dll_project)', + '../chrome.gyp:app_host', '../chrome.gyp:chrome', '../chrome.gyp:chrome_nacl_win64', '../chrome.gyp:default_extensions', @@ -179,6 +180,7 @@ ], 'inputs': [ '<(create_installer_archive_py_path)', + '<(PRODUCT_DIR)/app_host.exe', '<(PRODUCT_DIR)/chrome.exe', '<(chrome_dll_path)', '<(PRODUCT_DIR)/nacl64.exe', diff --git a/chrome/installer/mini_installer/appid.h b/chrome/installer/mini_installer/appid.h index 7dcd4e0..1ea93a4 100644 --- a/chrome/installer/mini_installer/appid.h +++ b/chrome/installer/mini_installer/appid.h @@ -1,4 +1,4 @@ -// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Copyright (c) 2012 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -9,6 +9,7 @@ namespace google_update { extern const wchar_t kAppGuid[]; extern const wchar_t kSxSAppGuid[]; +extern const wchar_t kChromeAppHostAppGuid[]; extern const wchar_t kChromeFrameAppGuid[]; extern const wchar_t kMultiInstallAppGuid[]; } diff --git a/chrome/installer/mini_installer/chrome.release b/chrome/installer/mini_installer/chrome.release index c04dd6c..a094ea8 100644 --- a/chrome/installer/mini_installer/chrome.release +++ b/chrome/installer/mini_installer/chrome.release @@ -3,6 +3,7 @@ # found in the LICENSE file. [GENERAL] +app_host.exe: %(ChromeDir)s\ chrome.exe: %(ChromeDir)s\ wow_helper.exe: %(ChromeDir)s\ chrome.dll: %(VersionDir)s\ diff --git a/chrome/installer/mini_installer/chrome_appid.cc b/chrome/installer/mini_installer/chrome_appid.cc index 3162523..841da52 100644 --- a/chrome/installer/mini_installer/chrome_appid.cc +++ b/chrome/installer/mini_installer/chrome_appid.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Copyright (c) 2012 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -6,8 +6,10 @@ namespace google_update { const wchar_t kAppGuid[] = L"{8A69D345-D564-463c-AFF1-A69D9E530F96}"; -const wchar_t kSxSAppGuid[] = L"{4ea16ac7-fd5a-47c3-875b-dbf4a2008c20}"; +const wchar_t kChromeAppHostAppGuid[] = + L"{FDA71E6F-AC4C-4a00-8B70-9958A68906BF}"; const wchar_t kChromeFrameAppGuid[] = L"{8BA986DA-5100-405E-AA35-86F34A02ACBF}"; const wchar_t kMultiInstallAppGuid[] = L"{4DC8B4CA-1BDA-483e-B5FA-D3C12E15B62D}"; +const wchar_t kSxSAppGuid[] = L"{4ea16ac7-fd5a-47c3-875b-dbf4a2008c20}"; } diff --git a/chrome/installer/mini_installer/configuration.cc b/chrome/installer/mini_installer/configuration.cc index cebe50c..6c9f5be 100644 --- a/chrome/installer/mini_installer/configuration.cc +++ b/chrome/installer/mini_installer/configuration.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Copyright (c) 2012 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -34,6 +34,7 @@ void Configuration::Clear() { argument_count_ = 0; has_chrome_ = false; has_chrome_frame_ = false; + has_app_host_ = false; is_multi_install_ = false; is_system_level_ = false; } @@ -59,6 +60,8 @@ bool Configuration::InitializeFromCommandLine(const wchar_t* command_line) { has_chrome_ = true; else if (0 == ::lstrcmpi(args_[i], L"--chrome-frame")) has_chrome_frame_ = true; + else if (0 == ::lstrcmpi(args_[i], L"--app-host")) + has_app_host_ = true; else if (0 == ::lstrcmpi(args_[i], L"--multi-install")) is_multi_install_ = true; else if (0 == ::lstrcmpi(args_[i], L"--system-level")) @@ -67,9 +70,9 @@ bool Configuration::InitializeFromCommandLine(const wchar_t* command_line) { operation_ = CLEANUP; } - // Single-install is either Chrome or Chrome Frame. + // Single-install defaults to Chrome. if (!is_multi_install_) - has_chrome_ = !has_chrome_frame_; + has_chrome_ = !(has_chrome_frame_ || has_app_host_); } return args_ != NULL; } diff --git a/chrome/installer/mini_installer/configuration.h b/chrome/installer/mini_installer/configuration.h index 351a129..fb955ad 100644 --- a/chrome/installer/mini_installer/configuration.h +++ b/chrome/installer/mini_installer/configuration.h @@ -1,4 +1,4 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Copyright (c) 2012 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -46,6 +46,9 @@ class Configuration { // Returns true if --chrome-frame is on the command line. bool has_chrome_frame() const { return has_chrome_frame_; } + // Returns true if --app-host is on the command line. + bool has_app_host() const { return has_app_host_; } + // Returns true if --multi-install is on the command line. bool is_multi_install() const { return is_multi_install_; } @@ -63,6 +66,7 @@ class Configuration { Operation operation_; bool has_chrome_; bool has_chrome_frame_; + bool has_app_host_; bool is_multi_install_; bool is_system_level_; diff --git a/chrome/installer/mini_installer/mini_installer.cc b/chrome/installer/mini_installer/mini_installer.cc index ea3add3..4414ea2 100644 --- a/chrome/installer/mini_installer/mini_installer.cc +++ b/chrome/installer/mini_installer/mini_installer.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Copyright (c) 2012 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -159,6 +159,7 @@ void SetInstallerFlags(const Configuration& configuration) { const REGSAM key_access = KEY_QUERY_VALUE | KEY_SET_VALUE; const HKEY root_key = configuration.is_system_level() ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER; + // This is ignored if multi-install is true. const wchar_t* app_guid = configuration.has_chrome_frame() ? google_update::kChromeFrameAppGuid : @@ -222,40 +223,48 @@ void SetInstallerFlags(const Configuration& configuration) { // Gets the setup.exe path from Registry by looking the value of Uninstall // string. |size| is measured in wchar_t units. +bool GetSetupExePathForGuidFromRegistry(bool system_level, + const wchar_t* app_guid, + wchar_t* path, + size_t size) { + const HKEY root_key = system_level ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER; + RegKey key; + return OpenClientStateKey(root_key, app_guid, KEY_QUERY_VALUE, &key) && + (key.ReadValue(kUninstallRegistryValueName, path, size) == ERROR_SUCCESS); +} + +// Gets the setup.exe path from Registry by looking the value of Uninstall +// string. |size| is measured in wchar_t units. bool GetSetupExePathFromRegistry(const Configuration& configuration, wchar_t* path, size_t size) { - const HKEY root_key = - configuration.is_system_level() ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER; - RegKey key; - bool succeeded = false; + bool system_level = configuration.is_system_level(); // If this is a multi install, first try looking in the binaries for the path. - if (configuration.is_multi_install() && - OpenClientStateKey(root_key, google_update::kMultiInstallAppGuid, - KEY_QUERY_VALUE, &key)) { - succeeded = (key.ReadValue(kUninstallRegistryValueName, path, - size) == ERROR_SUCCESS); + if (configuration.is_multi_install() && GetSetupExePathForGuidFromRegistry( + system_level, google_update::kMultiInstallAppGuid, path, size)) { + return true; } - // Failing that, look in Chrome Frame's client state key --chrome-frame was + // Failing that, look in Chrome Frame's client state key if --chrome-frame was // specified. - if (!succeeded && configuration.has_chrome_frame() && - OpenClientStateKey(root_key, google_update::kChromeFrameAppGuid, - KEY_QUERY_VALUE, &key)) { - succeeded = (key.ReadValue(kUninstallRegistryValueName, path, - size) == ERROR_SUCCESS); + if (configuration.has_chrome_frame() && GetSetupExePathForGuidFromRegistry( + system_level, google_update::kChromeFrameAppGuid, path, size)) { + return true; } - // Make a last-ditch effort to look in Chrome's client state key. - if (!succeeded && - OpenClientStateKey(root_key, configuration.chrome_app_guid(), - KEY_QUERY_VALUE, &key)) { - succeeded = (key.ReadValue(kUninstallRegistryValueName, path, - size) == ERROR_SUCCESS); + // Make a last-ditch effort to look in the Chrome and App Host client state + // keys. + if (GetSetupExePathForGuidFromRegistry( + system_level, configuration.chrome_app_guid(), path, size)) { + return true; + } + if (configuration.has_app_host() && GetSetupExePathForGuidFromRegistry( + system_level, google_update::kChromeAppHostAppGuid, path, size)) { + return true; } - return succeeded; + return false; } // Calls CreateProcess with good default parameters and waits for the process diff --git a/chrome/installer/setup/chrome_frame_quick_enable.cc b/chrome/installer/setup/chrome_frame_quick_enable.cc index a2202ab..f78038e 100644 --- a/chrome/installer/setup/chrome_frame_quick_enable.cc +++ b/chrome/installer/setup/chrome_frame_quick_enable.cc @@ -100,8 +100,6 @@ 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, @@ -114,7 +112,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, new_chrome_exe, opv, + AppendPostInstallTasks(*installer_state, setup_path, opv, new_version, temp_path.path(), item_list.get()); // Before updating the channel values, add Chrome back to the mix so that @@ -125,10 +123,11 @@ InstallStatus ChromeFrameQuickEnable(const InstallationState& machine_state, item_list.get()); // Add the items to remove the quick-enable-cf command from the registry. - AddQuickEnableWorkItems(*installer_state, machine_state, - &chrome_state->uninstall_command().GetProgram(), - &chrome_state->version(), - item_list.get()); + AddQuickEnableChromeFrameWorkItems( + *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 5895090..a3bb52f 100644 --- a/chrome/installer/setup/install.cc +++ b/chrome/installer/setup/install.cc @@ -427,6 +427,8 @@ 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 f7067c5..a8b2144 100644 --- a/chrome/installer/setup/install_worker.cc +++ b/chrome/installer/setup/install_worker.cc @@ -24,6 +24,7 @@ #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/util/conditional_work_item_list.h" @@ -100,16 +101,21 @@ void AddInstallerCopyTasks(const InstallerState& installer_state, FilePath exe_dst(installer_dir.Append(setup_path.BaseName())); FilePath archive_dst(installer_dir.Append(archive_path.BaseName())); - install_list->AddCopyTreeWorkItem(setup_path.value(), exe_dst.value(), - temp_path.value(), WorkItem::ALWAYS); + if (exe_dst != setup_path) { + install_list->AddCopyTreeWorkItem(setup_path.value(), exe_dst.value(), + temp_path.value(), WorkItem::ALWAYS); + } - // 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); + 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); + } } // This method adds work items to create (or update) Chrome uninstall entry in @@ -140,19 +146,16 @@ void AddUninstallShortcutWorkItems(const InstallerState& installer_state, AppendUninstallCommandLineFlags(installer_state, product, &uninstall_arguments); - // 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 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. if (product.is_chrome() && installer_state.operation() != InstallerState::UNINSTALL) { - 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); - } + const Product* chrome_frame = + installer_state.FindProduct(BrowserDistribution::CHROME_FRAME); + if (chrome_frame && chrome_frame->HasOption(kOptionReadyMode)) + chrome_frame->AppendProductFlags(&uninstall_arguments); } std::wstring update_state_key(browser_dist->GetStateKey()); @@ -225,28 +228,6 @@ 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, @@ -283,6 +264,32 @@ 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, @@ -295,6 +302,10 @@ 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); + } } } @@ -563,7 +574,6 @@ 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, @@ -572,6 +582,8 @@ 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, @@ -712,32 +724,29 @@ bool AppendPostInstallTasks(const InstallerState& installer_state, return true; } -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); - +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) { 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(archive_path.BaseName())); - install_list->AddDeleteTreeWorkItem(old_archive, temp_path) - ->set_ignore_failure(true); + 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); + } } // Delete any new_chrome.exe if present (we will end up creating a new one @@ -840,6 +849,48 @@ void AddInstallWorkItems(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. @@ -859,15 +910,6 @@ void AddInstallWorkItems(const InstallationState& original_state, *product, 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, @@ -876,13 +918,16 @@ void AddInstallWorkItems(const InstallationState& original_state, // Copy over brand, usagestats, and other values. AddGoogleUpdateWorkItems(original_state, installer_state, install_list); - AddQuickEnableWorkItems(installer_state, original_state, &setup_path, - &new_version, install_list); + AddQuickEnableApplicationHostWorkItems(installer_state, original_state, + &setup_path, &new_version, + install_list); + + AddQuickEnableChromeFrameWorkItems(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, @@ -1296,11 +1341,14 @@ void RefreshElevationPolicy() { } } -void AddQuickEnableWorkItems(const InstallerState& installer_state, - const InstallationState& machine_state, - const FilePath* setup_path, - const Version* new_version, - WorkItemList* work_item_list) { +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) { DCHECK(setup_path || installer_state.operation() == InstallerState::UNINSTALL); DCHECK(new_version || @@ -1308,27 +1356,17 @@ void AddQuickEnableWorkItems(const InstallerState& installer_state, DCHECK(work_item_list); const bool system_install = installer_state.system_install(); - bool have_multi_chrome = false; - bool have_chrome_frame = false; + bool have_chrome_binaries = false; // STEP 1: Figure out the state of the machine before the operation. const ProductState* product_state = NULL; - // Is multi-install Chrome already on the machine? + // Are the Chrome Binaries already on the machine? product_state = machine_state.GetProductState(system_install, - BrowserDistribution::CHROME_BROWSER); + BrowserDistribution::CHROME_BINARIES); if (product_state != NULL && product_state->is_multi_install()) - 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; + have_chrome_binaries = true; // STEP 2: Now take into account the current operation. const Product* product = NULL; @@ -1336,29 +1374,15 @@ void AddQuickEnableWorkItems(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_BROWSER); + installer_state.FindProduct(BrowserDistribution::CHROME_BINARIES); if (product != NULL && installer_state.is_multi_install()) - 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; + have_chrome_binaries = false; } else { - // Check if we're installing multi-install Chrome. + // Check if we're installing Chrome Binaries product = - installer_state.FindProduct(BrowserDistribution::CHROME_BROWSER); + installer_state.FindProduct(BrowserDistribution::CHROME_BINARIES); if (product != NULL && installer_state.is_multi_install()) - 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; + have_chrome_binaries = true; } // STEP 3: Decide what to do based on the final state of things. @@ -1369,31 +1393,29 @@ void AddQuickEnableWorkItems(const InstallerState& installer_state, } operation = DO_NOTHING; FilePath binaries_setup_path; - 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. + 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. operation = REMOVE_COMMAND; - } 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. + } 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. 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) { - // Chrome Frame is being uninstalled. Use the path to the currently - // installed Chrome setup.exe. + // One or more products are being uninstalled, but not the binaries. Use + // the path to the currently installed Chrome setup.exe. product_state = machine_state.GetProductState(system_install, - BrowserDistribution::CHROME_BROWSER); + BrowserDistribution::CHROME_BINARIES); DCHECK(product_state); binaries_setup_path = product_state->uninstall_command().GetProgram(); } else { - // Chrome is being installed, updated, or otherwise being operated on. + // Chrome Binaries are being installed, updated, or otherwise operated on. // Use the path to the given |setup_path| in the normal location of - // multi-install Chrome of the given |version|. + // multi-install Chrome Binaries of the given |version|. DCHECK(installer_state.is_multi_install()); binaries_setup_path = installer_state.GetInstallerDirectory(*new_version).Append( @@ -1409,26 +1431,116 @@ void AddQuickEnableWorkItems(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(kCmdQuickEnableCf); + .append(1, L'\\').append(command_id); if (operation == ADD_COMMAND) { DCHECK(!binaries_setup_path.empty()); CommandLine cmd_line(binaries_setup_path); - cmd_line.AppendSwitch(switches::kMultiInstall); - if (installer_state.system_install()) - cmd_line.AppendSwitch(switches::kSystemLevel); + cmd_line.AppendArguments(child_product_switches, + false); // include_program 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 quick-enable-cf command"); + "removing " + WideToASCII(command_id) + " 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 c47f78d..e9414c1 100644 --- a/chrome/installer/setup/install_worker.h +++ b/chrome/installer/setup/install_worker.h @@ -63,7 +63,6 @@ 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, @@ -172,11 +171,25 @@ 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 AddQuickEnableWorkItems(const InstallerState& installer_state, - const InstallationState& machine_state, - const FilePath* setup_path, - const Version* new_version, - WorkItemList* work_item_list); +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); } // namespace installer diff --git a/chrome/installer/setup/setup_main.cc b/chrome/installer/setup/setup_main.cc index 7925d79..e85ae54 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); diff --git a/chrome/installer/setup/uninstall.cc b/chrome/installer/setup/uninstall.cc index 5f7578b..6de704a 100644 --- a/chrome/installer/setup/uninstall.cc +++ b/chrome/installer/setup/uninstall.cc @@ -49,6 +49,23 @@ 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 @@ -72,17 +89,15 @@ 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 (int i = 0; i < arraysize(other_dist_types); ++i) { - BrowserDistribution::Type other_dist_type = other_dist_types[i]; + 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; + product_state = original_state.GetProductState(system_level, other_dist_type); // Only modify other products if they're installed and multi. @@ -117,8 +132,11 @@ void ProcessQuickEnableWorkItems( scoped_ptr<WorkItemList> work_item_list( WorkItem::CreateNoRollbackWorkItemList()); - AddQuickEnableWorkItems(installer_state, machine_state, NULL, NULL, - work_item_list.get()); + AddQuickEnableChromeFrameWorkItems(installer_state, machine_state, NULL, NULL, + work_item_list.get()); + + AddQuickEnableApplicationHostWorkItems(installer_state, machine_state, NULL, + NULL, work_item_list.get()); if (!work_item_list->Do()) LOG(ERROR) << "Failed to update quick-enable-cf command."; } @@ -396,44 +414,80 @@ bool MoveSetupOutOfInstallFolder(const InstallerState& installer_state, return ret; } -DeleteResult DeleteFilesAndFolders(const InstallerState& installer_state, - const Version& installed_version) { +DeleteResult DeleteAppHostFilesAndFolders(const InstallerState& installer_state, + const Version& installed_version) { const FilePath& target_path = installer_state.target_path(); if (target_path.empty()) { - LOG(ERROR) << "DeleteFilesAndFolders: no installation destination path."; + LOG(ERROR) << "DeleteAppHostFilesAndFolders: no installation destination " + << "path."; return DELETE_FAILED; // Nothing else we can do to uninstall, so we return. } + DeleteInstallTempDir(target_path); + DeleteResult result = DELETE_SUCCEEDED; - // 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(); - } + 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); } - 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; + 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. + } + + 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; + } } } } @@ -497,7 +551,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() && !installer_state.is_msi()) { + if (product.is_chrome_frame() && !installer_state.is_msi()) { should_delete = true; } else { should_delete = @@ -764,10 +818,10 @@ 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(); @@ -776,8 +830,13 @@ InstallStatus UninstallProduct(const InstallationState& original_state, // product.GetVersionKey(). string16 distribution_data(browser_dist->GetDistributionData(reg_root)); - // Remove Control Panel uninstall link and Omaha product key. - InstallUtil::DeleteRegistryKey(reg_root, browser_dist->GetUninstallRegPath()); + // Remove Control Panel uninstall link. + if (product.ShouldCreateUninstallEntry()) { + InstallUtil::DeleteRegistryKey(reg_root, + browser_dist->GetUninstallRegPath()); + } + + // Remove Omaha product key. InstallUtil::DeleteRegistryKey(reg_root, browser_dist->GetVersionKey()); // Also try to delete the MSI value in the ClientState key (it might not be @@ -786,61 +845,65 @@ 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; - 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(), + + 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, 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, + // 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, - 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, + installer_state.target_path(), &ret); + } - ProcessDelegateExecuteWorkItems(installer_state, product); + ProcessDelegateExecuteWorkItems(installer_state, product); + } - if (!is_chrome) { + if (product.is_chrome_frame()) { ProcessChromeFrameWorkItems(original_state, installer_state, setup_path, product); } @@ -888,7 +951,7 @@ InstallStatus UninstallProduct(const InstallationState& original_state, unreg_work_item_list->Do(); } - if (!is_chrome) + if (product.is_chrome_frame()) ProcessIELowRightsPolicyWorkItems(installer_state); } @@ -908,41 +971,25 @@ 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, 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()); - } - } + // (aka non-multi) installation or we are the Chrome Binaries. - FilePath backup_state_file(BackupLocalStateFile( - GetLocalStateFolder(product))); + FilePath backup_state_file( + BackupLocalStateFile(GetLocalStateFolder(product))); DeleteResult delete_result = DELETE_SUCCEEDED; - if (can_delete_files) { + + if (product.is_chrome_app_host()) { + DeleteAppHostFilesAndFolders(installer_state, product_state->version()); + } else if (!installer_state.is_multi_install() || + product.is_chrome_binaries()) { + // 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 = DeleteFilesAndFolders(installer_state, - product_state->version()); + delete_result = DeleteChromeFilesAndFolders(installer_state, + product_state->version()); } if (delete_profile) @@ -955,7 +1002,7 @@ InstallStatus UninstallProduct(const InstallationState& original_state, } if (!force_uninstall) { - VLOG(1) << "Uninstallation complete. Launching Uninstall survey."; + VLOG(1) << "Uninstallation complete. Launching post-uninstall operations."; browser_dist->DoPostUninstallOperations(product_state->version(), backup_state_file, distribution_data); } diff --git a/chrome/installer/util/browser_distribution.cc b/chrome/installer/util/browser_distribution.cc index f958db8..b39ff59 100644 --- a/chrome/installer/util/browser_distribution.cc +++ b/chrome/installer/util/browser_distribution.cc @@ -17,10 +17,11 @@ #include "base/win/registry.h" #include "base/win/windows_version.h" #include "chrome/common/env_vars.h" +#include "chrome/installer/util/chrome_app_host_distribution.h" #include "chrome/installer/util/chrome_frame_distribution.h" #include "chrome/installer/util/chromium_binaries_distribution.h" -#include "chrome/installer/util/google_chrome_distribution.h" #include "chrome/installer/util/google_chrome_binaries_distribution.h" +#include "chrome/installer/util/google_chrome_distribution.h" #include "chrome/installer/util/google_chrome_sxs_distribution.h" #include "chrome/installer/util/install_util.h" #include "chrome/installer/util/l10n_string_util.h" @@ -44,6 +45,7 @@ const wchar_t kICommandExecuteImplUuid[] = BrowserDistribution* g_browser_distribution = NULL; BrowserDistribution* g_chrome_frame_distribution = NULL; BrowserDistribution* g_binaries_distribution = NULL; +BrowserDistribution* g_chrome_app_host_distribution = NULL; // Returns true if currently running in npchrome_frame.dll bool IsChromeFrameModule() { @@ -54,6 +56,8 @@ bool IsChromeFrameModule() { } BrowserDistribution::Type GetCurrentDistributionType() { + // TODO(erikwright): If the app host is installed, but not Chrome, perhaps + // this should return CHROME_APP_HOST. static BrowserDistribution::Type type = (MasterPreferences::ForCurrentProcess().install_chrome_frame() || IsChromeFrameModule()) ? @@ -64,16 +68,6 @@ BrowserDistribution::Type GetCurrentDistributionType() { } // end namespace -// CHROME_BINARIES represents the binaries shared by multi-install products and -// is not a product in and of itself, so it is not present in this collection. -const BrowserDistribution::Type BrowserDistribution::kProductTypes[] = { - BrowserDistribution::CHROME_BROWSER, - BrowserDistribution::CHROME_FRAME, -}; - -const size_t BrowserDistribution::kNumProductTypes = - arraysize(BrowserDistribution::kProductTypes); - BrowserDistribution::BrowserDistribution() : type_(CHROME_BROWSER) { } @@ -126,6 +120,11 @@ BrowserDistribution* BrowserDistribution::GetSpecificDistribution( &g_chrome_frame_distribution); break; + case CHROME_APP_HOST: + dist = GetOrCreateBrowserDistribution<ChromeAppHostDistribution>( + &g_chrome_app_host_distribution); + break; + default: DCHECK_EQ(CHROME_BINARIES, type); #if defined(GOOGLE_CHROME_BUILD) diff --git a/chrome/installer/util/browser_distribution.h b/chrome/installer/util/browser_distribution.h index 6738037..4f609c9 100644 --- a/chrome/installer/util/browser_distribution.h +++ b/chrome/installer/util/browser_distribution.h @@ -29,6 +29,7 @@ class BrowserDistribution { CHROME_BROWSER, CHROME_FRAME, CHROME_BINARIES, + CHROME_APP_HOST, NUM_TYPES }; @@ -46,12 +47,6 @@ class BrowserDistribution { // experiment but does not participate. }; - // An array of the Types representing products; - static const Type kProductTypes[]; - - // The number of elements in the array |kProductTypes|. - static const size_t kNumProductTypes; - virtual ~BrowserDistribution() {} static BrowserDistribution* GetDistribution(); diff --git a/chrome/installer/util/browser_distribution_unittest.cc b/chrome/installer/util/browser_distribution_unittest.cc deleted file mode 100644 index d0e1059..0000000 --- a/chrome/installer/util/browser_distribution_unittest.cc +++ /dev/null @@ -1,50 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. -// -// Unit tests for BrowserDistribution class. - -#include "chrome/installer/util/browser_distribution.h" -#include "chrome/installer/util/shell_util.h" -#include "testing/gtest/include/gtest/gtest.h" - -// The distribution strings should not be empty. The unit tests are not linking -// with the chrome resources so we cannot test official build. -TEST(BrowserDistributionTest, StringsTest) { - for (size_t i = 0; i < BrowserDistribution::kNumProductTypes; ++i) { - BrowserDistribution* dist = - BrowserDistribution::GetSpecificDistribution( - BrowserDistribution::kProductTypes[i]); - ASSERT_TRUE(dist != NULL); - string16 name = dist->GetBaseAppName(); - EXPECT_FALSE(name.empty()); - string16 desc = dist->GetAppDescription(); - EXPECT_FALSE(desc.empty()); - string16 alt_name = dist->GetAlternateApplicationName(); - EXPECT_FALSE(alt_name.empty()); - } -} - -// The shortcut strings obtained by the shell utility functions should not -// be empty or be the same. -TEST(BrowserDistributionTest, AlternateAndNormalShortcutName) { - string16 normal_name; - string16 alternate_name; - string16 appended_name_one; - string16 appended_name_two; - BrowserDistribution* dist = BrowserDistribution::GetDistribution(); - EXPECT_TRUE(ShellUtil::GetChromeShortcutName(dist, false, L"", - &normal_name)); - EXPECT_TRUE(ShellUtil::GetChromeShortcutName(dist, true, L"", - &alternate_name)); - EXPECT_TRUE(ShellUtil::GetChromeShortcutName(dist, true, L"Sparky", - &appended_name_one)); - EXPECT_TRUE(ShellUtil::GetChromeShortcutName(dist, true, L"Sparkles", - &appended_name_two)); - EXPECT_NE(normal_name, alternate_name); - EXPECT_NE(appended_name_one, appended_name_two); - EXPECT_FALSE(normal_name.empty()); - EXPECT_FALSE(alternate_name.empty()); - EXPECT_FALSE(appended_name_one.empty()); - EXPECT_FALSE(appended_name_two.empty()); -} diff --git a/chrome/installer/util/channel_info.cc b/chrome/installer/util/channel_info.cc index 24c5199..a67e7fb 100644 --- a/chrome/installer/util/channel_info.cc +++ b/chrome/installer/util/channel_info.cc @@ -15,6 +15,7 @@ namespace { const wchar_t kModChrome[] = L"-chrome"; const wchar_t kModChromeFrame[] = L"-chromeframe"; +const wchar_t kModAppHost[] = L"-apphost"; const wchar_t kModMultiInstall[] = L"-multi"; const wchar_t kModReadyMode[] = L"-readymode"; const wchar_t kModStage[] = L"-stage:"; @@ -31,6 +32,7 @@ const wchar_t* const kModifiers[] = { kModMultiInstall, kModChrome, kModChromeFrame, + kModAppHost, kModReadyMode, kSfxMultiFail, kSfxFull @@ -41,6 +43,7 @@ enum ModifierIndex { MOD_MULTI_INSTALL, MOD_CHROME, MOD_CHROME_FRAME, + MOD_APP_HOST, MOD_READY_MODE, SFX_MULTI_FAIL, SFX_FULL, @@ -193,6 +196,14 @@ bool ChannelInfo::SetChromeFrame(bool value) { return SetModifier(MOD_CHROME_FRAME, value, &value_); } +bool ChannelInfo::IsAppHost() const { + return HasModifier(MOD_APP_HOST, value_); +} + +bool ChannelInfo::SetAppHost(bool value) { + return SetModifier(MOD_APP_HOST, value, &value_); +} + bool ChannelInfo::IsMultiInstall() const { return HasModifier(MOD_MULTI_INSTALL, value_); } diff --git a/chrome/installer/util/channel_info.h b/chrome/installer/util/channel_info.h index 9ceae32..605b87a 100644 --- a/chrome/installer/util/channel_info.h +++ b/chrome/installer/util/channel_info.h @@ -1,4 +1,4 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Copyright (c) 2012 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -57,6 +57,13 @@ class ChannelInfo { // modified. bool SetChromeFrame(bool value); + // Returns true if the -apphost modifier is present in the value. + bool IsAppHost() const; + + // Adds or removes the -apphost modifier, returning true if the value is + // modified. + bool SetAppHost(bool value); + // Returns true if the -multi modifier is present in the value. bool IsMultiInstall() const; diff --git a/chrome/installer/util/chrome_app_host_distribution.cc b/chrome/installer/util/chrome_app_host_distribution.cc new file mode 100644 index 0000000..4eef303 --- /dev/null +++ b/chrome/installer/util/chrome_app_host_distribution.cc @@ -0,0 +1,148 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// +// This file defines a specific implementation of BrowserDistribution class for +// Chrome App Host. It overrides the bare minimum of methods necessary to get a +// Chrome App Host installer that does not interact with Google Chrome or +// Chromium installations. + +#include "chrome/installer/util/chrome_app_host_distribution.h" + +#include "base/string_util.h" +#include "chrome/common/net/test_server_locations.h" +#include "chrome/installer/util/channel_info.h" +#include "chrome/installer/util/google_update_constants.h" +#include "chrome/installer/util/google_update_settings.h" +#include "chrome/installer/util/helper.h" +#include "chrome/installer/util/install_util.h" +#include "chrome/installer/util/l10n_string_util.h" + +#include "installer_util_strings.h" // NOLINT + +namespace { +const wchar_t kChromeAppHostGuid[] = L"{FDA71E6F-AC4C-4a00-8B70-9958A68906BF}"; +} + +ChromeAppHostDistribution::ChromeAppHostDistribution() + : BrowserDistribution(CHROME_APP_HOST) { +} + +string16 ChromeAppHostDistribution::GetAppGuid() { + return kChromeAppHostGuid; +} + +string16 ChromeAppHostDistribution::GetBaseAppName() { + return L"Google Chrome App Host"; +} + +string16 ChromeAppHostDistribution::GetAppShortCutName() { + const string16& product_name = + installer::GetLocalizedString(IDS_PRODUCT_APP_HOST_NAME_BASE); + return product_name; +} + +string16 ChromeAppHostDistribution::GetAlternateApplicationName() { + const string16& product_name = + installer::GetLocalizedString(IDS_PRODUCT_APP_HOST_NAME_BASE); + return product_name; +} + +string16 ChromeAppHostDistribution::GetInstallSubDir() { + return BrowserDistribution::GetSpecificDistribution( + BrowserDistribution::CHROME_BINARIES)->GetInstallSubDir(); +} + +string16 ChromeAppHostDistribution::GetPublisherName() { + const string16& publisher_name = + installer::GetLocalizedString(IDS_ABOUT_VERSION_COMPANY_NAME_BASE); + return publisher_name; +} + +string16 ChromeAppHostDistribution::GetAppDescription() { + NOTREACHED() << "This should never be accessed due to no start-menu/task-bar " + << "shortcuts."; + return L"A standalone platform for Chrome apps."; +} + +string16 ChromeAppHostDistribution::GetLongAppDescription() { + NOTREACHED() << "This should never be accessed as Chrome App Host is not a " + << "default browser option."; + return L"A standalone platform for Chrome apps."; +} + +std::string ChromeAppHostDistribution::GetSafeBrowsingName() { + return "googlechromeapphost"; +} + +string16 ChromeAppHostDistribution::GetStateKey() { + string16 key(google_update::kRegPathClientState); + key.append(L"\\"); + key.append(kChromeAppHostGuid); + return key; +} + +string16 ChromeAppHostDistribution::GetStateMediumKey() { + string16 key(google_update::kRegPathClientStateMedium); + key.append(L"\\"); + key.append(kChromeAppHostGuid); + return key; +} + +string16 ChromeAppHostDistribution::GetStatsServerURL() { + return L"https://clients4.google.com/firefox/metrics/collect"; +} + +std::string ChromeAppHostDistribution::GetNetworkStatsServer() const { + return chrome_common_net::kEchoTestServerLocation; +} + +std::string ChromeAppHostDistribution::GetHttpPipeliningTestServer() const { + return chrome_common_net::kPipelineTestServerBaseUrl; +} + +string16 ChromeAppHostDistribution::GetUninstallLinkName() { + NOTREACHED() << "This should never be accessed as Chrome App Host has no " + << "uninstall entry."; + return L"Uninstall Chrome App Host"; +} + +string16 ChromeAppHostDistribution::GetUninstallRegPath() { + NOTREACHED() << "This should never be accessed as Chrome App Host has no " + << "uninstall entry."; + return L"Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\" + L"Google Chrome App Host"; +} + +string16 ChromeAppHostDistribution::GetVersionKey() { + string16 key(google_update::kRegPathClients); + key.append(L"\\"); + key.append(kChromeAppHostGuid); + return key; +} + +bool ChromeAppHostDistribution::CanSetAsDefault() { + return false; +} + +bool ChromeAppHostDistribution::CanCreateDesktopShortcuts() { + return false; +} + +bool ChromeAppHostDistribution::GetDelegateExecuteHandlerData( + string16* handler_class_uuid, + string16* type_lib_uuid, + string16* type_lib_version, + string16* interface_uuid) { + return false; +} + +void ChromeAppHostDistribution::UpdateInstallStatus(bool system_install, + installer::ArchiveType archive_type, + installer::InstallStatus install_status) { +#if defined(GOOGLE_CHROME_BUILD) + GoogleUpdateSettings::UpdateInstallStatus(system_install, + archive_type, InstallUtil::GetInstallReturnCode(install_status), + kChromeAppHostGuid); +#endif +} diff --git a/chrome/installer/util/chrome_app_host_distribution.h b/chrome/installer/util/chrome_app_host_distribution.h new file mode 100644 index 0000000..1d5ea40 --- /dev/null +++ b/chrome/installer/util/chrome_app_host_distribution.h @@ -0,0 +1,70 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// +// This file extends the browser distribution with a specific implementation +// for Chrome AppHost. + +#ifndef CHROME_INSTALLER_UTIL_CHROME_APP_HOST_DISTRIBUTION_H_ +#define CHROME_INSTALLER_UTIL_CHROME_APP_HOST_DISTRIBUTION_H_ + +#include "chrome/installer/util/browser_distribution.h" +#include "chrome/installer/util/util_constants.h" + +class ChromeAppHostDistribution : public BrowserDistribution { + public: + virtual string16 GetAppGuid() OVERRIDE; + + virtual string16 GetBaseAppName() OVERRIDE; + + virtual string16 GetAppShortCutName() OVERRIDE; + + virtual string16 GetAlternateApplicationName() OVERRIDE; + + virtual string16 GetInstallSubDir() OVERRIDE; + + virtual string16 GetPublisherName() OVERRIDE; + + virtual string16 GetAppDescription() OVERRIDE; + + virtual string16 GetLongAppDescription() OVERRIDE; + + virtual std::string GetSafeBrowsingName() OVERRIDE; + + virtual string16 GetStateKey() OVERRIDE; + + virtual string16 GetStateMediumKey() OVERRIDE; + + virtual string16 GetStatsServerURL() OVERRIDE; + + virtual std::string GetNetworkStatsServer() const OVERRIDE; + + virtual std::string GetHttpPipeliningTestServer() const OVERRIDE; + + virtual string16 GetUninstallLinkName() OVERRIDE; + + virtual string16 GetUninstallRegPath() OVERRIDE; + + virtual string16 GetVersionKey() OVERRIDE; + + virtual bool CanSetAsDefault() OVERRIDE; + + virtual bool CanCreateDesktopShortcuts() OVERRIDE; + + virtual bool GetDelegateExecuteHandlerData(string16* handler_class_uuid, + string16* type_lib_uuid, + string16* type_lib_version, + string16* interface_uuid) OVERRIDE; + + virtual void UpdateInstallStatus(bool system_install, + installer::ArchiveType archive_type, + installer::InstallStatus install_status) OVERRIDE; + + protected: + friend class BrowserDistribution; + + // Disallow construction from non-friends. + ChromeAppHostDistribution(); +}; + +#endif // CHROME_INSTALLER_UTIL_CHROME_APP_HOST_DISTRIBUTION_H_ diff --git a/chrome/installer/util/chrome_app_host_operations.cc b/chrome/installer/util/chrome_app_host_operations.cc new file mode 100644 index 0000000..07427f5 --- /dev/null +++ b/chrome/installer/util/chrome_app_host_operations.cc @@ -0,0 +1,100 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/installer/util/chrome_app_host_operations.h" + +#include "base/command_line.h" +#include "base/file_path.h" +#include "base/logging.h" +#include "chrome/installer/util/browser_distribution.h" +#include "chrome/installer/util/channel_info.h" +#include "chrome/installer/util/helper.h" +#include "chrome/installer/util/master_preferences.h" +#include "chrome/installer/util/master_preferences_constants.h" +#include "chrome/installer/util/util_constants.h" + +namespace installer { + +void ChromeAppHostOperations::ReadOptions( + const MasterPreferences& prefs, + std::set<std::wstring>* options) const { + DCHECK(options); + + bool pref_value; + if (prefs.GetBool(master_preferences::kMultiInstall, &pref_value) && + pref_value) { + options->insert(kOptionMultiInstall); + } +} + +void ChromeAppHostOperations::ReadOptions( + const CommandLine& uninstall_command, + std::set<std::wstring>* options) const { + DCHECK(options); + + if (uninstall_command.HasSwitch(switches::kMultiInstall)) + options->insert(kOptionMultiInstall); +} + +void ChromeAppHostOperations::AddKeyFiles( + const std::set<std::wstring>& options, + std::vector<FilePath>* key_files) const { +} + +void ChromeAppHostOperations::AddComDllList( + const std::set<std::wstring>& options, + std::vector<FilePath>* com_dll_list) const { +} + +void ChromeAppHostOperations::AppendProductFlags( + const std::set<std::wstring>& options, + CommandLine* cmd_line) const { + DCHECK(cmd_line); + bool is_multi_install = options.find(kOptionMultiInstall) != options.end(); + + // Non-multi-install not supported for the app host. + DCHECK(is_multi_install); + + // Add --multi-install if it isn't already there. + if (is_multi_install && !cmd_line->HasSwitch(switches::kMultiInstall)) + cmd_line->AppendSwitch(switches::kMultiInstall); + + // --app-host is always needed. + cmd_line->AppendSwitch(switches::kChromeAppHost); +} + +void ChromeAppHostOperations::AppendRenameFlags( + const std::set<std::wstring>& options, + CommandLine* cmd_line) const { + DCHECK(cmd_line); + bool is_multi_install = options.find(kOptionMultiInstall) != options.end(); + + // Non-multi-install not supported for the app host. + DCHECK(is_multi_install); + + // Add --multi-install if it isn't already there. + if (is_multi_install && !cmd_line->HasSwitch(switches::kMultiInstall)) + cmd_line->AppendSwitch(switches::kMultiInstall); +} + +bool ChromeAppHostOperations::SetChannelFlags( + const std::set<std::wstring>& options, + bool set, + ChannelInfo* channel_info) const { +#if defined(GOOGLE_CHROME_BUILD) + DCHECK(channel_info); + bool modified = channel_info->SetAppHost(set); + + return modified; +#else + return false; +#endif +} + +bool ChromeAppHostOperations::ShouldCreateUninstallEntry( + const std::set<std::wstring>& options) const { + return false; +} + +} // namespace installer diff --git a/chrome/installer/util/chrome_app_host_operations.h b/chrome/installer/util/chrome_app_host_operations.h new file mode 100644 index 0000000..bbf0589 --- /dev/null +++ b/chrome/installer/util/chrome_app_host_operations.h @@ -0,0 +1,59 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_INSTALLER_UTIL_CHROME_APP_HOST_OPERATIONS_H_ +#define CHROME_INSTALLER_UTIL_CHROME_APP_HOST_OPERATIONS_H_ + +#include <set> +#include <string> +#include <vector> + +#include "base/basictypes.h" +#include "base/compiler_specific.h" +#include "base/file_path.h" +#include "chrome/installer/util/product_operations.h" + +namespace installer { + +// Operations specific to Chrome App Host; see ProductOperations for general +// info. +class ChromeAppHostOperations : public ProductOperations { + public: + ChromeAppHostOperations() {} + + virtual void ReadOptions(const MasterPreferences& prefs, + std::set<std::wstring>* options) const OVERRIDE; + + virtual void ReadOptions(const CommandLine& uninstall_command, + std::set<std::wstring>* options) const OVERRIDE; + + virtual void AddKeyFiles(const std::set<std::wstring>& options, + std::vector<FilePath>* key_files) const OVERRIDE; + + virtual void AddComDllList( + const std::set<std::wstring>& options, + std::vector<FilePath>* com_dll_list) const OVERRIDE; + + virtual void AppendProductFlags( + const std::set<std::wstring>& options, + CommandLine* cmd_line) const OVERRIDE; + + virtual void AppendRenameFlags( + const std::set<std::wstring>& options, + CommandLine* cmd_line) const OVERRIDE; + + virtual bool SetChannelFlags(const std::set<std::wstring>& options, + bool set, + ChannelInfo* channel_info) const OVERRIDE; + + virtual bool ShouldCreateUninstallEntry( + const std::set<std::wstring>& options) const OVERRIDE; + + private: + DISALLOW_COPY_AND_ASSIGN(ChromeAppHostOperations); +}; + +} // namespace installer + +#endif // CHROME_INSTALLER_UTIL_CHROME_APP_HOST_OPERATIONS_H_ diff --git a/chrome/installer/util/chrome_binaries_operations.cc b/chrome/installer/util/chrome_binaries_operations.cc new file mode 100644 index 0000000..326223a --- /dev/null +++ b/chrome/installer/util/chrome_binaries_operations.cc @@ -0,0 +1,88 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/installer/util/chrome_binaries_operations.h" + +#include "base/command_line.h" +#include "base/file_path.h" +#include "base/logging.h" +#include "chrome/installer/util/channel_info.h" +#include "chrome/installer/util/helper.h" +#include "chrome/installer/util/master_preferences.h" +#include "chrome/installer/util/master_preferences_constants.h" +#include "chrome/installer/util/util_constants.h" + +namespace installer { + +void ChromeBinariesOperations::ReadOptions( + const MasterPreferences& prefs, + std::set<std::wstring>* options) const { + DCHECK(options); + + bool pref_value; + + if (prefs.GetBool(master_preferences::kMultiInstall, &pref_value) && + pref_value) { + options->insert(kOptionMultiInstall); + } +} + +void ChromeBinariesOperations::ReadOptions( + const CommandLine& uninstall_command, + std::set<std::wstring>* options) const { + DCHECK(options); + + if (uninstall_command.HasSwitch(switches::kMultiInstall)) + options->insert(kOptionMultiInstall); +} + +void ChromeBinariesOperations::AddKeyFiles( + const std::set<std::wstring>& options, + std::vector<FilePath>* key_files) const { + DCHECK(key_files); + key_files->push_back(FilePath(installer::kChromeDll)); +} + +void ChromeBinariesOperations::AddComDllList( + const std::set<std::wstring>& options, + std::vector<FilePath>* com_dll_list) const { +} + +void ChromeBinariesOperations::AppendProductFlags( + const std::set<std::wstring>& options, + CommandLine* cmd_line) const { + DCHECK(cmd_line); + + if (options.find(kOptionMultiInstall) != options.end()) { + // Add --multi-install if it isn't already there. + if (!cmd_line->HasSwitch(switches::kMultiInstall)) + cmd_line->AppendSwitch(switches::kMultiInstall); + } +} + +void ChromeBinariesOperations::AppendRenameFlags( + const std::set<std::wstring>& options, + CommandLine* cmd_line) const { + DCHECK(cmd_line); + + // Add --multi-install if it isn't already there. + if (options.find(kOptionMultiInstall) != options.end() && + !cmd_line->HasSwitch(switches::kMultiInstall)) { + cmd_line->AppendSwitch(switches::kMultiInstall); + } +} + +bool ChromeBinariesOperations::SetChannelFlags( + const std::set<std::wstring>& options, + bool set, + ChannelInfo* channel_info) const { + return false; +} + +bool ChromeBinariesOperations::ShouldCreateUninstallEntry( + const std::set<std::wstring>& options) const { + return false; +} + +} // namespace installer diff --git a/chrome/installer/util/chrome_binaries_operations.h b/chrome/installer/util/chrome_binaries_operations.h new file mode 100644 index 0000000..a40ac41 --- /dev/null +++ b/chrome/installer/util/chrome_binaries_operations.h @@ -0,0 +1,58 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_INSTALLER_UTIL_CHROME_BINARIES_OPERATIONS_H_ +#define CHROME_INSTALLER_UTIL_CHROME_BINARIES_OPERATIONS_H_ + +#include <set> +#include <string> +#include <vector> + +#include "base/basictypes.h" +#include "base/compiler_specific.h" +#include "chrome/installer/util/product_operations.h" + +namespace installer { + +// Operations specific to the Chrome Binaries; see ProductOperations for general +// info. +class ChromeBinariesOperations : public ProductOperations { + public: + ChromeBinariesOperations() {} + + virtual void ReadOptions(const MasterPreferences& prefs, + std::set<std::wstring>* options) const OVERRIDE; + + virtual void ReadOptions(const CommandLine& uninstall_command, + std::set<std::wstring>* options) const OVERRIDE; + + virtual void AddKeyFiles(const std::set<std::wstring>& options, + std::vector<FilePath>* key_files) const OVERRIDE; + + virtual void AddComDllList( + const std::set<std::wstring>& options, + std::vector<FilePath>* com_dll_list) const OVERRIDE; + + virtual void AppendProductFlags( + const std::set<std::wstring>& options, + CommandLine* cmd_line) const OVERRIDE; + + virtual void AppendRenameFlags( + const std::set<std::wstring>& options, + CommandLine* cmd_line) const OVERRIDE; + + virtual bool SetChannelFlags(const std::set<std::wstring>& options, + bool set, + ChannelInfo* channel_info) const OVERRIDE; + + virtual bool ShouldCreateUninstallEntry( + const std::set<std::wstring>& options) const OVERRIDE; + + private: + DISALLOW_COPY_AND_ASSIGN(ChromeBinariesOperations); +}; + +} // namespace installer + +#endif // CHROME_INSTALLER_UTIL_CHROME_BINARIES_OPERATIONS_H_ diff --git a/chrome/installer/util/chrome_frame_operations.cc b/chrome/installer/util/chrome_frame_operations.cc index a1a46ee..ae790ab 100644 --- a/chrome/installer/util/chrome_frame_operations.cc +++ b/chrome/installer/util/chrome_frame_operations.cc @@ -86,7 +86,6 @@ void ChromeFrameOperations::AddComDllList( const std::set<std::wstring>& options, std::vector<FilePath>* com_dll_list) const { DCHECK(com_dll_list); - std::vector<FilePath> dll_list; com_dll_list->push_back(FilePath(installer::kChromeFrameDll)); } diff --git a/chrome/installer/util/chromium_binaries_distribution.cc b/chrome/installer/util/chromium_binaries_distribution.cc index e12f56b..e2d23e9 100644 --- a/chrome/installer/util/chromium_binaries_distribution.cc +++ b/chrome/installer/util/chromium_binaries_distribution.cc @@ -90,7 +90,6 @@ string16 ChromiumBinariesDistribution::GetVersionKey() { } bool ChromiumBinariesDistribution::CanSetAsDefault() { - NOTREACHED(); return false; } diff --git a/chrome/installer/util/installation_state.cc b/chrome/installer/util/installation_state.cc index 6f12eb7..c8c8604 100644 --- a/chrome/installer/util/installation_state.cc +++ b/chrome/installer/util/installation_state.cc @@ -226,9 +226,12 @@ int InstallationState::IndexFromDistType(BrowserDistribution::Type type) { unexpected_chrome_frame_distribution_value_); COMPILE_ASSERT(BrowserDistribution::CHROME_BINARIES == CHROME_BINARIES_INDEX, unexpected_chrome_frame_distribution_value_); + COMPILE_ASSERT(BrowserDistribution::CHROME_APP_HOST == CHROME_APP_HOST_INDEX, + unexpected_chrome_frame_distribution_value_); DCHECK(type == BrowserDistribution::CHROME_BROWSER || type == BrowserDistribution::CHROME_FRAME || - type == BrowserDistribution::CHROME_BINARIES); + type == BrowserDistribution::CHROME_BINARIES || + type == BrowserDistribution::CHROME_APP_HOST); return type; } @@ -249,6 +252,11 @@ void InstallationState::Initialize() { BrowserDistribution::CHROME_BINARIES); user_products_[CHROME_BINARIES_INDEX].Initialize(false, distribution); system_products_[CHROME_BINARIES_INDEX].Initialize(true, distribution); + + distribution = BrowserDistribution::GetSpecificDistribution( + BrowserDistribution::CHROME_APP_HOST); + user_products_[CHROME_APP_HOST_INDEX].Initialize(false, distribution); + system_products_[CHROME_APP_HOST_INDEX].Initialize(true, distribution); } const ProductState* InstallationState::GetNonVersionedProductState( diff --git a/chrome/installer/util/installation_state.h b/chrome/installer/util/installation_state.h index 05cec80..ce72014 100644 --- a/chrome/installer/util/installation_state.h +++ b/chrome/installer/util/installation_state.h @@ -1,4 +1,4 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Copyright (c) 2012 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -153,6 +153,7 @@ class InstallationState { CHROME_BROWSER_INDEX, CHROME_FRAME_INDEX, CHROME_BINARIES_INDEX, + CHROME_APP_HOST_INDEX, NUM_PRODUCTS }; diff --git a/chrome/installer/util/installation_validator.cc b/chrome/installer/util/installation_validator.cc index 2d109fe..ccfa0a9 100644 --- a/chrome/installer/util/installation_validator.cc +++ b/chrome/installer/util/installation_validator.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Copyright (c) 2012 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -11,6 +11,7 @@ #include "base/logging.h" #include "base/version.h" +#include "chrome/common/chrome_switches.h" #include "chrome/installer/util/browser_distribution.h" #include "chrome/installer/util/helper.h" #include "chrome/installer/util/installation_state.h" @@ -112,6 +113,44 @@ bool InstallationValidator::ChromeFrameRules::UsageStatsAllowed( } BrowserDistribution::Type + InstallationValidator::ChromeAppHostRules::distribution_type() const { + return BrowserDistribution::CHROME_APP_HOST; +} + +void InstallationValidator::ChromeAppHostRules::AddUninstallSwitchExpectations( + const InstallationState& machine_state, + bool system_install, + const ProductState& product_state, + SwitchExpectations* expectations) const { + DCHECK(!system_install); + + // --chrome-app-host must be present. + expectations->push_back(std::make_pair(std::string(switches::kChromeAppHost), + true)); + // --chrome must not be present. + expectations->push_back(std::make_pair(std::string(switches::kChrome), + false)); + + // --chrome-frame must not be present. + expectations->push_back(std::make_pair(std::string(switches::kChromeFrame), + false)); +} + +void InstallationValidator::ChromeAppHostRules::AddRenameSwitchExpectations( + const InstallationState& machine_state, + bool system_install, + const ProductState& product_state, + SwitchExpectations* expectations) const { + // TODO(erikwright): I guess there will be none? +} + +bool InstallationValidator::ChromeAppHostRules::UsageStatsAllowed( + const ProductState& product_state) const { + // App Host doesn't manage usage stats. The Chrome Binaries will. + return false; +} + +BrowserDistribution::Type InstallationValidator::ChromeBinariesRules::distribution_type() const { return BrowserDistribution::CHROME_BINARIES; } @@ -149,9 +188,59 @@ const InstallationValidator::InstallationType CHROME_FRAME_SINGLE_CHROME_MULTI, CHROME_FRAME_MULTI, CHROME_FRAME_MULTI_CHROME_MULTI, - CHROME_FRAME_READY_MODE_CHROME_MULTI + CHROME_FRAME_READY_MODE_CHROME_MULTI, + CHROME_APP_HOST, + CHROME_APP_HOST_CHROME_FRAME_SINGLE, + CHROME_APP_HOST_CHROME_FRAME_SINGLE_CHROME_MULTI, + CHROME_APP_HOST_CHROME_FRAME_MULTI, + CHROME_APP_HOST_CHROME_FRAME_MULTI_CHROME_MULTI, + CHROME_APP_HOST_CHROME_MULTI, + CHROME_APP_HOST_CHROME_MULTI_CHROME_FRAME_READY_MODE, }; +// Validates the "install-application" Google Update product command. +void InstallationValidator::ValidateInstallAppCommand( + const ProductContext& ctx, + const AppCommand& command, + bool* is_valid) { + DCHECK(is_valid); + + CommandLine the_command(CommandLine::FromString(command.command_line())); + + FilePath expected_path( + installer::GetChromeInstallPath(ctx.system_install, ctx.dist) + .Append(installer::kChromeAppHostExe)); + + if (!FilePath::CompareEqualIgnoreCase(expected_path.value(), + the_command.GetProgram().value())) { + *is_valid = false; + LOG(ERROR) << "install-application command's path is not " + << expected_path.value() << ": " + << the_command.GetProgram().value(); + } + + + SwitchExpectations expected; + + expected.push_back( + std::make_pair(std::string(::switches::kAppsInstallFromManifestURL), + true)); + + ValidateCommandExpectations(ctx, the_command, expected, "install application", + is_valid); + + if (!command.sends_pings()) { + *is_valid = false; + LOG(ERROR) << "install-application command is not configured to send " + << "pings."; + } + + if (!command.is_web_accessible()) { + *is_valid = false; + LOG(ERROR) << "install-application command is not web accessible."; + } +} + // Validates the "quick-enable-cf" Google Update product command. void InstallationValidator::ValidateQuickEnableCfCommand( const ProductContext& ctx, @@ -186,6 +275,48 @@ void InstallationValidator::ValidateQuickEnableCfCommand( } } +// Validates the "quick-enable-application-host" Google Update product command. +void InstallationValidator::ValidateQuickEnableApplicationHostCommand( + const ProductContext& ctx, + const AppCommand& command, + bool* is_valid) { + DCHECK(is_valid); + + CommandLine the_command(CommandLine::FromString(command.command_line())); + + ValidateSetupPath(ctx, + the_command.GetProgram(), + "quick enable application host", + is_valid); + + SwitchExpectations expected; + + expected.push_back( + std::make_pair(std::string(switches::kChromeAppHost), true)); + expected.push_back(std::make_pair(std::string(switches::kSystemLevel), + false)); + expected.push_back(std::make_pair(std::string(switches::kMultiInstall), + true)); + + ValidateCommandExpectations(ctx, + the_command, + expected, + "quick enable application host", + is_valid); + + if (!command.sends_pings()) { + *is_valid = false; + LOG(ERROR) << "Quick-enable-application-host command is not configured to " + << "send pings."; + } + + if (!command.is_web_accessible()) { + *is_valid = false; + LOG(ERROR) << "Quick-enable-application-host command is not web " + << "accessible."; + } +} + // Validates a product's set of Google Update product commands against a // collection of expectations. void InstallationValidator::ValidateAppCommandExpectations( @@ -232,18 +363,23 @@ void InstallationValidator::ValidateBinariesCommands( bool* is_valid) { DCHECK(is_valid); - // The quick-enable-cf command must be present if Chrome is installed either - // alone or with CF in ready-mode. + // The quick-enable-cf command must be present if Chrome Binaries are + // installed and Chrome Frame is not installed (or installed in ready mode). const ChannelInfo& channel = ctx.state.channel(); - const ProductState* chrome_state = ctx.machine_state.GetProductState( - ctx.system_install, BrowserDistribution::CHROME_BROWSER); + const ProductState* binaries_state = ctx.machine_state.GetProductState( + ctx.system_install, BrowserDistribution::CHROME_BINARIES); const ProductState* cf_state = ctx.machine_state.GetProductState( ctx.system_install, BrowserDistribution::CHROME_FRAME); CommandExpectations expectations; - if (chrome_state != NULL && (cf_state == NULL || channel.IsReadyMode())) - expectations[kCmdQuickEnableCf] = &ValidateQuickEnableCfCommand; + if (binaries_state != NULL) { + if (cf_state == NULL || channel.IsReadyMode()) + expectations[kCmdQuickEnableCf] = &ValidateQuickEnableCfCommand; + + expectations[kCmdQuickEnableApplicationHost] = + &ValidateQuickEnableApplicationHostCommand; + } ValidateAppCommandExpectations(ctx, expectations, is_valid); } @@ -310,8 +446,28 @@ void InstallationValidator::ValidateBinaries( << "\""; } - // Chrome or Chrome Frame must be present - if (chrome_state == NULL && cf_state == NULL) { + // ap must have -apphost iff Chrome Frame is installed multi + const ProductState* app_host_state = machine_state.GetProductState( + system_install, BrowserDistribution::CHROME_APP_HOST); + if (app_host_state != NULL) { + if (!app_host_state->is_multi_install()) { + *is_valid = false; + LOG(ERROR) << "Chrome App Host is installed in non-multi mode."; + } + if (!channel.IsAppHost()) { + *is_valid = false; + LOG(ERROR) << "Chrome Binaries are missing \"-apphost\" in channel" + " name: \"" << channel.value() << "\""; + } + } else if (channel.IsAppHost()) { + *is_valid = false; + LOG(ERROR) << "Chrome Binaries have \"-apphost\" in channel name, yet " + "Chrome App Host is not installed: \"" << channel.value() + << "\""; + } + + // Chrome, Chrome Frame, or App Host must be present + if (chrome_state == NULL && cf_state == NULL && app_host_state == NULL) { *is_valid = false; LOG(ERROR) << "Chrome Binaries are present with no other products."; } @@ -323,12 +479,12 @@ void InstallationValidator::ValidateBinaries( << "Chrome Binaries are present yet Chrome is not multi-install."; } - // Chrome Frame must be multi-install if Chrome is not present. - if (cf_state != NULL && chrome_state == NULL && + // Chrome Frame must be multi-install if Chrome & App Host are not present. + if (cf_state != NULL && app_host_state == NULL && chrome_state == NULL && !cf_state->is_multi_install()) { *is_valid = false; - LOG(ERROR) << "Chrome Binaries are present without Chrome yet Chrome Frame " - "is not multi-install."; + LOG(ERROR) << "Chrome Binaries are present without Chrome nor App Host " + << "yet Chrome Frame is not multi-install."; } ChromeBinariesRules binaries_rules; @@ -483,24 +639,44 @@ void InstallationValidator::ValidateMultiInstallProduct( const ProductState* binaries = ctx.machine_state.GetProductState(ctx.system_install, BrowserDistribution::CHROME_BINARIES); - DCHECK(binaries); - - // Version must match that of binaries. - if (ctx.state.version().CompareTo(binaries->version()) != 0) { - *is_valid = false; - LOG(ERROR) << "Version of " << ctx.dist->GetAppShortCutName() - << " (" << ctx.state.version().GetString() << ") does not " - "match that of Chrome Binaries (" - << binaries->version().GetString() << ")."; - } + if (!binaries) { + if (ctx.dist->GetType() == BrowserDistribution::CHROME_APP_HOST) { + if (!ctx.machine_state.GetProductState( + true, // system-level + BrowserDistribution::CHROME_BINARIES) && + !ctx.machine_state.GetProductState( + true, // system-level + BrowserDistribution::CHROME_BROWSER)) { + *is_valid = false; + LOG(ERROR) << ctx.dist->GetAppShortCutName() + << " (" << ctx.state.version().GetString() << ") is " + << "installed without Chrome Binaries or a system-level " + << "Chrome."; + } + } else { + *is_valid = false; + LOG(ERROR) << ctx.dist->GetAppShortCutName() + << " (" << ctx.state.version().GetString() << ") is installed " + << "without Chrome Binaries."; + } + } else { + // Version must match that of binaries. + if (ctx.state.version().CompareTo(binaries->version()) != 0) { + *is_valid = false; + LOG(ERROR) << "Version of " << ctx.dist->GetAppShortCutName() + << " (" << ctx.state.version().GetString() << ") does not " + "match that of Chrome Binaries (" + << binaries->version().GetString() << ")."; + } - // Channel value must match that of binaries. - if (!ctx.state.channel().Equals(binaries->channel())) { - *is_valid = false; - LOG(ERROR) << "Channel name of " << ctx.dist->GetAppShortCutName() - << " (" << ctx.state.channel().value() - << ") does not match that of Chrome Binaries (" - << binaries->channel().value() << ")."; + // Channel value must match that of binaries. + if (!ctx.state.channel().Equals(binaries->channel())) { + *is_valid = false; + LOG(ERROR) << "Channel name of " << ctx.dist->GetAppShortCutName() + << " (" << ctx.state.channel().value() + << ") does not match that of Chrome Binaries (" + << binaries->channel().value() << ")."; + } } } @@ -510,8 +686,13 @@ void InstallationValidator::ValidateAppCommands( bool* is_valid) { DCHECK(is_valid); - // Products are not expected to have any commands. - ValidateAppCommandExpectations(ctx, CommandExpectations(), is_valid); + CommandExpectations expectations; + + if (ctx.dist->GetType() == BrowserDistribution::CHROME_APP_HOST) { + expectations[kCmdInstallApp] = &ValidateInstallAppCommand; + } + + ValidateAppCommandExpectations(ctx, expectations, is_valid); } // Validates usagestats for the product or binaries in |ctx|. @@ -609,6 +790,25 @@ bool InstallationValidator::ValidateInstallationTypeForState( *type = static_cast<InstallationType>(*type | cf_bit); } + // Is Chrome App Host installed? + product_state = + machine_state.GetProductState(system_level, + BrowserDistribution::CHROME_APP_HOST); + if (product_state != NULL) { + ChromeAppHostRules chrome_app_host_rules; + ValidateProduct(machine_state, system_level, *product_state, + chrome_app_host_rules, &rock_on); + *type = static_cast<InstallationType>(*type | ProductBits::CHROME_APP_HOST); + if (system_level) { + LOG(ERROR) << "Chrome App Host must not be installed at system level."; + rock_on = false; + } + if (!product_state->is_multi_install()) { + LOG(ERROR) << "Chrome App Host must always be multi-install."; + rock_on = false; + } + } + DCHECK_NE(std::find(&kInstallationTypes[0], &kInstallationTypes[arraysize(kInstallationTypes)], *type), diff --git a/chrome/installer/util/installation_validator.h b/chrome/installer/util/installation_validator.h index ee8cc1c..d06ab9d 100644 --- a/chrome/installer/util/installation_validator.h +++ b/chrome/installer/util/installation_validator.h @@ -1,4 +1,4 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Copyright (c) 2012 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -36,6 +36,7 @@ class InstallationValidator { CHROME_FRAME_SINGLE = 0x04, CHROME_FRAME_MULTI = 0x08, CHROME_FRAME_READY_MODE = 0x10, + CHROME_APP_HOST = 0x20, }; }; // class ProductBits @@ -58,6 +59,23 @@ class InstallationValidator { ProductBits::CHROME_FRAME_MULTI | ProductBits::CHROME_MULTI, CHROME_FRAME_READY_MODE_CHROME_MULTI = ProductBits::CHROME_FRAME_READY_MODE | ProductBits::CHROME_MULTI, + CHROME_APP_HOST = + ProductBits::CHROME_APP_HOST, + CHROME_APP_HOST_CHROME_FRAME_SINGLE = + ProductBits::CHROME_APP_HOST | ProductBits::CHROME_FRAME_SINGLE, + CHROME_APP_HOST_CHROME_FRAME_SINGLE_CHROME_MULTI = + ProductBits::CHROME_APP_HOST | ProductBits::CHROME_FRAME_SINGLE | + ProductBits::CHROME_MULTI, + CHROME_APP_HOST_CHROME_FRAME_MULTI = + ProductBits::CHROME_APP_HOST | ProductBits::CHROME_FRAME_MULTI, + CHROME_APP_HOST_CHROME_FRAME_MULTI_CHROME_MULTI = + ProductBits::CHROME_APP_HOST | ProductBits::CHROME_FRAME_MULTI | + ProductBits::CHROME_MULTI, + CHROME_APP_HOST_CHROME_MULTI = + ProductBits::CHROME_APP_HOST | ProductBits::CHROME_MULTI, + CHROME_APP_HOST_CHROME_MULTI_CHROME_FRAME_READY_MODE = + ProductBits::CHROME_APP_HOST | ProductBits::CHROME_MULTI | + ProductBits::CHROME_FRAME_READY_MODE, }; // Validates |machine_state| at user or system level, returning true if valid. @@ -136,6 +154,24 @@ class InstallationValidator { const ProductState& product_state) const OVERRIDE; }; + // Validation rules for Chrome App Host. + class ChromeAppHostRules : public ProductRules { + public: + virtual BrowserDistribution::Type distribution_type() const OVERRIDE; + virtual void AddUninstallSwitchExpectations( + const InstallationState& machine_state, + bool system_install, + const ProductState& product_state, + SwitchExpectations* expectations) const OVERRIDE; + virtual void AddRenameSwitchExpectations( + const InstallationState& machine_state, + bool system_install, + const ProductState& product_state, + SwitchExpectations* expectations) const OVERRIDE; + virtual bool UsageStatsAllowed( + const ProductState& product_state) const OVERRIDE; + }; + // Validation rules for the multi-install Chrome binaries. class ChromeBinariesRules : public ProductRules { public: @@ -162,9 +198,17 @@ class InstallationValidator { const ProductRules& rules; }; + static void ValidateInstallAppCommand(const ProductContext& ctx, + const AppCommand& command, + bool* is_valid); static void ValidateQuickEnableCfCommand(const ProductContext& ctx, const AppCommand& command, bool* is_valid); + static void ValidateQuickEnableApplicationHostCommand( + const ProductContext& ctx, + const AppCommand& command, + bool* is_valid); + static void ValidateAppCommandExpectations( const ProductContext& ctx, const CommandExpectations& expectations, diff --git a/chrome/installer/util/installation_validator_unittest.cc b/chrome/installer/util/installation_validator_unittest.cc index 56e854c..c997110 100644 --- a/chrome/installer/util/installation_validator_unittest.cc +++ b/chrome/installer/util/installation_validator_unittest.cc @@ -78,11 +78,14 @@ class FakeProductState : public ProductState { const char* version, int channel_modifiers, Vehicle vehicle); + void AddQuickEnableApplicationHostCommand(BrowserDistribution::Type dist_type, + Level install_level, + const char* version, + int channel_modifiers); void AddQuickEnableCfCommand(BrowserDistribution::Type dist_type, Level install_level, const char* version, int channel_modifiers); - void RemoveQuickEnableCfCommand(BrowserDistribution::Type dist_type); void set_multi_install(bool is_multi_install) { multi_install_ = is_multi_install; } @@ -194,6 +197,23 @@ void FakeProductState::SetUninstallCommand(BrowserDistribution::Type dist_type, uninstall_command_.AppendSwitch(installer::switches::kMsi); } +// Adds the "quick-enable-application-host" Google Update product command. +void FakeProductState::AddQuickEnableApplicationHostCommand( + BrowserDistribution::Type dist_type, + Level install_level, + const char* version, + int channel_modifiers) { + DCHECK_EQ(dist_type, BrowserDistribution::CHROME_BINARIES); + DCHECK_NE(channel_modifiers & CM_MULTI, 0); + + CommandLine cmd_line(GetSetupExePath(dist_type, install_level, version, + channel_modifiers)); + cmd_line.AppendSwitch(installer::switches::kMultiInstall); + cmd_line.AppendSwitch(installer::switches::kChromeAppHost); + commands_.Set(installer::kCmdQuickEnableApplicationHost, + AppCommand(cmd_line.GetCommandLineString(), true, true)); +} + // Adds the "quick-enable-cf" Google Update product command. void FakeProductState::AddQuickEnableCfCommand( BrowserDistribution::Type dist_type, @@ -213,14 +233,6 @@ void FakeProductState::AddQuickEnableCfCommand( AppCommand(cmd_line.GetCommandLineString(), true, true)); } -// Removes the "quick-enable-cf" Google Update product command. -void FakeProductState::RemoveQuickEnableCfCommand( - BrowserDistribution::Type dist_type) { - DCHECK_EQ(dist_type, BrowserDistribution::CHROME_BINARIES); - - commands_.Remove(installer::kCmdQuickEnableCf); -} - } // namespace // Fixture for testing the InstallationValidator. Errors logged by the @@ -412,6 +424,12 @@ void InstallationValidatorTest::MakeProductState( state->AddQuickEnableCfCommand(prod_type, install_level, chrome::kChromeVersion, channel_modifiers); } + if (prod_type == BrowserDistribution::CHROME_BINARIES) { + state->AddQuickEnableApplicationHostCommand(prod_type, + install_level, + chrome::kChromeVersion, + channel_modifiers); + } } // static diff --git a/chrome/installer/util/installer_state.cc b/chrome/installer/util/installer_state.cc index 34ceff4..9e69398 100644 --- a/chrome/installer/util/installer_state.cc +++ b/chrome/installer/util/installer_state.cc @@ -126,6 +126,117 @@ void InstallerState::Initialize(const CommandLine& command_line, VLOG(1) << (is_uninstall ? "Uninstall" : "Install") << " distribution: " << p->distribution()->GetAppShortCutName(); } + if (prefs.install_chrome_app_host()) { + Product* p = + AddProductFromPreferences(BrowserDistribution::CHROME_APP_HOST, prefs, + machine_state); + VLOG(1) << (is_uninstall ? "Uninstall" : "Install") + << " distribution: " << p->distribution()->GetAppShortCutName(); + } + + if (!is_uninstall && is_multi_install()) { + bool need_binaries = false; + if (FindProduct(BrowserDistribution::CHROME_APP_HOST)) { + // App Host will happily use Chrome at system level, or binaries at system + // level, even if app host is user level. + const ProductState* chrome_state = machine_state.GetProductState( + true, // system level + BrowserDistribution::CHROME_BROWSER); + // If Chrome is at system-level, multi- or otherwise. We'll use it. + if (!chrome_state) { + const ProductState* binaries_state = machine_state.GetProductState( + true, // system level + BrowserDistribution::CHROME_BINARIES); + if (!binaries_state) + need_binaries = true; + } + } + + // Chrome/Chrome Frame multi need Binaries at their own level. + if (FindProduct(BrowserDistribution::CHROME_BROWSER)) + need_binaries = true; + + if (FindProduct(BrowserDistribution::CHROME_FRAME)) + need_binaries = true; + + if (need_binaries && !FindProduct(BrowserDistribution::CHROME_BINARIES)) { + // Force binaries to be installed/updated. + Product* p = + AddProductFromPreferences(BrowserDistribution::CHROME_BINARIES, + prefs, + machine_state); + VLOG(1) << "Install distribution: " + << p->distribution()->GetAppShortCutName(); + } + } + + if (is_uninstall && prefs.is_multi_install()) { + if (FindProduct(BrowserDistribution::CHROME_BROWSER)) { + const ProductState* chrome_frame_state = machine_state.GetProductState( + system_install(), BrowserDistribution::CHROME_FRAME); + + if (chrome_frame_state != NULL && + chrome_frame_state->uninstall_command().HasSwitch( + switches::kChromeFrameReadyMode) && + !FindProduct(BrowserDistribution::CHROME_FRAME)) { + // Chrome Frame is installed in Ready Mode. Remove it along with Chrome. + Product* p = AddProductFromPreferences( + BrowserDistribution::CHROME_FRAME, prefs, machine_state); + + VLOG(1) << "Uninstall distribution: " + << p->distribution()->GetAppShortCutName(); + } + } + + bool keep_binaries = false; + // Look for a product that is not the binaries and that is not being + // uninstalled. If not found, binaries are uninstalled too. + for (size_t i = 0; i < BrowserDistribution::NUM_TYPES; ++i) { + BrowserDistribution::Type type = + static_cast<BrowserDistribution::Type>(i); + + if (type == BrowserDistribution::CHROME_BINARIES) + continue; + + if (machine_state.GetProductState(system_install(), type) == NULL) { + // The product is not installed. + continue; + } + + // The product is installed. + + if (!FindProduct(type)) { + // The product is not being uninstalled. + if (type != BrowserDistribution::CHROME_APP_HOST) { + keep_binaries = true; + break; + } else { + // If binaries/chrome are at system-level, we can discard them at + // user-level... + if (!machine_state.GetProductState( + true, // system-level + BrowserDistribution::CHROME_BROWSER) && + !machine_state.GetProductState( + true, // system-level + BrowserDistribution::CHROME_BINARIES)) { + // ... otherwise keep them. + keep_binaries = true; + break; + } + + } + } + + // The product is being uninstalled. + } + if (!keep_binaries) { + Product* p = + AddProductFromPreferences(BrowserDistribution::CHROME_BINARIES, prefs, + machine_state); + VLOG(1) << (is_uninstall ? "Uninstall" : "Install") + << " distribution: " << p->distribution()->GetAppShortCutName(); + } + } BrowserDistribution* operand = NULL; @@ -141,17 +252,26 @@ void InstallerState::Initialize(const CommandLine& command_line, operand = multi_package_distribution_; operation_ = MULTI_UPDATE; } else { - // Initial and over installs will always take place under one of the - // product app guids. Chrome Frame's will be used if only Chrome Frame - // is being installed. In all other cases, Chrome's is used. operation_ = MULTI_INSTALL; } + // Initial, over, and un-installs will always take place under one of the + // product app guids (Chrome, Chrome Frame, or App Host, in order of + // preference). if (operand == NULL) { + BrowserDistribution::Type operand_distribution_type = + BrowserDistribution::CHROME_BINARIES; + if (prefs.install_chrome()) + operand_distribution_type = BrowserDistribution::CHROME_BROWSER; + else if (prefs.install_chrome_frame()) + operand_distribution_type = BrowserDistribution::CHROME_FRAME; + else if (prefs.install_chrome_app_host()) + operand_distribution_type = BrowserDistribution::CHROME_APP_HOST; + else + NOTREACHED(); + operand = BrowserDistribution::GetSpecificDistribution( - prefs.install_chrome() ? - BrowserDistribution::CHROME_BROWSER : - BrowserDistribution::CHROME_FRAME); + operand_distribution_type); } state_key_ = operand->GetStateKey(); diff --git a/chrome/installer/util/installer_state.h b/chrome/installer/util/installer_state.h index 5fe4fc8..6e18ebd 100644 --- a/chrome/installer/util/installer_state.h +++ b/chrome/installer/util/installer_state.h @@ -1,4 +1,4 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Copyright (c) 2012 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -37,6 +37,12 @@ typedef std::vector<Product*> Products; // Encapsulates the state of the current installation operation. Only valid // for installs and upgrades (not for uninstalls or non-install commands). +// This class interprets the command-line arguments and master preferences and +// determines the operations to be performed. For example, the Chrome Binaries +// are automatically added if required in multi-install mode. +// TODO(erikwright): This is now used a fair bit during uninstall, and +// InstallerState::Initialize() contains a lot of code for uninstall. The class +// comment should probably be updated. // TODO(grt): Rename to InstallerEngine/Conductor or somesuch? class InstallerState { public: diff --git a/chrome/installer/util/master_preferences.cc b/chrome/installer/util/master_preferences.cc index 008c148..59f7270 100644 --- a/chrome/installer/util/master_preferences.cc +++ b/chrome/installer/util/master_preferences.cc @@ -82,6 +82,7 @@ namespace installer { MasterPreferences::MasterPreferences() : distribution_(NULL), preferences_read_from_file_(false), chrome_(true), + chrome_app_host_(false), chrome_frame_(false), multi_install_(false) { InitializeFromCommandLine(*CommandLine::ForCurrentProcess()); @@ -91,6 +92,7 @@ MasterPreferences::MasterPreferences(const CommandLine& cmd_line) : distribution_(NULL), preferences_read_from_file_(false), chrome_(true), + chrome_app_host_(false), chrome_frame_(false), multi_install_(false) { InitializeFromCommandLine(cmd_line); @@ -98,7 +100,8 @@ MasterPreferences::MasterPreferences(const CommandLine& cmd_line) MasterPreferences::MasterPreferences(const FilePath& prefs_path) : distribution_(NULL), preferences_read_from_file_(false), - chrome_(true), chrome_frame_(false), multi_install_(false) { + chrome_(true), chrome_app_host_(false), chrome_frame_(false), + multi_install_(false) { master_dictionary_.reset(ParseDistributionPreferences(prefs_path)); if (!master_dictionary_.get()) { @@ -136,6 +139,8 @@ void MasterPreferences::InitializeFromCommandLine(const CommandLine& cmd_line) { } translate_switches[] = { { installer::switches::kAutoLaunchChrome, installer::master_preferences::kAutoLaunchChrome }, + { installer::switches::kChromeAppHost, + installer::master_preferences::kChromeAppHost }, { installer::switches::kChrome, installer::master_preferences::kChrome }, { installer::switches::kChromeFrame, @@ -207,10 +212,12 @@ void MasterPreferences::InitializeProductFlags() { // Make sure we start out with the correct defaults. multi_install_ = false; chrome_frame_ = false; + chrome_app_host_ = false; chrome_ = true; GetBool(installer::master_preferences::kMultiInstall, &multi_install_); GetBool(installer::master_preferences::kChromeFrame, &chrome_frame_); + GetBool(installer::master_preferences::kChromeAppHost, &chrome_app_host_); // When multi-install is specified, the checks are pretty simple (in theory): // In order to be installed/uninstalled, each product must have its switch diff --git a/chrome/installer/util/master_preferences.h b/chrome/installer/util/master_preferences.h index 8baf9d6a..e698d1d 100644 --- a/chrome/installer/util/master_preferences.h +++ b/chrome/installer/util/master_preferences.h @@ -164,6 +164,10 @@ class MasterPreferences { return chrome_; } + bool install_chrome_app_host() const { + return chrome_app_host_; + } + bool install_chrome_frame() const { return chrome_frame_; } @@ -188,6 +192,7 @@ class MasterPreferences { base::DictionaryValue* distribution_; bool preferences_read_from_file_; bool chrome_; + bool chrome_app_host_; bool chrome_frame_; bool multi_install_; diff --git a/chrome/installer/util/master_preferences_constants.cc b/chrome/installer/util/master_preferences_constants.cc index 2ee5557..8884ce0 100644 --- a/chrome/installer/util/master_preferences_constants.cc +++ b/chrome/installer/util/master_preferences_constants.cc @@ -9,6 +9,7 @@ namespace master_preferences { const char kAltShortcutText[] = "alternate_shortcut_text"; const char kAutoLaunchChrome[] = "auto_launch_chrome"; const char kChrome[] = "chrome"; + const char kChromeAppHost[] = "app_host"; const char kChromeFrame[] = "chrome_frame"; const char kChromeFrameReadyMode[] = "ready_mode"; const char kChromeShortcutIconIndex[] = "chrome_shortcut_icon_index"; diff --git a/chrome/installer/util/master_preferences_constants.h b/chrome/installer/util/master_preferences_constants.h index 45806bb..8a6f6c2 100644 --- a/chrome/installer/util/master_preferences_constants.h +++ b/chrome/installer/util/master_preferences_constants.h @@ -22,6 +22,8 @@ extern const char kAltShortcutText[]; extern const char kAutoLaunchChrome[]; // Boolean. This is to be a Chrome install. (When using MultiInstall) extern const char kChrome[]; +// Boolean. This is to be a Chrome App Host install. +extern const char kChromeAppHost[]; // Boolean. This is to be a Chrome Frame install. extern const char kChromeFrame[]; // Boolean. Chrome Frame is to be installed in ready-mode. diff --git a/chrome/installer/util/prebuild/create_string_rc.py b/chrome/installer/util/prebuild/create_string_rc.py index dd1043b..4dd2852 100755 --- a/chrome/installer/util/prebuild/create_string_rc.py +++ b/chrome/installer/util/prebuild/create_string_rc.py @@ -44,11 +44,14 @@ import FP kStringIds = [ 'IDS_PRODUCT_NAME', 'IDS_SXS_SHORTCUT_NAME', + 'IDS_PRODUCT_APP_HOST_NAME', + 'IDS_PRODUCT_BINARIES_NAME', 'IDS_PRODUCT_DESCRIPTION', 'IDS_PRODUCT_FRAME_NAME', 'IDS_UNINSTALL_CHROME', 'IDS_ABOUT_VERSION_COMPANY_NAME', 'IDS_INSTALL_HIGHER_VERSION', + 'IDS_INSTALL_HIGHER_VERSION_APP_HOST', 'IDS_INSTALL_HIGHER_VERSION_CF', 'IDS_INSTALL_HIGHER_VERSION_CB_CF', 'IDS_INSTALL_SYSTEM_LEVEL_EXISTS', diff --git a/chrome/installer/util/product.cc b/chrome/installer/util/product.cc index f2ab2a7..7747401 100644 --- a/chrome/installer/util/product.cc +++ b/chrome/installer/util/product.cc @@ -10,6 +10,8 @@ #include "base/logging.h" #include "base/process_util.h" #include "base/win/registry.h" +#include "chrome/installer/util/chrome_app_host_operations.h" +#include "chrome/installer/util/chrome_binaries_operations.h" #include "chrome/installer/util/chrome_browser_operations.h" #include "chrome/installer/util/chrome_browser_sxs_operations.h" #include "chrome/installer/util/chrome_frame_operations.h" @@ -36,6 +38,12 @@ Product::Product(BrowserDistribution* distribution) case BrowserDistribution::CHROME_FRAME: operations_.reset(new ChromeFrameOperations()); break; + case BrowserDistribution::CHROME_APP_HOST: + operations_.reset(new ChromeAppHostOperations()); + break; + case BrowserDistribution::CHROME_BINARIES: + operations_.reset(new ChromeBinariesOperations()); + break; default: NOTREACHED() << "Unsupported BrowserDistribution::Type: " << distribution->GetType(); diff --git a/chrome/installer/util/product.h b/chrome/installer/util/product.h index 4b4ec65..eabc3c9 100644 --- a/chrome/installer/util/product.h +++ b/chrome/installer/util/product.h @@ -56,6 +56,14 @@ class Product { return distribution_->GetType() == BrowserDistribution::CHROME_FRAME; } + bool is_chrome_app_host() const { + return distribution_->GetType() == BrowserDistribution::CHROME_APP_HOST; + } + + bool is_chrome_binaries() const { + return distribution_->GetType() == BrowserDistribution::CHROME_BINARIES; + } + bool HasOption(const std::wstring& option) const { return options_.find(option) != options_.end(); } diff --git a/chrome/installer/util/util_constants.cc b/chrome/installer/util/util_constants.cc index cc444be..1e613ce 100644 --- a/chrome/installer/util/util_constants.cc +++ b/chrome/installer/util/util_constants.cc @@ -15,6 +15,9 @@ const char kAutoLaunchChrome[] = "auto-launch-chrome"; // Currently this is only required when used in combination with kMultiInstall. const char kChrome[] = "chrome"; +// Install Chrome App Host. +const char kChromeAppHost[] = "app-host"; + // Install Chrome Frame. const char kChromeFrame[] = "chrome-frame"; @@ -161,6 +164,7 @@ const char kToastResultsKey[] = "toast-results-key"; } // namespace switches +const wchar_t kChromeAppHostExe[] = L"app_host.exe"; const wchar_t kChromeDll[] = L"chrome.dll"; const wchar_t kChromeExe[] = L"chrome.exe"; const wchar_t kChromeFrameDll[] = L"npchrome_frame.dll"; @@ -170,6 +174,9 @@ const wchar_t kChromeFrameReadyModeField[] = L"ChromeFrameReadyMode"; const wchar_t kChromeLauncherExe[] = L"chrome_launcher.exe"; const wchar_t kChromeNewExe[] = L"new_chrome.exe"; const wchar_t kChromeOldExe[] = L"old_chrome.exe"; +const wchar_t kCmdInstallApp[] = L"install-application"; +const wchar_t kCmdQuickEnableApplicationHost[] = + L"quick-enable-application-host"; const wchar_t kCmdQuickEnableCf[] = L"quick-enable-cf"; const wchar_t kDelegateExecuteExe[] = L"delegate_execute.exe"; const wchar_t kGoogleChromeInstallSubDir1[] = L"Google"; diff --git a/chrome/installer/util/util_constants.h b/chrome/installer/util/util_constants.h index 81e2d73..b8685db 100644 --- a/chrome/installer/util/util_constants.h +++ b/chrome/installer/util/util_constants.h @@ -124,6 +124,7 @@ COMPILE_ASSERT(CREATING_VISUAL_MANIFEST == 17, namespace switches { extern const char kAutoLaunchChrome[]; extern const char kChrome[]; +extern const char kChromeAppHost[]; extern const char kChromeFrame[]; extern const char kChromeFrameQuickEnable[]; extern const char kChromeFrameReadyMode[]; @@ -165,6 +166,7 @@ extern const char kExperimentGroup[]; extern const char kToastResultsKey[]; } // namespace switches +extern const wchar_t kChromeAppHostExe[]; extern const wchar_t kChromeDll[]; extern const wchar_t kChromeExe[]; extern const wchar_t kChromeFrameDll[]; @@ -174,6 +176,8 @@ extern const wchar_t kChromeFrameReadyModeField[]; extern const wchar_t kChromeLauncherExe[]; extern const wchar_t kChromeOldExe[]; extern const wchar_t kChromeNewExe[]; +extern const wchar_t kCmdInstallApp[]; +extern const wchar_t kCmdQuickEnableApplicationHost[]; extern const wchar_t kCmdQuickEnableCf[]; extern const wchar_t kDelegateExecuteExe[]; extern const wchar_t kGoogleChromeInstallSubDir1[]; |