summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorgrt@chromium.org <grt@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-01-25 16:44:37 +0000
committergrt@chromium.org <grt@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-01-25 16:44:37 +0000
commitf0260d27d34e40f2e619fb7a16dcd7f9d63fc683 (patch)
tree7e7c9e83bbd2f67b4bbbe11d076c7cc70abd8855
parentce7937429f63f3d966346fcd973d720f268cd888 (diff)
downloadchromium_src-f0260d27d34e40f2e619fb7a16dcd7f9d63fc683.zip
chromium_src-f0260d27d34e40f2e619fb7a16dcd7f9d63fc683.tar.gz
chromium_src-f0260d27d34e40f2e619fb7a16dcd7f9d63fc683.tar.bz2
More installer refactoring in the interest of fixing some bugs and cleaning things up:
- Introduced ProductOperations: an interface implemented for each product that takes care of product-specific functions. Each Product owns an instance and delegates certain operations to it. - Removed the use of MasterPreferences by BrowserDistribution so that the former isn't needed outside of the installer. - Replaced PackageProperties with a new BrowserDistribution type (CHROME_BINARIES) - Plumbed the concept of InstallerState more thoroughly through installer - Removed ProductPackageMapping and Package - Moved more registry read ops into ProductState - Validation of products to be installed is now done in CheckPreInstallConditions - Ignore --chrome-frame --ready-mode if chrome is also being installed/updated and a SxS GCF is found (chrome is updated). - Migrates existing single-install Chrome to multi-install where appropriate. - Fixes update to Chrome's uninstallation arguments when Chrome Frame is uninstalled. - Removed dead code from install.cc. - Added code to update products' "ap" values when ready-mode is accepted. - Skip post-install things such as launching the browser when Chrome was implicitly added to the install/upgrade process by virtue of being part of a multi-install. BUG=61609 TEST=run the installer, see it work. existing tests in installer_util_unittests have been updated; new tests are included for ProductState, ChannelInfo, etc. Review URL: http://codereview.chromium.org/6288009 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@72497 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--chrome/chrome_installer.gypi9
-rw-r--r--chrome/chrome_installer_util.gypi15
-rw-r--r--chrome/common/chrome_paths_win.cc4
-rw-r--r--chrome/installer/setup/chrome_frame_ready_mode.cc314
-rw-r--r--chrome/installer/setup/chrome_frame_ready_mode.h13
-rw-r--r--chrome/installer/setup/install.cc248
-rw-r--r--chrome/installer/setup/install.h15
-rw-r--r--chrome/installer/setup/install_worker.cc412
-rw-r--r--chrome/installer/setup/install_worker.h36
-rw-r--r--chrome/installer/setup/install_worker_unittest.cc54
-rw-r--r--chrome/installer/setup/setup_main.cc466
-rw-r--r--chrome/installer/setup/setup_unittests.rc65
-rw-r--r--chrome/installer/setup/setup_unittests_resource.h18
-rw-r--r--chrome/installer/setup/setup_util.cc1
-rw-r--r--chrome/installer/setup/uninstall.cc209
-rw-r--r--chrome/installer/util/browser_distribution.cc92
-rw-r--r--chrome/installer/util/browser_distribution.h40
-rw-r--r--chrome/installer/util/browser_distribution_unittest.cc22
-rw-r--r--chrome/installer/util/channel_info.cc12
-rw-r--r--chrome/installer/util/channel_info.h4
-rw-r--r--chrome/installer/util/channel_info_unittest.cc36
-rw-r--r--chrome/installer/util/chrome_browser_operations.cc82
-rw-r--r--chrome/installer/util/chrome_browser_operations.h54
-rw-r--r--chrome/installer/util/chrome_browser_sxs_operations.cc22
-rw-r--r--chrome/installer/util/chrome_browser_sxs_operations.h33
-rw-r--r--chrome/installer/util/chrome_frame_distribution.cc94
-rw-r--r--chrome/installer/util/chrome_frame_distribution.h20
-rw-r--r--chrome/installer/util/chrome_frame_operations.cc148
-rw-r--r--chrome/installer/util/chrome_frame_operations.h58
-rw-r--r--chrome/installer/util/chromium_binaries_distribution.cc105
-rw-r--r--chrome/installer/util/chromium_binaries_distribution.h64
-rw-r--r--chrome/installer/util/google_chrome_binaries_distribution.cc56
-rw-r--r--chrome/installer/util/google_chrome_binaries_distribution.h38
-rw-r--r--chrome/installer/util/google_chrome_distribution.cc18
-rw-r--r--chrome/installer/util/google_chrome_distribution.h8
-rw-r--r--chrome/installer/util/google_chrome_distribution_dummy.cc15
-rw-r--r--chrome/installer/util/google_chrome_distribution_unittest.cc6
-rw-r--r--chrome/installer/util/google_chrome_sxs_distribution.cc13
-rw-r--r--chrome/installer/util/google_chrome_sxs_distribution.h4
-rw-r--r--chrome/installer/util/google_update_settings.cc40
-rw-r--r--chrome/installer/util/google_update_settings.h4
-rw-r--r--chrome/installer/util/google_update_settings_unittest.cc46
-rw-r--r--chrome/installer/util/helper.cc107
-rw-r--r--chrome/installer/util/helper.h27
-rw-r--r--chrome/installer/util/helper_unittest.cc204
-rw-r--r--chrome/installer/util/install_util.cc26
-rw-r--r--chrome/installer/util/install_util.h12
-rw-r--r--chrome/installer/util/install_util_unittest.cc47
-rw-r--r--chrome/installer/util/installation_state.cc140
-rw-r--r--chrome/installer/util/installation_state.h77
-rw-r--r--chrome/installer/util/installer_state.cc385
-rw-r--r--chrome/installer/util/installer_state.h148
-rw-r--r--chrome/installer/util/installer_state_unittest.cc327
-rw-r--r--chrome/installer/util/package.cc188
-rw-r--r--chrome/installer/util/package.h90
-rw-r--r--chrome/installer/util/package_properties.cc94
-rw-r--r--chrome/installer/util/package_properties.h109
-rw-r--r--chrome/installer/util/package_properties_unittest.cc40
-rw-r--r--chrome/installer/util/package_unittest.cc190
-rw-r--r--chrome/installer/util/product.cc189
-rw-r--r--chrome/installer/util/product.h122
-rw-r--r--chrome/installer/util/product_operations.h74
-rw-r--r--chrome/installer/util/product_state_unittest.cc416
-rw-r--r--chrome/installer/util/product_unittest.cc129
-rw-r--r--chrome/installer/util/util_constants.cc4
-rw-r--r--chrome/installer/util/util_constants.h8
-rw-r--r--chrome_frame/ready_mode/ready_mode.cc13
67 files changed, 3511 insertions, 2668 deletions
diff --git a/chrome/chrome_installer.gypi b/chrome/chrome_installer.gypi
index 8aaf57f..4599130 100644
--- a/chrome/chrome_installer.gypi
+++ b/chrome/chrome_installer.gypi
@@ -86,18 +86,17 @@
'installer/util/delete_tree_work_item_unittest.cc',
'installer/util/google_chrome_distribution_unittest.cc',
'installer/util/google_update_settings_unittest.cc',
- 'installer/util/helper_unittest.cc',
'installer/util/install_util_unittest.cc',
+ 'installer/util/installer_state_unittest.cc',
'installer/util/installer_util_unittests.rc',
'installer/util/installer_util_unittests_resource.h',
'installer/util/language_selector_unittest.cc',
'installer/util/lzma_util_unittest.cc',
'installer/util/master_preferences_unittest.cc',
'installer/util/move_tree_work_item_unittest.cc',
- 'installer/util/package_properties_unittest.cc',
- 'installer/util/package_unittest.cc',
'installer/util/product_unittest.h',
'installer/util/product_unittest.cc',
+ 'installer/util/product_state_unittest.cc',
'installer/util/run_all_unittests.cc',
'installer/util/set_reg_value_work_item_unittest.cc',
'installer/util/shell_util_unittest.cc',
@@ -309,6 +308,7 @@
'msvs_guid': 'C0AE4E06-F023-460F-BC14-6302CEAC51F8',
'dependencies': [
'installer_util',
+ 'installer_util_strings',
'<(DEPTH)/base/base.gyp:base',
'<(DEPTH)/base/base.gyp:base_i18n',
'<(DEPTH)/base/base.gyp:test_support_base',
@@ -329,6 +329,9 @@
'installer/setup/run_all_unittests.cc',
'installer/setup/setup_constants.cc', # Move to lib
'installer/setup/setup_constants.h', # Move to lib
+ 'installer/setup/setup_unittests.rc',
+ 'installer/setup/setup_unittests.rc',
+ 'installer/setup/setup_unittests_resource.h',
'installer/setup/setup_util.cc',
'installer/setup/setup_util_unittest.cc',
],
diff --git a/chrome/chrome_installer_util.gypi b/chrome/chrome_installer_util.gypi
index 72601bb..3f852bc 100644
--- a/chrome/chrome_installer_util.gypi
+++ b/chrome/chrome_installer_util.gypi
@@ -17,6 +17,8 @@
'installer/util/channel_info.h',
'installer/util/chrome_frame_distribution.cc',
'installer/util/chrome_frame_distribution.h',
+ 'installer/util/chromium_binaries_distribution.cc',
+ 'installer/util/chromium_binaries_distribution.h',
'installer/util/conditional_work_item_list.cc',
'installer/util/conditional_work_item_list.h',
'installer/util/copy_tree_work_item.cc',
@@ -31,6 +33,8 @@
'installer/util/delete_reg_value_work_item.h',
'installer/util/delete_tree_work_item.cc',
'installer/util/delete_tree_work_item.h',
+ 'installer/util/google_chrome_binaries_distribution.cc',
+ 'installer/util/google_chrome_binaries_distribution.h',
'installer/util/google_chrome_sxs_distribution.cc',
'installer/util/google_chrome_sxs_distribution.h',
'installer/util/google_update_constants.cc',
@@ -53,10 +57,6 @@
'installer/util/master_preferences_constants.h',
'installer/util/move_tree_work_item.cc',
'installer/util/move_tree_work_item.h',
- 'installer/util/package.h',
- 'installer/util/package.cc',
- 'installer/util/package_properties.h',
- 'installer/util/package_properties.cc',
'installer/util/self_reg_work_item.cc',
'installer/util/self_reg_work_item.h',
'installer/util/set_reg_value_work_item.cc',
@@ -99,6 +99,12 @@
'<(DEPTH)/third_party/lzma_sdk/lzma_sdk.gyp:lzma_sdk',
],
'sources': [
+ 'installer/util/chrome_browser_operations.cc',
+ 'installer/util/chrome_browser_operations.h',
+ 'installer/util/chrome_browser_sxs_operations.cc',
+ 'installer/util/chrome_browser_sxs_operations.h',
+ 'installer/util/chrome_frame_operations.cc',
+ 'installer/util/chrome_frame_operations.h',
'installer/util/compat_checks.cc',
'installer/util/compat_checks.h',
'installer/util/delete_after_reboot_helper.cc',
@@ -115,6 +121,7 @@
'installer/util/master_preferences.h',
'installer/util/product.h',
'installer/util/product.cc',
+ 'installer/util/product_operations.h',
'installer/util/shell_util.cc',
'installer/util/shell_util.h',
],
diff --git a/chrome/common/chrome_paths_win.cc b/chrome/common/chrome_paths_win.cc
index 062c43b..1892b43 100644
--- a/chrome/common/chrome_paths_win.cc
+++ b/chrome/common/chrome_paths_win.cc
@@ -15,7 +15,6 @@
#include "base/path_service.h"
#include "chrome/common/chrome_constants.h"
#include "chrome/installer/util/browser_distribution.h"
-#include "chrome/installer/util/master_preferences.h"
namespace chrome {
@@ -32,8 +31,7 @@ bool GetChromeFrameUserDataDirectory(FilePath* result) {
if (!PathService::Get(base::DIR_LOCAL_APP_DATA, result))
return false;
BrowserDistribution* dist = BrowserDistribution::GetSpecificDistribution(
- BrowserDistribution::CHROME_FRAME,
- installer::MasterPreferences::ForCurrentProcess());
+ BrowserDistribution::CHROME_FRAME);
*result = result->Append(dist->GetInstallSubDir());
*result = result->Append(chrome::kUserDataDirname);
return true;
diff --git a/chrome/installer/setup/chrome_frame_ready_mode.cc b/chrome/installer/setup/chrome_frame_ready_mode.cc
index 26584d2..c647a9b 100644
--- a/chrome/installer/setup/chrome_frame_ready_mode.cc
+++ b/chrome/installer/setup/chrome_frame_ready_mode.cc
@@ -22,8 +22,6 @@
#include "chrome/installer/util/installer_state.h"
#include "chrome/installer/util/master_preferences.h"
#include "chrome/installer/util/master_preferences_constants.h"
-#include "chrome/installer/util/package.h"
-#include "chrome/installer/util/package_properties.h"
#include "chrome/installer/util/product.h"
#include "chrome/installer/util/util_constants.h"
#include "chrome/installer/util/work_item.h"
@@ -31,76 +29,100 @@
namespace installer {
-InstallStatus ChromeFrameReadyModeOptIn(const InstallerState& installer_state,
- const CommandLine& cmd_line) {
+// If Chrome is not multi-installed at the appropriate level, error.
+// If Chrome Frame is already multi-installed at the appropriate level, noop.
+// If Chrome Frame is single-installed at the appropriate level, error.
+// Add uninstall for Chrome Frame.
+// Update uninstall for Chrome.
+// Update ChannelInfo for all multi-installed products.
+// Remove ready-mode.
+InstallStatus ChromeFrameReadyModeOptIn(
+ const InstallationState& machine_state,
+ const InstallerState& installer_state) {
VLOG(1) << "Opting into Chrome Frame";
InstallStatus status = INSTALL_REPAIRED;
- const MasterPreferences& prefs = MasterPreferences::ForCurrentProcess();
- bool system_install = false;
- prefs.GetBool(master_preferences::kSystemLevel, &system_install);
- BrowserDistribution* cf = BrowserDistribution::GetSpecificDistribution(
- BrowserDistribution::CHROME_FRAME, prefs);
- DCHECK(cf->ShouldCreateUninstallEntry())
- << "Opting into CF should create an uninstall entry";
- BrowserDistribution* chrome = BrowserDistribution::GetSpecificDistribution(
- BrowserDistribution::CHROME_BROWSER, prefs);
-
- ActivePackageProperties package_properties;
-
- // Remove ChromeFrameReadyMode, update Chrome's uninstallation commands to
- // only uninstall Chrome, and add an entry to the Add/Remove Programs
- // dialog for GCF.
-
- FilePath path(GetChromeFrameInstallPath(true, system_install, cf));
- if (path.empty()) {
- LOG(ERROR) << "Conflicting installations";
- status = NON_MULTI_INSTALLATION_EXISTS;
- } else {
- InstallationState original_state;
- original_state.Initialize(prefs);
-
- scoped_refptr<Package> package(new Package(prefs.is_multi_install(),
- system_install, path, &package_properties));
- scoped_refptr<Product> cf_product(new Product(cf, package));
- DCHECK(cf_product->ShouldCreateUninstallEntry() || cf_product->IsMsi());
- scoped_refptr<Product> chrome_product(new Product(chrome, package));
- const ProductState* product_state =
- original_state.GetProductState(system_install, cf->GetType());
- if (product_state == NULL) {
- LOG(ERROR) << "No Chrome Frame installation found for opt-in.";
- return CHROME_NOT_INSTALLED;
- }
- scoped_ptr<WorkItemList> item_list(WorkItem::CreateWorkItemList());
-
- // This creates the uninstallation entry for GCF.
- AddUninstallShortcutWorkItems(cmd_line.GetProgram(),
- product_state->version(), item_list.get(), *cf_product.get());
- // This updates the Chrome uninstallation entries.
- AddUninstallShortcutWorkItems(cmd_line.GetProgram(),
- product_state->version(), item_list.get(), *chrome_product.get());
-
- // Add a work item to delete the ChromeFrameReadyMode registry value.
- HKEY root = system_install ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER;
- item_list->AddDeleteRegValueWorkItem(root, package_properties.GetStateKey(),
- kChromeFrameReadyModeField);
-
- // Delete the command elevation registry keys
- std::wstring version_key(cf->GetVersionKey());
- item_list->AddDeleteRegValueWorkItem(
- root, version_key, google_update::kRegCFTempOptOutCmdField);
- item_list->AddDeleteRegValueWorkItem(
- root, version_key, google_update::kRegCFEndTempOptOutCmdField);
- item_list->AddDeleteRegValueWorkItem(root, version_key,
- google_update::kRegCFOptOutCmdField);
- item_list->AddDeleteRegValueWorkItem(root, version_key,
- google_update::kRegCFOptInCmdField);
-
- if (!item_list->Do()) {
- LOG(ERROR) << "Failed to opt into GCF";
- item_list->Rollback();
- status = READY_MODE_OPT_IN_FAILED;
- }
+ // Make sure Chrome and Chrome Frame are both multi-installed.
+ const ProductState* chrome_state =
+ machine_state.GetProductState(installer_state.system_install(),
+ BrowserDistribution::CHROME_BROWSER);
+ const ProductState* cf_state =
+ machine_state.GetProductState(installer_state.system_install(),
+ BrowserDistribution::CHROME_FRAME);
+ if (chrome_state == NULL) {
+ LOG(ERROR) << "Chrome Frame opt-in requires multi-install of Chrome.";
+ return CHROME_NOT_INSTALLED;
+ }
+ if (!chrome_state->is_multi_install()) {
+ LOG(ERROR) << "Chrome Frame opt-in requires multi-install of Chrome.";
+ return NON_MULTI_INSTALLATION_EXISTS;
+ }
+ if (cf_state == NULL) {
+ LOG(ERROR) << "Chrome Frame opt-in requires multi-install of Chrome Frame.";
+ return CHROME_NOT_INSTALLED;
+ }
+ if (!cf_state->is_multi_install()) {
+ LOG(ERROR) << "Chrome Frame opt-in requires multi-install of Chrome Frame.";
+ return NON_MULTI_INSTALLATION_EXISTS;
+ }
+
+ // Create a new InstallerState to be used for this operation.
+ InstallerState opt_in_state(installer_state.level());
+
+ // Add the two products we're going to operate on.
+ const Product* chrome =
+ opt_in_state.AddProductFromState(BrowserDistribution::CHROME_BROWSER,
+ *chrome_state);
+ Product* cf =
+ opt_in_state.AddProductFromState(BrowserDistribution::CHROME_FRAME,
+ *cf_state);
+ // DCHECKs will fire in this case if it ever happens (it won't).
+ if (chrome == NULL || cf == NULL)
+ return READY_MODE_OPT_IN_FAILED;
+
+ // Turn off ready-mode on Chrome Frame, thereby making it fully installed.
+ if (!cf->SetOption(kOptionReadyMode, false)) {
+ LOG(WARNING)
+ << "Chrome Frame is already fully installed; opting-in nonetheless.";
+ }
+
+ // Update Chrome's uninstallation commands to only uninstall Chrome, and add
+ // an entry to the Add/Remove Programs dialog for GCF.
+ DCHECK(cf->ShouldCreateUninstallEntry() || opt_in_state.is_msi());
+
+ scoped_ptr<WorkItemList> item_list(WorkItem::CreateWorkItemList());
+
+ // This creates the uninstallation entry for GCF.
+ AddUninstallShortcutWorkItems(opt_in_state, cf_state->GetSetupPath(),
+ cf_state->version(), item_list.get(), *cf);
+ // This updates the Chrome uninstallation entries.
+ AddUninstallShortcutWorkItems(opt_in_state, chrome_state->GetSetupPath(),
+ chrome_state->version(), item_list.get(), *chrome);
+
+ // Add a work item to delete the ChromeFrameReadyMode registry value.
+ HKEY root = opt_in_state.root_key();
+ item_list->AddDeleteRegValueWorkItem(root,
+ opt_in_state.multi_package_binaries_distribution()->GetStateKey(),
+ kChromeFrameReadyModeField);
+
+ // Update the Google Update channel ("ap") value.
+ AddGoogleUpdateWorkItems(opt_in_state, item_list.get());
+
+ // Delete the command elevation registry keys
+ std::wstring version_key(cf->distribution()->GetVersionKey());
+ item_list->AddDeleteRegValueWorkItem(
+ root, version_key, google_update::kRegCFTempOptOutCmdField);
+ item_list->AddDeleteRegValueWorkItem(
+ root, version_key, google_update::kRegCFEndTempOptOutCmdField);
+ item_list->AddDeleteRegValueWorkItem(root, version_key,
+ google_update::kRegCFOptOutCmdField);
+ item_list->AddDeleteRegValueWorkItem(root, version_key,
+ google_update::kRegCFOptInCmdField);
+
+ if (!item_list->Do()) {
+ LOG(ERROR) << "Failed to opt into GCF";
+ item_list->Rollback();
+ status = READY_MODE_OPT_IN_FAILED;
}
return status;
@@ -111,100 +133,104 @@ const wchar_t kPostPlatformUAKey[] =
L"User Agent\\Post Platform";
const wchar_t kChromeFramePrefix[] = L"chromeframe/";
-InstallStatus ChromeFrameReadyModeTempOptOut(const CommandLine& cmd_line) {
+InstallStatus ChromeFrameReadyModeTempOptOut(
+ const InstallationState& machine_state,
+ const InstallerState& installer_state) {
VLOG(1) << "Temporarily opting out of Chrome Frame";
InstallStatus status = INSTALL_REPAIRED;
- const MasterPreferences& prefs = MasterPreferences::ForCurrentProcess();
- bool system_install = false;
- prefs.GetBool(master_preferences::kSystemLevel, &system_install);
- BrowserDistribution* cf = BrowserDistribution::GetSpecificDistribution(
- BrowserDistribution::CHROME_FRAME, prefs);
+ // Make sure Chrome Frame is multi-installed.
+ const ProductState* cf_state =
+ machine_state.GetProductState(installer_state.system_install(),
+ BrowserDistribution::CHROME_FRAME);
+ if (cf_state == NULL) {
+ LOG(ERROR)
+ << "Chrome Frame temp opt-out requires multi-install of Chrome Frame.";
+ return CHROME_NOT_INSTALLED;
+ }
+ if (!cf_state->is_multi_install()) {
+ LOG(ERROR)
+ << "Chrome Frame temp opt-out requires multi-install of Chrome Frame.";
+ return NON_MULTI_INSTALLATION_EXISTS;
+ }
- installer::ActivePackageProperties package_properties;
+ scoped_ptr<WorkItemList> item_list(WorkItem::CreateWorkItemList());
- // Remove the ChromeFrame user agent string from the registry, modify the
- // ReadyMode state flag.
- FilePath path(GetChromeFrameInstallPath(true, system_install, cf));
- if (path.empty()) {
- LOG(ERROR) << "Conflicting installations";
- status = NON_MULTI_INSTALLATION_EXISTS;
- } else {
- scoped_ptr<WorkItemList> item_list(WorkItem::CreateWorkItemList());
-
- HKEY root = system_install ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER;
-
- // Add a work item to delete the ChromeFrame user agent registry value.
- base::win::RegistryValueIterator values(root, kPostPlatformUAKey);
- while (values.Valid()) {
- const wchar_t* name = values.Name();
- if (StartsWith(name, kChromeFramePrefix, true)) {
- item_list->AddDeleteRegValueWorkItem(root, kPostPlatformUAKey, name);
- }
- ++values;
- }
+ HKEY root = installer_state.root_key();
- // Add a work item to update the Ready Mode state flag
- int64 timestamp = base::Time::Now().ToInternalValue();
- item_list->AddSetRegValueWorkItem(root, package_properties.GetStateKey(),
- kChromeFrameReadyModeField, timestamp,
- true);
-
- if (!item_list->Do()) {
- LOG(ERROR) << "Failed to temporarily opt out of GCF";
- item_list->Rollback();
- status = READY_MODE_TEMP_OPT_OUT_FAILED;
+ // Add a work item to delete the ChromeFrame user agent registry value.
+ base::win::RegistryValueIterator values(root, kPostPlatformUAKey);
+ while (values.Valid()) {
+ const wchar_t* name = values.Name();
+ if (StartsWith(name, kChromeFramePrefix, true)) {
+ item_list->AddDeleteRegValueWorkItem(root, kPostPlatformUAKey, name);
}
+ ++values;
+ }
+
+ // Add a work item to update the Ready Mode state flag
+ int64 timestamp = base::Time::Now().ToInternalValue();
+ BrowserDistribution* dist = BrowserDistribution::GetSpecificDistribution(
+ BrowserDistribution::CHROME_BINARIES);
+ item_list->AddSetRegValueWorkItem(root, dist->GetStateKey(),
+ kChromeFrameReadyModeField, timestamp,
+ true);
+
+ if (!item_list->Do()) {
+ LOG(ERROR) << "Failed to temporarily opt out of GCF";
+ item_list->Rollback();
+ status = READY_MODE_TEMP_OPT_OUT_FAILED;
}
return status;
}
-InstallStatus ChromeFrameReadyModeEndTempOptOut(const CommandLine& cmd_line) {
+InstallStatus ChromeFrameReadyModeEndTempOptOut(
+ const InstallationState& machine_state,
+ const InstallerState& installer_state) {
VLOG(1) << "Ending temporary opt-out of Chrome Frame";
InstallStatus status = INSTALL_REPAIRED;
- const MasterPreferences& prefs = MasterPreferences::ForCurrentProcess();
- bool system_install = false;
- prefs.GetBool(master_preferences::kSystemLevel, &system_install);
- BrowserDistribution* cf = BrowserDistribution::GetSpecificDistribution(
- BrowserDistribution::CHROME_FRAME, prefs);
-
- installer::ActivePackageProperties package_properties;
+ // Make sure Chrome Frame is multi-installed.
+ const ProductState* cf_state =
+ machine_state.GetProductState(installer_state.system_install(),
+ BrowserDistribution::CHROME_FRAME);
+ if (cf_state == NULL) {
+ LOG(ERROR)
+ << "Chrome Frame temp opt-out requires multi-install of Chrome Frame.";
+ return CHROME_NOT_INSTALLED;
+ }
+ if (!cf_state->is_multi_install()) {
+ LOG(ERROR)
+ << "Chrome Frame temp opt-out requires multi-install of Chrome Frame.";
+ return NON_MULTI_INSTALLATION_EXISTS;
+ }
// Replace the ChromeFrame user agent string in the registry, modify the
// ReadyMode state flag.
- FilePath path(GetChromeFrameInstallPath(true, system_install, cf));
- scoped_ptr<Version> installed_version(
- InstallUtil::GetChromeVersion(cf, system_install));
-
- if (path.empty()) {
- LOG(ERROR) << "Conflicting installations";
- status = NON_MULTI_INSTALLATION_EXISTS;
- } else if (installed_version == NULL) {
- LOG(ERROR) << "Failed to query installed version of Chrome Frame";
+ const Version& installed_version = cf_state->version();
+
+ scoped_ptr<WorkItemList> item_list(WorkItem::CreateWorkItemList());
+
+ HKEY root = installer_state.root_key();
+
+ std::wstring chrome_frame_ua_value_name(kChromeFramePrefix);
+ chrome_frame_ua_value_name += ASCIIToWide(installed_version.GetString());
+
+ // Store the Chrome Frame user agent string
+ item_list->AddSetRegValueWorkItem(root, kPostPlatformUAKey,
+ chrome_frame_ua_value_name, L"", true);
+ // Add a work item to update the Ready Mode state flag
+ BrowserDistribution* dist = BrowserDistribution::GetSpecificDistribution(
+ BrowserDistribution::CHROME_BINARIES);
+ item_list->AddSetRegValueWorkItem(root, dist->GetStateKey(),
+ kChromeFrameReadyModeField,
+ static_cast<int64>(1), true);
+
+ if (!item_list->Do()) {
+ LOG(ERROR) << "Failed to end temporary opt out of GCF";
+ item_list->Rollback();
status = READY_MODE_END_TEMP_OPT_OUT_FAILED;
- } else {
- scoped_ptr<WorkItemList> item_list(WorkItem::CreateWorkItemList());
-
- HKEY root = system_install ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER;
-
- std::wstring chrome_frame_ua_value_name = kChromeFramePrefix;
- chrome_frame_ua_value_name += ASCIIToWide(installed_version->GetString());
-
- // Store the Chrome Frame user agent string
- item_list->AddSetRegValueWorkItem(root, kPostPlatformUAKey,
- chrome_frame_ua_value_name, L"", true);
- // Add a work item to update the Ready Mode state flag
- item_list->AddSetRegValueWorkItem(root, package_properties.GetStateKey(),
- kChromeFrameReadyModeField,
- static_cast<int64>(1), true);
-
- if (!item_list->Do()) {
- LOG(ERROR) << "Failed to end temporary opt out of GCF";
- item_list->Rollback();
- status = READY_MODE_END_TEMP_OPT_OUT_FAILED;
- }
}
return status;
diff --git a/chrome/installer/setup/chrome_frame_ready_mode.h b/chrome/installer/setup/chrome_frame_ready_mode.h
index 35c9507..2541bb8 100644
--- a/chrome/installer/setup/chrome_frame_ready_mode.h
+++ b/chrome/installer/setup/chrome_frame_ready_mode.h
@@ -13,21 +13,26 @@ class CommandLine;
namespace installer {
enum InstallStatus;
+class InstallationState;
class InstallerState;
// Removes the ChromeFrameReadyMode flag from the registry, updates Chrome's
// uninstallation commands to only uninstall Chrome, and adds an entry to the
// Add/Remove Programs list for GCF.
-InstallStatus ChromeFrameReadyModeOptIn(const InstallerState& installer_state,
- const CommandLine& cmd_line);
+InstallStatus ChromeFrameReadyModeOptIn(const InstallationState& machine_state,
+ const InstallerState& installer_state);
// Unregisters the ChromeFrame user agent modification, sets a timestamp for
// restoring it.
-InstallStatus ChromeFrameReadyModeTempOptOut(const CommandLine& cmd_line);
+InstallStatus ChromeFrameReadyModeTempOptOut(
+ const InstallationState& machine_state,
+ const InstallerState& installer_state);
// Re-registers the ChromeFrame user agent modification, restores Ready Mode
// active state flag.
-InstallStatus ChromeFrameReadyModeEndTempOptOut(const CommandLine& cmd_line);
+InstallStatus ChromeFrameReadyModeEndTempOptOut(
+ const InstallationState& machine_state,
+ const InstallerState& installer_state);
} // namespace installer
diff --git a/chrome/installer/setup/install.cc b/chrome/installer/setup/install.cc
index dced77c..b8ae6fd 100644
--- a/chrome/installer/setup/install.cc
+++ b/chrome/installer/setup/install.cc
@@ -16,13 +16,9 @@
#include "base/scoped_ptr.h"
#include "base/string_util.h"
#include "base/utf_string_conversions.h"
-#include "base/win/registry.h"
#include "chrome/installer/setup/setup_constants.h"
#include "chrome/installer/setup/install_worker.h"
#include "chrome/installer/util/browser_distribution.h"
-#include "chrome/installer/util/channel_info.h"
-#include "chrome/installer/util/chrome_frame_distribution.h"
-#include "chrome/installer/util/conditional_work_item_list.h"
#include "chrome/installer/util/create_reg_key_work_item.h"
#include "chrome/installer/util/delete_after_reboot_helper.h"
#include "chrome/installer/util/google_update_constants.h"
@@ -32,8 +28,6 @@
#include "chrome/installer/util/installer_state.h"
#include "chrome/installer/util/master_preferences.h"
#include "chrome/installer/util/master_preferences_constants.h"
-#include "chrome/installer/util/package.h"
-#include "chrome/installer/util/package_properties.h"
#include "chrome/installer/util/product.h"
#include "chrome/installer/util/set_reg_value_work_item.h"
#include "chrome/installer/util/shell_util.h"
@@ -44,15 +38,9 @@
#include "installer_util_strings.h" // NOLINT
#include "registered_dlls.h" // NOLINT
-using base::win::RegKey;
-using installer::ChannelInfo;
using installer::InstallerState;
using installer::InstallationState;
-using installer::MasterPreferences;
-using installer::Products;
using installer::Product;
-using installer::Package;
-using installer::PackageProperties;
namespace {
@@ -69,14 +57,14 @@ void AddChromeToMediaPlayerList() {
LOG(ERROR) << "Could not add Chrome to media player inclusion list.";
}
-void AddInstallerCopyTasks(const FilePath& setup_path,
+void AddInstallerCopyTasks(const InstallerState& installer_state,
+ const FilePath& setup_path,
const FilePath& archive_path,
const FilePath& temp_path,
const Version& new_version,
- WorkItemList* install_list,
- const Package& package) {
+ WorkItemList* install_list) {
DCHECK(install_list);
- FilePath installer_dir(package.GetInstallerDirectory(new_version));
+ FilePath installer_dir(installer_state.GetInstallerDirectory(new_version));
install_list->AddCreateDirWorkItem(installer_dir);
FilePath exe_dst(installer_dir.Append(setup_path.BaseName()));
@@ -84,7 +72,7 @@ void AddInstallerCopyTasks(const FilePath& setup_path,
install_list->AddCopyTreeWorkItem(setup_path.value(), exe_dst.value(),
temp_path.value(), WorkItem::ALWAYS);
- if (package.system_level()) {
+ if (installer_state.system_install()) {
install_list->AddCopyTreeWorkItem(archive_path.value(), archive_dst.value(),
temp_path.value(), WorkItem::ALWAYS);
} else {
@@ -93,139 +81,12 @@ void AddInstallerCopyTasks(const FilePath& setup_path,
}
}
-// Adds work items that make registry adjustments for Google Update. When a
-// product is installed (including overinstall), Google Update will write the
-// channel ("ap") value into either Chrome or Chrome Frame's ClientState key.
-// In the multi-install case, this value is used as the basis upon which the
-// package's channel value is built (by adding the ordered list of installed
-// products and their options).
-void AddGoogleUpdateWorkItems(const InstallationState& original_state,
- const InstallerState& installer_state,
- const Package& package,
- WorkItemList* install_list) {
- // Is a multi-install product being installed or over-installed?
- if (installer_state.operation() != InstallerState::MULTI_INSTALL)
- return;
-
- const HKEY reg_root = package.system_level() ? HKEY_LOCAL_MACHINE :
- HKEY_CURRENT_USER;
- const std::wstring key_path = installer_state.state_key();
- ChannelInfo channel_info;
-
- // Update the "ap" value for the product being installed/updated.
- // It is completely acceptable for there to be no "ap" value or even no
- // ClientState key. Note that we check the registry rather than
- // original_state since on a fresh install the "ap" value will be present
- // sans "pv" value.
- channel_info.Initialize(RegKey(reg_root, key_path.c_str(), KEY_QUERY_VALUE));
-
- // This is a multi-install product.
- bool modified = channel_info.SetMultiInstall(true);
-
- // Add the appropriate modifiers for all products and their options.
- Products::const_iterator scan = package.products().begin();
- const Products::const_iterator end = package.products().end();
- for (; scan != end; ++scan) {
- modified |= scan->get()->distribution()->SetChannelFlags(true,
- &channel_info);
- }
-
- // Write the results if needed.
- if (modified) {
- install_list->AddSetRegValueWorkItem(reg_root, key_path,
- google_update::kRegApField,
- channel_info.value(), true);
- }
-
- // Synchronize the other products and the package with this one.
- std::wstring other_key;
- std::vector<std::wstring> keys;
-
- keys.reserve(package.products().size());
- other_key = package.properties()->GetStateKey();
- if (other_key != key_path)
- keys.push_back(other_key);
- scan = package.products().begin();
- for (; scan != end; ++scan) {
- other_key = scan->get()->distribution()->GetStateKey();
- if (other_key != key_path)
- keys.push_back(other_key);
- }
-
- RegKey key;
- ChannelInfo other_info;
- std::vector<std::wstring>::const_iterator kscan = keys.begin();
- std::vector<std::wstring>::const_iterator kend = keys.end();
- for (; kscan != kend; ++kscan) {
- // Handle the case where the ClientState key doesn't exist by creating it.
- // This takes care of the multi-installer's package key, which is not
- // created by Google Update for us.
- if (key.Open(reg_root, kscan->c_str(), KEY_QUERY_VALUE) != ERROR_SUCCESS ||
- !other_info.Initialize(key)) {
- other_info.set_value(std::wstring());
- }
- if (!other_info.Equals(channel_info)) {
- if (!key.Valid())
- install_list->AddCreateRegKeyWorkItem(reg_root, *kscan);
- install_list->AddSetRegValueWorkItem(reg_root, *kscan,
- google_update::kRegApField,
- channel_info.value(), true);
- }
- }
- // TODO(grt): check for other keys/values we should put in the package's
- // ClientState and/or Clients key.
-}
-
-// This is called when an MSI installation is run. It may be that a user is
-// attempting to install the MSI on top of a non-MSI managed installation.
-// If so, try and remove any existing uninstallation shortcuts, as we want the
-// uninstall to be managed entirely by the MSI machinery (accessible via the
-// Add/Remove programs dialog).
-void AddDeleteUninstallShortcutsForMSIWorkItems(const Product& product,
- WorkItemList* work_item_list) {
- DCHECK(product.IsMsi()) << "This must only be called for MSI installations!";
-
- // First attempt to delete the old installation's ARP dialog entry.
- HKEY reg_root = product.system_level() ? HKEY_LOCAL_MACHINE :
- HKEY_CURRENT_USER;
- base::win::RegKey root_key(reg_root, L"", KEY_ALL_ACCESS);
- std::wstring uninstall_reg(product.distribution()->GetUninstallRegPath());
-
- WorkItem* delete_reg_key = work_item_list->AddDeleteRegKeyWorkItem(
- reg_root, uninstall_reg);
- delete_reg_key->set_ignore_failure(true);
-
- // Then attempt to delete the old installation's start menu shortcut.
- FilePath uninstall_link;
- if (product.system_level()) {
- PathService::Get(base::DIR_COMMON_START_MENU, &uninstall_link);
- } else {
- PathService::Get(base::DIR_START_MENU, &uninstall_link);
- }
-
- if (uninstall_link.empty()) {
- LOG(ERROR) << "Failed to get location for shortcut.";
- } else {
- uninstall_link = uninstall_link.Append(
- product.distribution()->GetAppShortCutName());
- uninstall_link = uninstall_link.Append(
- product.distribution()->GetUninstallLinkName() + L".lnk");
- VLOG(1) << "Deleting old uninstall shortcut (if present): "
- << uninstall_link.value();
- WorkItem* delete_link = work_item_list->AddDeleteTreeWorkItem(
- uninstall_link);
- delete_link->set_ignore_failure(true);
- delete_link->set_log_message(
- "Failed to delete old uninstall shortcut.");
- }
-}
-
// Copy master preferences file provided to installer, in the same folder
// as chrome.exe so Chrome first run can find it. This function will be called
// only on the first install of Chrome.
-void CopyPreferenceFileForFirstRun(const Package& package,
+void CopyPreferenceFileForFirstRun(const InstallerState& installer_state,
const FilePath& prefs_source_path) {
- FilePath prefs_dest_path(package.path().AppendASCII(
+ FilePath prefs_dest_path(installer_state.target_path().AppendASCII(
installer::kDefaultMasterPrefs));
if (!file_util::CopyFile(prefs_source_path, prefs_dest_path)) {
VLOG(1) << "Failed to copy master preferences from:"
@@ -247,7 +108,8 @@ void CopyPreferenceFileForFirstRun(const Package& package,
//
// If the shortcuts do not exist, the function does not recreate them during
// update.
-bool CreateOrUpdateChromeShortcuts(const FilePath& setup_path,
+bool CreateOrUpdateChromeShortcuts(const InstallerState& installer_state,
+ const FilePath& setup_path,
const Version& new_version,
installer::InstallStatus install_status,
const Product& product,
@@ -257,7 +119,7 @@ bool CreateOrUpdateChromeShortcuts(const FilePath& setup_path,
DCHECK(product.is_chrome());
FilePath shortcut_path;
- int dir_enum = product.system_level() ?
+ int dir_enum = installer_state.system_install() ?
base::DIR_COMMON_START_MENU : base::DIR_START_MENU;
if (!PathService::Get(dir_enum, &shortcut_path)) {
LOG(ERROR) << "Failed to get location for shortcut.";
@@ -283,7 +145,7 @@ bool CreateOrUpdateChromeShortcuts(const FilePath& setup_path,
chrome_link = chrome_link.Append(product_name + L".lnk");
// Chrome link target
FilePath chrome_exe(
- product.package().path().Append(installer::kChromeExe));
+ installer_state.target_path().Append(installer::kChromeExe));
if ((install_status == installer::FIRST_INSTALL_SUCCESS) ||
(install_status == installer::INSTALL_REPAIRED)) {
@@ -309,7 +171,7 @@ bool CreateOrUpdateChromeShortcuts(const FilePath& setup_path,
// installations are, for the time being, managed only through the
// Add/Remove Programs dialog.
// TODO(robertshield): We could add a shortcut to msiexec /X {GUID} here.
- if (ret && !product.IsMsi()) {
+ if (ret && !installer_state.is_msi()) {
FilePath uninstall_link(shortcut_path); // Uninstall Chrome link
uninstall_link = uninstall_link.Append(
browser_dist->GetUninstallLinkName() + L".lnk");
@@ -319,12 +181,11 @@ bool CreateOrUpdateChromeShortcuts(const FilePath& setup_path,
if (!file_util::PathExists(shortcut_path))
file_util::CreateDirectory(shortcut_path);
- FilePath setup_exe(
- product.package().GetInstallerDirectory(new_version)
- .Append(setup_path.BaseName()));
+ FilePath setup_exe(installer_state.GetInstallerDirectory(new_version)
+ .Append(setup_path.BaseName()));
CommandLine arguments(CommandLine::NO_PROGRAM);
- AppendUninstallCommandLineFlags(&arguments, product);
+ AppendUninstallCommandLineFlags(installer_state, product, &arguments);
VLOG(1) << "Creating/updating uninstall link at "
<< uninstall_link.value();
ret = file_util::CreateShortcutLink(setup_exe.value().c_str(),
@@ -342,7 +203,7 @@ bool CreateOrUpdateChromeShortcuts(const FilePath& setup_path,
// is specified we want to create them, otherwise we update them only if
// they exist.
if (ret) {
- if (product.system_level()) {
+ if (installer_state.system_install()) {
ret = ShellUtil::CreateChromeDesktopShortcut(product.distribution(),
chrome_exe.value(), product_desc, ShellUtil::SYSTEM_LEVEL,
alt_shortcut, create_all_shortcut);
@@ -367,8 +228,8 @@ bool CreateOrUpdateChromeShortcuts(const FilePath& setup_path,
return ret;
}
-
-void RegisterChromeOnMachine(const Product& product,
+void RegisterChromeOnMachine(const InstallerState& installer_state,
+ const Product& product,
bool make_chrome_default) {
DCHECK(product.is_chrome());
@@ -380,11 +241,11 @@ void RegisterChromeOnMachine(const Product& product,
// Is --make-chrome-default option is given we make Chrome default browser
// otherwise we only register it on the machine as a valid browser.
FilePath chrome_exe(
- product.package().path().Append(installer::kChromeExe));
+ installer_state.target_path().Append(installer::kChromeExe));
VLOG(1) << "Registering Chrome as browser: " << chrome_exe.value();
if (make_chrome_default) {
int level = ShellUtil::CURRENT_USER;
- if (product.system_level())
+ if (installer_state.system_install())
level = level | ShellUtil::SYSTEM_LEVEL;
ShellUtil::MakeChromeDefault(product.distribution(), level,
chrome_exe.value(), true);
@@ -417,33 +278,29 @@ void RegisterChromeOnMachine(const Product& product,
installer::InstallStatus InstallNewVersion(
const InstallationState& original_state,
const InstallerState& installer_state,
- bool multi_install,
const FilePath& setup_path,
const FilePath& archive_path,
const FilePath& src_path,
const FilePath& temp_dir,
const Version& new_version,
- scoped_ptr<Version>* current_version,
- const Package& package) {
+ scoped_ptr<Version>* current_version) {
DCHECK(current_version);
- current_version->reset(package.GetCurrentVersion());
+ current_version->reset(installer_state.GetCurrentVersion(original_state));
scoped_ptr<WorkItemList> install_list(WorkItem::CreateWorkItemList());
AddInstallWorkItems(original_state,
installer_state,
- multi_install,
setup_path,
archive_path,
src_path,
temp_dir,
new_version,
current_version,
- package,
install_list.get());
FilePath new_chrome_exe(
- package.path().Append(installer::kChromeNewExe));
+ installer_state.target_path().Append(installer::kChromeNewExe));
if (!install_list->Do()) {
installer::InstallStatus result =
@@ -488,61 +345,63 @@ installer::InstallStatus InstallNewVersion(
namespace installer {
-installer::InstallStatus InstallOrUpdateProduct(
+InstallStatus InstallOrUpdateProduct(
const InstallationState& original_state,
const InstallerState& installer_state,
- const FilePath& setup_path, const FilePath& archive_path,
- const FilePath& install_temp_path, const FilePath& prefs_path,
- const installer::MasterPreferences& prefs, const Version& new_version,
- const Package& install) {
+ const FilePath& setup_path,
+ const FilePath& archive_path,
+ const FilePath& install_temp_path,
+ const FilePath& prefs_path,
+ const MasterPreferences& prefs,
+ const Version& new_version) {
FilePath src_path(install_temp_path);
src_path = src_path.Append(kInstallSourceDir).Append(kInstallSourceChromeDir);
// TODO(robertshield): Removing the pending on-reboot moves should be done
// elsewhere.
- const Products& products = install.products();
+ const Products& products = installer_state.products();
DCHECK(products.size());
- if (FindProduct(products, BrowserDistribution::CHROME_FRAME)) {
+ if (installer_state.FindProduct(BrowserDistribution::CHROME_FRAME)) {
// Make sure that we don't end up deleting installed files on next reboot.
- if (!RemoveFromMovesPendingReboot(install.path().value().c_str())) {
+ if (!RemoveFromMovesPendingReboot(
+ installer_state.target_path().value().c_str())) {
LOG(ERROR) << "Error accessing pending moves value.";
}
}
scoped_ptr<Version> existing_version;
- installer::InstallStatus result = InstallNewVersion(original_state,
- installer_state, prefs.is_multi_install(), setup_path, archive_path,
- src_path, install_temp_path, new_version, &existing_version, install);
+ InstallStatus result = InstallNewVersion(original_state, installer_state,
+ setup_path, archive_path, src_path, install_temp_path, new_version,
+ &existing_version);
// TODO(robertshield): Everything below this line should instead be captured
// by WorkItems.
if (!InstallUtil::GetInstallReturnCode(result)) {
- if (result == installer::FIRST_INSTALL_SUCCESS && !prefs_path.empty())
- CopyPreferenceFileForFirstRun(install, prefs_path);
+ if (result == FIRST_INSTALL_SUCCESS && !prefs_path.empty())
+ CopyPreferenceFileForFirstRun(installer_state, prefs_path);
bool do_not_create_shortcuts = false;
- prefs.GetBool(installer::master_preferences::kDoNotCreateShortcuts,
+ prefs.GetBool(master_preferences::kDoNotCreateShortcuts,
&do_not_create_shortcuts);
// Currently this only creates shortcuts for Chrome, but for other products
// we might want to create shortcuts.
const Product* chrome_install =
- FindProduct(install.products(), BrowserDistribution::CHROME_BROWSER);
+ installer_state.FindProduct(BrowserDistribution::CHROME_BROWSER);
if (chrome_install && !do_not_create_shortcuts) {
bool create_all_shortcut = false;
- prefs.GetBool(installer::master_preferences::kCreateAllShortcuts,
+ prefs.GetBool(master_preferences::kCreateAllShortcuts,
&create_all_shortcut);
bool alt_shortcut = false;
- prefs.GetBool(installer::master_preferences::kAltShortcutText,
- &alt_shortcut);
- if (!CreateOrUpdateChromeShortcuts(setup_path, new_version, result,
- *chrome_install, create_all_shortcut,
- alt_shortcut)) {
+ prefs.GetBool(master_preferences::kAltShortcutText, &alt_shortcut);
+ if (!CreateOrUpdateChromeShortcuts(installer_state, setup_path,
+ new_version, result, *chrome_install,
+ create_all_shortcut, alt_shortcut)) {
PLOG(WARNING) << "Failed to create/update start menu shortcut.";
}
bool make_chrome_default = false;
- prefs.GetBool(installer::master_preferences::kMakeChromeDefault,
+ prefs.GetBool(master_preferences::kMakeChromeDefault,
&make_chrome_default);
// If this is not the user's first Chrome install, but they have chosen
@@ -550,18 +409,17 @@ installer::InstallStatus InstallOrUpdateProduct(
// force it here because the master_preferences file will not get copied
// into the build.
bool force_chrome_default_for_user = false;
- if (result == installer::NEW_VERSION_UPDATED ||
- result == installer::INSTALL_REPAIRED) {
- prefs.GetBool(
- installer::master_preferences::kMakeChromeDefaultForUser,
- &force_chrome_default_for_user);
+ if (result == NEW_VERSION_UPDATED ||
+ result == INSTALL_REPAIRED) {
+ prefs.GetBool(master_preferences::kMakeChromeDefaultForUser,
+ &force_chrome_default_for_user);
}
- RegisterChromeOnMachine(*chrome_install,
+ RegisterChromeOnMachine(installer_state, *chrome_install,
make_chrome_default || force_chrome_default_for_user);
}
- install.RemoveOldVersionDirectories(existing_version.get() ?
+ installer_state.RemoveOldVersionDirectories(existing_version.get() ?
*existing_version.get() : new_version);
}
diff --git a/chrome/installer/setup/install.h b/chrome/installer/setup/install.h
index c3ff033..d05a955 100644
--- a/chrome/installer/setup/install.h
+++ b/chrome/installer/setup/install.h
@@ -13,7 +13,6 @@
#include "base/version.h"
#include "chrome/installer/util/product.h"
-#include "chrome/installer/util/master_preferences.h"
#include "chrome/installer/util/util_constants.h"
class DictionaryValue;
@@ -24,7 +23,7 @@ namespace installer {
class InstallationState;
class InstallerState;
-class Package;
+class MasterPreferences;
// This function installs or updates a new version of Chrome. It returns
// install status (failed, new_install, updated etc).
@@ -46,12 +45,12 @@ class Package;
InstallStatus InstallOrUpdateProduct(
const InstallationState& original_state,
const InstallerState& installer_state,
- const FilePath& setup_path, const FilePath& archive_path,
- const FilePath& install_temp_path, const FilePath& prefs_path,
- const installer::MasterPreferences& prefs, const Version& new_version,
- const Package& package);
-
-
+ const FilePath& setup_path,
+ const FilePath& archive_path,
+ const FilePath& install_temp_path,
+ const FilePath& prefs_path,
+ const installer::MasterPreferences& prefs,
+ const Version& new_version);
} // namespace installer
diff --git a/chrome/installer/setup/install_worker.cc b/chrome/installer/setup/install_worker.cc
index f9a534a..8965edf 100644
--- a/chrome/installer/setup/install_worker.cc
+++ b/chrome/installer/setup/install_worker.cc
@@ -21,7 +21,6 @@
#include "base/win/registry.h"
#include "chrome/installer/setup/install.h"
#include "chrome/installer/setup/setup_constants.h"
-#include "chrome/installer/util/chrome_frame_distribution.h"
#include "chrome/installer/util/conditional_work_item_list.h"
#include "chrome/installer/util/create_reg_key_work_item.h"
#include "chrome/installer/util/google_update_constants.h"
@@ -29,10 +28,6 @@
#include "chrome/installer/util/installation_state.h"
#include "chrome/installer/util/installer_state.h"
#include "chrome/installer/util/install_util.h"
-#include "chrome/installer/util/master_preferences.h"
-#include "chrome/installer/util/master_preferences_constants.h"
-#include "chrome/installer/util/package.h"
-#include "chrome/installer/util/package_properties.h"
#include "chrome/installer/util/product.h"
#include "chrome/installer/util/set_reg_value_work_item.h"
#include "chrome/installer/util/shell_util.h"
@@ -63,20 +58,13 @@ namespace installer {
// Local helper to call AddRegisterComDllWorkItems for all DLLs in a set of
// products managed by a given package.
-void AddRegisterComDllWorkItemsForPackage(const Package& package,
+void AddRegisterComDllWorkItemsForPackage(const InstallerState& installer_state,
const Version* old_version,
const Version& new_version,
WorkItemList* work_item_list) {
// First collect the list of DLLs to be registered from each product.
- const Products& products = package.products();
- Products::const_iterator product_iter(products.begin());
std::vector<FilePath> com_dll_list;
- for (; product_iter != products.end(); ++product_iter) {
- BrowserDistribution* dist = product_iter->get()->distribution();
- std::vector<FilePath> dist_dll_list(dist->GetComDllList());
- com_dll_list.insert(com_dll_list.end(), dist_dll_list.begin(),
- dist_dll_list.end());
- }
+ installer_state.AddComDllList(&com_dll_list);
// Then, if we got some, attempt to unregister the DLLs from the old
// version directory and then re-register them in the new one.
@@ -88,36 +76,36 @@ void AddRegisterComDllWorkItemsForPackage(const Package& package,
// saved state instead of assuming it is the same as the registration list.
if (!com_dll_list.empty()) {
if (old_version) {
- FilePath old_dll_path(
- package.path().Append(UTF8ToWide(old_version->GetString())));
+ FilePath old_dll_path(installer_state.target_path().Append(
+ UTF8ToWide(old_version->GetString())));
installer::AddRegisterComDllWorkItems(old_dll_path,
com_dll_list,
- package.system_level(),
+ installer_state.system_install(),
false, // Unregister
true, // May fail
work_item_list);
}
- FilePath dll_path(
- package.path().Append(UTF8ToWide(new_version.GetString())));
+ FilePath dll_path(installer_state.target_path().Append(
+ UTF8ToWide(new_version.GetString())));
installer::AddRegisterComDllWorkItems(dll_path,
com_dll_list,
- package.system_level(),
+ installer_state.system_install(),
true, // Register
false, // Must succeed.
work_item_list);
}
}
-void AddInstallerCopyTasks(const FilePath& setup_path,
+void AddInstallerCopyTasks(const InstallerState& installer_state,
+ const FilePath& setup_path,
const FilePath& archive_path,
const FilePath& temp_path,
const Version& new_version,
- WorkItemList* install_list,
- const Package& package) {
+ WorkItemList* install_list) {
DCHECK(install_list);
- FilePath installer_dir(package.GetInstallerDirectory(new_version));
+ FilePath installer_dir(installer_state.GetInstallerDirectory(new_version));
install_list->AddCreateDirWorkItem(installer_dir);
FilePath exe_dst(installer_dir.Append(setup_path.BaseName()));
@@ -125,7 +113,7 @@ void AddInstallerCopyTasks(const FilePath& setup_path,
install_list->AddCopyTreeWorkItem(setup_path.value(), exe_dst.value(),
temp_path.value(), WorkItem::ALWAYS);
- if (package.system_level()) {
+ if (installer_state.system_install()) {
install_list->AddCopyTreeWorkItem(archive_path.value(), archive_dst.value(),
temp_path.value(), WorkItem::ALWAYS);
} else {
@@ -137,12 +125,12 @@ void AddInstallerCopyTasks(const FilePath& setup_path,
// This method adds work items to create (or update) Chrome uninstall entry in
// either the Control Panel->Add/Remove Programs list or in the Omaha client
// state key if running under an MSI installer.
-void AddUninstallShortcutWorkItems(const FilePath& setup_path,
+void AddUninstallShortcutWorkItems(const InstallerState& installer_state,
+ const FilePath& setup_path,
const Version& new_version,
WorkItemList* install_list,
const Product& product) {
- HKEY reg_root = product.system_level() ? HKEY_LOCAL_MACHINE :
- HKEY_CURRENT_USER;
+ HKEY reg_root = installer_state.root_key();
BrowserDistribution* browser_dist = product.distribution();
DCHECK(browser_dist);
@@ -152,24 +140,26 @@ void AddUninstallShortcutWorkItems(const FilePath& setup_path,
// install is updated by a non-msi installer (which would confuse the MSI
// machinery if these strings were not also updated).
// Do not quote the command line for the MSI invocation.
- FilePath install_path(product.package().path());
- FilePath installer_path(
- product.package().GetInstallerDirectory(new_version));
+ FilePath install_path(installer_state.target_path());
+ FilePath installer_path(installer_state.GetInstallerDirectory(new_version));
installer_path = installer_path.Append(setup_path.BaseName());
CommandLine uninstall_arguments(CommandLine::NO_PROGRAM);
- AppendUninstallCommandLineFlags(&uninstall_arguments, product);
-
- if (product.is_chrome()) {
- // 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.
- const Products& products = product.package().products();
+ 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 (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.distribution()->AppendUninstallCommandLineFlags(&uninstall_arguments);
- }
+ if (!p.is_chrome() && !p.ShouldCreateUninstallEntry())
+ p.AppendProductFlags(&uninstall_arguments);
}
}
@@ -181,7 +171,8 @@ void AddUninstallShortcutWorkItems(const FilePath& setup_path,
installer::kUninstallArgumentsField,
uninstall_arguments.command_line_string(), true);
- if (product.ShouldCreateUninstallEntry()) {
+ // MSI installations will manage their own uninstall shortcuts.
+ if (!installer_state.is_msi() && product.ShouldCreateUninstallEntry()) {
// We need to quote the command line for the Add/Remove Programs dialog.
CommandLine quoted_uninstall_cmd(installer_path);
DCHECK_EQ(quoted_uninstall_cmd.command_line_string()[0], '"');
@@ -241,15 +232,15 @@ void AddUninstallShortcutWorkItems(const FilePath& setup_path,
// Create Version key for a product (if not already present) and sets the new
// product version as the last step.
void AddVersionKeyWorkItems(HKEY root,
- const Product& product,
+ BrowserDistribution* dist,
const Version& new_version,
WorkItemList* list) {
// Create Version key for each distribution (if not already present) and set
// the new product version as the last step.
- std::wstring version_key(product.distribution()->GetVersionKey());
+ std::wstring version_key(dist->GetVersionKey());
list->AddCreateRegKeyWorkItem(root, version_key);
- std::wstring product_name(product.distribution()->GetAppShortCutName());
+ std::wstring product_name(dist->GetAppShortCutName());
list->AddSetRegValueWorkItem(root, version_key, google_update::kRegNameField,
product_name, true); // overwrite name also
list->AddSetRegValueWorkItem(root, version_key,
@@ -262,16 +253,17 @@ void AddVersionKeyWorkItems(HKEY root,
true); // overwrite version
}
-void AddProductSpecificWorkItems(bool install,
+void AddProductSpecificWorkItems(const InstallationState& original_state,
+ const InstallerState& installer_state,
const FilePath& setup_path,
const Version& new_version,
- const Package& package,
WorkItemList* list) {
- const Products& products = package.products();
+ const Products& products = installer_state.products();
for (size_t i = 0; i < products.size(); ++i) {
const Product& p = *products[i];
if (p.is_chrome_frame()) {
- AddChromeFrameWorkItems(install, setup_path, new_version, p, list);
+ AddChromeFrameWorkItems(original_state, installer_state, setup_path,
+ new_version, p, list);
}
}
}
@@ -282,36 +274,28 @@ void AddProductSpecificWorkItems(bool install,
// In the multi-install case, this value is used as the basis upon which the
// package's channel value is built (by adding the ordered list of installed
// products and their options).
-void AddGoogleUpdateWorkItems(const InstallationState& original_state,
- const InstallerState& installer_state,
- const Package& package,
+void AddGoogleUpdateWorkItems(const InstallerState& installer_state,
WorkItemList* install_list) {
// Is a multi-install product being installed or over-installed?
if (installer_state.operation() != InstallerState::MULTI_INSTALL)
return;
- const HKEY reg_root = package.system_level() ? HKEY_LOCAL_MACHINE :
- HKEY_CURRENT_USER;
+ const HKEY reg_root = installer_state.root_key();
const std::wstring key_path = installer_state.state_key();
ChannelInfo channel_info;
// Update the "ap" value for the product being installed/updated.
// It is completely acceptable for there to be no "ap" value or even no
- // ClientState key. Note that we check the registry rather than
- // original_state since on a fresh install the "ap" value will be present
- // sans "pv" value.
+ // ClientState key. Note that we check the registry rather than an
+ // InstallationState instance since on a fresh install the "ap" value will be
+ // present sans "pv" value.
channel_info.Initialize(RegKey(reg_root, key_path.c_str(), KEY_QUERY_VALUE));
// This is a multi-install product.
bool modified = channel_info.SetMultiInstall(true);
// Add the appropriate modifiers for all products and their options.
- Products::const_iterator scan = package.products().begin();
- const Products::const_iterator end = package.products().end();
- for (; scan != end; ++scan) {
- modified |= scan->get()->distribution()->SetChannelFlags(true,
- &channel_info);
- }
+ modified |= installer_state.SetChannelFlags(true, &channel_info);
// Write the results if needed.
if (modified) {
@@ -324,13 +308,15 @@ void AddGoogleUpdateWorkItems(const InstallationState& original_state,
std::wstring other_key;
std::vector<std::wstring> keys;
- keys.reserve(package.products().size());
- other_key = package.properties()->GetStateKey();
+ keys.reserve(installer_state.products().size());
+ other_key =
+ installer_state.multi_package_binaries_distribution()->GetStateKey();
if (other_key != key_path)
keys.push_back(other_key);
- scan = package.products().begin();
+ Products::const_iterator scan = installer_state.products().begin();
+ Products::const_iterator end = installer_state.products().end();
for (; scan != end; ++scan) {
- other_key = scan->get()->distribution()->GetStateKey();
+ other_key = (*scan)->distribution()->GetStateKey();
if (other_key != key_path)
keys.push_back(other_key);
}
@@ -364,14 +350,15 @@ void AddGoogleUpdateWorkItems(const InstallationState& original_state,
// If so, try and remove any existing uninstallation shortcuts, as we want the
// uninstall to be managed entirely by the MSI machinery (accessible via the
// Add/Remove programs dialog).
-void AddDeleteUninstallShortcutsForMSIWorkItems(const Product& product,
- WorkItemList* work_item_list) {
- DCHECK(product.IsMsi()) << "This must only be called for MSI installations!";
+void AddDeleteUninstallShortcutsForMSIWorkItems(
+ const InstallerState& installer_state,
+ const Product& product,
+ WorkItemList* work_item_list) {
+ DCHECK(installer_state.is_msi())
+ << "This must only be called for MSI installations!";
// First attempt to delete the old installation's ARP dialog entry.
- HKEY reg_root = product.system_level() ? HKEY_LOCAL_MACHINE :
- HKEY_CURRENT_USER;
- base::win::RegKey root_key(reg_root, L"", KEY_ALL_ACCESS);
+ HKEY reg_root = installer_state.root_key();
std::wstring uninstall_reg(product.distribution()->GetUninstallRegPath());
WorkItem* delete_reg_key = work_item_list->AddDeleteRegKeyWorkItem(
@@ -380,7 +367,7 @@ void AddDeleteUninstallShortcutsForMSIWorkItems(const Product& product,
// Then attempt to delete the old installation's start menu shortcut.
FilePath uninstall_link;
- if (product.system_level()) {
+ if (installer_state.system_install()) {
PathService::Get(base::DIR_COMMON_START_MENU, &uninstall_link);
} else {
PathService::Get(base::DIR_START_MENU, &uninstall_link);
@@ -412,18 +399,16 @@ void AddDeleteUninstallShortcutsForMSIWorkItems(const Product& product,
// it if not.
// If these operations are successful, the function returns true, otherwise
// false.
-bool AppendPostInstallTasks(bool multi_install,
+bool AppendPostInstallTasks(const InstallerState& installer_state,
const FilePath& setup_path,
const FilePath& new_chrome_exe,
const Version* current_version,
const Version& new_version,
- const Package& package,
WorkItemList* post_install_task_list) {
DCHECK(post_install_task_list);
- HKEY root = package.system_level() ? HKEY_LOCAL_MACHINE :
- HKEY_CURRENT_USER;
- const Products& products = package.products();
+ HKEY root = installer_state.root_key();
+ const Products& products = installer_state.products();
// Append work items that will only be executed if this was an update.
// We update the 'opv' key with the current version that is active and 'cmd'
@@ -434,18 +419,18 @@ bool AppendPostInstallTasks(bool multi_install,
new ConditionRunIfFileExists(new_chrome_exe)));
in_use_update_work_items->set_log_message("InUseUpdateWorkItemList");
- FilePath installer_path(package.GetInstallerDirectory(new_version)
+ FilePath installer_path(installer_state.GetInstallerDirectory(new_version)
.Append(setup_path.BaseName()));
CommandLine rename(installer_path);
rename.AppendSwitch(installer::switches::kRenameChromeExe);
- if (package.system_level())
+ if (installer_state.system_install())
rename.AppendSwitch(installer::switches::kSystemLevel);
if (InstallUtil::IsChromeSxSProcess())
rename.AppendSwitch(installer::switches::kChromeSxS);
- if (multi_install)
+ if (installer_state.is_multi_install())
rename.AppendSwitch(installer::switches::kMultiInstall);
std::wstring version_key;
@@ -472,18 +457,17 @@ bool AppendPostInstallTasks(bool multi_install,
true);
}
- if (multi_install) {
- PackageProperties* props = package.properties();
- if (props->ReceivesUpdates() && current_version != NULL) {
- in_use_update_work_items->AddSetRegValueWorkItem(
- root,
- props->GetVersionKey(),
- google_update::kRegOldVersionField,
- UTF8ToWide(current_version->GetString()),
- true);
- // TODO(tommi): We should move the rename command here. We also need to
- // update Upgrade::SwapNewChromeExeIfPresent.
- }
+ if (current_version != NULL && installer_state.is_multi_install()) {
+ BrowserDistribution* dist =
+ installer_state.multi_package_binaries_distribution();
+ in_use_update_work_items->AddSetRegValueWorkItem(
+ root,
+ dist->GetVersionKey(),
+ google_update::kRegOldVersionField,
+ UTF8ToWide(current_version->GetString()),
+ true);
+ // TODO(tommi): We should move the rename command here. We also need to
+ // update Upgrade::SwapNewChromeExeIfPresent.
}
post_install_task_list->AddWorkItem(in_use_update_work_items.release());
@@ -494,8 +478,7 @@ bool AppendPostInstallTasks(bool multi_install,
scoped_ptr<WorkItemList> regular_update_work_items(
WorkItem::CreateConditionalWorkItemList(
new Not(new ConditionRunIfFileExists(new_chrome_exe))));
- regular_update_work_items->set_log_message(
- "RegularUpdateWorkItemList");
+ regular_update_work_items->set_log_message("RegularUpdateWorkItemList");
// Since this was not an in-use-update, delete 'opv' and 'cmd' keys.
for (size_t i = 0; i < products.size(); ++i) {
@@ -510,23 +493,29 @@ bool AppendPostInstallTasks(bool multi_install,
post_install_task_list->AddWorkItem(regular_update_work_items.release());
}
- AddRegisterComDllWorkItemsForPackage(package, current_version, new_version,
- post_install_task_list);
+ AddRegisterComDllWorkItemsForPackage(installer_state, current_version,
+ new_version, post_install_task_list);
- for (size_t i = 0; i < products.size(); ++i) {
- const Product* product = products[i];
- // If we're told that we're an MSI install, make sure to set the marker
- // in the client state key so that future updates do the right thing.
- if (product->IsMsi()) {
- AddSetMsiMarkerWorkItem(*product, true, post_install_task_list);
+ // If we're told that we're an MSI install, make sure to set the marker
+ // in the client state key so that future updates do the right thing.
+ if (installer_state.is_msi()) {
+ for (size_t i = 0; i < products.size(); ++i) {
+ const Product* product = products[i];
+ AddSetMsiMarkerWorkItem(installer_state, product->distribution(), true,
+ post_install_task_list);
// We want MSI installs to take over the Add/Remove Programs shortcut.
// Make a best-effort attempt to delete any shortcuts left over from
// previous non-MSI installations for the same type of install (system or
// per user).
- AddDeleteUninstallShortcutsForMSIWorkItems(*product,
+ AddDeleteUninstallShortcutsForMSIWorkItems(installer_state, *product,
post_install_task_list);
}
+ if (installer_state.is_multi_install()) {
+ AddSetMsiMarkerWorkItem(installer_state,
+ installer_state.multi_package_binaries_distribution(), true,
+ post_install_task_list);
+ }
}
return true;
@@ -534,112 +523,101 @@ bool AppendPostInstallTasks(bool multi_install,
void AddInstallWorkItems(const InstallationState& original_state,
const InstallerState& installer_state,
- bool multi_install,
const FilePath& setup_path,
const FilePath& archive_path,
const FilePath& src_path,
const FilePath& temp_dir,
const Version& new_version,
scoped_ptr<Version>* current_version,
- const Package& package,
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_dir);
- install_list->AddCreateDirWorkItem(package.path());
+ install_list->AddCreateDirWorkItem(target_path);
// Delete any new_chrome.exe if present (we will end up creating a new one
// if required) and then copy chrome.exe
FilePath new_chrome_exe(
- package.path().Append(installer::kChromeNewExe));
+ target_path.Append(installer::kChromeNewExe));
install_list->AddDeleteTreeWorkItem(new_chrome_exe);
install_list->AddCopyTreeWorkItem(
src_path.Append(installer::kChromeExe).value(),
- package.path().Append(installer::kChromeExe).value(),
+ target_path.Append(installer::kChromeExe).value(),
temp_dir.value(), WorkItem::NEW_NAME_IF_IN_USE, new_chrome_exe.value());
// Extra executable for 64 bit systems.
if (Is64bit()) {
install_list->AddCopyTreeWorkItem(
src_path.Append(installer::kWowHelperExe).value(),
- package.path().Append(installer::kWowHelperExe).value(),
+ target_path.Append(installer::kWowHelperExe).value(),
temp_dir.value(), WorkItem::ALWAYS);
}
// If it is system level install copy the version folder (since we want to
// take the permissions of %ProgramFiles% folder) otherwise just move it.
- if (package.system_level()) {
+ if (installer_state.system_install()) {
install_list->AddCopyTreeWorkItem(
src_path.Append(UTF8ToWide(new_version.GetString())).value(),
- package.path().Append(UTF8ToWide(new_version.GetString())).value(),
+ target_path.Append(UTF8ToWide(new_version.GetString())).value(),
temp_dir.value(), WorkItem::ALWAYS);
} else {
install_list->AddMoveTreeWorkItem(
src_path.Append(UTF8ToWide(new_version.GetString())).value(),
- package.path().Append(UTF8ToWide(new_version.GetString())).value(),
+ target_path.Append(UTF8ToWide(new_version.GetString())).value(),
temp_dir.value());
}
// Copy the default Dictionaries only if the folder doesn't exist already.
install_list->AddCopyTreeWorkItem(
src_path.Append(installer::kDictionaries).value(),
- package.path().Append(installer::kDictionaries).value(),
+ target_path.Append(installer::kDictionaries).value(),
temp_dir.value(), WorkItem::IF_NOT_PRESENT);
// Delete any old_chrome.exe if present.
install_list->AddDeleteTreeWorkItem(
- package.path().Append(installer::kChromeOldExe));
+ target_path.Append(installer::kChromeOldExe));
// Copy installer in install directory and
// add shortcut in Control Panel->Add/Remove Programs.
- AddInstallerCopyTasks(setup_path, archive_path, temp_dir, new_version,
- install_list, package);
+ AddInstallerCopyTasks(installer_state, setup_path, archive_path, temp_dir,
+ new_version, install_list);
- HKEY root = package.system_level() ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER;
+ const HKEY root = installer_state.root_key();
- const Products& products = package.products();
+ const Products& products = installer_state.products();
for (size_t i = 0; i < products.size(); ++i) {
const Product* product = products[i];
- AddUninstallShortcutWorkItems(setup_path, new_version, install_list,
- *product);
+ AddUninstallShortcutWorkItems(installer_state, setup_path, new_version,
+ install_list, *product);
- AddVersionKeyWorkItems(root, *product, new_version, install_list);
+ AddVersionKeyWorkItems(root, product->distribution(), new_version,
+ install_list);
}
- if (multi_install) {
- PackageProperties* props = package.properties();
- if (props->ReceivesUpdates()) {
- std::wstring version_key(props->GetVersionKey());
- install_list->AddCreateRegKeyWorkItem(root, version_key);
- install_list->AddSetRegValueWorkItem(root, version_key,
- google_update::kRegVersionField,
- UTF8ToWide(new_version.GetString()),
- true); // overwrite version
- install_list->AddSetRegValueWorkItem(root, version_key,
- google_update::kRegNameField,
- ASCIIToWide(installer::PackageProperties::kPackageProductName),
- true); // overwrite name also
- }
+ if (installer_state.is_multi_install()) {
+ AddVersionKeyWorkItems(root,
+ installer_state.multi_package_binaries_distribution(), new_version,
+ install_list);
}
// Add any remaining work items that involve special settings for
// each product.
- AddProductSpecificWorkItems(true, setup_path, new_version, package,
- install_list);
+ AddProductSpecificWorkItems(original_state, installer_state, setup_path,
+ new_version, install_list);
- AddGoogleUpdateWorkItems(original_state, installer_state, package,
- install_list);
+ AddGoogleUpdateWorkItems(installer_state, install_list);
// Append the tasks that run after the installation.
- AppendPostInstallTasks(multi_install,
+ AppendPostInstallTasks(installer_state,
setup_path,
new_chrome_exe,
current_version->get(),
new_version,
- package,
install_list);
}
@@ -664,93 +642,74 @@ void AddRegisterComDllWorkItems(const FilePath& dll_folder,
}
}
-void AddSetMsiMarkerWorkItem(const Product& product,
+void AddSetMsiMarkerWorkItem(const InstallerState& installer_state,
+ BrowserDistribution* dist,
bool set,
WorkItemList* work_item_list) {
DCHECK(work_item_list);
- BrowserDistribution* dist = product.distribution();
- HKEY reg_root = product.system_level() ? HKEY_LOCAL_MACHINE :
- HKEY_CURRENT_USER;
DWORD msi_value = set ? 1 : 0;
WorkItem* set_msi_work_item = work_item_list->AddSetRegValueWorkItem(
- reg_root, dist->GetStateKey(), google_update::kRegMSIField,
- msi_value, true);
+ installer_state.root_key(), dist->GetStateKey(),
+ google_update::kRegMSIField, msi_value, true);
DCHECK(set_msi_work_item);
set_msi_work_item->set_ignore_failure(true);
set_msi_work_item->set_log_message("Could not write MSI marker!");
}
-void AddChromeFrameWorkItems(bool install,
+void AddChromeFrameWorkItems(const InstallationState& original_state,
+ const InstallerState& installer_state,
const FilePath& setup_path,
const Version& new_version,
const Product& product,
WorkItemList* list) {
DCHECK(product.is_chrome_frame());
- if (!product.package().multi_install()) {
+ if (!installer_state.is_multi_install()) {
VLOG(1) << "Not adding GCF specific work items for single install.";
return;
}
- const MasterPreferences& prefs = MasterPreferences::ForCurrentProcess();
-
- BrowserDistribution* cf = BrowserDistribution::GetSpecificDistribution(
- BrowserDistribution::CHROME_FRAME, prefs);
- std::wstring version_key(cf->GetVersionKey());
-
- // TODO(tommi): This assumes we know exactly how ShouldCreateUninstallEntry
- // is implemented. Since there is logic in ChromeFrameDistribution for how
- // to determine when this is enabled, this is how we have to figure out if
- // this feature is enabled right now, but it's a hack and we need a cleaner
- // way to figure this out.
- // Note that we cannot just check the master preferences for
- // kChromeFrameReadyMode, since there are other things that need to be correct
- // in the environment in order to enable this feature.
- bool ready_mode = !product.distribution()->ShouldCreateUninstallEntry();
-
- HKEY root = product.package().system_level() ? HKEY_LOCAL_MACHINE :
- HKEY_CURRENT_USER;
+ std::wstring version_key(product.distribution()->GetVersionKey());
+ bool ready_mode = product.HasOption(kOptionReadyMode);
+ HKEY root = installer_state.root_key();
+ const bool is_install =
+ (installer_state.operation() != InstallerState::UNINSTALL);
bool update_chrome_uninstall_command = false;
+ BrowserDistribution* dist =
+ installer_state.multi_package_binaries_distribution();
if (ready_mode) {
// If GCF is being installed in ready mode, we write an entry to the
// multi-install state key. If the value already exists, we will not
// overwrite it since the user might have opted out.
- list->AddCreateRegKeyWorkItem(root,
- product.package().properties()->GetStateKey());
- list->AddSetRegValueWorkItem(root,
- product.package().properties()->GetStateKey(),
- installer::kChromeFrameReadyModeField,
- static_cast<int64>(install ? 1 : 0), // The value we want to set.
- install ? false : true); // Overwrite existing value.
- if (install) {
- FilePath installer_path(product.package()
+ list->AddCreateRegKeyWorkItem(root, dist->GetStateKey());
+ list->AddSetRegValueWorkItem(root, dist->GetStateKey(),
+ kChromeFrameReadyModeField,
+ static_cast<int64>(is_install ? 1 : 0), // The value we want to set.
+ is_install ? false : true); // Overwrite existing value.
+ if (is_install) {
+ FilePath installer_path(installer_state
.GetInstallerDirectory(new_version).Append(setup_path.BaseName()));
CommandLine basic_cl(installer_path);
- basic_cl.AppendSwitch(installer::switches::kChromeFrame);
- basic_cl.AppendSwitch(installer::switches::kMultiInstall);
-
- if (product.package().system_level())
- basic_cl.AppendSwitch(installer::switches::kSystemLevel);
+ basic_cl.AppendSwitch(switches::kChromeFrame);
+ basic_cl.AppendSwitch(switches::kMultiInstall);
- if (InstallUtil::IsChromeSxSProcess())
- basic_cl.AppendSwitch(installer::switches::kChromeSxS);
+ if (installer_state.system_install())
+ basic_cl.AppendSwitch(switches::kSystemLevel);
CommandLine temp_opt_out(basic_cl);
- temp_opt_out.AppendSwitch(
- installer::switches::kChromeFrameReadyModeTempOptOut);
+ temp_opt_out.AppendSwitch(switches::kChromeFrameReadyModeTempOptOut);
CommandLine end_temp_opt_out(basic_cl);
end_temp_opt_out.AppendSwitch(
- installer::switches::kChromeFrameReadyModeEndTempOptOut);
+ switches::kChromeFrameReadyModeEndTempOptOut);
CommandLine opt_out(installer_path);
- AppendUninstallCommandLineFlags(&opt_out, product);
+ AppendUninstallCommandLineFlags(installer_state, product, &opt_out);
// Force Uninstall silences the prompt to reboot to complete uninstall.
- opt_out.AppendSwitch(installer::switches::kForceUninstall);
+ opt_out.AppendSwitch(switches::kForceUninstall);
CommandLine opt_in(basic_cl);
- opt_in.AppendSwitch(
- installer::switches::kChromeFrameReadyModeOptIn);
+ opt_in.AppendSwitch(switches::kChromeFrameReadyModeOptIn);
list->AddSetRegValueWorkItem(root, version_key,
google_update::kRegCFTempOptOutCmdField,
@@ -769,8 +728,8 @@ void AddChromeFrameWorkItems(bool install,
// If Chrome is not also being uninstalled, we need to update its command
// line so that it doesn't include uninstalling Chrome Frame now.
update_chrome_uninstall_command =
- (installer::FindProduct(product.package().products(),
- BrowserDistribution::CHROME_BROWSER) == NULL);
+ (installer_state.FindProduct(BrowserDistribution::CHROME_BROWSER) ==
+ NULL);
}
} else {
// It doesn't matter here if we're installing or uninstalling Chrome Frame.
@@ -784,15 +743,11 @@ void AddChromeFrameWorkItems(bool install,
// uninstallation command line does not include the --chrome-frame switch
// so that uninstalling Chrome will no longer uninstall Chrome Frame.
- if (RegKey(root, product.package().properties()->GetStateKey().c_str(),
- KEY_QUERY_VALUE).Valid()) {
- list->AddDeleteRegValueWorkItem(root,
- product.package().properties()->GetStateKey(),
- installer::kChromeFrameReadyModeField);
- }
+ list->AddDeleteRegValueWorkItem(root, dist->GetStateKey(),
+ kChromeFrameReadyModeField);
- const Product* chrome = installer::FindProduct(product.package().products(),
- BrowserDistribution::CHROME_BROWSER);
+ const Product* chrome =
+ installer_state.FindProduct(BrowserDistribution::CHROME_BROWSER);
if (chrome) {
// Chrome is already a part of this installation run, so we can assume
// that the uninstallation arguments will be updated correctly.
@@ -800,15 +755,15 @@ void AddChromeFrameWorkItems(bool install,
// Chrome is not a part of this installation run, so we have to explicitly
// check if Chrome is installed, and if so, update its uninstallation
// command lines.
- BrowserDistribution* dist = BrowserDistribution::GetSpecificDistribution(
- BrowserDistribution::CHROME_BROWSER,
- MasterPreferences::ForCurrentProcess());
+ const ProductState* chrome_state = original_state.GetProductState(
+ installer_state.system_install(),
+ BrowserDistribution::CHROME_BROWSER);
update_chrome_uninstall_command =
- IsInstalledAsMulti(product.system_level(), dist);
+ (chrome_state != NULL) && chrome_state->is_multi_install();
}
}
- if (!ready_mode || !install) {
+ if (!ready_mode || !is_install) {
list->AddDeleteRegValueWorkItem(root, version_key,
google_update::kRegCFTempOptOutCmdField);
list->AddDeleteRegValueWorkItem(root, version_key,
@@ -823,44 +778,41 @@ void AddChromeFrameWorkItems(bool install,
// Chrome is not a part of this installation run, so we have to explicitly
// check if Chrome is installed, and if so, update its uninstallation
// command lines.
- BrowserDistribution* chrome_dist =
- BrowserDistribution::GetSpecificDistribution(
- BrowserDistribution::CHROME_BROWSER, prefs);
- const Package& pack = product.package();
- scoped_refptr<Package> package(new Package(pack.multi_install(),
- pack.system_level(), pack.path(), pack.properties()));
- scoped_refptr<Product> chrome_product(new Product(chrome_dist, package));
- AddUninstallShortcutWorkItems(setup_path, new_version, list,
- *chrome_product.get());
+ const ProductState* chrome_state = original_state.GetProductState(
+ installer_state.system_install(),
+ BrowserDistribution::CHROME_BROWSER);
+ if (chrome_state != NULL) {
+ DCHECK(chrome_state->is_multi_install());
+ Product chrome(BrowserDistribution::GetSpecificDistribution(
+ BrowserDistribution::CHROME_BROWSER));
+ chrome.InitializeFromUninstallCommand(chrome_state->uninstall_command());
+ AddUninstallShortcutWorkItems(installer_state, setup_path,
+ chrome_state->version(), list, chrome);
+ } else {
+ NOTREACHED() << "What happened to Chrome?";
+ }
}
}
-void AppendUninstallCommandLineFlags(CommandLine* uninstall_cmd,
- const Product& product) {
+void AppendUninstallCommandLineFlags(const InstallerState& installer_state,
+ const Product& product,
+ CommandLine* uninstall_cmd) {
DCHECK(uninstall_cmd);
uninstall_cmd->AppendSwitch(installer::switches::kUninstall);
// Append the product-specific uninstall flags.
- product.distribution()->AppendUninstallCommandLineFlags(uninstall_cmd);
- if (product.IsMsi()) {
+ product.AppendProductFlags(uninstall_cmd);
+ if (installer_state.is_msi()) {
uninstall_cmd->AppendSwitch(installer::switches::kMsi);
// See comment in uninstall.cc where we check for the kDeleteProfile switch.
if (product.is_chrome_frame()) {
uninstall_cmd->AppendSwitch(installer::switches::kDeleteProfile);
}
}
- if (product.system_level())
+ if (installer_state.system_install())
uninstall_cmd->AppendSwitch(installer::switches::kSystemLevel);
-
- // Propagate switches obtained from preferences as well.
- const MasterPreferences& prefs = MasterPreferences::ForCurrentProcess();
- if (prefs.is_multi_install()) {
- uninstall_cmd->AppendSwitch(installer::switches::kMultiInstall);
- }
- bool value = false;
- if (prefs.GetBool(installer::master_preferences::kVerboseLogging,
- &value) && value)
+ if (installer_state.verbose_logging())
uninstall_cmd->AppendSwitch(installer::switches::kVerboseLogging);
}
diff --git a/chrome/installer/setup/install_worker.h b/chrome/installer/setup/install_worker.h
index 167ed9b..0769ec3 100644
--- a/chrome/installer/setup/install_worker.h
+++ b/chrome/installer/setup/install_worker.h
@@ -13,6 +13,7 @@
#include "base/scoped_ptr.h"
+class BrowserDistribution;
class CommandLine;
class FilePath;
class Version;
@@ -25,6 +26,15 @@ class InstallerState;
class Package;
class Product;
+// Adds work items that make registry adjustments for Google Update. When a
+// product is installed (including overinstall), Google Update will write the
+// channel ("ap") value into either Chrome or Chrome Frame's ClientState key.
+// In the multi-install case, this value is used as the basis upon which the
+// package's channel value is built (by adding the ordered list of installed
+// products and their options).
+void AddGoogleUpdateWorkItems(const InstallerState& installer_state,
+ WorkItemList* install_list);
+
// Builds the complete WorkItemList used to build the set of installation steps
// needed to lay down one or more installed products.
//
@@ -38,14 +48,12 @@ class Product;
// does not need to exist.
void AddInstallWorkItems(const InstallationState& original_state,
const InstallerState& installer_state,
- bool multi_install,
const FilePath& setup_path,
const FilePath& archive_path,
const FilePath& src_path,
const FilePath& temp_dir,
const Version& new_version,
scoped_ptr<Version>* current_version,
- const Package& package,
WorkItemList* install_list);
// Appends registration or unregistration work items to |work_item_list| for the
@@ -64,34 +72,34 @@ void AddRegisterComDllWorkItems(const FilePath& dll_folder,
bool ignore_failures,
WorkItemList* work_item_list);
-void AddSetMsiMarkerWorkItem(const Product& product,
+void AddSetMsiMarkerWorkItem(const InstallerState& installer_state,
+ BrowserDistribution* dist,
bool set,
WorkItemList* work_item_list);
// Called for either installation or uninstallation. This method updates the
// registry according to Chrome Frame specific options for the current
// installation. This includes handling of the ready-mode option.
-void AddChromeFrameWorkItems(bool install, const FilePath& setup_path,
- const Version& new_version, const Product& product,
+void AddChromeFrameWorkItems(const InstallationState& original_state,
+ const InstallerState& installer_state,
+ const FilePath& setup_path,
+ const Version& new_version,
+ const Product& product,
WorkItemList* list);
-
// This method adds work items to create (or update) Chrome uninstall entry in
// either the Control Panel->Add/Remove Programs list or in the Omaha client
// state key if running under an MSI installer.
-void AddUninstallShortcutWorkItems(const FilePath& setup_path,
- const Version& new_version,
- WorkItemList* install_list,
- const Product& product);
-
-void AddUninstallShortcutWorkItems(const FilePath& setup_path,
+void AddUninstallShortcutWorkItems(const InstallerState& installer_state,
+ const FilePath& setup_path,
const Version& new_version,
WorkItemList* install_list,
const Product& product);
// Utility method currently shared between install.cc and install_worker.cc
-void AppendUninstallCommandLineFlags(CommandLine* uninstall_cmd,
- const Product& product);
+void AppendUninstallCommandLineFlags(const InstallerState& installer_state,
+ const Product& product,
+ CommandLine* uninstall_cmd);
} // namespace installer
diff --git a/chrome/installer/setup/install_worker_unittest.cc b/chrome/installer/setup/install_worker_unittest.cc
index 51f066e..5703ba3 100644
--- a/chrome/installer/setup/install_worker_unittest.cc
+++ b/chrome/installer/setup/install_worker_unittest.cc
@@ -8,19 +8,13 @@
#include "base/version.h"
#include "chrome/installer/util/installation_state.h"
#include "chrome/installer/util/installer_state.h"
-#include "chrome/installer/util/package.h"
-#include "chrome/installer/util/package_properties.h"
#include "chrome/installer/util/work_item_list.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "testing/gmock/include/gmock/gmock.h"
-using installer::ChromiumPackageProperties;
using installer::InstallationState;
using installer::InstallerState;
-using installer::Package;
-using installer::PackageProperties;
-using installer::PackagePropertiesImpl;
using installer::ProductState;
using ::testing::_;
@@ -66,20 +60,17 @@ class MockWorkItemList : public WorkItemList {
bool));
};
+class MockProductState : public ProductState {
+ public:
+ // Takes ownership of |version|.
+ void set_version(Version* version) { version_.reset(version); }
+};
+
// Okay, so this isn't really a mock as such, but it does add setter methods
// to make it easier to build custom InstallationStates.
class MockInstallationState : public InstallationState {
public:
// Included for testing.
- void SetMultiPackageState(bool system_install,
- const ProductState& package_state) {
- ProductState& target =
- (system_install ? system_products_ : user_products_)
- [MULTI_PACKAGE_INDEX];
- target.CopyFrom(package_state);
- }
-
- // Included for testing.
void SetProductState(bool system_install,
BrowserDistribution::Type type,
const ProductState& product_state) {
@@ -91,8 +82,8 @@ class MockInstallationState : public InstallationState {
class MockInstallerState : public InstallerState {
public:
- void set_system_install(bool system_install) {
- system_install_ = system_install;
+ void set_level(Level level) {
+ level_ = level;
}
void set_operation(Operation operation) { operation_ = operation; }
@@ -125,14 +116,13 @@ class InstallWorkerTest : public testing::Test {
}
virtual void TearDown() {
-
}
MockInstallationState* BuildChromeSingleSystemInstallationState() {
scoped_ptr<MockInstallationState> installation_state(
new MockInstallationState());
- ProductState product_state;
+ MockProductState product_state;
product_state.set_version(current_version_->Clone());
// Do not call SetMultiPackageState since this is a single install.
installation_state->SetProductState(true,
@@ -142,14 +132,19 @@ class InstallWorkerTest : public testing::Test {
return installation_state.release();
}
- MockInstallerState* BuildChromeSingleSystemInstallerState() {
+ MockInstallerState* BuildChromeSingleSystemInstallerState(
+ const InstallationState& machine_state) {
scoped_ptr<MockInstallerState> installer_state(new MockInstallerState());
- installer_state->set_system_install(true);
+ installer_state->set_level(InstallerState::SYSTEM_LEVEL);
installer_state->set_operation(InstallerState::SINGLE_INSTALL_OR_UPDATE);
// Hope this next one isn't checked for now.
installer_state->set_state_key(L"PROBABLY_INVALID_REG_PATH");
-
+ const ProductState* chrome =
+ machine_state.GetProductState(true,
+ BrowserDistribution::CHROME_BROWSER);
+ installer_state->AddProductFromState(BrowserDistribution::CHROME_BROWSER,
+ *chrome);
return installer_state.release();
}
@@ -173,18 +168,7 @@ TEST_F(InstallWorkerTest, TestInstallChromeSingleSystem) {
BuildChromeSingleSystemInstallationState());
scoped_ptr<InstallerState> installer_state(
- BuildChromeSingleSystemInstallerState());
-
- // This MUST outlive the package, since the package doesn't assume ownership
- // of it. Note: This feels like an implementation bug:
- // The PackageProperties <-> Package relationship is 1:1 and nothing else
- // uses the PackageProperties. I have the feeling that PackageProperties, and
- // perhaps Package itself should not exist at all.
- scoped_ptr<PackageProperties> package_properties(
- new ChromiumPackageProperties());
-
- scoped_refptr<Package> package(
- new Package(false, true, installation_path_, package_properties.get()));
+ BuildChromeSingleSystemInstallerState(*installation_state));
// Set up some expectations.
// TODO(robertshield): Set up some real expectations.
@@ -193,13 +177,11 @@ TEST_F(InstallWorkerTest, TestInstallChromeSingleSystem) {
AddInstallWorkItems(*installation_state.get(),
*installer_state.get(),
- false,
setup_path_,
archive_path_,
src_path_,
temp_dir_,
*new_version_.get(),
&current_version_,
- *package.get(),
&work_item_list);
}
diff --git a/chrome/installer/setup/setup_main.cc b/chrome/installer/setup/setup_main.cc
index b385b8b..78d641c 100644
--- a/chrome/installer/setup/setup_main.cc
+++ b/chrome/installer/setup/setup_main.cc
@@ -20,6 +20,7 @@
#include "base/string_util.h"
#include "base/utf_string_conversions.h"
#include "base/values.h"
+#include "base/win/registry.h"
#include "base/win/scoped_handle.h"
#include "base/win/win_util.h"
#include "base/win/windows_version.h"
@@ -31,6 +32,7 @@
#include "chrome/installer/setup/setup_util.h"
#include "chrome/installer/setup/uninstall.h"
#include "chrome/installer/util/browser_distribution.h"
+#include "chrome/installer/util/channel_info.h"
#include "chrome/installer/util/delete_after_reboot_helper.h"
#include "chrome/installer/util/delete_tree_work_item.h"
#include "chrome/installer/util/google_update_settings.h"
@@ -45,7 +47,6 @@
#include "chrome/installer/util/lzma_util.h"
#include "chrome/installer/util/master_preferences.h"
#include "chrome/installer/util/master_preferences_constants.h"
-#include "chrome/installer/util/package_properties.h"
#include "chrome/installer/util/shell_util.h"
#include "chrome/installer/util/util_constants.h"
@@ -54,11 +55,8 @@
using installer::InstallerState;
using installer::InstallationState;
using installer::Product;
-using installer::ProductPackageMapping;
using installer::ProductState;
using installer::Products;
-using installer::Package;
-using installer::Packages;
using installer::MasterPreferences;
const wchar_t kChromePipeName[] = L"\\\\.\\pipe\\ChromeCrashServices";
@@ -83,7 +81,7 @@ namespace {
// present on the system already. As the final step the new archive file
// is unpacked in the path specified by parameter "output_directory".
DWORD UnPackArchive(const FilePath& archive,
- const Package& installation,
+ const InstallerState& installer_state,
const FilePath& temp_path,
const FilePath& output_directory,
bool& incremental_install) {
@@ -98,7 +96,7 @@ DWORD UnPackArchive(const FilePath& archive,
FilePath uncompressed_archive(temp_path.Append(installer::kChromeArchive));
scoped_ptr<Version> archive_version(
- installer::GetVersionFromArchiveDir(installation.path()));
+ installer::GetVersionFromArchiveDir(installer_state.target_path()));
// Check if this is differential update and if it is, patch it to the
// installer archive that should already be on the machine. We assume
@@ -112,7 +110,7 @@ DWORD UnPackArchive(const FilePath& archive,
return installer::CHROME_NOT_INSTALLED;
}
- FilePath existing_archive(installation.path().Append(
+ FilePath existing_archive(installer_state.target_path().Append(
UTF8ToWide(archive_version->GetString())));
existing_archive = existing_archive.Append(installer::kInstallerDir);
existing_archive = existing_archive.Append(installer::kChromeArchive);
@@ -136,12 +134,11 @@ DWORD UnPackArchive(const FilePath& archive,
// system and a key called 'opv' in the registry. This function will move
// new_chrome.exe to chrome.exe and delete 'opv' key in one atomic operation.
installer::InstallStatus RenameChromeExecutables(
- const Package& installation) {
- FilePath chrome_exe(installation.path().Append(installer::kChromeExe));
- FilePath chrome_old_exe(installation.path().Append(
- installer::kChromeOldExe));
- FilePath chrome_new_exe(installation.path().Append(
- installer::kChromeNewExe));
+ const InstallerState& installer_state) {
+ const FilePath &target_path = installer_state.target_path();
+ FilePath chrome_exe(target_path.Append(installer::kChromeExe));
+ FilePath chrome_old_exe(target_path.Append(installer::kChromeOldExe));
+ FilePath chrome_new_exe(target_path.Append(installer::kChromeNewExe));
scoped_ptr<WorkItemList> install_list(WorkItem::CreateWorkItemList());
install_list->AddDeleteTreeWorkItem(chrome_old_exe);
@@ -158,9 +155,8 @@ installer::InstallStatus RenameChromeExecutables(
std::wstring());
install_list->AddDeleteTreeWorkItem(chrome_new_exe);
- HKEY reg_root = installation.system_level() ? HKEY_LOCAL_MACHINE :
- HKEY_CURRENT_USER;
- const Products& products = installation.products();
+ HKEY reg_root = installer_state.root_key();
+ const Products& products = installer_state.products();
for (size_t i = 0; i < products.size(); ++i) {
const Product* product = products[i];
BrowserDistribution* browser_dist = product->distribution();
@@ -182,44 +178,218 @@ installer::InstallStatus RenameChromeExecutables(
return ret;
}
+// The supported multi-install modes are:
+// --multi-install --chrome --chrome-frame --ready-mode
+// - If a non-multi Chrome Frame installation is present, Chrome Frame is
+// removed from |installer_state|'s list of products (thereby preserving
+// the existing SxS install).
+// - If a multi Chrome Frame installation is present, its options are
+// preserved (i.e., the --ready-mode command-line option is ignored).
+// --multi-install --chrome-frame
+// - If a non-multi Chrome Frame installation is present, fail.
+// - If a Chrome installation on a different channel is present, fail.
+// - If --ready-mode and no Chrome installation is present, fail.
+// - If a Chrome installation is present, add it to the set of products to
+// install.
+bool CheckMultiInstallConditions(const InstallationState& original_state,
+ InstallerState* installer_state,
+ installer::InstallStatus* status) {
+ const Products& products = installer_state->products();
+ DCHECK(products.size());
+
+ bool is_first_install = true;
+ const bool system_level = installer_state->system_install();
+
+ if (installer_state->is_multi_install()) {
+ const Product* chrome =
+ installer_state->FindProduct(BrowserDistribution::CHROME_BROWSER);
+ 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 &&
+ 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
+ // is already present, don't touch it; if a multi-install of Chrome
+ // Frame is present, preserve its settings (ready-mode, CEEE).
+ if (cf_state != NULL) {
+ installer_state->RemoveProduct(chrome_frame);
+ chrome_frame = NULL;
+ if (cf_state->is_multi_install()) {
+ chrome_frame = installer_state->AddProductFromState(
+ BrowserDistribution::CHROME_FRAME, *cf_state);
+ VLOG(1) << "Upgrading existing multi-install Chrome Frame rather "
+ "than installing in ready-mode.";
+ } else {
+ VLOG(1) << "Skipping upgrade of single-install Chrome Frame rather "
+ "than installing in ready-mode.";
+ }
+ } else {
+ 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) {
+ base::win::RegKey key;
+ installer::ChannelInfo cf_channel;
+ // Chrome Frame may not yet be installed, so peek into the registry
+ // directly to see what channel Google Update has specified. There will
+ // be no value if we're not being managed by Google Update.
+ if (key.Open(installer_state->root_key(),
+ chrome_frame->distribution()->GetStateKey().c_str(),
+ KEY_QUERY_VALUE) == ERROR_SUCCESS) {
+ cf_channel.Initialize(key);
+ }
+ // Fail if Chrome is already installed but is on a different update
+ // channel.
+ if (!cf_channel.EqualsBaseOf(chrome_state->channel())) {
+ LOG(ERROR) << "Cannot install Chrome Frame because existing Chrome "
+ "install is on a different update channel.";
+ *status = installer::CONFLICTING_CHANNEL_EXISTS;
+ InstallUtil::WriteInstallerResult(system_level,
+ installer_state->state_key(), *status,
+ IDS_INSTALL_CONFLICTING_CHANNEL_EXISTS_BASE, NULL);
+ return false;
+ }
+ // Otherwise, 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()->GetApplicationName();
+ } 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;
+ InstallUtil::WriteInstallerResult(system_level,
+ installer_state->state_key(), *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()) {
+ LOG(ERROR) << "Cannot migrate existing Chrome Frame installation to "
+ "multi-install.";
+ *status = installer::NON_MULTI_INSTALLATION_EXISTS;
+ InstallUtil::WriteInstallerResult(system_level,
+ installer_state->state_key(), *status,
+ IDS_INSTALL_NON_MULTI_INSTALLATION_EXISTS_BASE, NULL);
+ return false;
+ }
+ } else if (DCHECK_IS_ON()) {
+ // It isn't possible to stuff two products into a single-install
+ // InstallerState. Abort the process here in debug builds just in case
+ // someone finds a way.
+ DCHECK_EQ(1U, products.size());
+ }
+
+ return true;
+}
+
+// In multi-install, adds all products to |installer_state| that are
+// multi-installed and must be updated along with the products already present
+// in |installer_state|.
+void AddExistingMultiInstalls(const InstallationState& original_state,
+ InstallerState* installer_state) {
+ if (installer_state->is_multi_install()) {
+ BrowserDistribution::Type product_checks[] = {
+ BrowserDistribution::CHROME_BROWSER,
+ BrowserDistribution::CHROME_FRAME
+ };
+
+ for (size_t i = 0; i < arraysize(product_checks); ++i) {
+ BrowserDistribution::Type type = product_checks[i];
+ if (!installer_state->FindProduct(type)) {
+ const ProductState* state =
+ original_state.GetProductState(installer_state->system_install(),
+ type);
+ if ((state != NULL) && state->is_multi_install()) {
+ installer_state->AddProductFromState(type, *state);
+ VLOG(1) << "Product already installed and must be included: "
+ << BrowserDistribution::GetSpecificDistribution(
+ type)->GetApplicationName();
+ }
+ }
+ }
+ }
+}
+
+// Checks for compatibility between the current state of the system and the
+// desired operation. Also applies policy that mutates the desired operation;
+// specifically, the |installer_state| object.
+// Also blocks simultaneous user-level and system-level installs. In the case
+// of trying to install user-level Chrome when system-level exists, the
+// existing system-level Chrome is launched.
bool CheckPreInstallConditions(const InstallationState& original_state,
- const InstallerState& installer_state,
- const Package& installation,
- const MasterPreferences& prefs,
+ InstallerState* installer_state,
installer::InstallStatus* status) {
- const Products& products = installation.products();
+ const Products& products = installer_state->products();
DCHECK(products.size());
+ if (!CheckMultiInstallConditions(original_state, installer_state, status))
+ return false;
+
bool is_first_install = true;
- const bool system_level = installation.system_level();
+ const bool system_level = installer_state->system_install();
for (size_t i = 0; i < products.size(); ++i) {
const Product* product = products[i];
BrowserDistribution* browser_dist = product->distribution();
+
+ // Check for an existing installation of the product.
const ProductState* product_state =
original_state.GetProductState(system_level, browser_dist->GetType());
- if (product_state != NULL)
+ 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->GetApplicationName()
+ << " exists; aborting single install.";
+ *status = installer::MULTI_INSTALLATION_EXISTS;
+ InstallUtil::WriteInstallerResult(system_level,
+ installer_state->state_key(), *status,
+ IDS_INSTALL_MULTI_INSTALLATION_EXISTS_BASE, NULL);
+ return false;
+ }
+ }
// Check to avoid simultaneous per-user and per-machine installs.
const ProductState* other_state =
original_state.GetProductState(!system_level, browser_dist->GetType());
-
if (other_state != NULL) {
LOG(ERROR) << "Already installed version "
<< other_state->version().GetString()
<< " conflicts with the current install mode.";
if (!system_level && is_first_install && product->is_chrome()) {
// This is user-level install and there is a system-level chrome
- // installation. Instruct Omaha to launch the existing one. There
- // should be no error dialog.
+ // installation. Instruct Google Update to launch the existing one.
+ // 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.
*status = installer::OS_ERROR;
InstallUtil::WriteInstallerResult(system_level,
- installer_state.state_key(), *status, IDS_INSTALL_OS_ERROR_BASE,
+ installer_state->state_key(), *status, IDS_INSTALL_OS_ERROR_BASE,
NULL);
} else {
*status = installer::EXISTING_VERSION_LAUNCHED;
@@ -227,7 +397,7 @@ bool CheckPreInstallConditions(const InstallationState& original_state,
CommandLine cmd(chrome_exe);
cmd.AppendSwitch(switches::kFirstRun);
InstallUtil::WriteInstallerResult(system_level,
- installer_state.state_key(), *status, 0, NULL);
+ installer_state->state_key(), *status, 0, NULL);
VLOG(1) << "Launching existing system-level chrome instead.";
base::LaunchApp(cmd, false, false, NULL);
}
@@ -237,7 +407,7 @@ bool CheckPreInstallConditions(const InstallationState& original_state,
// If the following compile assert fires it means that the InstallStatus
// enumeration changed which will break the contract between the old
// chrome installed and the new setup.exe that is trying to upgrade.
- COMPILE_ASSERT(installer::SXS_OPTION_NOT_SUPPORTED == 33,
+ COMPILE_ASSERT(installer::CONFLICTING_CHANNEL_EXISTS == 39,
dont_change_enum);
// This is an update, not an install. Omaha should know the difference
@@ -247,23 +417,28 @@ bool CheckPreInstallConditions(const InstallationState& original_state,
int str_id = system_level ? IDS_INSTALL_USER_LEVEL_EXISTS_BASE :
IDS_INSTALL_SYSTEM_LEVEL_EXISTS_BASE;
InstallUtil::WriteInstallerResult(system_level,
- installer_state.state_key(), *status, str_id, NULL);
+ installer_state->state_key(), *status, str_id, NULL);
return false;
}
}
+ // See what products are already installed in multi mode. When we do multi
+ // installs, we must upgrade all installations since they share the binaries.
+ AddExistingMultiInstalls(original_state, installer_state);
+
// If 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(installation.path()) &&
- !file_util::Delete(installation.path(), true)) {
- LOG(ERROR) << "Installation directory " << installation.path().value()
+ 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;
InstallUtil::WriteInstallerResult(system_level,
- installer_state.state_key(), *status, str_id, NULL);
+ installer_state->state_key(), *status, str_id, NULL);
return false;
}
}
@@ -271,13 +446,15 @@ bool CheckPreInstallConditions(const InstallationState& original_state,
return true;
}
-installer::InstallStatus InstallChrome(const InstallationState& original_state,
- const InstallerState& installer_state,
- const CommandLine& cmd_line, const Package& installation,
- const MasterPreferences& prefs) {
+installer::InstallStatus InstallProducts(
+ const InstallationState& original_state,
+ const CommandLine& cmd_line,
+ const MasterPreferences& prefs,
+ InstallerState* installer_state) {
+ const bool system_install = installer_state->system_install();
installer::InstallStatus install_status = installer::UNKNOWN_STATUS;
- if (!CheckPreInstallConditions(original_state, installer_state, installation,
- prefs, &install_status))
+ if (!CheckPreInstallConditions(original_state, installer_state,
+ &install_status))
return install_status;
// For install the default location for chrome.packed.7z is in current
@@ -291,15 +468,15 @@ installer::InstallStatus InstallChrome(const InstallationState& original_state,
installer::switches::kInstallArchive);
}
VLOG(1) << "Archive found to install Chrome " << archive.value();
- const Products& products = installation.products();
+ const Products& products = installer_state->products();
// Create a temp folder where we will unpack Chrome archive. If it fails,
// then we are doomed, so return immediately and no cleanup is required.
FilePath temp_path;
if (!file_util::CreateNewTempDirectory(L"chrome_", &temp_path)) {
LOG(ERROR) << "Could not create temporary path.";
- InstallUtil::WriteInstallerResult(installer_state.system_install(),
- installer_state.state_key(), installer::TEMP_DIR_FAILED,
+ InstallUtil::WriteInstallerResult(system_install,
+ installer_state->state_key(), installer::TEMP_DIR_FAILED,
IDS_INSTALL_TEMP_DIR_FAILED_BASE, NULL);
return installer::TEMP_DIR_FAILED;
}
@@ -307,11 +484,11 @@ installer::InstallStatus InstallChrome(const InstallationState& original_state,
FilePath unpack_path(temp_path.Append(installer::kInstallSourceDir));
bool incremental_install = false;
- if (UnPackArchive(archive, installation, temp_path, unpack_path,
+ if (UnPackArchive(archive, *installer_state, temp_path, unpack_path,
incremental_install)) {
install_status = installer::UNCOMPRESSION_FAILED;
- InstallUtil::WriteInstallerResult(installer_state.system_install(),
- installer_state.state_key(), install_status,
+ InstallUtil::WriteInstallerResult(system_install,
+ installer_state->state_key(), install_status,
IDS_INSTALL_UNCOMPRESSION_FAILED_BASE, NULL);
} else {
VLOG(1) << "unpacked to " << unpack_path.value();
@@ -321,8 +498,8 @@ installer::InstallStatus InstallChrome(const InstallationState& original_state,
if (!installer_version.get()) {
LOG(ERROR) << "Did not find any valid version in installer.";
install_status = installer::INVALID_ARCHIVE;
- InstallUtil::WriteInstallerResult(installer_state.system_install(),
- installer_state.state_key(), install_status,
+ InstallUtil::WriteInstallerResult(system_install,
+ installer_state->state_key(), install_status,
IDS_INSTALL_INVALID_ARCHIVE_BASE, NULL);
} else {
// TODO(tommi): Move towards having only a single version that is common
@@ -332,10 +509,10 @@ installer::InstallStatus InstallChrome(const InstallationState& original_state,
// (or rather must) be upgraded.
VLOG(1) << "version to install: " << installer_version->GetString();
bool higher_version_installed = false;
- for (size_t i = 0; i < installation.products().size(); ++i) {
- const Product* product = installation.products()[i];
+ for (size_t i = 0; i < installer_state->products().size(); ++i) {
+ const Product* product = installer_state->products()[i];
const ProductState* product_state =
- original_state.GetProductState(installer_state.system_install(),
+ original_state.GetProductState(system_install,
product->distribution()->GetType());
if (product_state != NULL &&
(product_state->version().CompareTo(*installer_version) > 0)) {
@@ -346,12 +523,12 @@ installer::InstallStatus InstallChrome(const InstallationState& original_state,
if (product->is_chrome()) {
// TODO(robertshield): We should take the installer result text
// strings from the Product.
- InstallUtil::WriteInstallerResult(installer_state.system_install(),
- installer_state.state_key(), install_status,
+ InstallUtil::WriteInstallerResult(system_install,
+ installer_state->state_key(), install_status,
IDS_INSTALL_HIGHER_VERSION_BASE, NULL);
} else {
- InstallUtil::WriteInstallerResult(installer_state.system_install(),
- installer_state.state_key(), install_status,
+ InstallUtil::WriteInstallerResult(system_install,
+ installer_state->state_key(), install_status,
IDS_INSTALL_HIGHER_VERSION_CF_BASE, NULL);
}
}
@@ -364,33 +541,37 @@ installer::InstallStatus InstallChrome(const InstallationState& original_state,
FilePath prefs_source_path(cmd_line.GetSwitchValueNative(
installer::switches::kInstallerData));
install_status = installer::InstallOrUpdateProduct(original_state,
- installer_state, cmd_line.GetProgram(), archive_to_copy, temp_path,
- prefs_source_path, prefs, *installer_version, installation);
+ *installer_state, cmd_line.GetProgram(), archive_to_copy, temp_path,
+ prefs_source_path, prefs, *installer_version);
int install_msg_base = IDS_INSTALL_FAILED_BASE;
std::wstring chrome_exe;
if (install_status == installer::SAME_VERSION_REPAIR_FAILED) {
- if (FindProduct(products, BrowserDistribution::CHROME_FRAME)) {
+ if (installer_state->FindProduct(BrowserDistribution::CHROME_FRAME)) {
install_msg_base = IDS_SAME_VERSION_REPAIR_FAILED_CF_BASE;
} else {
install_msg_base = IDS_SAME_VERSION_REPAIR_FAILED_BASE;
}
} else if (install_status != installer::INSTALL_FAILED) {
- if (installation.path().empty()) {
+ if (installer_state->target_path().empty()) {
// If we failed to construct install path, it means the OS call to
// get %ProgramFiles% or %AppData% failed. Report this as failure.
install_msg_base = IDS_INSTALL_OS_ERROR_BASE;
install_status = installer::OS_ERROR;
} else {
- chrome_exe = installation.path()
+ chrome_exe = installer_state->target_path()
.Append(installer::kChromeExe).value();
chrome_exe = L"\"" + chrome_exe + L"\"";
install_msg_base = 0;
}
}
- const Product* chrome_install =
- FindProduct(products, BrowserDistribution::CHROME_BROWSER);
+ // Only do Chrome-specific stuff (like launching the browser) if
+ // Chrome was specifically requested (rather than being upgraded as
+ // part of a multi-install).
+ const Product* chrome_install = prefs.install_chrome() ?
+ installer_state->FindProduct(BrowserDistribution::CHROME_BROWSER) :
+ NULL;
bool value = false;
if (chrome_install) {
@@ -404,8 +585,8 @@ installer::InstallStatus InstallChrome(const InstallationState& original_state,
bool write_chrome_launch_string = (!value) &&
(install_status != installer::IN_USE_UPDATED);
- InstallUtil::WriteInstallerResult(installer_state.system_install(),
- installer_state.state_key(), install_status, install_msg_base,
+ InstallUtil::WriteInstallerResult(system_install,
+ installer_state->state_key(), install_status, install_msg_base,
write_chrome_launch_string ? &chrome_exe : NULL);
if (install_status == installer::FIRST_INSTALL_SUCCESS) {
@@ -416,8 +597,8 @@ installer::InstallStatus InstallChrome(const InstallationState& original_state,
prefs.GetBool(
installer::master_preferences::kDoNotLaunchChrome,
&do_not_launch_chrome);
- if (!installation.system_level() && !do_not_launch_chrome)
- chrome_install->LaunchChrome();
+ if (!system_install && !do_not_launch_chrome)
+ chrome_install->LaunchChrome(installer_state->target_path());
}
} else if ((install_status == installer::NEW_VERSION_UPDATED) ||
(install_status == installer::IN_USE_UPDATED)) {
@@ -438,7 +619,7 @@ installer::InstallStatus InstallChrome(const InstallationState& original_state,
for (size_t i = 0; i < products.size(); ++i) {
const Product* product = products[i];
product->distribution()->LaunchUserExperiment(install_status,
- *installer_version, *product, installation.system_level());
+ *installer_version, *product, system_install);
}
}
@@ -472,14 +653,13 @@ installer::InstallStatus InstallChrome(const InstallationState& original_state,
for (size_t i = 0; i < products.size(); ++i) {
const Product* product = products[i];
product->distribution()->UpdateInstallStatus(
- installer_state.system_install(), incremental_install,
- prefs.is_multi_install(), install_status);
- }
- if (prefs.is_multi_install()) {
- installation.properties()->UpdateInstallStatus(
- installer_state.system_install(), incremental_install, true,
+ system_install, incremental_install, prefs.is_multi_install(),
install_status);
}
+ if (installer_state->is_multi_install()) {
+ installer_state->multi_package_binaries_distribution()->UpdateInstallStatus(
+ system_install, incremental_install, true, install_status);
+ }
return install_status;
}
@@ -539,11 +719,10 @@ installer::InstallStatus ShowEULADialog(const std::wstring& inner_frame) {
// various tasks other than installation (renaming chrome.exe, showing eula
// among others). This function returns true if any such command line option
// has been found and processed (so setup.exe should exit at that point).
-bool HandleNonInstallCmdLineOptions(const InstallerState& installer_state,
+bool HandleNonInstallCmdLineOptions(const InstallationState& original_state,
const CommandLine& cmd_line,
- const ProductPackageMapping& installs,
+ const InstallerState& installer_state,
int* exit_code) {
- DCHECK(installs.products().size());
bool handled = true;
// TODO(tommi): Split these checks up into functions and use a data driven
// map of switch->function.
@@ -588,12 +767,11 @@ bool HandleNonInstallCmdLineOptions(const InstallerState& installer_state,
cmd_line.GetSwitchValueNative(installer::switches::kShowEula);
*exit_code = ShowEULADialog(inner_frame);
if (installer::EULA_REJECTED != *exit_code)
- GoogleUpdateSettings::SetEULAConsent(*installs.packages()[0].get(), true);
+ GoogleUpdateSettings::SetEULAConsent(installer_state, true);
} else if (cmd_line.HasSwitch(
installer::switches::kRegisterChromeBrowser)) {
const Product* chrome_install =
- FindProduct(installs.products(), BrowserDistribution::CHROME_BROWSER);
- DCHECK(chrome_install);
+ installer_state.FindProduct(BrowserDistribution::CHROME_BROWSER);
if (chrome_install) {
// If --register-chrome-browser option is specified, register all
// Chrome protocol/file associations as well as register it as a valid
@@ -611,16 +789,13 @@ bool HandleNonInstallCmdLineOptions(const InstallerState& installer_state,
*exit_code = ShellUtil::RegisterChromeBrowser(
chrome_install->distribution(), chrome_exe, suffix, false);
} else {
- LOG(ERROR) << "Can't register browser - Chrome distribution not found";
+ LOG(DFATAL) << "Can't register browser - Chrome distribution not found";
*exit_code = installer::UNKNOWN_STATUS;
}
} else if (cmd_line.HasSwitch(installer::switches::kRenameChromeExe)) {
// If --rename-chrome-exe is specified, we want to rename the executables
// and exit.
- const Packages& packages = installs.packages();
- DCHECK_EQ(1U, packages.size());
- for (size_t i = 0; i < packages.size(); ++i)
- *exit_code = RenameChromeExecutables(*packages[i].get());
+ *exit_code = RenameChromeExecutables(installer_state);
} else if (cmd_line.HasSwitch(
installer::switches::kRemoveChromeRegistration)) {
// This is almost reverse of --register-chrome-browser option above.
@@ -635,7 +810,7 @@ bool HandleNonInstallCmdLineOptions(const InstallerState& installer_state,
}
installer::InstallStatus tmp = installer::UNKNOWN_STATUS;
const Product* chrome_install =
- FindProduct(installs.products(), BrowserDistribution::CHROME_BROWSER);
+ installer_state.FindProduct(BrowserDistribution::CHROME_BROWSER);
DCHECK(chrome_install);
if (chrome_install) {
installer::DeleteChromeRegistrationKeys(chrome_install->distribution(),
@@ -651,37 +826,41 @@ bool HandleNonInstallCmdLineOptions(const InstallerState& installer_state,
if (flavor == -1) {
*exit_code = installer::UNKNOWN_STATUS;
} else {
- const Products& products = installs.products();
+ const Products& products = installer_state.products();
for (size_t i = 0; i < products.size(); ++i) {
const Product* product = products[i];
BrowserDistribution* browser_dist = product->distribution();
- browser_dist->InactiveUserToastExperiment(flavor, *product);
+ browser_dist->InactiveUserToastExperiment(flavor, *product,
+ installer_state.target_path());
}
}
} else if (cmd_line.HasSwitch(installer::switches::kSystemLevelToast)) {
- const Products& products = installs.products();
+ const Products& products = installer_state.products();
for (size_t i = 0; i < products.size(); ++i) {
const Product* product = products[i];
BrowserDistribution* browser_dist = product->distribution();
// We started as system-level and have been re-launched as user level
// to continue with the toast experiment.
scoped_ptr<Version> installed_version(
- InstallUtil::GetChromeVersion(browser_dist, installs.system_level()));
+ InstallUtil::GetChromeVersion(browser_dist,
+ installer_state.system_install()));
browser_dist->LaunchUserExperiment(installer::REENTRY_SYS_UPDATE,
*installed_version, *product, true);
}
} else if (cmd_line.HasSwitch(
installer::switches::kChromeFrameReadyModeOptIn)) {
*exit_code = InstallUtil::GetInstallReturnCode(
- installer::ChromeFrameReadyModeOptIn(installer_state, cmd_line));
+ installer::ChromeFrameReadyModeOptIn(original_state, installer_state));
} else if (cmd_line.HasSwitch(
installer::switches::kChromeFrameReadyModeTempOptOut)) {
*exit_code = InstallUtil::GetInstallReturnCode(
- installer::ChromeFrameReadyModeTempOptOut(cmd_line));
+ installer::ChromeFrameReadyModeTempOptOut(original_state,
+ installer_state));
} else if (cmd_line.HasSwitch(
installer::switches::kChromeFrameReadyModeEndTempOptOut)) {
*exit_code = InstallUtil::GetInstallReturnCode(
- installer::ChromeFrameReadyModeEndTempOptOut(cmd_line));
+ installer::ChromeFrameReadyModeEndTempOptOut(original_state,
+ installer_state));
} else {
handled = false;
}
@@ -743,54 +922,9 @@ class AutoCom {
bool initialized_;
};
-bool PopulateInstallations(bool for_uninstall,
- const MasterPreferences& prefs,
- ProductPackageMapping* installations) {
- DCHECK(installations);
- bool success = true;
-
- bool implicit_chrome_install = false;
- bool implicit_gcf_install = false;
-
- // See what products are already installed in multi mode.
- // When we do multi installs, we must upgrade all installations in sync since
- // they share the binaries. Be careful to not do this when we're uninstalling
- // a product.
- if (prefs.is_multi_install() && !for_uninstall) {
- struct CheckInstall {
- bool* installed;
- BrowserDistribution::Type type;
- } product_checks[] = {
- {&implicit_chrome_install, BrowserDistribution::CHROME_BROWSER},
- {&implicit_gcf_install, BrowserDistribution::CHROME_FRAME},
- };
- for (size_t i = 0; i < arraysize(product_checks); ++i) {
- BrowserDistribution* dist = BrowserDistribution::GetSpecificDistribution(
- product_checks[i].type, prefs);
- *product_checks[i].installed = installer::IsInstalledAsMulti(
- installations->system_level(), dist);
- LOG_IF(INFO, *product_checks[i].installed)
- << "Product already installed and must be included: "
- << dist->GetApplicationName();
- }
- }
- if (prefs.install_chrome() || implicit_chrome_install) {
- VLOG(1) << (for_uninstall ? "Uninstall" : "Install")
- << " distribution: Chrome";
- success = installations->AddDistribution(
- BrowserDistribution::CHROME_BROWSER, prefs);
- }
- if (success && (prefs.install_chrome_frame() || implicit_gcf_install)) {
- VLOG(1) << (for_uninstall ? "Uninstall" : "Install")
- << " distribution: Chrome Frame";
- success = installations->AddDistribution(
- BrowserDistribution::CHROME_FRAME, prefs);
- }
- return success;
-}
// Returns the Custom information for the client identified by the exe path
// passed in. This information is used for crash reporting.
@@ -883,28 +1017,12 @@ int WINAPI wWinMain(HINSTANCE instance, HINSTANCE prev_instance,
InitializeCrashReporting(system_install));
InstallationState original_state;
- original_state.Initialize(prefs);
+ original_state.Initialize();
InstallerState installer_state;
- installer_state.Initialize(prefs, original_state);
+ installer_state.Initialize(cmd_line, prefs, original_state);
const bool is_uninstall = cmd_line.HasSwitch(installer::switches::kUninstall);
- ProductPackageMapping installations(prefs.is_multi_install(), system_install);
- if (!PopulateInstallations(is_uninstall, prefs, &installations)) {
- // Currently this can only fail if one of the installations is a multi and
- // a pre-existing single installation exists or vice versa.
- installer::InstallStatus status = installer::NON_MULTI_INSTALLATION_EXISTS;
- int string_id = IDS_INSTALL_NON_MULTI_INSTALLATION_EXISTS_BASE;
- if (!prefs.is_multi_install()) {
- status = installer::MULTI_INSTALLATION_EXISTS;
- string_id = IDS_INSTALL_MULTI_INSTALLATION_EXISTS_BASE;
- }
- LOG(ERROR) << "Failed to populate installations: " << status;
- InstallUtil::WriteInstallerResult(system_install,
- installer_state.state_key(), status, string_id, NULL);
- return status;
- }
-
// Check to make sure current system is WinXP or later. If not, log
// error message and get out.
if (!InstallUtil::IsOSSupported()) {
@@ -940,8 +1058,8 @@ int WINAPI wWinMain(HINSTANCE instance, HINSTANCE prev_instance,
}
int exit_code = 0;
- if (HandleNonInstallCmdLineOptions(installer_state, cmd_line, installations,
- &exit_code))
+ if (HandleNonInstallCmdLineOptions(original_state, cmd_line, installer_state,
+ &exit_code))
return exit_code;
if (system_install && !IsUserAnAdmin()) {
@@ -965,24 +1083,22 @@ int WINAPI wWinMain(HINSTANCE instance, HINSTANCE prev_instance,
}
installer::InstallStatus install_status = installer::UNKNOWN_STATUS;
- // If --uninstall option is given, uninstall chrome
+ // If --uninstall option is given, uninstall the identified product(s)
if (is_uninstall) {
- for (size_t i = 0; i < installations.products().size(); ++i) {
+ const Products& products = installer_state.products();
+ for (size_t i = 0; i < products.size(); ++i) {
install_status = UninstallProduct(original_state, installer_state,
- cmd_line, *installations.products()[i]);
+ cmd_line, *products[i]);
}
} else {
// If --uninstall option is not specified, we assume it is install case.
- const Packages& packages = installations.packages();
- VLOG(1) << "Installing to " << packages.size() << " target paths";
- for (size_t i = 0; i < packages.size(); ++i) {
- install_status = InstallChrome(original_state, installer_state, cmd_line,
- *packages[i].get(), prefs);
- }
+ VLOG(1) << "Installing to " << installer_state.target_path().value();
+ install_status = InstallProducts(original_state, cmd_line, prefs,
+ &installer_state);
}
const Product* cf_install =
- FindProduct(installations.products(), BrowserDistribution::CHROME_FRAME);
+ installer_state.FindProduct(BrowserDistribution::CHROME_FRAME);
if (cf_install &&
!cmd_line.HasSwitch(installer::switches::kForceUninstall)) {
@@ -991,7 +1107,7 @@ int WINAPI wWinMain(HINSTANCE instance, HINSTANCE prev_instance,
} else if (is_uninstall) {
// Only show the message box if Chrome Frame was the only product being
// uninstalled.
- if (installations.products().size() == 1U) {
+ if (installer_state.products().size() == 1U) {
::MessageBoxW(NULL,
installer::GetLocalizedString(
IDS_UNINSTALL_COMPLETE_BASE).c_str(),
@@ -1005,17 +1121,11 @@ int WINAPI wWinMain(HINSTANCE instance, HINSTANCE prev_instance,
// MSI demands that custom actions always return 0 (ERROR_SUCCESS) or it will
// rollback the action. If we're uninstalling we want to avoid this, so always
// report success, squashing any more informative return codes.
- // TODO(tommi): Fix this loop when IsMsi has been moved out of the Product
- // class.
- for (size_t i = 0; i < installations.products().size(); ++i) {
- const Product* product = installations.products()[i];
- if (!(product->IsMsi() && is_uninstall)) {
- // Note that we allow the status installer::UNINSTALL_REQUIRES_REBOOT
- // to pass through, since this is only returned on uninstall which is
- // never invoked directly by Google Update.
- return_code = InstallUtil::GetInstallReturnCode(install_status);
- }
- }
+ if (!(installer_state.is_msi() && is_uninstall))
+ // Note that we allow the status installer::UNINSTALL_REQUIRES_REBOOT
+ // to pass through, since this is only returned on uninstall which is
+ // never invoked directly by Google Update.
+ return_code = InstallUtil::GetInstallReturnCode(install_status);
VLOG(1) << "Installation complete, returning: " << return_code;
diff --git a/chrome/installer/setup/setup_unittests.rc b/chrome/installer/setup/setup_unittests.rc
new file mode 100644
index 0000000..201a12b
--- /dev/null
+++ b/chrome/installer/setup/setup_unittests.rc
@@ -0,0 +1,65 @@
+// Microsoft Visual C++ generated resource script.
+//
+#include "setup_unittests_resource.h"
+
+#define APSTUDIO_READONLY_SYMBOLS
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 2 resource.
+//
+#include "afxres.h"
+
+/////////////////////////////////////////////////////////////////////////////
+#undef APSTUDIO_READONLY_SYMBOLS
+
+/////////////////////////////////////////////////////////////////////////////
+// English (U.S.) resources
+
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
+LANGUAGE 9, 1
+#pragma code_page(1252)
+
+#ifdef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// TEXTINCLUDE
+//
+
+1 TEXTINCLUDE
+BEGIN
+ "setup_unittests_resource.h\0"
+END
+
+2 TEXTINCLUDE
+BEGIN
+ "#include ""afxres.h""\r\n"
+ "\0"
+END
+
+3 TEXTINCLUDE
+BEGIN
+ "\r\n"
+ "\0"
+END
+
+#endif // APSTUDIO_INVOKED
+
+#endif // English (U.S.) resources
+/////////////////////////////////////////////////////////////////////////////
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// String Table
+//
+#include "installer_util_strings.rc"
+
+#ifndef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 3 resource.
+//
+
+
+/////////////////////////////////////////////////////////////////////////////
+#endif // not APSTUDIO_INVOKED
+
diff --git a/chrome/installer/setup/setup_unittests_resource.h b/chrome/installer/setup/setup_unittests_resource.h
new file mode 100644
index 0000000..6b3a0ee
--- /dev/null
+++ b/chrome/installer/setup/setup_unittests_resource.h
@@ -0,0 +1,18 @@
+// Copyright (c) 2011 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.
+
+//{{NO_DEPENDENCIES}}
+// Microsoft Visual C++ generated include file.
+// Used by setup_unittests.rc
+
+// Next default values for new objects
+//
+#ifdef APSTUDIO_INVOKED
+#ifndef APSTUDIO_READONLY_SYMBOLS
+#define _APS_NEXT_RESOURCE_VALUE 101
+#define _APS_NEXT_COMMAND_VALUE 40001
+#define _APS_NEXT_CONTROL_VALUE 1001
+#define _APS_NEXT_SYMED_VALUE 101
+#endif
+#endif
diff --git a/chrome/installer/setup/setup_util.cc b/chrome/installer/setup/setup_util.cc
index d982792..7c6ec1c 100644
--- a/chrome/installer/setup/setup_util.cc
+++ b/chrome/installer/setup/setup_util.cc
@@ -9,7 +9,6 @@
#include "base/file_util.h"
#include "base/logging.h"
#include "base/string_util.h"
-#include "chrome/installer/util/master_preferences.h"
#include "chrome/installer/util/util_constants.h"
#include "courgette/courgette.h"
#include "third_party/bspatch/mbspatch.h"
diff --git a/chrome/installer/setup/uninstall.cc b/chrome/installer/setup/uninstall.cc
index e21cc01..038525b 100644
--- a/chrome/installer/setup/uninstall.cc
+++ b/chrome/installer/setup/uninstall.cc
@@ -29,7 +29,6 @@
#include "chrome/installer/util/installation_state.h"
#include "chrome/installer/util/installer_state.h"
#include "chrome/installer/util/logging_installer.h"
-#include "chrome/installer/util/package_properties.h"
#include "chrome/installer/util/shell_util.h"
#include "chrome/installer/util/util_constants.h"
@@ -38,6 +37,7 @@
using base::win::RegKey;
using installer::InstallStatus;
+using installer::MasterPreferences;
namespace {
@@ -47,10 +47,12 @@ namespace {
// installed products and for the multi-installer package.
void ProcessGoogleUpdateItems(
const installer::InstallationState& original_state,
+ const installer::InstallerState& installer_state,
const installer::Product& product) {
- const bool system_level = product.system_level();
+ DCHECK(installer_state.is_multi_install());
+ const bool system_level = installer_state.system_install();
BrowserDistribution* distribution = product.distribution();
- const HKEY reg_root = system_level ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER;
+ const HKEY reg_root = installer_state.root_key();
const installer::ProductState* product_state =
original_state.GetProductState(system_level, distribution->GetType());
DCHECK(product_state != NULL);
@@ -58,39 +60,40 @@ void ProcessGoogleUpdateItems(
// Remove product's flags from the channel value.
channel_info.set_value(product_state->channel().value());
- const bool modified = distribution->SetChannelFlags(false, &channel_info);
+ const bool modified = product.SetChannelFlags(false, &channel_info);
// Apply the new channel value to all other products and to the multi package.
if (modified) {
- BrowserDistribution::Type other_dist_type =
+ BrowserDistribution::Type other_dist_types[] = {
(distribution->GetType() == BrowserDistribution::CHROME_BROWSER) ?
- BrowserDistribution::CHROME_FRAME :
- BrowserDistribution::CHROME_BROWSER;
- BrowserDistribution* other_dist =
- BrowserDistribution::GetSpecificDistribution(other_dist_type,
- installer::MasterPreferences::ForCurrentProcess());
+ BrowserDistribution::CHROME_FRAME :
+ BrowserDistribution::CHROME_BROWSER,
+ BrowserDistribution::CHROME_BINARIES
+ };
scoped_ptr<WorkItemList>
update_list(WorkItem::CreateNoRollbackWorkItemList());
- product_state = original_state.GetProductState(system_level,
- other_dist_type);
- if (installer::IsInstalledAsMulti(system_level, other_dist) &&
- !product_state->channel().Equals(channel_info)) {
- update_list->AddSetRegValueWorkItem(reg_root, other_dist->GetStateKey(),
- google_update::kRegApField, channel_info.value(), true);
- } else {
- VLOG(1) << other_dist->GetApplicationName()
- << "'s ap value is unexpectedly up to date.";
- }
-
- product_state = original_state.GetMultiPackageState(system_level);
- DCHECK(product_state != NULL);
- if (!product_state->channel().Equals(channel_info)) {
- update_list->AddSetRegValueWorkItem(reg_root,
- product.package().properties()->GetStateKey(),
- google_update::kRegApField, channel_info.value(), true);
- } else {
- VLOG(1) << "Multi-install package's ap value is unexpectedly up to date.";
+ for (int i = 0; i < arraysize(other_dist_types); ++i) {
+ BrowserDistribution::Type other_dist_type = other_dist_types[i];
+ product_state =
+ original_state.GetProductState(system_level, other_dist_type);
+ // Only modify other products if they're installed and multi.
+ if (product_state != NULL &&
+ product_state->is_multi_install() &&
+ !product_state->channel().Equals(channel_info)) {
+ BrowserDistribution* other_dist =
+ BrowserDistribution::GetSpecificDistribution(other_dist_type);
+ update_list->AddSetRegValueWorkItem(reg_root, other_dist->GetStateKey(),
+ google_update::kRegApField, channel_info.value(), true);
+ } else {
+ LOG_IF(DFATAL,
+ product_state != NULL && product_state->is_multi_install())
+ << "Channel value for "
+ << BrowserDistribution::GetSpecificDistribution(
+ other_dist_type)->GetAppShortCutName()
+ << " is somehow already set to the desired new value of "
+ << channel_info.value();
+ }
}
bool success = update_list->Do();
@@ -175,14 +178,16 @@ void CloseChromeFrameHelperProcess() {
// It returns true iff:
// - Software\Clients\StartMenuInternet\Chromium\"" key has a valid value.
// - The value is same as chrome.exe path for the current installation.
-bool CurrentUserHasDefaultBrowser(const Product& product) {
+bool CurrentUserHasDefaultBrowser(const InstallerState& installer_state,
+ const Product& product) {
std::wstring reg_key(ShellUtil::kRegStartMenuInternet);
- reg_key.append(L"\\" + product.distribution()->GetApplicationName() +
- ShellUtil::kRegShellOpen);
+ reg_key.append(1, L'\\')
+ .append(product.distribution()->GetApplicationName())
+ .append(ShellUtil::kRegShellOpen);
RegKey key(HKEY_LOCAL_MACHINE, reg_key.c_str(), KEY_READ);
std::wstring reg_exe;
if (key.ReadValue(L"", &reg_exe) == ERROR_SUCCESS && reg_exe.length() > 2) {
- FilePath chrome_exe(product.package().path()
+ FilePath chrome_exe(installer_state.target_path()
.Append(installer::kChromeExe));
// The path in the registry will always have quotes.
reg_exe = reg_exe.substr(1, reg_exe.length() - 2);
@@ -199,14 +204,15 @@ bool CurrentUserHasDefaultBrowser(const Product& product) {
// We try to remove the standard desktop shortcut but if that fails we try
// to remove the alternate desktop shortcut. Only one of them should be
// present in a given install but at this point we don't know which one.
-void DeleteChromeShortcuts(const Product& product) {
+void DeleteChromeShortcuts(const InstallerState& installer_state,
+ const Product& product) {
if (!product.is_chrome()) {
VLOG(1) << __FUNCTION__ " called for non-CHROME distribution";
return;
}
FilePath shortcut_path;
- if (product.system_level()) {
+ if (installer_state.system_install()) {
PathService::Get(base::DIR_COMMON_START_MENU, &shortcut_path);
if (!ShellUtil::RemoveChromeDesktopShortcut(product.distribution(),
ShellUtil::CURRENT_USER | ShellUtil::SYSTEM_LEVEL, false)) {
@@ -332,11 +338,11 @@ DeleteResult DeleteLocalState(const Product& product) {
return result;
}
-bool MoveSetupOutOfInstallFolder(const Package& package,
+bool MoveSetupOutOfInstallFolder(const InstallerState& installer_state,
const FilePath& setup_path,
const Version& installed_version) {
bool ret = false;
- FilePath setup_exe(package.GetInstallerDirectory(installed_version)
+ FilePath setup_exe(installer_state.GetInstallerDirectory(installed_version)
.Append(setup_path.BaseName()));
FilePath temp_file;
if (!file_util::CreateTemporaryFile(&temp_file)) {
@@ -349,33 +355,33 @@ bool MoveSetupOutOfInstallFolder(const Package& package,
return ret;
}
-DeleteResult DeleteFilesAndFolders(const Package& package,
+DeleteResult DeleteFilesAndFolders(const InstallerState& installer_state,
const Version& installed_version) {
- VLOG(1) << "DeleteFilesAndFolders: " << package.path().value();
- if (package.path().empty()) {
+ VLOG(1) << "DeleteFilesAndFolders: " << installer_state.target_path().value();
+ if (installer_state.target_path().empty()) {
LOG(ERROR) << "Could not get installation destination path.";
return DELETE_FAILED; // Nothing else we can do to uninstall, so we return.
}
DeleteResult result = DELETE_SUCCEEDED;
- VLOG(1) << "Deleting install path " << package.path().value();
- if (!file_util::Delete(package.path(), true)) {
+ VLOG(1) << "Deleting install path " << installer_state.target_path().value();
+ if (!file_util::Delete(installer_state.target_path(), true)) {
LOG(ERROR) << "Failed to delete folder (1st try): "
- << package.path().value();
- if (FindProduct(package.products(),
- BrowserDistribution::CHROME_FRAME)) {
+ << installer_state.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(package.path().value().c_str());
+ ScheduleDirectoryForDeletion(
+ installer_state.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(package.path(), true)) {
+ if (!file_util::Delete(installer_state.target_path(), true)) {
LOG(ERROR) << "Failed to delete folder (2nd try): "
- << package.path().value();
+ << installer_state.target_path().value();
result = DELETE_FAILED;
}
}
@@ -385,11 +391,11 @@ DeleteResult DeleteFilesAndFolders(const Package& package,
// If we need a reboot to continue, schedule the parent directories for
// deletion unconditionally. If they are not empty, the session manager
// will not delete them on reboot.
- ScheduleParentAndGrandparentForDeletion(package.path());
+ ScheduleParentAndGrandparentForDeletion(installer_state.target_path());
} else {
// Now check and delete if the parent directories are empty
// For example Google\Chrome or Chromium
- DeleteEmptyParentDir(package.path());
+ DeleteEmptyParentDir(installer_state.target_path());
}
return result;
}
@@ -397,7 +403,9 @@ DeleteResult DeleteFilesAndFolders(const Package& package,
// This method checks if Chrome is currently running or if the user has
// cancelled the uninstall operation by clicking Cancel on the confirmation
// box that Chrome pops up.
-InstallStatus IsChromeActiveOrUserCancelled(const Product& product) {
+InstallStatus IsChromeActiveOrUserCancelled(
+ const InstallerState& installer_state,
+ const Product& product) {
int32 exit_code = ResultCodes::NORMAL_EXIT;
CommandLine options(CommandLine::NO_PROGRAM);
options.AppendSwitch(installer::switches::kUninstall);
@@ -411,7 +419,8 @@ InstallStatus IsChromeActiveOrUserCancelled(const Product& product) {
// give this method some brains and not kill chrome.exe launched
// by us, we will not uninstall if we get this return code).
VLOG(1) << "Launching Chrome to do uninstall tasks.";
- if (product.LaunchChromeAndWait(options, &exit_code)) {
+ if (product.LaunchChromeAndWait(installer_state.target_path(), options,
+ &exit_code)) {
VLOG(1) << "chrome.exe launched for uninstall confirmation returned: "
<< exit_code;
if ((exit_code == ResultCodes::UNINSTALL_CHROME_ALIVE) ||
@@ -428,7 +437,8 @@ InstallStatus IsChromeActiveOrUserCancelled(const Product& product) {
return installer::UNINSTALL_CONFIRMED;
}
-bool ShouldDeleteProfile(const CommandLine& cmd_line, InstallStatus status,
+bool ShouldDeleteProfile(const InstallerState& installer_state,
+ const CommandLine& cmd_line, InstallStatus status,
const Product& product) {
bool should_delete = false;
@@ -436,7 +446,7 @@ bool ShouldDeleteProfile(const CommandLine& cmd_line, InstallStatus status,
// 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() && !product.IsMsi()) {
+ if (!product.is_chrome() && !installer_state.is_msi()) {
should_delete = true;
} else {
should_delete =
@@ -542,16 +552,16 @@ const wchar_t kChromeExtProgId[] = L"ChromiumExt";
}
}
-bool ProcessChromeFrameWorkItems(const FilePath& setup_path,
- const Product& product,
- const ProductState* product_state) {
+bool ProcessChromeFrameWorkItems(const InstallationState& original_state,
+ const InstallerState& installer_state,
+ const FilePath& setup_path,
+ const Product& product) {
if (!product.is_chrome_frame())
return false;
- DCHECK(product_state != NULL);
scoped_ptr<WorkItemList> item_list(WorkItem::CreateWorkItemList());
- AddChromeFrameWorkItems(false, setup_path, product_state->version(), product,
- item_list.get());
+ AddChromeFrameWorkItems(original_state, installer_state, setup_path,
+ Version(), product, item_list.get());
return item_list->Do();
}
@@ -581,7 +591,7 @@ InstallStatus UninstallProduct(const InstallationState& original_state,
CloseAllChromeProcesses();
} else if (is_chrome) {
// no --force-uninstall so lets show some UI dialog boxes.
- status = IsChromeActiveOrUserCancelled(product);
+ status = IsChromeActiveOrUserCancelled(installer_state, product);
if (status != installer::UNINSTALL_CONFIRMED &&
status != installer::UNINSTALL_DELETE_PROFILE)
return status;
@@ -590,7 +600,8 @@ InstallStatus UninstallProduct(const InstallationState& original_state,
// another uninstaller (silent) in elevated mode to do HKLM cleanup.
// And continue uninstalling in the current process also to do HKCU cleanup.
if (remove_all &&
- (!suffix.empty() || CurrentUserHasDefaultBrowser(product)) &&
+ (!suffix.empty() ||
+ CurrentUserHasDefaultBrowser(installer_state, product)) &&
!::IsUserAnAdmin() &&
base::win::GetVersion() >= base::win::VERSION_VISTA &&
!cmd_line.HasSwitch(installer::switches::kRunAsAdmin)) {
@@ -615,11 +626,10 @@ InstallStatus UninstallProduct(const InstallationState& original_state,
// in case of errors.
// First delete shortcuts from Start->Programs, Desktop & Quick Launch.
- DeleteChromeShortcuts(product);
+ DeleteChromeShortcuts(installer_state, product);
// Delete the registry keys (Uninstall key and Version key).
- HKEY reg_root = product.system_level() ? HKEY_LOCAL_MACHINE :
- HKEY_CURRENT_USER;
+ HKEY reg_root = installer_state.root_key();
RegKey key(reg_root, L"", KEY_ALL_ACCESS);
// Note that we must retrieve the distribution-specific data before deleting
@@ -634,31 +644,34 @@ InstallStatus UninstallProduct(const InstallationState& original_state,
// there). This is due to a Google Update behaviour where an uninstall and a
// rapid reinstall might result in stale values from the old ClientState key
// being picked up on reinstall.
- product.SetMsiMarker(false);
+ product.SetMsiMarker(installer_state.system_install(), false);
// Remove all Chrome registration keys.
InstallStatus ret = installer::UNKNOWN_STATUS;
DeleteChromeRegistrationKeys(product.distribution(), reg_root, suffix, ret);
- // Get the state of the installed product (if any)
- const ProductState* product_state =
- original_state.GetProductState(installer_state.system_install(),
- browser_dist->GetType());
-
- if (!is_chrome)
- ProcessChromeFrameWorkItems(setup_path, product, product_state);
+ if (!is_chrome) {
+ ProcessChromeFrameWorkItems(original_state, installer_state, setup_path,
+ product);
+ }
- if (product.package().multi_install())
- ProcessGoogleUpdateItems(original_state, product);
+ if (installer_state.is_multi_install())
+ ProcessGoogleUpdateItems(original_state, installer_state, product);
// For user level install also we end up creating some keys in HKLM if user
// sets Chrome as default browser. So delete those as well (needs admin).
- if (remove_all && !product.system_level() &&
- (!suffix.empty() || CurrentUserHasDefaultBrowser(product))) {
+ if (remove_all && !installer_state.system_install() &&
+ (!suffix.empty() || CurrentUserHasDefaultBrowser(installer_state,
+ product))) {
DeleteChromeRegistrationKeys(product.distribution(), HKEY_LOCAL_MACHINE,
suffix, ret);
}
+ // Get the state of the installed product (if any)
+ const ProductState* product_state =
+ original_state.GetProductState(installer_state.system_install(),
+ browser_dist->GetType());
+
// Delete shared registry keys as well (these require admin rights) if
// remove_all option is specified.
if (remove_all) {
@@ -675,8 +688,9 @@ InstallStatus UninstallProduct(const InstallationState& original_state,
// Unregister any dll servers that we may have registered for this
// product.
if (product_state != NULL) {
- std::vector<FilePath> com_dll_list(browser_dist->GetComDllList());
- FilePath dll_folder = product.package().path().Append(
+ std::vector<FilePath> com_dll_list;
+ product.AddComDllList(&com_dll_list);
+ FilePath dll_folder = installer_state.target_path().Append(
UTF8ToWide(product_state->version().GetString()));
scoped_ptr<WorkItemList> unreg_work_item_list(
@@ -685,7 +699,7 @@ InstallStatus UninstallProduct(const InstallationState& original_state,
AddRegisterComDllWorkItems(dll_folder,
com_dll_list,
- product.system_level(),
+ installer_state.system_install(),
false, // Unregister
true, // May fail
unreg_work_item_list.get());
@@ -704,25 +718,35 @@ InstallStatus UninstallProduct(const InstallationState& original_state,
// Finally delete all the files from Chrome folder after moving setup.exe
// and the user's Local State to a temp location.
- bool delete_profile = ShouldDeleteProfile(cmd_line, status, product);
+ bool delete_profile = ShouldDeleteProfile(installer_state, cmd_line, status,
+ product);
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;
- if (product.package().multi_install()) {
- can_delete_files =
- (product.package().GetMultiInstallDependencyCount() == 0);
+ bool can_delete_files = true;
+ if (installer_state.is_multi_install()) {
+ BrowserDistribution::Type types[] = {
+ BrowserDistribution::CHROME_BROWSER,
+ BrowserDistribution::CHROME_FRAME
+ };
+ ProductState prod_state;
+ for (int i = 0; i < arraysize(types); ++i) {
+ if (prod_state.Initialize(installer_state.system_install(), types[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.");
- PackageProperties* props = product.package().properties();
- if (can_delete_files && props->ReceivesUpdates()) {
- InstallUtil::DeleteRegistryKey(key, props->GetVersionKey());
+ if (can_delete_files) {
+ BrowserDistribution* multi_dist =
+ installer_state.multi_package_binaries_distribution();
+ InstallUtil::DeleteRegistryKey(key, multi_dist->GetVersionKey());
}
- } else {
- can_delete_files = true;
}
FilePath backup_state_file(BackupLocalStateFile(
@@ -733,9 +757,9 @@ InstallStatus UninstallProduct(const InstallationState& original_state,
// 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(product.package(), setup_path,
+ MoveSetupOutOfInstallFolder(installer_state, setup_path,
product_state->version());
- delete_result = DeleteFilesAndFolders(product.package(),
+ delete_result = DeleteFilesAndFolders(installer_state,
product_state->version());
}
@@ -763,4 +787,3 @@ InstallStatus UninstallProduct(const InstallationState& original_state,
}
} // namespace installer
-
diff --git a/chrome/installer/util/browser_distribution.cc b/chrome/installer/util/browser_distribution.cc
index 4387b51..be452c5 100644
--- a/chrome/installer/util/browser_distribution.cc
+++ b/chrome/installer/util/browser_distribution.cc
@@ -17,7 +17,9 @@
#include "base/win/registry.h"
#include "chrome/common/env_vars.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_sxs_distribution.h"
#include "chrome/installer/util/install_util.h"
#include "chrome/installer/util/l10n_string_util.h"
@@ -31,6 +33,7 @@ namespace {
// The BrowserDistribution objects are never freed.
BrowserDistribution* g_browser_distribution = NULL;
BrowserDistribution* g_chrome_frame_distribution = NULL;
+BrowserDistribution* g_binaries_distribution = NULL;
// Returns true if currently running in npchrome_frame.dll
bool IsChromeFrameModule() {
@@ -59,17 +62,19 @@ BrowserDistribution::Type GetCurrentDistributionType() {
} // end namespace
-BrowserDistribution::BrowserDistribution(
- const installer::MasterPreferences& prefs)
- : type_(BrowserDistribution::CHROME_BROWSER) {
+BrowserDistribution::BrowserDistribution()
+ : type_(CHROME_BROWSER) {
+}
+
+BrowserDistribution::BrowserDistribution(Type type)
+ : type_(type) {
}
template<class DistributionClass>
BrowserDistribution* BrowserDistribution::GetOrCreateBrowserDistribution(
- const installer::MasterPreferences& prefs,
BrowserDistribution** dist) {
if (!*dist) {
- DistributionClass* temp = new DistributionClass(prefs);
+ DistributionClass* temp = new DistributionClass();
if (base::subtle::NoBarrier_CompareAndSwap(
reinterpret_cast<base::subtle::AtomicWord*>(dist), NULL,
reinterpret_cast<base::subtle::AtomicWord>(temp)) != NULL)
@@ -80,33 +85,43 @@ BrowserDistribution* BrowserDistribution::GetOrCreateBrowserDistribution(
}
BrowserDistribution* BrowserDistribution::GetDistribution() {
- const installer::MasterPreferences& prefs =
- installer::MasterPreferences::ForCurrentProcess();
- return GetSpecificDistribution(GetCurrentDistributionType(), prefs);
+ return GetSpecificDistribution(GetCurrentDistributionType());
}
// static
BrowserDistribution* BrowserDistribution::GetSpecificDistribution(
- BrowserDistribution::Type type,
- const installer::MasterPreferences& prefs) {
+ BrowserDistribution::Type type) {
BrowserDistribution* dist = NULL;
- if (type == CHROME_FRAME) {
- dist = GetOrCreateBrowserDistribution<ChromeFrameDistribution>(
- prefs, &g_chrome_frame_distribution);
- } else {
- DCHECK_EQ(CHROME_BROWSER, type);
+ switch (type) {
+ case CHROME_BROWSER:
+#if defined(GOOGLE_CHROME_BUILD)
+ if (InstallUtil::IsChromeSxSProcess()) {
+ dist = GetOrCreateBrowserDistribution<GoogleChromeSxSDistribution>(
+ &g_browser_distribution);
+ } else {
+ dist = GetOrCreateBrowserDistribution<GoogleChromeDistribution>(
+ &g_browser_distribution);
+ }
+#else
+ dist = GetOrCreateBrowserDistribution<BrowserDistribution>(
+ &g_browser_distribution);
+#endif
+ break;
+
+ case CHROME_FRAME:
+ dist = GetOrCreateBrowserDistribution<ChromeFrameDistribution>(
+ &g_chrome_frame_distribution);
+ break;
+
+ default:
+ DCHECK_EQ(CHROME_BINARIES, type);
#if defined(GOOGLE_CHROME_BUILD)
- if (InstallUtil::IsChromeSxSProcess()) {
- dist = GetOrCreateBrowserDistribution<GoogleChromeSxSDistribution>(
- prefs, &g_browser_distribution);
- } else {
- dist = GetOrCreateBrowserDistribution<GoogleChromeDistribution>(
- prefs, &g_browser_distribution);
- }
+ dist = GetOrCreateBrowserDistribution<GoogleChromeBinariesDistribution>(
+ &g_binaries_distribution);
#else
- dist = GetOrCreateBrowserDistribution<BrowserDistribution>(
- prefs, &g_browser_distribution);
+ dist = GetOrCreateBrowserDistribution<ChromiumBinariesDistribution>(
+ &g_binaries_distribution);
#endif
}
@@ -212,31 +227,6 @@ void BrowserDistribution::LaunchUserExperiment(
void BrowserDistribution::InactiveUserToastExperiment(int flavor,
- const installer::Product& installation) {
-}
-
-std::vector<FilePath> BrowserDistribution::GetKeyFiles() {
- std::vector<FilePath> key_files;
- key_files.push_back(FilePath(installer::kChromeDll));
- return key_files;
-}
-
-std::vector<FilePath> BrowserDistribution::GetComDllList() {
- return std::vector<FilePath>();
-}
-
-void BrowserDistribution::AppendUninstallCommandLineFlags(
- CommandLine* cmd_line) {
- DCHECK(cmd_line);
- cmd_line->AppendSwitch(installer::switches::kChrome);
-}
-
-bool BrowserDistribution::ShouldCreateUninstallEntry() {
- return true;
-}
-
-bool BrowserDistribution::SetChannelFlags(
- bool set,
- installer::ChannelInfo* channel_info) {
- return false;
+ const installer::Product& installation,
+ const FilePath& application_path) {
}
diff --git a/chrome/installer/util/browser_distribution.h b/chrome/installer/util/browser_distribution.h
index 1f6a1c9..3fb1ded 100644
--- a/chrome/installer/util/browser_distribution.h
+++ b/chrome/installer/util/browser_distribution.h
@@ -35,12 +35,12 @@ class BrowserDistribution {
enum Type {
CHROME_BROWSER,
CHROME_FRAME,
+ CHROME_BINARIES,
};
static BrowserDistribution* GetDistribution();
- static BrowserDistribution* GetSpecificDistribution(
- Type type, const installer::MasterPreferences& prefs);
+ static BrowserDistribution* GetSpecificDistribution(Type type);
Type GetType() const { return type_; }
@@ -104,45 +104,21 @@ class BrowserDistribution {
// The user has qualified for the inactive user toast experiment and this
// function just performs it.
virtual void InactiveUserToastExperiment(int flavor,
- const installer::Product& installation);
-
- // A key-file is a file such as a DLL on Windows that is expected to be
- // in use when the product is being used. For example "chrome.dll" for
- // Chrome. Before attempting to delete an installation directory during
- // an uninstallation, the uninstaller will check if any one of a potential
- // set of key files is in use and if they are, abort the delete operation.
- // Only if none of the key files are in use, can the folder be deleted.
- // Note that this function does not return a full path to the key file(s),
- // only (a) file name(s).
- virtual std::vector<FilePath> GetKeyFiles();
-
- // Returns the list of Com Dlls that this product cares about having
- // registered and unregistered. The list may be empty.
- virtual std::vector<FilePath> GetComDllList();
-
- // Given a command line, appends the set of uninstall flags the uninstaller
- // for this distribution will require.
- virtual void AppendUninstallCommandLineFlags(CommandLine* cmd_line);
-
- // Returns true if install should create an uninstallation entry in the
- // Add/Remove Programs dialog for this distribution.
- virtual bool ShouldCreateUninstallEntry();
-
- // Adds or removes product-specific flags in |channel_info|. Returns true if
- // |channel_info| is modified.
- virtual bool SetChannelFlags(bool set, installer::ChannelInfo* channel_info);
+ const installer::Product& installation,
+ const FilePath& application_path);
protected:
- explicit BrowserDistribution(const installer::MasterPreferences& prefs);
+ explicit BrowserDistribution(Type type);
template<class DistributionClass>
static BrowserDistribution* GetOrCreateBrowserDistribution(
- const installer::MasterPreferences& prefs,
BrowserDistribution** dist);
- Type type_;
+ const Type type_;
private:
+ BrowserDistribution();
+
DISALLOW_COPY_AND_ASSIGN(BrowserDistribution);
};
diff --git a/chrome/installer/util/browser_distribution_unittest.cc b/chrome/installer/util/browser_distribution_unittest.cc
index f35ad3f..61c9652 100644
--- a/chrome/installer/util/browser_distribution_unittest.cc
+++ b/chrome/installer/util/browser_distribution_unittest.cc
@@ -5,7 +5,6 @@
// Unit tests for BrowserDistribution class.
#include "chrome/installer/util/browser_distribution.h"
-#include "chrome/installer/util/master_preferences.h"
#include "chrome/installer/util/shell_util.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -25,21 +24,14 @@ class BrowserDistributionTest : public testing::Test {
// 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) {
- struct browser_test_type {
- BrowserDistribution::Type type;
- bool has_com_dlls;
- } browser_tests[] = {
- { BrowserDistribution::CHROME_BROWSER, false },
- { BrowserDistribution::CHROME_FRAME, true },
+ BrowserDistribution::Type browser_tests[] = {
+ BrowserDistribution::CHROME_BROWSER,
+ BrowserDistribution::CHROME_FRAME,
};
- const installer::MasterPreferences& prefs =
- installer::MasterPreferences::ForCurrentProcess();
-
for (int i = 0; i < arraysize(browser_tests); ++i) {
BrowserDistribution* dist =
- BrowserDistribution::GetSpecificDistribution(browser_tests[i].type,
- prefs);
+ BrowserDistribution::GetSpecificDistribution(browser_tests[i]);
ASSERT_TRUE(dist != NULL);
std::wstring name = dist->GetApplicationName();
EXPECT_FALSE(name.empty());
@@ -47,12 +39,6 @@ TEST(BrowserDistributionTest, StringsTest) {
EXPECT_FALSE(desc.empty());
std::wstring alt_name = dist->GetAlternateApplicationName();
EXPECT_FALSE(alt_name.empty());
- std::vector<FilePath> com_dlls(dist->GetComDllList());
- if (browser_tests[i].has_com_dlls) {
- EXPECT_FALSE(com_dlls.empty());
- } else {
- EXPECT_TRUE(com_dlls.empty());
- }
}
}
diff --git a/chrome/installer/util/channel_info.cc b/chrome/installer/util/channel_info.cc
index 4abcb70..98f54d8 100644
--- a/chrome/installer/util/channel_info.cc
+++ b/chrome/installer/util/channel_info.cc
@@ -153,6 +153,18 @@ bool ChannelInfo::GetChannelName(std::wstring* channel_name) const {
return false;
}
+bool ChannelInfo::EqualsBaseOf(const ChannelInfo& other) const {
+ std::wstring::size_type this_base_end;
+ std::wstring::size_type other_base_end;
+
+ if (!FindModifier(MOD_MULTI_INSTALL, value_, &this_base_end))
+ this_base_end = FindInsertionPoint(MOD_MULTI_INSTALL, value_);
+ if (!FindModifier(MOD_MULTI_INSTALL, other.value_, &other_base_end))
+ other_base_end = FindInsertionPoint(MOD_MULTI_INSTALL, other.value_);
+ return value_.compare(0, this_base_end,
+ other.value_.c_str(), other_base_end) == 0;
+}
+
bool ChannelInfo::IsCeee() const {
return HasModifier(MOD_CEEE, value_);
}
diff --git a/chrome/installer/util/channel_info.h b/chrome/installer/util/channel_info.h
index 7954e1c..a5b895d 100644
--- a/chrome/installer/util/channel_info.h
+++ b/chrome/installer/util/channel_info.h
@@ -41,6 +41,10 @@ class ChannelInfo {
// determined.
bool GetChannelName(std::wstring* channel_name) const;
+ // Returns true if this object and |other| have a common base (that which
+ // remains when all modifiers and suffixes are omitted).
+ bool EqualsBaseOf(const ChannelInfo& other) const;
+
// Returns true if the -CEEE modifier is present in the value.
bool IsCeee() const;
diff --git a/chrome/installer/util/channel_info_unittest.cc b/chrome/installer/util/channel_info_unittest.cc
index febc33a..5c03040 100644
--- a/chrome/installer/util/channel_info_unittest.cc
+++ b/chrome/installer/util/channel_info_unittest.cc
@@ -2,6 +2,9 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#include <utility>
+
+#include "base/basictypes.h"
#include "chrome/installer/util/channel_info.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -158,3 +161,36 @@ TEST(ChannelInfoTest, Combinations) {
ci.set_value(L"2.0-beta-chromeframe-chrome");
EXPECT_TRUE(ci.IsChrome());
}
+
+TEST(ChannelInfoTest, EqualsBaseOf) {
+ installer::ChannelInfo ci1;
+ installer::ChannelInfo ci2;
+
+ std::pair<std::wstring, std::wstring> trues[] = {
+ std::make_pair(std::wstring(L""), std::wstring(L"")),
+ std::make_pair(std::wstring(L"2.0-beta"), std::wstring(L"2.0-beta")),
+ std::make_pair(std::wstring(L"-full"), std::wstring(L"-full")),
+ std::make_pair(std::wstring(L""), std::wstring(L"-multi"))
+ };
+ for (int i = 0; i < arraysize(trues); ++i) {
+ std::pair<std::wstring, std::wstring>& the_pair = trues[i];
+ ci1.set_value(the_pair.first);
+ ci2.set_value(the_pair.second);
+ EXPECT_TRUE(ci1.EqualsBaseOf(ci2)) << the_pair.first << " "
+ << the_pair.second;
+ }
+
+ std::pair<std::wstring, std::wstring> falses[] = {
+ std::make_pair(std::wstring(L""), std::wstring(L"2.0-beta")),
+ std::make_pair(std::wstring(L"2.0-gamma"), std::wstring(L"2.0-beta")),
+ std::make_pair(std::wstring(L"spam-full"), std::wstring(L"-full")),
+ std::make_pair(std::wstring(L"multi"), std::wstring(L"-multi"))
+ };
+ for (int i = 0; i < arraysize(falses); ++i) {
+ std::pair<std::wstring, std::wstring>& the_pair = falses[i];
+ ci1.set_value(the_pair.first);
+ ci2.set_value(the_pair.second);
+ EXPECT_FALSE(ci1.EqualsBaseOf(ci2)) << the_pair.first << " "
+ << the_pair.second;
+ }
+}
diff --git a/chrome/installer/util/chrome_browser_operations.cc b/chrome/installer/util/chrome_browser_operations.cc
new file mode 100644
index 0000000..c4acd5c
--- /dev/null
+++ b/chrome/installer/util/chrome_browser_operations.cc
@@ -0,0 +1,82 @@
+// Copyright (c) 2011 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_browser_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 ChromeBrowserOperations::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 ChromeBrowserOperations::ReadOptions(
+ const CommandLine& uninstall_command,
+ std::set<std::wstring>* options) const {
+ DCHECK(options);
+
+ if (uninstall_command.HasSwitch(switches::kMultiInstall))
+ options->insert(kOptionMultiInstall);
+}
+
+void ChromeBrowserOperations::AddKeyFiles(
+ const std::set<std::wstring>& options,
+ std::vector<FilePath>* key_files) const {
+ DCHECK(key_files);
+ key_files->push_back(FilePath(installer::kChromeDll));
+}
+
+void ChromeBrowserOperations::AddComDllList(
+ const std::set<std::wstring>& options,
+ std::vector<FilePath>* com_dll_list) const {
+}
+
+void ChromeBrowserOperations::AppendProductFlags(
+ const std::set<std::wstring>& options,
+ CommandLine* uninstall_command) const {
+ DCHECK(uninstall_command);
+
+ if (options.find(kOptionMultiInstall) != options.end()) {
+ if (!uninstall_command->HasSwitch(switches::kMultiInstall))
+ uninstall_command->AppendSwitch(switches::kMultiInstall);
+ uninstall_command->AppendSwitch(switches::kChrome);
+ }
+}
+
+bool ChromeBrowserOperations::SetChannelFlags(
+ const std::set<std::wstring>& options,
+ bool set,
+ ChannelInfo* channel_info) const {
+#if defined(GOOGLE_CHROME_BUILD)
+ DCHECK(channel_info);
+ return channel_info->SetChrome(set);
+#else
+ return false;
+#endif
+}
+
+bool ChromeBrowserOperations::ShouldCreateUninstallEntry(
+ const std::set<std::wstring>& options) const {
+ return true;
+}
+
+} // namespace installer
diff --git a/chrome/installer/util/chrome_browser_operations.h b/chrome/installer/util/chrome_browser_operations.h
new file mode 100644
index 0000000..5628b7d
--- /dev/null
+++ b/chrome/installer/util/chrome_browser_operations.h
@@ -0,0 +1,54 @@
+// Copyright (c) 2011 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_BROWSER_OPERATIONS_H_
+#define CHROME_INSTALLER_UTIL_CHROME_BROWSER_OPERATIONS_H_
+#pragma once
+
+#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 Chrome; see ProductOperations for general info.
+class ChromeBrowserOperations : public ProductOperations {
+ public:
+ ChromeBrowserOperations() {}
+
+ 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* uninstall_command) 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(ChromeBrowserOperations);
+};
+
+} // namespace installer
+
+#endif // CHROME_INSTALLER_UTIL_CHROME_BROWSER_OPERATIONS_H_
diff --git a/chrome/installer/util/chrome_browser_sxs_operations.cc b/chrome/installer/util/chrome_browser_sxs_operations.cc
new file mode 100644
index 0000000..6c7fd81
--- /dev/null
+++ b/chrome/installer/util/chrome_browser_sxs_operations.cc
@@ -0,0 +1,22 @@
+// Copyright (c) 2011 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_browser_sxs_operations.h"
+
+#include "base/command_line.h"
+#include "base/logging.h"
+#include "chrome/installer/util/util_constants.h"
+
+namespace installer {
+
+void ChromeBrowserSxSOperations::AppendProductFlags(
+ const std::set<std::wstring>& options,
+ CommandLine* uninstall_command) const {
+ DCHECK(uninstall_command);
+
+ uninstall_command->AppendSwitch(switches::kChromeSxS);
+ ChromeBrowserOperations::AppendProductFlags(options, uninstall_command);
+}
+
+} // namespace installer
diff --git a/chrome/installer/util/chrome_browser_sxs_operations.h b/chrome/installer/util/chrome_browser_sxs_operations.h
new file mode 100644
index 0000000..de6101e
--- /dev/null
+++ b/chrome/installer/util/chrome_browser_sxs_operations.h
@@ -0,0 +1,33 @@
+// Copyright (c) 2011 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_BROWSER_SXS_OPERATIONS_H_
+#define CHROME_INSTALLER_UTIL_CHROME_BROWSER_SXS_OPERATIONS_H_
+#pragma once
+
+#include <set>
+#include <string>
+
+#include "base/basictypes.h"
+#include "base/compiler_specific.h"
+#include "chrome/installer/util/chrome_browser_operations.h"
+
+namespace installer {
+
+// Operations specific to Chrome SxS; see ProductOperations for general info.
+class ChromeBrowserSxSOperations : public ChromeBrowserOperations {
+ public:
+ ChromeBrowserSxSOperations() {}
+
+ virtual void AppendProductFlags(
+ const std::set<std::wstring>& options,
+ CommandLine* uninstall_command) const OVERRIDE;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(ChromeBrowserSxSOperations);
+};
+
+} // namespace installer
+
+#endif // CHROME_INSTALLER_UTIL_CHROME_BROWSER_SXS_OPERATIONS_H_
diff --git a/chrome/installer/util/chrome_frame_distribution.cc b/chrome/installer/util/chrome_frame_distribution.cc
index 2507f1d..86a1abc 100644
--- a/chrome/installer/util/chrome_frame_distribution.cc
+++ b/chrome/installer/util/chrome_frame_distribution.cc
@@ -18,8 +18,6 @@
#include "chrome/installer/util/helper.h"
#include "chrome/installer/util/install_util.h"
#include "chrome/installer/util/l10n_string_util.h"
-#include "chrome/installer/util/master_preferences.h"
-#include "chrome/installer/util/master_preferences_constants.h"
#include "installer_util_strings.h" // NOLINT
@@ -27,38 +25,8 @@ namespace {
const wchar_t kChromeFrameGuid[] = L"{8BA986DA-5100-405E-AA35-86F34A02ACBF}";
}
-ChromeFrameDistribution::ChromeFrameDistribution(
- const installer::MasterPreferences& prefs)
- : BrowserDistribution(prefs), ceee_(prefs.install_ceee()),
- ready_mode_(false) {
- type_ = BrowserDistribution::CHROME_FRAME;
- prefs.GetBool(installer::master_preferences::kChromeFrameReadyMode,
- &ready_mode_);
-
- bool system_install = false;
- prefs.GetBool(installer::master_preferences::kSystemLevel, &system_install);
-
- // See if Chrome Frame is already installed. If so, we must make sure that
- // the ceee and ready mode flags match.
- CommandLine uninstall(CommandLine::NO_PROGRAM);
- if (installer::GetUninstallSwitches(system_install, this, &uninstall)) {
- if (!ceee_ && uninstall.HasSwitch(installer::switches::kCeee)) {
- LOG(INFO) << "CEEE is not specified on the command line but CEEE is "
- "already installed. Implicitly enabling CEEE.";
- ceee_ = true;
- }
-
- // If the user has already opted in to CF, we shouldn't set the ready-mode
- // flag. If we don't do this, we might have two entries in the Add/Remove
- // Programs list that can uninstall GCF.
- if (ready_mode_) {
- if (!uninstall.HasSwitch(installer::switches::kChromeFrameReadyMode)) {
- LOG(INFO) << "Ready mode was specified on the command line but GCF "
- "is already fully installed. Ignoring command line.";
- ready_mode_ = false;
- }
- }
- }
+ChromeFrameDistribution::ChromeFrameDistribution()
+ : BrowserDistribution(CHROME_FRAME) {
}
std::wstring ChromeFrameDistribution::GetAppGuid() {
@@ -146,61 +114,3 @@ void ChromeFrameDistribution::UpdateInstallStatus(bool system_install,
InstallUtil::GetInstallReturnCode(install_status), kChromeFrameGuid);
#endif
}
-
-std::vector<FilePath> ChromeFrameDistribution::GetKeyFiles() {
- std::vector<FilePath> key_files;
- key_files.push_back(FilePath(installer::kChromeFrameDll));
- if (ceee_) {
- key_files.push_back(FilePath(installer::kCeeeIeDll));
- key_files.push_back(FilePath(installer::kCeeeBrokerExe));
- }
- return key_files;
-}
-
-std::vector<FilePath> ChromeFrameDistribution::GetComDllList() {
- std::vector<FilePath> dll_list;
- dll_list.push_back(FilePath(installer::kChromeFrameDll));
- if (ceee_) {
- dll_list.push_back(FilePath(installer::kCeeeInstallHelperDll));
- dll_list.push_back(FilePath(installer::kCeeeIeDll));
- }
- return dll_list;
-}
-
-void ChromeFrameDistribution::AppendUninstallCommandLineFlags(
- CommandLine* cmd_line) {
- DCHECK(cmd_line);
- cmd_line->AppendSwitch(installer::switches::kChromeFrame);
-
- if (ceee_)
- cmd_line->AppendSwitch(installer::switches::kCeee);
-
- if (ready_mode_)
- cmd_line->AppendSwitch(installer::switches::kChromeFrameReadyMode);
-}
-
-bool ChromeFrameDistribution::ShouldCreateUninstallEntry() {
- // If Chrome Frame is being installed in ready mode, then we will not
- // add an entry to the add/remove dialog.
- return !ready_mode_;
-}
-
-bool ChromeFrameDistribution::SetChannelFlags(
- bool set,
- installer::ChannelInfo* channel_info) {
-#if defined(GOOGLE_CHROME_BUILD)
- DCHECK(channel_info);
- bool modified = channel_info->SetChromeFrame(set);
-
- // Always remove the options if we're called to remove flags.
- if (!set || ceee_)
- modified |= channel_info->SetCeee(set);
-
- if (!set || ready_mode_)
- modified |= channel_info->SetReadyMode(set);
-
- return modified;
-#else
- return false;
-#endif
-}
diff --git a/chrome/installer/util/chrome_frame_distribution.h b/chrome/installer/util/chrome_frame_distribution.h
index f34cc86..043dc68 100644
--- a/chrome/installer/util/chrome_frame_distribution.h
+++ b/chrome/installer/util/chrome_frame_distribution.h
@@ -55,29 +55,11 @@ class ChromeFrameDistribution : public BrowserDistribution {
bool incremental_install, bool multi_install,
installer::InstallStatus install_status);
- virtual std::vector<FilePath> GetKeyFiles();
-
- virtual std::vector<FilePath> GetComDllList();
-
- virtual void AppendUninstallCommandLineFlags(CommandLine* cmd_line);
-
- virtual bool ShouldCreateUninstallEntry();
-
- virtual bool SetChannelFlags(bool set, installer::ChannelInfo* channel_info);
-
protected:
friend class BrowserDistribution;
// Disallow construction from non-friends.
- explicit ChromeFrameDistribution(
- const installer::MasterPreferences& prefs);
-
- // Determines whether this Chrome Frame distribution is being used to work
- // with CEEE bits as well.
- bool ceee_;
-
- // True when Chrome Frame is installed in ready mode (users have to opt in).
- bool ready_mode_;
+ ChromeFrameDistribution();
};
#endif // CHROME_INSTALLER_UTIL_CHROME_FRAME_DISTRIBUTION_H_
diff --git a/chrome/installer/util/chrome_frame_operations.cc b/chrome/installer/util/chrome_frame_operations.cc
new file mode 100644
index 0000000..4ab5b2a
--- /dev/null
+++ b/chrome/installer/util/chrome_frame_operations.cc
@@ -0,0 +1,148 @@
+// Copyright (c) 2011 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_frame_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 {
+
+// Remove ready-mode if not multi-install.
+void ChromeFrameOperations::NormalizeOptions(
+ std::set<std::wstring>* options) const {
+ std::set<std::wstring>::iterator ready_mode(options->find(kOptionReadyMode));
+ if (ready_mode != options->end() &&
+ options->find(kOptionMultiInstall) == options->end()) {
+ LOG(WARNING) << "--ready-mode option does not apply when --multi-install "
+ "is not also specified; ignoring.";
+ options->erase(ready_mode);
+ }
+}
+
+void ChromeFrameOperations::ReadOptions(
+ const MasterPreferences& prefs,
+ std::set<std::wstring>* options) const {
+ DCHECK(options);
+
+ static const struct PrefToOption {
+ const char* pref_name;
+ const wchar_t* option_name;
+ } map[] = {
+ { master_preferences::kCeee, kOptionCeee },
+ { master_preferences::kChromeFrameReadyMode, kOptionReadyMode },
+ { master_preferences::kMultiInstall, kOptionMultiInstall }
+ };
+
+ bool pref_value;
+
+ for (const PrefToOption* scan = &map[0], *end = &map[arraysize(map)];
+ scan != end; ++scan) {
+ if (prefs.GetBool(scan->pref_name, &pref_value) && pref_value)
+ options->insert(scan->option_name);
+ }
+
+ NormalizeOptions(options);
+}
+
+void ChromeFrameOperations::ReadOptions(
+ const CommandLine& uninstall_command,
+ std::set<std::wstring>* options) const {
+ DCHECK(options);
+
+ static const struct FlagToOption {
+ const char* flag_name;
+ const wchar_t* option_name;
+ } map[] = {
+ { switches::kCeee, kOptionCeee },
+ { switches::kChromeFrameReadyMode, kOptionReadyMode },
+ { switches::kMultiInstall, kOptionMultiInstall }
+ };
+
+ for (const FlagToOption* scan = &map[0], *end = &map[arraysize(map)];
+ scan != end; ++scan) {
+ if (uninstall_command.HasSwitch(scan->flag_name))
+ options->insert(scan->option_name);
+ }
+
+ NormalizeOptions(options);
+}
+
+void ChromeFrameOperations::AddKeyFiles(
+ const std::set<std::wstring>& options,
+ std::vector<FilePath>* key_files) const {
+ DCHECK(key_files);
+ key_files->push_back(FilePath(installer::kChromeFrameDll));
+ if (options.find(kOptionCeee) != options.end()) {
+ key_files->push_back(FilePath(installer::kCeeeIeDll));
+ key_files->push_back(FilePath(installer::kCeeeBrokerExe));
+ }
+}
+
+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));
+ if (options.find(kOptionCeee) != options.end()) {
+ com_dll_list->push_back(FilePath(installer::kCeeeInstallHelperDll));
+ com_dll_list->push_back(FilePath(installer::kCeeeIeDll));
+ }
+}
+
+void ChromeFrameOperations::AppendProductFlags(
+ const std::set<std::wstring>& options,
+ CommandLine* uninstall_command) const {
+ DCHECK(uninstall_command);
+ uninstall_command->AppendSwitch(switches::kChromeFrame);
+
+ if (options.find(kOptionCeee) != options.end())
+ uninstall_command->AppendSwitch(switches::kCeee);
+
+ if (options.find(kOptionMultiInstall) != options.end()) {
+ if (!uninstall_command->HasSwitch(switches::kMultiInstall))
+ uninstall_command->AppendSwitch(switches::kMultiInstall);
+
+ // ready-mode is only supported in multi-installs of Chrome Frame.
+ if (options.find(kOptionReadyMode) != options.end())
+ uninstall_command->AppendSwitch(switches::kChromeFrameReadyMode);
+ }
+}
+
+bool ChromeFrameOperations::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->SetChromeFrame(set);
+
+ // Always remove the options if we're called to remove flags or if the
+ // corresponding option isn't set.
+ modified |= channel_info->SetCeee(
+ set && options.find(kOptionCeee) != options.end());
+
+ modified |= channel_info->SetReadyMode(
+ set && options.find(kOptionReadyMode) != options.end());
+
+ return modified;
+#else
+ return false;
+#endif
+}
+
+bool ChromeFrameOperations::ShouldCreateUninstallEntry(
+ const std::set<std::wstring>& options) const {
+ return options.find(kOptionReadyMode) == options.end();
+}
+
+} // namespace installer
diff --git a/chrome/installer/util/chrome_frame_operations.h b/chrome/installer/util/chrome_frame_operations.h
new file mode 100644
index 0000000..267eef6
--- /dev/null
+++ b/chrome/installer/util/chrome_frame_operations.h
@@ -0,0 +1,58 @@
+// Copyright (c) 2011 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_FRAME_OPERATIONS_H_
+#define CHROME_INSTALLER_UTIL_CHROME_FRAME_OPERATIONS_H_
+#pragma once
+
+#include <set>
+#include <string>
+#include <vector>
+
+#include "base/basictypes.h"
+#include "base/file_path.h"
+#include "base/compiler_specific.h"
+#include "chrome/installer/util/product_operations.h"
+
+namespace installer {
+
+// Operations specific to Chrome Frame; see ProductOperations for general info.
+class ChromeFrameOperations : public ProductOperations {
+ public:
+ ChromeFrameOperations() {}
+
+ 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* uninstall_command) 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;
+
+ protected:
+ void NormalizeOptions(std::set<std::wstring>* options) const;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(ChromeFrameOperations);
+};
+
+} // namespace installer
+
+#endif // CHROME_INSTALLER_UTIL_CHROME_FRAME_OPERATIONS_H_
diff --git a/chrome/installer/util/chromium_binaries_distribution.cc b/chrome/installer/util/chromium_binaries_distribution.cc
new file mode 100644
index 0000000..8e39ffb
--- /dev/null
+++ b/chrome/installer/util/chromium_binaries_distribution.cc
@@ -0,0 +1,105 @@
+// Copyright (c) 2011 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 declares a class that contains various method related to branding.
+
+#include "chrome/installer/util/google_chrome_binaries_distribution.h"
+
+#include "base/logging.h"
+
+namespace {
+
+const wchar_t kChromiumBinariesName[] = L"Chromium Binaries";
+
+} // namespace
+
+ChromiumBinariesDistribution::ChromiumBinariesDistribution()
+ : BrowserDistribution(CHROME_BINARIES),
+ browser_distribution_(
+ BrowserDistribution::GetSpecificDistribution(CHROME_BROWSER)) {
+}
+
+std::wstring ChromiumBinariesDistribution::GetAppGuid() {
+ return std::wstring();
+}
+
+std::wstring ChromiumBinariesDistribution::GetApplicationName() {
+ NOTREACHED() << "GetApplicationName unsupported";
+ return std::wstring();
+}
+
+std::wstring ChromiumBinariesDistribution::GetAppShortCutName() {
+ return kChromiumBinariesName;
+}
+
+std::wstring ChromiumBinariesDistribution::GetAlternateApplicationName() {
+ NOTREACHED() << "GetApplicationName unsupported";
+ return std::wstring();
+}
+
+std::wstring ChromiumBinariesDistribution::GetBrowserAppId() {
+ NOTREACHED() << "GetApplicationName unsupported";
+ return std::wstring();
+}
+
+std::wstring ChromiumBinariesDistribution::GetInstallSubDir() {
+ return browser_distribution_->GetInstallSubDir();
+}
+
+std::wstring ChromiumBinariesDistribution::GetPublisherName() {
+ NOTREACHED() << "GetApplicationName unsupported";
+ return std::wstring();
+}
+
+std::wstring ChromiumBinariesDistribution::GetAppDescription() {
+ NOTREACHED() << "GetApplicationName unsupported";
+ return std::wstring();
+}
+
+std::wstring ChromiumBinariesDistribution::GetLongAppDescription() {
+ NOTREACHED() << "GetApplicationName unsupported";
+ return std::wstring();
+}
+
+std::string ChromiumBinariesDistribution::GetSafeBrowsingName() {
+ NOTREACHED() << "GetApplicationName unsupported";
+ return std::string();
+}
+
+std::wstring ChromiumBinariesDistribution::GetStateKey() {
+ return std::wstring(L"Software\\").append(kChromiumBinariesName);
+}
+
+std::wstring ChromiumBinariesDistribution::GetStateMediumKey() {
+ return std::wstring(L"Software\\").append(kChromiumBinariesName);
+}
+
+std::wstring ChromiumBinariesDistribution::GetUninstallLinkName() {
+ NOTREACHED() << "GetApplicationName unsupported";
+ return std::wstring();
+}
+
+std::wstring ChromiumBinariesDistribution::GetUninstallRegPath() {
+ NOTREACHED() << "GetApplicationName unsupported";
+ return std::wstring();
+}
+
+std::wstring ChromiumBinariesDistribution::GetVersionKey() {
+ return std::wstring(L"Software\\").append(kChromiumBinariesName);
+}
+
+bool ChromiumBinariesDistribution::CanSetAsDefault() {
+ NOTREACHED() << "GetApplicationName unsupported";
+ return false;
+}
+
+int ChromiumBinariesDistribution::GetIconIndex() {
+ NOTREACHED() << "GetApplicationName unsupported";
+ return 0;
+}
+
+bool ChromiumBinariesDistribution::GetChromeChannel(std::wstring* channel) {
+ NOTREACHED() << "GetApplicationName unsupported";
+ return false;
+}
diff --git a/chrome/installer/util/chromium_binaries_distribution.h b/chrome/installer/util/chromium_binaries_distribution.h
new file mode 100644
index 0000000..6ee0c4f
--- /dev/null
+++ b/chrome/installer/util/chromium_binaries_distribution.h
@@ -0,0 +1,64 @@
+// Copyright (c) 2011 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 declares a class that contains various method related to branding.
+
+#ifndef CHROME_INSTALLER_UTIL_CHROMIUM_BINARIES_DISTRIBUTION_H_
+#define CHROME_INSTALLER_UTIL_CHROMIUM_BINARIES_DISTRIBUTION_H_
+#pragma once
+
+#include <string>
+
+#include "chrome/installer/util/browser_distribution.h"
+
+class ChromiumBinariesDistribution : public BrowserDistribution {
+ public:
+ virtual std::wstring GetAppGuid();
+
+ virtual std::wstring GetApplicationName();
+
+ virtual std::wstring GetAppShortCutName();
+
+ virtual std::wstring GetAlternateApplicationName();
+
+ virtual std::wstring GetBrowserAppId();
+
+ virtual std::wstring GetInstallSubDir();
+
+ virtual std::wstring GetPublisherName();
+
+ virtual std::wstring GetAppDescription();
+
+ virtual std::wstring GetLongAppDescription();
+
+ virtual std::string GetSafeBrowsingName();
+
+ virtual std::wstring GetStateKey();
+
+ virtual std::wstring GetStateMediumKey();
+
+ virtual std::wstring GetUninstallLinkName();
+
+ virtual std::wstring GetUninstallRegPath();
+
+ virtual std::wstring GetVersionKey();
+
+ virtual bool CanSetAsDefault();
+
+ virtual int GetIconIndex();
+
+ virtual bool GetChromeChannel(std::wstring* channel);
+
+ protected:
+ friend class BrowserDistribution;
+
+ ChromiumBinariesDistribution();
+
+ BrowserDistribution* browser_distribution_;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(ChromiumBinariesDistribution);
+};
+
+#endif // CHROME_INSTALLER_UTIL_CHROMIUM_BINARIES_DISTRIBUTION_H_
diff --git a/chrome/installer/util/google_chrome_binaries_distribution.cc b/chrome/installer/util/google_chrome_binaries_distribution.cc
new file mode 100644
index 0000000..00229bf
--- /dev/null
+++ b/chrome/installer/util/google_chrome_binaries_distribution.cc
@@ -0,0 +1,56 @@
+// Copyright (c) 2011 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 declares a class that contains various method related to branding.
+
+#include "chrome/installer/util/google_chrome_binaries_distribution.h"
+
+#include "chrome/installer/util/google_update_constants.h"
+#include "chrome/installer/util/google_update_settings.h"
+#include "chrome/installer/util/install_util.h"
+
+namespace {
+
+const wchar_t kChromeBinariesGuid[] = L"{4DC8B4CA-1BDA-483e-B5FA-D3C12E15B62D}";
+const wchar_t kChromeBinariesName[] = L"Google Chrome binaries";
+
+} // namespace
+
+GoogleChromeBinariesDistribution::GoogleChromeBinariesDistribution()
+ : ChromiumBinariesDistribution() {
+}
+
+std::wstring GoogleChromeBinariesDistribution::GetAppGuid() {
+ return kChromeBinariesGuid;
+}
+
+std::wstring GoogleChromeBinariesDistribution::GetAppShortCutName() {
+ return kChromeBinariesName;
+}
+
+std::wstring GoogleChromeBinariesDistribution::GetStateKey() {
+ return std::wstring(google_update::kRegPathClientState)
+ .append(1, L'\\')
+ .append(kChromeBinariesGuid);
+}
+
+std::wstring GoogleChromeBinariesDistribution::GetStateMediumKey() {
+ return std::wstring(google_update::kRegPathClientStateMedium)
+ .append(1, L'\\')
+ .append(kChromeBinariesGuid);
+}
+
+std::wstring GoogleChromeBinariesDistribution::GetVersionKey() {
+ return std::wstring(google_update::kRegPathClients)
+ .append(1, L'\\')
+ .append(kChromeBinariesGuid);
+}
+
+void GoogleChromeBinariesDistribution::UpdateInstallStatus(bool system_install,
+ bool incremental_install, bool multi_install,
+ installer::InstallStatus install_status) {
+ GoogleUpdateSettings::UpdateInstallStatus(system_install,
+ incremental_install, multi_install,
+ InstallUtil::GetInstallReturnCode(install_status), kChromeBinariesGuid);
+}
diff --git a/chrome/installer/util/google_chrome_binaries_distribution.h b/chrome/installer/util/google_chrome_binaries_distribution.h
new file mode 100644
index 0000000..3ddbf34
--- /dev/null
+++ b/chrome/installer/util/google_chrome_binaries_distribution.h
@@ -0,0 +1,38 @@
+// Copyright (c) 2011 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 declares a class that contains various method related to branding.
+
+#ifndef CHROME_INSTALLER_UTIL_GOOGLE_CHROME_BINARIES_DISTRIBUTION_H_
+#define CHROME_INSTALLER_UTIL_GOOGLE_CHROME_BINARIES_DISTRIBUTION_H_
+#pragma once
+
+#include "chrome/installer/util/chromium_binaries_distribution.h"
+
+class GoogleChromeBinariesDistribution : public ChromiumBinariesDistribution {
+ public:
+ virtual std::wstring GetAppGuid();
+
+ virtual std::wstring GetAppShortCutName();
+
+ virtual std::wstring GetStateKey();
+
+ virtual std::wstring GetStateMediumKey();
+
+ virtual std::wstring GetVersionKey();
+
+ virtual void UpdateInstallStatus(bool system_install,
+ bool incremental_install, bool multi_install,
+ installer::InstallStatus install_status);
+
+ protected:
+ friend class BrowserDistribution;
+
+ GoogleChromeBinariesDistribution();
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(GoogleChromeBinariesDistribution);
+};
+
+#endif // CHROME_INSTALLER_UTIL_GOOGLE_CHROME_BINARIES_DISTRIBUTION_H_
diff --git a/chrome/installer/util/google_chrome_distribution.cc b/chrome/installer/util/google_chrome_distribution.cc
index e0ab343..300ee1d 100644
--- a/chrome/installer/util/google_chrome_distribution.cc
+++ b/chrome/installer/util/google_chrome_distribution.cc
@@ -253,9 +253,9 @@ bool RelaunchSetupAsConsoleUser(const std::string& flag) {
} // namespace
-GoogleChromeDistribution::GoogleChromeDistribution(
- const installer::MasterPreferences& prefs)
- : BrowserDistribution(prefs), product_guid_(kChromeGuid) {
+GoogleChromeDistribution::GoogleChromeDistribution()
+ : BrowserDistribution(CHROME_BROWSER),
+ product_guid_(kChromeGuid) {
}
// The functions below are not used by the 64-bit Windows binary -
@@ -633,7 +633,8 @@ void GoogleChromeDistribution::LaunchUserExperiment(
// User qualifies for the experiment. Launch chrome with --try-chrome=flavor.
void GoogleChromeDistribution::InactiveUserToastExperiment(int flavor,
- const installer::Product& installation) {
+ const installer::Product& installation,
+ const FilePath& application_path) {
bool has_welcome_url = (flavor == 0);
// Possibly add a url to launch depending on the experiment flavor.
CommandLine options(CommandLine::NO_PROGRAM);
@@ -651,7 +652,7 @@ void GoogleChromeDistribution::InactiveUserToastExperiment(int flavor,
}
// Launch chrome now. It will show the toast UI.
int32 exit_code = 0;
- if (!installation.LaunchChromeAndWait(options, &exit_code))
+ if (!installation.LaunchChromeAndWait(application_path, options, &exit_code))
return;
// The chrome process has exited, figure out what happened.
@@ -688,10 +689,3 @@ void GoogleChromeDistribution::InactiveUserToastExperiment(int flavor,
base::LaunchApp(cmd, false, false, NULL);
}
#endif
-
-bool GoogleChromeDistribution::SetChannelFlags(
- bool set,
- installer::ChannelInfo* channel_info) {
- DCHECK(channel_info);
- return channel_info->SetChrome(set);
-}
diff --git a/chrome/installer/util/google_chrome_distribution.h b/chrome/installer/util/google_chrome_distribution.h
index 038d27b..9610518 100644
--- a/chrome/installer/util/google_chrome_distribution.h
+++ b/chrome/installer/util/google_chrome_distribution.h
@@ -79,18 +79,16 @@ class GoogleChromeDistribution : public BrowserDistribution {
// toast experiment. It will use chrome to show the UI and it will record the
// outcome in the registry.
virtual void InactiveUserToastExperiment(int flavor,
- const installer::Product& installation);
+ const installer::Product& installation,
+ const FilePath& application_path);
const std::wstring& product_guid() { return product_guid_; }
- virtual bool SetChannelFlags(bool set, installer::ChannelInfo* channel_info);
-
protected:
void set_product_guid(const std::wstring& guid) { product_guid_ = guid; }
// Disallow construction from others.
- explicit GoogleChromeDistribution(
- const installer::MasterPreferences& prefs);
+ GoogleChromeDistribution();
private:
friend class BrowserDistribution;
diff --git a/chrome/installer/util/google_chrome_distribution_dummy.cc b/chrome/installer/util/google_chrome_distribution_dummy.cc
index 1b515d9..9b022be 100644
--- a/chrome/installer/util/google_chrome_distribution_dummy.cc
+++ b/chrome/installer/util/google_chrome_distribution_dummy.cc
@@ -15,9 +15,8 @@
#include "base/file_path.h"
#include "base/logging.h"
-GoogleChromeDistribution::GoogleChromeDistribution(
- const installer::MasterPreferences& prefs)
- : BrowserDistribution(prefs) {
+GoogleChromeDistribution::GoogleChromeDistribution()
+ : BrowserDistribution(CHROME_BROWSER) {
}
void GoogleChromeDistribution::DoPostUninstallOperations(
@@ -114,7 +113,8 @@ void GoogleChromeDistribution::LaunchUserExperiment(
}
void GoogleChromeDistribution::InactiveUserToastExperiment(int flavor,
- const installer::Product& installation) {
+ const installer::Product& installation,
+ const FilePath& application_path) {
NOTREACHED();
}
@@ -135,10 +135,3 @@ bool GoogleChromeDistribution::BuildUninstallMetricsString(
NOTREACHED();
return false;
}
-
-bool GoogleChromeDistribution::SetChannelFlags(
- bool set,
- installer::ChannelInfo* channel_info) {
- NOTREACHED();
- return false;
-}
diff --git a/chrome/installer/util/google_chrome_distribution_unittest.cc b/chrome/installer/util/google_chrome_distribution_unittest.cc
index 1222ff3..ed566ea 100644
--- a/chrome/installer/util/google_chrome_distribution_unittest.cc
+++ b/chrome/installer/util/google_chrome_distribution_unittest.cc
@@ -11,7 +11,6 @@
#include "chrome/installer/util/browser_distribution.h"
#include "chrome/installer/util/google_update_constants.h"
#include "chrome/installer/util/google_chrome_distribution.h"
-#include "chrome/installer/util/master_preferences.h"
#include "testing/gtest/include/gtest/gtest.h"
#if defined(GOOGLE_CHROME_BUILD)
@@ -52,12 +51,9 @@ TEST(GoogleChromeDistTest, TestExtractUninstallMetrics) {
ASSERT_TRUE(root.get());
std::wstring uninstall_metrics_string;
- const installer::MasterPreferences& prefs =
- installer::MasterPreferences::ForCurrentProcess();
-
GoogleChromeDistribution* dist = static_cast<GoogleChromeDistribution*>(
BrowserDistribution::GetSpecificDistribution(
- BrowserDistribution::CHROME_BROWSER, prefs));
+ BrowserDistribution::CHROME_BROWSER));
EXPECT_TRUE(
dist->ExtractUninstallMetrics(*static_cast<DictionaryValue*>(root.get()),
diff --git a/chrome/installer/util/google_chrome_sxs_distribution.cc b/chrome/installer/util/google_chrome_sxs_distribution.cc
index 9461a52..9ea35f1 100644
--- a/chrome/installer/util/google_chrome_sxs_distribution.cc
+++ b/chrome/installer/util/google_chrome_sxs_distribution.cc
@@ -9,7 +9,7 @@
#include "base/command_line.h"
#include "base/logging.h"
-#include "installer_util_strings.h"
+#include "installer_util_strings.h" // NOLINT
namespace {
@@ -20,9 +20,8 @@ const int kSxSIconIndex = 4;
} // namespace
-GoogleChromeSxSDistribution::GoogleChromeSxSDistribution(
- const installer::MasterPreferences& prefs)
- : GoogleChromeDistribution(prefs) {
+GoogleChromeSxSDistribution::GoogleChromeSxSDistribution()
+ : GoogleChromeDistribution() {
GoogleChromeDistribution::set_product_guid(kChromeSxSGuid);
}
@@ -62,9 +61,3 @@ bool GoogleChromeSxSDistribution::GetChromeChannel(std::wstring* channel) {
std::wstring GoogleChromeSxSDistribution::ChannelName() {
return kChannelName;
}
-
-void GoogleChromeSxSDistribution::AppendUninstallCommandLineFlags(
- CommandLine* cmd_line) {
- DCHECK(cmd_line);
- cmd_line->AppendSwitch(installer::switches::kChromeSxS);
-}
diff --git a/chrome/installer/util/google_chrome_sxs_distribution.h b/chrome/installer/util/google_chrome_sxs_distribution.h
index 7088c56..10df80a 100644
--- a/chrome/installer/util/google_chrome_sxs_distribution.h
+++ b/chrome/installer/util/google_chrome_sxs_distribution.h
@@ -32,13 +32,11 @@ class GoogleChromeSxSDistribution : public GoogleChromeDistribution {
virtual bool GetChromeChannel(std::wstring* channel);
// returns the channel name for GoogleChromeSxSDistribution
static std::wstring ChannelName();
- virtual void AppendUninstallCommandLineFlags(CommandLine* cmd_line);
private:
friend class BrowserDistribution;
// Disallow construction from non-friends.
- explicit GoogleChromeSxSDistribution(
- const installer::MasterPreferences& prefs);
+ GoogleChromeSxSDistribution();
};
#endif // CHROME_INSTALLER_UTIL_GOOGLE_CHROME_SXS_DISTRIBUTION_H_
diff --git a/chrome/installer/util/google_update_settings.cc b/chrome/installer/util/google_update_settings.cc
index 44ee0f0..76d13d2 100644
--- a/chrome/installer/util/google_update_settings.cc
+++ b/chrome/installer/util/google_update_settings.cc
@@ -17,11 +17,11 @@
#include "chrome/installer/util/channel_info.h"
#include "chrome/installer/util/google_update_constants.h"
#include "chrome/installer/util/install_util.h"
-#include "chrome/installer/util/package.h"
-#include "chrome/installer/util/package_properties.h"
+#include "chrome/installer/util/installer_state.h"
#include "chrome/installer/util/product.h"
using base::win::RegKey;
+using installer::InstallerState;
namespace {
@@ -126,33 +126,43 @@ bool GoogleUpdateSettings::SetMetricsId(const std::wstring& metrics_id) {
}
bool GoogleUpdateSettings::SetEULAConsent(
- const installer::Package& package,
+ const InstallerState& installer_state,
bool consented) {
// If this is a multi install, Google Update will have put eulaaccepted=0 into
// the ClientState key of the multi-installer. Conduct a brief search for
// this value and store the consent in the corresponding location.
- HKEY root = package.system_level() ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER;
-
- std::wstring reg_path = package.properties()->GetStateMediumKey();
- EulaSearchResult status = HasEULASetting(
- root, package.properties()->GetStateKey(), !consented);
+ HKEY root = installer_state.root_key();
+ EulaSearchResult status = NO_SETTING;
+ std::wstring reg_path;
+ std::wstring fallback_reg_path;
+
+ if (installer_state.package_type() == InstallerState::MULTI_PACKAGE) {
+ BrowserDistribution* binaries_dist =
+ installer_state.multi_package_binaries_distribution();
+ fallback_reg_path = reg_path = binaries_dist->GetStateMediumKey();
+ status = HasEULASetting(root, binaries_dist->GetStateKey(), !consented);
+ }
if (status != FOUND_SAME_SETTING) {
EulaSearchResult new_status = NO_SETTING;
- installer::Products::const_iterator scan = package.products().begin();
- installer::Products::const_iterator end = package.products().end();
+ installer::Products::const_iterator scan =
+ installer_state.products().begin();
+ installer::Products::const_iterator end =
+ installer_state.products().end();
for (; status != FOUND_SAME_SETTING && scan != end; ++scan) {
- const installer::Product& product = *(scan->get());
- new_status = HasEULASetting(root, product.distribution()->GetStateKey(),
+ if (fallback_reg_path.empty())
+ fallback_reg_path = (*scan)->distribution()->GetStateMediumKey();
+ new_status = HasEULASetting(root, (*scan)->distribution()->GetStateKey(),
!consented);
if (new_status > status) {
status = new_status;
- reg_path = product.distribution()->GetStateMediumKey();
+ reg_path = (*scan)->distribution()->GetStateMediumKey();
}
}
if (status == NO_SETTING) {
LOG(WARNING)
- << "eulaaccepted value not found; setting consent on package";
- reg_path = package.properties()->GetStateMediumKey();
+ << "eulaaccepted value not found; setting consent in key "
+ << fallback_reg_path;
+ reg_path = fallback_reg_path;
}
}
RegKey key(HKEY_LOCAL_MACHINE, reg_path.c_str(), KEY_SET_VALUE);
diff --git a/chrome/installer/util/google_update_settings.h b/chrome/installer/util/google_update_settings.h
index 36e020c..12b5fa5 100644
--- a/chrome/installer/util/google_update_settings.h
+++ b/chrome/installer/util/google_update_settings.h
@@ -12,7 +12,7 @@
namespace installer {
class ChannelInfo;
-class Package;
+class InstallerState;
}
// This class provides accessors to the Google Update 'ClientState' information
@@ -38,7 +38,7 @@ class GoogleUpdateSettings {
// Sets the machine-wide EULA consented flag required on OEM installs.
// Returns false if the setting could not be recorded.
- static bool SetEULAConsent(const installer::Package& package,
+ static bool SetEULAConsent(const installer::InstallerState& installer_state,
bool consented);
// Returns the last time chrome was run in days. It uses a recorded value
diff --git a/chrome/installer/util/google_update_settings_unittest.cc b/chrome/installer/util/google_update_settings_unittest.cc
index 96a6dae..2234192 100644
--- a/chrome/installer/util/google_update_settings_unittest.cc
+++ b/chrome/installer/util/google_update_settings_unittest.cc
@@ -15,9 +15,9 @@
#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/installation_state.h"
+#include "chrome/installer/util/installer_state.h"
#include "chrome/installer/util/master_preferences.h"
-#include "chrome/installer/util/package.h"
-#include "chrome/installer/util/package_properties.h"
#include "chrome/installer/util/product.h"
#include "chrome/installer/util/work_item_list.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -404,28 +404,32 @@ TEST_F(GoogleUpdateSettingsTest, UpdateInstallStatusTest) {
}
TEST_F(GoogleUpdateSettingsTest, SetEULAConsent) {
- const bool multi_install = false;
+ const bool multi_install = true;
const bool system_level = true;
- HKEY root = system_level ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER;
-
- const installer::MasterPreferences& prefs =
- installer::MasterPreferences::ForCurrentProcess();
- installer::ChromePackageProperties properties;
- BrowserDistribution* distribution =
- BrowserDistribution::GetSpecificDistribution(
- BrowserDistribution::CHROME_BROWSER, prefs);
- scoped_refptr<installer::Package> package(
- new installer::Package(multi_install, system_level, FilePath(),
- &properties));
- scoped_refptr<installer::Product> product(
- new installer::Product(distribution, package.get()));
+ CommandLine cmd_line = CommandLine::FromString(
+ std::wstring(L"setup.exe") +
+ (multi_install ? L" --multi-install --chrome" : L"") +
+ (system_level ? L" --system-level" : L""));
+ installer::MasterPreferences prefs(cmd_line);
+ installer::InstallationState machine_state;
+ machine_state.Initialize();
+ installer::InstallerState installer_state;
+ installer_state.Initialize(cmd_line, prefs, machine_state);
+ HKEY root = installer_state.root_key();
+
RegKey key;
DWORD value;
+ BrowserDistribution* binaries =
+ installer_state.multi_package_binaries_distribution();
+ EXPECT_EQ(BrowserDistribution::CHROME_BINARIES, binaries->GetType());
+ BrowserDistribution* chrome =
+ installer_state.products()[0]->distribution();
+ EXPECT_EQ(BrowserDistribution::CHROME_BROWSER, chrome->GetType());
// By default, eulaconsent ends up on the package.
- EXPECT_TRUE(GoogleUpdateSettings::SetEULAConsent(*package.get(), true));
+ EXPECT_TRUE(GoogleUpdateSettings::SetEULAConsent(installer_state, true));
EXPECT_EQ(ERROR_SUCCESS,
- key.Open(HKEY_LOCAL_MACHINE, properties.GetStateMediumKey().c_str(),
+ key.Open(HKEY_LOCAL_MACHINE, binaries->GetStateMediumKey().c_str(),
KEY_QUERY_VALUE | KEY_SET_VALUE));
EXPECT_EQ(ERROR_SUCCESS,
key.ReadValueDW(google_update::kRegEULAAceptedField, &value));
@@ -435,14 +439,14 @@ TEST_F(GoogleUpdateSettingsTest, SetEULAConsent) {
// But it will end up on the product if needed
EXPECT_EQ(ERROR_SUCCESS,
- key.Create(HKEY_LOCAL_MACHINE, distribution->GetStateKey().c_str(),
+ key.Create(HKEY_LOCAL_MACHINE, chrome->GetStateKey().c_str(),
KEY_SET_VALUE));
EXPECT_EQ(ERROR_SUCCESS,
key.WriteValue(google_update::kRegEULAAceptedField,
static_cast<DWORD>(0)));
- EXPECT_TRUE(GoogleUpdateSettings::SetEULAConsent(*package.get(), true));
+ EXPECT_TRUE(GoogleUpdateSettings::SetEULAConsent(installer_state, true));
EXPECT_EQ(ERROR_SUCCESS,
- key.Open(HKEY_LOCAL_MACHINE, distribution->GetStateMediumKey().c_str(),
+ key.Open(HKEY_LOCAL_MACHINE, chrome->GetStateMediumKey().c_str(),
KEY_QUERY_VALUE | KEY_SET_VALUE));
EXPECT_EQ(ERROR_SUCCESS,
key.ReadValueDW(google_update::kRegEULAAceptedField, &value));
diff --git a/chrome/installer/util/helper.cc b/chrome/installer/util/helper.cc
index 6cddf25..82f8a36 100644
--- a/chrome/installer/util/helper.cc
+++ b/chrome/installer/util/helper.cc
@@ -4,17 +4,13 @@
#include "chrome/installer/util/helper.h"
-#include "base/command_line.h"
-#include "base/file_path.h"
#include "base/logging.h"
+#include "base/file_path.h"
#include "base/path_service.h"
-#include "base/win/registry.h"
#include "chrome/installer/util/browser_distribution.h"
+#include "chrome/installer/util/installation_state.h"
#include "chrome/installer/util/install_util.h"
-#include "chrome/installer/util/master_preferences.h"
-#include "chrome/installer/util/package_properties.h"
-
-using base::win::RegKey;
+#include "chrome/installer/util/util_constants.h"
namespace {
@@ -40,101 +36,32 @@ FilePath GetChromeInstallBasePath(bool system,
namespace installer {
-bool IsInstalledAsMulti(bool system_install, BrowserDistribution* dist) {
- bool installed_as_multi = false;
- CommandLine cmd(CommandLine::NO_PROGRAM);
- if (GetUninstallSwitches(system_install, dist, &cmd))
- installed_as_multi = cmd.HasSwitch(installer::switches::kMultiInstall);
- return installed_as_multi;
-}
-
-bool GetUninstallSwitches(bool system_install, BrowserDistribution* dist,
- CommandLine* cmd_line_switches) {
- scoped_ptr<Version> installed(InstallUtil::GetChromeVersion(dist,
- system_install));
- if (installed.get()) {
- HKEY root = system_install ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER;
- RegKey key(root, dist->GetStateKey().c_str(), KEY_READ);
- if (key.Valid()) {
- std::wstring args;
- key.ReadValue(installer::kUninstallArgumentsField, &args);
- if (!args.empty()) {
- args.insert(0, L"foo.exe ");
- *cmd_line_switches = CommandLine::FromString(args);
- } else {
- LOG(ERROR) << "No uninstallation arguments for "
- << dist->GetApplicationName();
- installed.reset();
- }
- } else {
- LOG(ERROR) << "Product looks to be installed but we can't access the "
- "state key: " << dist->GetApplicationName();
- installed.reset();
- }
- }
-
- return installed.get() != NULL;
-}
-
FilePath GetChromeInstallPath(bool system_install, BrowserDistribution* dist) {
- return GetChromeInstallBasePath(system_install, dist,
- installer::kInstallBinaryDir);
+ return GetChromeInstallBasePath(system_install, dist, kInstallBinaryDir);
}
FilePath GetChromeUserDataPath(BrowserDistribution* dist) {
return GetChromeInstallBasePath(false, dist, kInstallUserDataDir);
}
-FilePath GetChromeFrameInstallPath(bool multi_install, bool system_install,
- BrowserDistribution* dist) {
- DCHECK_EQ(BrowserDistribution::CHROME_FRAME, dist->GetType());
-
- scoped_ptr<Version> installed_version(
- InstallUtil::GetChromeVersion(dist, system_install));
-
- if (!multi_install) {
- // Check if Chrome Frame is installed as multi. If it is, return an empty
- // path and log an error.
- if (installed_version.get() && IsInstalledAsMulti(system_install, dist)) {
- LOG(ERROR) << "Cannot install Chrome Frame in single mode as a multi mode"
- " installation already exists.";
- return FilePath();
- }
- VLOG(1) << "Chrome Frame will be installed as 'single'";
- return GetChromeInstallPath(system_install, dist);
- }
-
- // TODO(tommi): If Chrome Frame is installed as single and the installed
- // channel is older than the one we're installing, we should migrate
- // CF to Chrome's install folder and change its channel.
+BrowserDistribution* GetBinariesDistribution(bool system_install) {
+ BrowserDistribution* dist = BrowserDistribution::GetDistribution();
+ ProductState state;
- // Multi install. Check if Chrome Frame is already installed.
- // If CF is installed as single (i.e. not multi), we will return an empty
- // path (for now). Otherwise, if CF is not installed or if it is installed
- // as multi, we will return Chrome's install folder.
- if (installed_version.get() && !IsInstalledAsMulti(system_install, dist)) {
- LOG(ERROR) << "Cannot install Chrome Frame in multi mode as a single mode"
- " installation already exists.";
- return FilePath();
+ // If we're part of a multi-install, we need to poll using the multi-installer
+ // package's app guid rather than the browser's or Chrome Frame's app guid.
+ // If we can't read the app's state from the registry, assume it isn't
+ // multi-installed.
+ if (state.Initialize(system_install, dist) && state.is_multi_install()) {
+ return BrowserDistribution::GetSpecificDistribution(
+ BrowserDistribution::CHROME_BINARIES);
+ } else {
+ return dist;
}
-
- // Return Chrome's installation folder.
- VLOG(1) << "Chrome Frame will be installed as 'multi'";
- const MasterPreferences& prefs = MasterPreferences::ForCurrentProcess();
- BrowserDistribution* chrome =
- BrowserDistribution::GetSpecificDistribution(
- BrowserDistribution::CHROME_BROWSER, prefs);
- return GetChromeInstallPath(system_install, chrome);
}
std::wstring GetAppGuidForUpdates(bool system_install) {
- BrowserDistribution* dist = BrowserDistribution::GetDistribution();
-
- // If we're part of a multi-install, we need to poll using the multi-installer
- // package's app guid rather than the browser's or Chrome Frame's app guid.
- return IsInstalledAsMulti(system_install, dist) ?
- ActivePackageProperties().GetAppGuid() :
- dist->GetAppGuid();
+ return GetBinariesDistribution(system_install)->GetAppGuid();
}
} // namespace installer.
diff --git a/chrome/installer/util/helper.h b/chrome/installer/util/helper.h
index bcee4c6..fa996b6 100644
--- a/chrome/installer/util/helper.h
+++ b/chrome/installer/util/helper.h
@@ -16,17 +16,6 @@ class FilePath;
namespace installer {
-// Checks if a distribution is currently installed as part of a multi-install.
-bool IsInstalledAsMulti(bool system_install, BrowserDistribution* dist);
-
-// Retrieves the command line switches for uninstalling the distribution.
-// Note that the returned CommandLine object does not include a "program".
-// Only the switches should be used.
-// Returns true if the product is installed and the uninstall switches
-// were successfully retrieved, otherwise false.
-bool GetUninstallSwitches(bool system_install, BrowserDistribution* dist,
- CommandLine* cmd_line_switches);
-
// This function returns the install path for Chrome depending on whether its
// system wide install or user specific install.
// system_install: if true, the function returns system wide location
@@ -40,18 +29,10 @@ FilePath GetChromeInstallPath(bool system_install, BrowserDistribution* dist);
// that it can be overriden with a command line parameter.
FilePath GetChromeUserDataPath(BrowserDistribution* dist);
-// This is a workaround while we unify Chrome and Chrome Frame installation
-// folders. Right now, Chrome Frame can be installed into two different
-// folders: 1) A special "Chrome Frame" folder next to Chrome's folder
-// 2) The same folder as Chrome is installed into.
-// Right now this function will only return Chrome's installation folder
-// if Chrome Frame is not already installed or if Chrome Frame is installed
-// in multi_install mode.
-// If multi_install is false or if CF is installed in single mode, then the
-// returned path will be the "Chrome Frame" subfolder of either the user or
-// system default installation folders.
-FilePath GetChromeFrameInstallPath(bool multi_install, bool system_install,
- BrowserDistribution* dist);
+// Returns the distribution corresponding to the current process's binaries.
+// In the case of a multi-install product, this will be the CHROME_BINARIES
+// distribution.
+BrowserDistribution* GetBinariesDistribution(bool system_install);
// Returns the app guid under which the current process receives updates from
// Google Update.
diff --git a/chrome/installer/util/helper_unittest.cc b/chrome/installer/util/helper_unittest.cc
deleted file mode 100644
index 48b2476..0000000
--- a/chrome/installer/util/helper_unittest.cc
+++ /dev/null
@@ -1,204 +0,0 @@
-// Copyright (c) 2006-2008 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 <windows.h>
-
-#include <fstream>
-
-#include "base/base_paths.h"
-#include "base/file_util.h"
-#include "base/path_service.h"
-#include "base/process_util.h"
-#include "base/string_util.h"
-#include "base/version.h"
-#include "chrome/installer/util/helper.h"
-#include "chrome/installer/util/package.h"
-#include "chrome/installer/util/package_properties.h"
-#include "chrome/installer/util/work_item.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-using installer::ChromePackageProperties;
-using installer::Package;
-
-namespace {
- class SetupHelperTest : public testing::Test {
- protected:
- virtual void SetUp() {
- // Name a subdirectory of the user temp directory.
- ASSERT_TRUE(PathService::Get(base::DIR_TEMP, &test_dir_));
- test_dir_ = test_dir_.AppendASCII("SetupHelperTest");
-
- // Create a fresh, empty copy of this test directory.
- file_util::Delete(test_dir_, true);
- file_util::CreateDirectoryW(test_dir_);
- ASSERT_TRUE(file_util::PathExists(test_dir_));
- }
-
- virtual void TearDown() {
- logging::CloseLogFile();
- // Clean up test directory
- ASSERT_TRUE(file_util::Delete(test_dir_, true));
- ASSERT_FALSE(file_util::PathExists(test_dir_));
- }
-
- // the path to temporary directory used to contain the test operations
- FilePath test_dir_;
- };
-
- // Simple function to dump some text into a new file.
- void CreateTextFile(const std::wstring& filename,
- const std::wstring& contents) {
- std::ofstream file;
- file.open(filename.c_str());
- ASSERT_TRUE(file.is_open());
- file << contents;
- file.close();
- }
-
- wchar_t text_content_1[] = L"delete me";
- wchar_t text_content_2[] = L"delete me as well";
-};
-
-// Delete version directories. Everything lower than the given version
-// should be deleted.
-TEST_F(SetupHelperTest, Delete) {
- // Create a Chrome dir
- FilePath chrome_dir(test_dir_);
- chrome_dir = chrome_dir.AppendASCII("chrome");
- file_util::CreateDirectory(chrome_dir);
- ASSERT_TRUE(file_util::PathExists(chrome_dir));
-
- FilePath chrome_dir_1(chrome_dir);
- chrome_dir_1 = chrome_dir_1.AppendASCII("1.0.1.0");
- file_util::CreateDirectory(chrome_dir_1);
- ASSERT_TRUE(file_util::PathExists(chrome_dir_1));
-
- FilePath chrome_dir_2(chrome_dir);
- chrome_dir_2 = chrome_dir_2.AppendASCII("1.0.2.0");
- file_util::CreateDirectory(chrome_dir_2);
- ASSERT_TRUE(file_util::PathExists(chrome_dir_2));
-
- FilePath chrome_dir_3(chrome_dir);
- chrome_dir_3 = chrome_dir_3.AppendASCII("1.0.3.0");
- file_util::CreateDirectory(chrome_dir_3);
- ASSERT_TRUE(file_util::PathExists(chrome_dir_3));
-
- FilePath chrome_dir_4(chrome_dir);
- chrome_dir_4 = chrome_dir_4.AppendASCII("1.0.4.0");
- file_util::CreateDirectory(chrome_dir_4);
- ASSERT_TRUE(file_util::PathExists(chrome_dir_4));
-
- FilePath chrome_dll_1(chrome_dir_1);
- chrome_dll_1 = chrome_dll_1.AppendASCII("chrome.dll");
- CreateTextFile(chrome_dll_1.value(), text_content_1);
- ASSERT_TRUE(file_util::PathExists(chrome_dll_1));
-
- FilePath chrome_dll_2(chrome_dir_2);
- chrome_dll_2 = chrome_dll_2.AppendASCII("chrome.dll");
- CreateTextFile(chrome_dll_2.value(), text_content_1);
- ASSERT_TRUE(file_util::PathExists(chrome_dll_2));
-
- FilePath chrome_dll_3(chrome_dir_3);
- chrome_dll_3 = chrome_dll_3.AppendASCII("chrome.dll");
- CreateTextFile(chrome_dll_3.value(), text_content_1);
- ASSERT_TRUE(file_util::PathExists(chrome_dll_3));
-
- FilePath chrome_dll_4(chrome_dir_4);
- chrome_dll_4 = chrome_dll_4.AppendASCII("chrome.dll");
- CreateTextFile(chrome_dll_4.value(), text_content_1);
- ASSERT_TRUE(file_util::PathExists(chrome_dll_4));
-
- scoped_ptr<Version> latest_version(Version::GetVersionFromString("1.0.4.0"));
- ChromePackageProperties properties;
- scoped_refptr<Package> package(new Package(false, true, chrome_dir,
- &properties));
- package->RemoveOldVersionDirectories(*latest_version.get());
-
- // old versions should be gone
- EXPECT_FALSE(file_util::PathExists(chrome_dir_1));
- EXPECT_FALSE(file_util::PathExists(chrome_dir_2));
- EXPECT_FALSE(file_util::PathExists(chrome_dir_3));
- // the latest version should stay
- EXPECT_TRUE(file_util::PathExists(chrome_dll_4));
-}
-
-// Delete older version directories, keeping the one in used intact.
-TEST_F(SetupHelperTest, DeleteInUsed) {
- // Create a Chrome dir
- FilePath chrome_dir(test_dir_);
- chrome_dir = chrome_dir.AppendASCII("chrome");
- file_util::CreateDirectory(chrome_dir);
- ASSERT_TRUE(file_util::PathExists(chrome_dir));
-
- FilePath chrome_dir_1(chrome_dir);
- chrome_dir_1 = chrome_dir_1.AppendASCII("1.0.1.0");
- file_util::CreateDirectory(chrome_dir_1);
- ASSERT_TRUE(file_util::PathExists(chrome_dir_1));
-
- FilePath chrome_dir_2(chrome_dir);
- chrome_dir_2 = chrome_dir_2.AppendASCII("1.0.2.0");
- file_util::CreateDirectory(chrome_dir_2);
- ASSERT_TRUE(file_util::PathExists(chrome_dir_2));
-
- FilePath chrome_dir_3(chrome_dir);
- chrome_dir_3 = chrome_dir_3.AppendASCII("1.0.3.0");
- file_util::CreateDirectory(chrome_dir_3);
- ASSERT_TRUE(file_util::PathExists(chrome_dir_3));
-
- FilePath chrome_dir_4(chrome_dir);
- chrome_dir_4 = chrome_dir_4.AppendASCII("1.0.4.0");
- file_util::CreateDirectory(chrome_dir_4);
- ASSERT_TRUE(file_util::PathExists(chrome_dir_4));
-
- FilePath chrome_dll_1(chrome_dir_1);
- chrome_dll_1 = chrome_dll_1.AppendASCII("chrome.dll");
- CreateTextFile(chrome_dll_1.value(), text_content_1);
- ASSERT_TRUE(file_util::PathExists(chrome_dll_1));
-
- FilePath chrome_dll_2(chrome_dir_2);
- chrome_dll_2 = chrome_dll_2.AppendASCII("chrome.dll");
- CreateTextFile(chrome_dll_2.value(), text_content_1);
- ASSERT_TRUE(file_util::PathExists(chrome_dll_2));
-
- // Open the file to make it in use.
- std::ofstream file;
- file.open(chrome_dll_2.value().c_str());
-
- FilePath chrome_othera_2(chrome_dir_2);
- chrome_othera_2 = chrome_othera_2.AppendASCII("othera.dll");
- CreateTextFile(chrome_othera_2.value(), text_content_2);
- ASSERT_TRUE(file_util::PathExists(chrome_othera_2));
-
- FilePath chrome_otherb_2(chrome_dir_2);
- chrome_otherb_2 = chrome_otherb_2.AppendASCII("otherb.dll");
- CreateTextFile(chrome_otherb_2.value(), text_content_2);
- ASSERT_TRUE(file_util::PathExists(chrome_otherb_2));
-
- FilePath chrome_dll_3(chrome_dir_3);
- chrome_dll_3 = chrome_dll_3.AppendASCII("chrome.dll");
- CreateTextFile(chrome_dll_3.value(), text_content_1);
- ASSERT_TRUE(file_util::PathExists(chrome_dll_3));
-
- FilePath chrome_dll_4(chrome_dir_4);
- chrome_dll_4 = chrome_dll_4.AppendASCII("chrome.dll");
- CreateTextFile(chrome_dll_4.value(), text_content_1);
- ASSERT_TRUE(file_util::PathExists(chrome_dll_4));
-
- scoped_ptr<Version> latest_version(Version::GetVersionFromString("1.0.4.0"));
- ChromePackageProperties properties;
- scoped_refptr<Package> install_path(new Package(false, true, chrome_dir,
- &properties));
- install_path->RemoveOldVersionDirectories(*latest_version.get());
-
- // old versions not in used should be gone
- EXPECT_FALSE(file_util::PathExists(chrome_dir_1));
- EXPECT_FALSE(file_util::PathExists(chrome_dir_3));
- // every thing under in used version should stay
- EXPECT_TRUE(file_util::PathExists(chrome_dir_2));
- EXPECT_TRUE(file_util::PathExists(chrome_dll_2));
- EXPECT_TRUE(file_util::PathExists(chrome_othera_2));
- EXPECT_TRUE(file_util::PathExists(chrome_otherb_2));
- // the latest version should stay
- EXPECT_TRUE(file_util::PathExists(chrome_dll_4));
-}
diff --git a/chrome/installer/util/install_util.cc b/chrome/installer/util/install_util.cc
index 0e598dd..48af659 100644
--- a/chrome/installer/util/install_util.cc
+++ b/chrome/installer/util/install_util.cc
@@ -12,24 +12,24 @@
#include <algorithm>
+#include "base/command_line.h"
#include "base/file_util.h"
#include "base/logging.h"
#include "base/path_service.h"
#include "base/scoped_ptr.h"
#include "base/string_util.h"
#include "base/values.h"
+#include "base/version.h"
#include "base/win/registry.h"
#include "base/win/windows_version.h"
#include "chrome/common/json_value_serializer.h"
#include "chrome/installer/util/browser_distribution.h"
#include "chrome/installer/util/google_update_constants.h"
#include "chrome/installer/util/l10n_string_util.h"
-#include "chrome/installer/util/master_preferences_constants.h"
#include "chrome/installer/util/util_constants.h"
#include "chrome/installer/util/work_item_list.h"
using base::win::RegKey;
-using installer::MasterPreferences;
bool InstallUtil::ExecuteExeAsAdmin(const CommandLine& cmd, DWORD* exit_code) {
FilePath::StringType program(cmd.GetProgram().value());
@@ -240,3 +240,25 @@ int InstallUtil::GetInstallReturnCode(installer::InstallStatus status) {
return status;
}
}
+
+// static
+void InstallUtil::MakeUninstallCommand(const std::wstring& exe_path,
+ const std::wstring& arguments,
+ CommandLine* command_line) {
+ const bool no_program = exe_path.empty();
+
+ // Return a bunch of nothingness.
+ if (no_program && arguments.empty()) {
+ *command_line = CommandLine(CommandLine::NO_PROGRAM);
+ } else {
+ // Form a full command line string.
+ std::wstring command;
+ command.append(1, L'"')
+ .append(no_program ? L"" : exe_path)
+ .append(L"\" ")
+ .append(arguments);
+
+ // If we have a program name, return this complete command line.
+ *command_line = CommandLine::FromString(command);
+ }
+}
diff --git a/chrome/installer/util/install_util.h b/chrome/installer/util/install_util.h
index f2ba551..1912c09 100644
--- a/chrome/installer/util/install_util.h
+++ b/chrome/installer/util/install_util.h
@@ -15,13 +15,12 @@
#include <string>
#include "base/basictypes.h"
-#include "base/command_line.h"
-#include "base/version.h"
-#include "chrome/installer/util/master_preferences.h"
#include "chrome/installer/util/util_constants.h"
-class WorkItemList;
class BrowserDistribution;
+class CommandLine;
+class Version;
+class WorkItemList;
namespace base {
namespace win {
@@ -107,6 +106,11 @@ class InstallUtil {
// Returns zero on install success, or an InstallStatus value otherwise.
static int GetInstallReturnCode(installer::InstallStatus install_status);
+ // Composes |exe_path| and |arguments| into |command_line|.
+ static void MakeUninstallCommand(const std::wstring& exe_path,
+ const std::wstring& arguments,
+ CommandLine* command_line);
+
private:
DISALLOW_COPY_AND_ASSIGN(InstallUtil);
};
diff --git a/chrome/installer/util/install_util_unittest.cc b/chrome/installer/util/install_util_unittest.cc
index b0e05ba..a5cb86f 100644
--- a/chrome/installer/util/install_util_unittest.cc
+++ b/chrome/installer/util/install_util_unittest.cc
@@ -3,6 +3,7 @@
// found in the LICENSE file.
#include <string>
+#include <utility>
#include "base/command_line.h"
#include "base/win/registry.h"
@@ -34,17 +35,17 @@ TEST_F(InstallUtilTest, InstallerResult) {
// check results for a fresh install of single Chrome
{
TempRegKeyOverride override(root, L"root_inst_res");
- const MasterPreferences prefs(
- CommandLine::FromString(L"setup.exe --system-level"));
+ CommandLine cmd_line = CommandLine::FromString(L"setup.exe --system-level");
+ const MasterPreferences prefs(cmd_line);
InstallationState machine_state;
- machine_state.Initialize(prefs);
+ machine_state.Initialize();
InstallerState state;
- state.Initialize(prefs, machine_state);
+ state.Initialize(cmd_line, prefs, machine_state);
InstallUtil::WriteInstallerResult(system_level, state.state_key(),
installer::FIRST_INSTALL_SUCCESS, 0, &launch_cmd);
BrowserDistribution* distribution =
BrowserDistribution::GetSpecificDistribution(
- BrowserDistribution::CHROME_BROWSER, prefs);
+ BrowserDistribution::CHROME_BROWSER);
EXPECT_EQ(ERROR_SUCCESS,
key.Open(root, distribution->GetStateKey().c_str(), KEY_READ));
EXPECT_EQ(ERROR_SUCCESS,
@@ -56,18 +57,18 @@ TEST_F(InstallUtilTest, InstallerResult) {
// check results for a fresh install of multi Chrome
{
TempRegKeyOverride override(root, L"root_inst_res");
- const MasterPreferences prefs(
- CommandLine::FromString(
- L"setup.exe --system-level --multi-install --chrome"));
+ CommandLine cmd_line = CommandLine::FromString(
+ L"setup.exe --system-level --multi-install --chrome");
+ const MasterPreferences prefs(cmd_line);
InstallationState machine_state;
- machine_state.Initialize(prefs);
+ machine_state.Initialize();
InstallerState state;
- state.Initialize(prefs, machine_state);
+ state.Initialize(cmd_line, prefs, machine_state);
InstallUtil::WriteInstallerResult(system_level, state.state_key(),
installer::FIRST_INSTALL_SUCCESS, 0, &launch_cmd);
BrowserDistribution* distribution =
BrowserDistribution::GetSpecificDistribution(
- BrowserDistribution::CHROME_BROWSER, prefs);
+ BrowserDistribution::CHROME_BROWSER);
EXPECT_EQ(ERROR_SUCCESS,
key.Open(root, distribution->GetStateKey().c_str(), KEY_READ));
EXPECT_EQ(ERROR_SUCCESS,
@@ -77,3 +78,27 @@ TEST_F(InstallUtilTest, InstallerResult) {
}
TempRegKeyOverride::DeleteAllTempKeys();
}
+
+TEST_F(InstallUtilTest, MakeUninstallCommand) {
+ CommandLine command_line(CommandLine::NO_PROGRAM);
+
+ std::pair<std::wstring, std::wstring> params[] = {
+ std::make_pair(std::wstring(L""), std::wstring(L"")),
+ std::make_pair(std::wstring(L""), std::wstring(L"--do-something --silly")),
+ std::make_pair(std::wstring(L"spam.exe"), std::wstring(L"")),
+ std::make_pair(std::wstring(L"spam.exe"),
+ std::wstring(L"--do-something --silly")),
+ };
+ for (int i = 0; i < arraysize(params); ++i) {
+ std::pair<std::wstring, std::wstring>& param = params[i];
+ InstallUtil::MakeUninstallCommand(param.first, param.second, &command_line);
+ EXPECT_EQ(param.first, command_line.GetProgram().value());
+ if (param.second.empty()) {
+ EXPECT_EQ(0U, command_line.GetSwitchCount());
+ } else {
+ EXPECT_EQ(2U, command_line.GetSwitchCount());
+ EXPECT_TRUE(command_line.HasSwitch("do-something"));
+ EXPECT_TRUE(command_line.HasSwitch("silly"));
+ }
+ }
+}
diff --git a/chrome/installer/util/installation_state.cc b/chrome/installer/util/installation_state.cc
index c0ab82d..f766195 100644
--- a/chrome/installer/util/installation_state.cc
+++ b/chrome/installer/util/installation_state.cc
@@ -9,33 +9,82 @@
#include "base/version.h"
#include "base/win/registry.h"
#include "chrome/installer/util/google_update_constants.h"
-#include "chrome/installer/util/package_properties.h"
+#include "chrome/installer/util/install_util.h"
namespace installer {
-ProductState::ProductState() {
+ProductState::ProductState()
+ : uninstall_command_(CommandLine::NO_PROGRAM),
+ msi_(false),
+ multi_install_(false) {
}
-void ProductState::Initialize(bool system_install,
- const std::wstring& version_key,
- const std::wstring& state_key) {
+bool ProductState::Initialize(bool system_install,
+ BrowserDistribution::Type type) {
+ return Initialize(system_install,
+ BrowserDistribution::GetSpecificDistribution(type));
+}
+
+bool ProductState::Initialize(bool system_install,
+ BrowserDistribution* distribution) {
+ const std::wstring version_key(distribution->GetVersionKey());
+ const std::wstring state_key(distribution->GetStateKey());
const HKEY root_key = system_install ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER;
base::win::RegKey key(root_key, version_key.c_str(), KEY_QUERY_VALUE);
std::wstring version_str;
- if (key.ReadValue(google_update::kRegVersionField, &version_str)
- == ERROR_SUCCESS) {
+ if (key.ReadValue(google_update::kRegVersionField,
+ &version_str) == ERROR_SUCCESS) {
version_.reset(Version::GetVersionFromString(WideToASCII(version_str)));
if (version_.get() != NULL) {
- // The product is installed. Check for the channel value (absent if not
- // installed/managed by Google Update).
- if ((key.Open(root_key, state_key.c_str(), KEY_QUERY_VALUE) !=
- ERROR_SUCCESS) || !channel_.Initialize(key)) {
- channel_.set_value(std::wstring());
+ // The product is installed.
+ if (key.ReadValue(google_update::kRegOldVersionField,
+ &version_str) == ERROR_SUCCESS) {
+ old_version_.reset(
+ Version::GetVersionFromString(WideToASCII(version_str)));
+ } else {
+ old_version_.reset();
+ }
+ if (key.ReadValue(google_update::kRegRenameCmdField,
+ &rename_cmd_) != ERROR_SUCCESS)
+ rename_cmd_.clear();
+ // Read from the ClientState key.
+ channel_.set_value(std::wstring());
+ uninstall_command_ = CommandLine(CommandLine::NO_PROGRAM);
+ msi_ = false;
+ multi_install_ = false;
+ if (key.Open(root_key, state_key.c_str(),
+ KEY_QUERY_VALUE) == ERROR_SUCCESS) {
+ std::wstring setup_path;
+ std::wstring uninstall_arguments;
+ // "ap" will be absent if not managed by Google Update.
+ channel_.Initialize(key);
+ // "UninstallString" will be absent for the multi-installer package.
+ key.ReadValue(kUninstallStringField, &setup_path);
+ // "UninstallArguments" will be absent for the multi-installer package.
+ key.ReadValue(kUninstallArgumentsField, &uninstall_arguments);
+ InstallUtil::MakeUninstallCommand(setup_path, uninstall_arguments,
+ &uninstall_command_);
+ // "msi" may be absent, 0 or 1
+ DWORD dw_value = 0;
+ msi_ = (key.ReadValueDW(google_update::kRegMSIField,
+ &dw_value) == ERROR_SUCCESS) && (dw_value != 0);
+ // Multi-install is implied or is derived from the command-line.
+ if (distribution->GetType() == BrowserDistribution::CHROME_BINARIES) {
+ multi_install_ = true;
+ } else {
+ multi_install_ = uninstall_command_.HasSwitch(
+ switches::kMultiInstall);
+ }
}
}
} else {
version_.reset();
}
+ return version_.get() != NULL;
+}
+
+FilePath ProductState::GetSetupPath() const {
+ return uninstall_command_.GetProgram();
}
const Version& ProductState::version() const {
@@ -43,12 +92,17 @@ const Version& ProductState::version() const {
return *version_;
}
-void ProductState::CopyFrom(const ProductState& other) {
+ProductState& ProductState::CopyFrom(const ProductState& other) {
channel_.set_value(other.channel_.value());
- if (other.version_.get() == NULL)
- version_.reset();
- else
- version_.reset(other.version_->Clone());
+ version_.reset(other.version_.get() == NULL ? NULL : other.version_->Clone());
+ old_version_.reset(
+ other.old_version_.get() == NULL ? NULL : other.old_version_->Clone());
+ rename_cmd_ = other.rename_cmd_;
+ uninstall_command_ = other.uninstall_command_;
+ msi_ = other.msi_;
+ multi_install_ = other.multi_install_;
+
+ return *this;
}
InstallationState::InstallationState() {
@@ -60,53 +114,31 @@ int InstallationState::IndexFromDistType(BrowserDistribution::Type type) {
unexpected_chrome_browser_distribution_value_);
COMPILE_ASSERT(BrowserDistribution::CHROME_FRAME == CHROME_FRAME_INDEX,
unexpected_chrome_frame_distribution_value_);
+ COMPILE_ASSERT(BrowserDistribution::CHROME_BINARIES == CHROME_BINARIES_INDEX,
+ unexpected_chrome_frame_distribution_value_);
DCHECK(type == BrowserDistribution::CHROME_BROWSER ||
- type == BrowserDistribution::CHROME_FRAME);
+ type == BrowserDistribution::CHROME_FRAME ||
+ type == BrowserDistribution::CHROME_BINARIES);
return type;
}
-void InstallationState::Initialize(const MasterPreferences& prefs) {
+void InstallationState::Initialize() {
BrowserDistribution* distribution;
distribution = BrowserDistribution::GetSpecificDistribution(
- BrowserDistribution::CHROME_BROWSER, prefs);
- InitializeProduct(false, distribution, &user_products_[CHROME_BROWSER_INDEX]);
- InitializeProduct(true, distribution,
- &system_products_[CHROME_BROWSER_INDEX]);
+ BrowserDistribution::CHROME_BROWSER);
+ user_products_[CHROME_BROWSER_INDEX].Initialize(false, distribution);
+ system_products_[CHROME_BROWSER_INDEX].Initialize(true, distribution);
distribution = BrowserDistribution::GetSpecificDistribution(
- BrowserDistribution::CHROME_FRAME, prefs);
- InitializeProduct(false, distribution, &user_products_[CHROME_FRAME_INDEX]);
- InitializeProduct(true, distribution, &system_products_[CHROME_FRAME_INDEX]);
-
- ActivePackageProperties package_properties;
- InitializeMultiPackage(false, package_properties,
- &user_products_[MULTI_PACKAGE_INDEX]);
- InitializeMultiPackage(true, package_properties,
- &system_products_[MULTI_PACKAGE_INDEX]);
-}
+ BrowserDistribution::CHROME_FRAME);
+ user_products_[CHROME_FRAME_INDEX].Initialize(false, distribution);
+ system_products_[CHROME_FRAME_INDEX].Initialize(true, distribution);
-// static
-void InstallationState::InitializeProduct(bool system_install,
- BrowserDistribution* distribution,
- ProductState* product) {
- product->Initialize(system_install, distribution->GetVersionKey(),
- distribution->GetStateKey());
-}
-
-// static
-void InstallationState::InitializeMultiPackage(bool system_install,
- PackageProperties& properties,
- ProductState* product) {
- product->Initialize(system_install, properties.GetVersionKey(),
- properties.GetStateKey());
-}
-
-const ProductState* InstallationState::GetMultiPackageState(
- bool system_install) const {
- const ProductState& product_state =
- (system_install ? system_products_ : user_products_)[MULTI_PACKAGE_INDEX];
- return product_state.version_.get() == NULL ? NULL : &product_state;
+ distribution = BrowserDistribution::GetSpecificDistribution(
+ BrowserDistribution::CHROME_BINARIES);
+ user_products_[CHROME_BINARIES_INDEX].Initialize(false, distribution);
+ system_products_[CHROME_BINARIES_INDEX].Initialize(true, distribution);
}
const ProductState* InstallationState::GetProductState(
diff --git a/chrome/installer/util/installation_state.h b/chrome/installer/util/installation_state.h
index 3657c62..817e0af 100644
--- a/chrome/installer/util/installation_state.h
+++ b/chrome/installer/util/installation_state.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Copyright (c) 2011 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,8 @@
#include <string>
#include "base/basictypes.h"
+#include "base/command_line.h"
+#include "base/file_path.h"
#include "base/scoped_ptr.h"
#include "chrome/installer/util/browser_distribution.h"
#include "chrome/installer/util/channel_info.h"
@@ -19,44 +21,75 @@ namespace installer {
class InstallationState;
class MasterPreferences;
-class PackageProperties;
+// A representation of a product's state on the machine based on the contents
+// of the Windows registry.
+// TODO(grt): Pull this out into its own file.
class ProductState {
public:
ProductState();
- void Initialize(bool system_install,
- const std::wstring& version_key,
- const std::wstring& state_key);
+ // Returns true if the product is installed (i.e., the product's Clients key
+ // exists and has a "pv" value); false otherwise.
+ bool Initialize(bool system_install,
+ BrowserDistribution::Type type);
+ bool Initialize(bool system_install,
+ BrowserDistribution* distribution);
+
+ // Returns the product's channel info (i.e., the Google Update "ap" value).
const ChannelInfo& channel() const { return channel_; }
- ChannelInfo& channel() { return channel_; }
+ // Returns the path to the product's "setup.exe"; may be empty.
+ FilePath GetSetupPath() const;
+
+ // Returns the product's version. This method may only be called on an
+ // instance that has been initialized for an installed product.
const Version& version() const;
- // Takes ownership of |version|.
- void set_version(Version* version) { version_.reset(version); }
- void CopyFrom(const ProductState& other);
+ // Returns the current version of the product if a new version is awaiting
+ // update; may be NULL. Ownership of a returned value is not passed to the
+ // caller.
+ const Version* old_version() const { return old_version_.get(); }
- private:
- friend class InstallationState;
+ // Returns the command to be used to update to the new version that is
+ // awaiting update; may be empty.
+ const std::wstring& rename_cmd() const { return rename_cmd_; }
+
+ // True if the "msi" value in the ClientState key is present and non-zero.
+ bool is_msi() const { return msi_; }
+
+ // The command to uninstall the product; may be empty.
+ const CommandLine& uninstall_command() const { return uninstall_command_; }
+
+ // True if |uninstall_command| contains --multi-install.
+ bool is_multi_install() const { return multi_install_; }
+
+ // Returns this object a la operator=().
+ ProductState& CopyFrom(const ProductState& other);
+ protected:
ChannelInfo channel_;
scoped_ptr<Version> version_;
+ scoped_ptr<Version> old_version_;
+ std::wstring rename_cmd_;
+ CommandLine uninstall_command_;
+ bool msi_;
+ bool multi_install_;
+
+ private:
+ friend class InstallationState;
+
DISALLOW_COPY_AND_ASSIGN(ProductState);
}; // class ProductState
// Encapsulates the state of all products on the system.
+// TODO(grt): Rename this to MachineState and put it in its own file.
class InstallationState {
public:
InstallationState();
- // Initializes |this| with the machine's current state.
- void Initialize(const MasterPreferences& prefs);
-
- // Returns the state of the multi-installer package or NULL if no
- // multi-install products are installed.
- // Caller does NOT assume ownership of returned pointer.
- const ProductState* GetMultiPackageState(bool system_install) const;
+ // Initializes this object with the machine's current state.
+ void Initialize();
// Returns the state of a product or NULL if not installed.
// Caller does NOT assume ownership of returned pointer.
@@ -67,17 +100,11 @@ class InstallationState {
enum {
CHROME_BROWSER_INDEX,
CHROME_FRAME_INDEX,
- MULTI_PACKAGE_INDEX,
+ CHROME_BINARIES_INDEX,
NUM_PRODUCTS
};
static int IndexFromDistType(BrowserDistribution::Type type);
- static void InitializeProduct(bool system_install,
- BrowserDistribution* distribution,
- ProductState* product);
- static void InitializeMultiPackage(bool system_install,
- PackageProperties& properties,
- ProductState* product);
ProductState user_products_[NUM_PRODUCTS];
ProductState system_products_[NUM_PRODUCTS];
diff --git a/chrome/installer/util/installer_state.cc b/chrome/installer/util/installer_state.cc
index 69d2841..9137b29 100644
--- a/chrome/installer/util/installer_state.cc
+++ b/chrome/installer/util/installer_state.cc
@@ -4,11 +4,23 @@
#include "chrome/installer/util/installer_state.h"
+#include <algorithm>
+#include <functional>
+#include <utility>
+
+#include "base/command_line.h"
+#include "base/file_util.h"
#include "base/logging.h"
+#include "base/scoped_ptr.h"
+#include "base/string_util.h"
+#include "base/utf_string_conversions.h"
+#include "chrome/installer/util/delete_tree_work_item.h"
+#include "chrome/installer/util/helper.h"
#include "chrome/installer/util/installation_state.h"
#include "chrome/installer/util/master_preferences.h"
#include "chrome/installer/util/master_preferences_constants.h"
-#include "chrome/installer/util/package_properties.h"
+#include "chrome/installer/util/product.h"
+#include "chrome/installer/util/work_item.h"
namespace installer {
@@ -16,7 +28,8 @@ bool InstallerState::IsMultiInstallUpdate(const MasterPreferences& prefs,
const InstallationState& machine_state) {
// First, is the package present?
const ProductState* package =
- machine_state.GetMultiPackageState(system_install_);
+ machine_state.GetProductState(level_ == SYSTEM_LEVEL,
+ BrowserDistribution::CHROME_BINARIES);
if (package == NULL) {
// The multi-install package has not been installed, so it certainly isn't
// being updated.
@@ -33,7 +46,7 @@ bool InstallerState::IsMultiInstallUpdate(const MasterPreferences& prefs,
for (const BrowserDistribution::Type* scan = &types[0],
*end = &types[num_types]; scan != end; ++scan) {
const ProductState* product =
- machine_state.GetProductState(system_install_, *scan);
+ machine_state.GetProductState(level_ == SYSTEM_LEVEL, *scan);
if (product == NULL) {
VLOG(2) << "It seems that distribution type " << *scan
<< " is being installed for the first time.";
@@ -51,42 +64,382 @@ bool InstallerState::IsMultiInstallUpdate(const MasterPreferences& prefs,
return true;
}
-InstallerState::InstallerState() : operation_(UNINITIALIZED) {
+InstallerState::InstallerState()
+ : operation_(UNINITIALIZED),
+ multi_package_distribution_(NULL),
+ level_(UNKNOWN_LEVEL),
+ package_type_(UNKNOWN_PACKAGE_TYPE),
+ root_key_(NULL),
+ msi_(false),
+ verbose_logging_(false) {
+}
+
+InstallerState::InstallerState(Level level)
+ : operation_(UNINITIALIZED),
+ multi_package_distribution_(NULL),
+ level_(UNKNOWN_LEVEL),
+ package_type_(UNKNOWN_PACKAGE_TYPE),
+ root_key_(NULL),
+ msi_(false),
+ verbose_logging_(false) {
+ // Use set_level() so that root_key_ is updated properly.
+ set_level(level);
}
-void InstallerState::Initialize(const MasterPreferences& prefs,
+void InstallerState::Initialize(const CommandLine& command_line,
+ const MasterPreferences& prefs,
const InstallationState& machine_state) {
- if (!prefs.GetBool(installer::master_preferences::kSystemLevel,
- &system_install_))
- system_install_ = false;
+ bool pref_bool;
+ if (!prefs.GetBool(master_preferences::kSystemLevel, &pref_bool))
+ pref_bool = false;
+ set_level(pref_bool ? SYSTEM_LEVEL : USER_LEVEL);
+
+ if (!prefs.GetBool(master_preferences::kVerboseLogging, &verbose_logging_))
+ verbose_logging_ = false;
+
+ if (!prefs.GetBool(master_preferences::kMultiInstall, &pref_bool))
+ pref_bool = false;
+ set_package_type(pref_bool ? MULTI_PACKAGE : SINGLE_PACKAGE);
+
+ if (!prefs.GetBool(master_preferences::kMsi, &msi_))
+ msi_ = false;
+
+ const bool is_uninstall = command_line.HasSwitch(switches::kUninstall);
+
+ if (prefs.install_chrome()) {
+ Product* p =
+ AddProductFromPreferences(BrowserDistribution::CHROME_BROWSER, prefs,
+ machine_state);
+ VLOG(1) << (is_uninstall ? "Uninstall" : "Install")
+ << " distribution: " << p->distribution()->GetApplicationName();
+ }
+ if (prefs.install_chrome_frame()) {
+ Product* p =
+ AddProductFromPreferences(BrowserDistribution::CHROME_FRAME, prefs,
+ machine_state);
+ VLOG(1) << (is_uninstall ? "Uninstall" : "Install")
+ << " distribution: " << p->distribution()->GetApplicationName();
+ }
BrowserDistribution* operand = NULL;
- if (!prefs.is_multi_install()) {
+ if (is_uninstall) {
+ operation_ = UNINSTALL;
+ } else if (!prefs.is_multi_install()) {
// For a single-install, the current browser dist is the operand.
operand = BrowserDistribution::GetDistribution();
operation_ = SINGLE_INSTALL_OR_UPDATE;
} else if (IsMultiInstallUpdate(prefs, machine_state)) {
// Updates driven by Google Update take place under the multi-installer's
// app guid.
- installer::ActivePackageProperties package_properties;
+ operand = multi_package_distribution_;
operation_ = MULTI_UPDATE;
- state_key_ = package_properties.GetStateKey();
} 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;
+ }
+
+ if (operand == NULL) {
operand = BrowserDistribution::GetSpecificDistribution(
prefs.install_chrome() ?
BrowserDistribution::CHROME_BROWSER :
- BrowserDistribution::CHROME_FRAME,
- prefs);
- operation_ = MULTI_INSTALL;
+ BrowserDistribution::CHROME_FRAME);
}
- if (operand != NULL) {
- state_key_ = operand->GetStateKey();
+ state_key_ = operand->GetStateKey();
+}
+
+void InstallerState::set_level(Level level) {
+ level_ = level;
+ switch (level) {
+ case USER_LEVEL:
+ root_key_ = HKEY_CURRENT_USER;
+ break;
+ case SYSTEM_LEVEL:
+ root_key_ = HKEY_LOCAL_MACHINE;
+ break;
+ default:
+ DCHECK(level == UNKNOWN_LEVEL);
+ level_ = UNKNOWN_LEVEL;
+ root_key_ = NULL;
+ break;
+ }
+}
+
+void InstallerState::set_package_type(PackageType type) {
+ package_type_ = type;
+ switch (type) {
+ case SINGLE_PACKAGE:
+ multi_package_distribution_ = NULL;
+ break;
+ case MULTI_PACKAGE:
+ multi_package_distribution_ =
+ BrowserDistribution::GetSpecificDistribution(
+ BrowserDistribution::CHROME_BINARIES);
+ break;
+ default:
+ DCHECK(type == UNKNOWN_PACKAGE_TYPE);
+ package_type_ = UNKNOWN_PACKAGE_TYPE;
+ multi_package_distribution_ = NULL;
+ break;
+ }
+}
+
+// Returns the Chrome binaries directory for multi-install or |dist|'s directory
+// otherwise.
+FilePath InstallerState::GetDefaultProductInstallPath(
+ BrowserDistribution* dist) const {
+ DCHECK(dist);
+ DCHECK(package_type_ != UNKNOWN_PACKAGE_TYPE);
+
+ if (package_type_ == SINGLE_PACKAGE) {
+ return GetChromeInstallPath(system_install(), dist);
+ } else {
+ return GetChromeInstallPath(system_install(),
+ BrowserDistribution::GetSpecificDistribution(
+ BrowserDistribution::CHROME_BINARIES));
+ }
+}
+
+// Evaluates a product's eligibility for participation in this operation.
+// We never expect these checks to fail, hence they all terminate the process in
+// debug builds. See the log messages for details.
+bool InstallerState::CanAddProduct(const Product& product,
+ const FilePath* product_dir) const {
+ switch (package_type_) {
+ case SINGLE_PACKAGE:
+ if (!products_.empty()) {
+ LOG(DFATAL) << "Cannot process more than one single-install product.";
+ return false;
+ }
+ break;
+ case MULTI_PACKAGE:
+ if (!product.HasOption(kOptionMultiInstall)) {
+ LOG(DFATAL) << "Cannot process a single-install product with a "
+ "multi-install state.";
+ return false;
+ }
+ if (FindProduct(product.distribution()->GetType()) != NULL) {
+ LOG(DFATAL) << "Cannot process more than one product of the same type.";
+ return false;
+ }
+ if (!target_path_.empty()) {
+ FilePath default_dir;
+ if (product_dir == NULL)
+ default_dir = GetDefaultProductInstallPath(product.distribution());
+ if (!FilePath::CompareEqualIgnoreCase(
+ (product_dir == NULL ? default_dir : *product_dir).value(),
+ target_path_.value())) {
+ LOG(DFATAL) << "Cannot process products in different directories.";
+ return false;
+ }
+ }
+ break;
+ default:
+ DCHECK_EQ(UNKNOWN_PACKAGE_TYPE, package_type_);
+ break;
+ }
+ return true;
+}
+
+// Adds |product|, installed in |product_dir| to this object's collection. If
+// |product_dir| is NULL, the product's default install location is used.
+// Returns NULL if |product| is incompatible with this object. Otherwise,
+// returns a pointer to the product (ownership is held by this object).
+Product* InstallerState::AddProductInDirectory(const FilePath* product_dir,
+ scoped_ptr<Product>* product) {
+ DCHECK(product != NULL);
+ DCHECK(product->get() != NULL);
+ const Product& the_product = *product->get();
+
+ if (!CanAddProduct(the_product, product_dir))
+ return NULL;
+
+ if (package_type_ == UNKNOWN_PACKAGE_TYPE) {
+ set_package_type(the_product.HasOption(kOptionMultiInstall) ?
+ MULTI_PACKAGE : SINGLE_PACKAGE);
+ }
+
+ if (target_path_.empty()) {
+ if (product_dir == NULL)
+ target_path_ = GetDefaultProductInstallPath(the_product.distribution());
+ else
+ target_path_ = *product_dir;
+ }
+
+ if (state_key_.empty())
+ state_key_ = the_product.distribution()->GetStateKey();
+
+ products_.push_back(product->release());
+ return products_[products_->size() - 1];
+}
+
+Product* InstallerState::AddProduct(scoped_ptr<Product>* product) {
+ return AddProductInDirectory(NULL, product);
+}
+
+// Adds a product of type |distribution_type| constructed on the basis of
+// |prefs|, setting this object's msi flag if the product is represented in
+// |machine_state| and is msi-installed. Returns the product that was added,
+// or NULL if |state| is incompatible with this object. Ownership is not passed
+// to the caller.
+Product* InstallerState::AddProductFromPreferences(
+ BrowserDistribution::Type distribution_type,
+ const MasterPreferences& prefs,
+ const InstallationState& machine_state) {
+ scoped_ptr<Product> product_ptr(
+ new Product(BrowserDistribution::GetSpecificDistribution(
+ distribution_type)));
+ product_ptr->InitializeFromPreferences(prefs);
+
+ Product* product = AddProductInDirectory(NULL, &product_ptr);
+
+ if (product != NULL && !msi_) {
+ const ProductState* product_state = machine_state.GetProductState(
+ system_install(), distribution_type);
+ if (product_state != NULL)
+ msi_ = product_state->is_msi();
+ }
+
+ return product;
+}
+
+Product* InstallerState::AddProductFromState(
+ BrowserDistribution::Type type,
+ const ProductState& state) {
+ scoped_ptr<Product> product_ptr(
+ new Product(BrowserDistribution::GetSpecificDistribution(type)));
+ product_ptr->InitializeFromUninstallCommand(state.uninstall_command());
+
+ // Strip off <version>/Installer/setup.exe; see GetInstallerDirectory().
+ FilePath product_dir = state.GetSetupPath().DirName().DirName().DirName();
+
+ Product* product = AddProductInDirectory(&product_dir, &product_ptr);
+
+ if (product != NULL)
+ msi_ |= state.is_msi();
+
+ return product;
+}
+
+bool InstallerState::system_install() const {
+ DCHECK(level_ == USER_LEVEL || level_ == SYSTEM_LEVEL);
+ return level_ == SYSTEM_LEVEL;
+}
+
+bool InstallerState::is_multi_install() const {
+ DCHECK(package_type_ == SINGLE_PACKAGE || package_type_ == MULTI_PACKAGE);
+ return package_type_ != SINGLE_PACKAGE;
+}
+
+bool InstallerState::RemoveProduct(const Product* product) {
+ ScopedVector<Product>::iterator it =
+ std::find(products_.begin(), products_.end(), product);
+ if (it != products_.end()) {
+ products_->erase(it);
+ return true;
+ }
+ return false;
+}
+
+const Product* InstallerState::FindProduct(
+ BrowserDistribution::Type distribution_type) const {
+ for (Products::const_iterator scan = products_.begin(), end = products_.end();
+ scan != end; ++scan) {
+ if ((*scan)->is_type(distribution_type))
+ return *scan;
+ }
+ return NULL;
+}
+
+Version* InstallerState::GetCurrentVersion(
+ const InstallationState& machine_state) const {
+ DCHECK(!products_.empty());
+ scoped_ptr<Version> current_version;
+ const BrowserDistribution::Type prod_type = (package_type_ == MULTI_PACKAGE) ?
+ BrowserDistribution::CHROME_BINARIES :
+ products_[0]->distribution()->GetType();
+ const ProductState* product_state =
+ machine_state.GetProductState(level_ == SYSTEM_LEVEL, prod_type);
+
+ if (product_state != NULL) {
+ const Version* version = NULL;
+
+ // Be aware that there might be a pending "new_chrome.exe" already in the
+ // installation path. If so, we use old_version, which holds the version of
+ // "chrome.exe" itself.
+ if (file_util::PathExists(target_path().Append(kChromeNewExe)))
+ version = product_state->old_version();
+
+ if (version == NULL)
+ version = &product_state->version();
+
+ current_version.reset(version->Clone());
+ }
+
+ return current_version.release();
+}
+
+FilePath InstallerState::GetInstallerDirectory(const Version& version) const {
+ return target_path().Append(ASCIIToWide(version.GetString()))
+ .Append(kInstallerDir);
+}
+
+void InstallerState::RemoveOldVersionDirectories(
+ const Version& latest_version) const {
+ file_util::FileEnumerator version_enum(target_path(), false,
+ file_util::FileEnumerator::DIRECTORIES);
+ scoped_ptr<Version> version;
+ std::vector<FilePath> key_files;
+
+ // We try to delete all directories whose versions are lower than
+ // latest_version.
+ FilePath next_version = version_enum.Next();
+ while (!next_version.empty()) {
+ file_util::FileEnumerator::FindInfo find_data = {0};
+ version_enum.GetFindInfo(&find_data);
+ VLOG(1) << "directory found: " << find_data.cFileName;
+ version.reset(Version::GetVersionFromString(
+ WideToASCII(find_data.cFileName)));
+ if (version.get() && latest_version.CompareTo(*version) > 0) {
+ key_files.clear();
+ std::for_each(products_.begin(), products_.end(),
+ std::bind2nd(std::mem_fun(&Product::AddKeyFiles),
+ &key_files));
+ const std::vector<FilePath>::iterator end = key_files.end();
+ for (std::vector<FilePath>::iterator scan = key_files.begin();
+ scan != end; ++scan) {
+ *scan = next_version.Append(*scan);
+ }
+
+ VLOG(1) << "Deleting directory: " << next_version.value();
+
+ scoped_ptr<WorkItem> item(
+ WorkItem::CreateDeleteTreeWorkItem(next_version, key_files));
+ if (!item->Do())
+ item->Rollback();
+ }
+
+ next_version = version_enum.Next();
+ }
+}
+
+void InstallerState::AddComDllList(std::vector<FilePath>* com_dll_list) const {
+ std::for_each(products_.begin(), products_.end(),
+ std::bind2nd(std::mem_fun(&Product::AddComDllList),
+ com_dll_list));
+}
+
+bool InstallerState::SetChannelFlags(bool set,
+ ChannelInfo* channel_info) const {
+ bool modified = false;
+ for (Products::const_iterator scan = products_.begin(), end = products_.end();
+ scan != end; ++scan) {
+ modified |= (*scan)->SetChannelFlags(set, channel_info);
}
+ return modified;
}
} // namespace installer
diff --git a/chrome/installer/util/installer_state.h b/chrome/installer/util/installer_state.h
index 0bc2a5f..0b4ea0b 100644
--- a/chrome/installer/util/installer_state.h
+++ b/chrome/installer/util/installer_state.h
@@ -7,47 +7,183 @@
#pragma once
#include <string>
+#include <vector>
#include "base/basictypes.h"
+#include "base/file_path.h"
+#include "base/logging.h"
+#include "base/scoped_ptr.h"
+#include "base/scoped_vector.h"
#include "chrome/installer/util/browser_distribution.h"
+#include "chrome/installer/util/product.h"
+
+#if defined(OS_WIN)
+#include <windows.h> // NOLINT
+#endif
+
+class CommandLine;
+class Version;
namespace installer {
+class ChannelInfo;
class InstallationState;
class MasterPreferences;
+class ProductState;
+
+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)
+// for installs and upgrades (not for uninstalls or non-install commands).
+// TODO(grt): Rename to InstallerEngine/Conductor or somesuch?
class InstallerState {
public:
+ enum Level {
+ UNKNOWN_LEVEL,
+ USER_LEVEL,
+ SYSTEM_LEVEL
+ };
+
+ enum PackageType {
+ UNKNOWN_PACKAGE_TYPE,
+ SINGLE_PACKAGE,
+ MULTI_PACKAGE
+ };
+
enum Operation {
UNINITIALIZED,
SINGLE_INSTALL_OR_UPDATE,
MULTI_INSTALL,
MULTI_UPDATE,
+ UNINSTALL
};
+ // Constructs an uninitialized instance; see Initialize().
InstallerState();
- // Initializes |this| based on the current operation.
- void Initialize(const MasterPreferences& prefs,
+ // Constructs an initialized but empty instance.
+ explicit InstallerState(Level level);
+
+ // Initializes this object based on the current operation.
+ void Initialize(const CommandLine& command_line,
+ const MasterPreferences& prefs,
const InstallationState& machine_state);
- // true if system-level, false if user-level.
- bool system_install() const { return system_install_; }
+ // Adds a product constructed on the basis of |state|, setting this object's
+ // msi flag if |state| is msi-installed. Returns the product that was added,
+ // or NULL if |state| is incompatible with this object. Ownership is not
+ // passed to the caller.
+ Product* AddProductFromState(BrowserDistribution::Type type,
+ const ProductState& state);
+
+ // Returns the product that was added, or NULL if |product| is incompatible
+ // with this object. Ownership of |product| is taken by this object, while
+ // ownership of the return value is not passed to the caller.
+ Product* AddProduct(scoped_ptr<Product>* product);
+
+ // Removes |product| from the set of products to be operated on. The object
+ // pointed to by |product| is freed. Returns false if |product| is not
+ // present in the set.
+ bool RemoveProduct(const Product* product);
+
+ // The level (user or system) of this operation.
+ Level level() const { return level_; }
+ // The package type (single or multi) of this operation.
+ PackageType package_type() const { return package_type_; }
+
+ // An identifier of this operation.
Operation operation() const { return operation_; }
+ // A convenience method returning level() == SYSTEM_LEVEL.
+ // TODO(grt): Eradicate the bool in favor of the enum.
+ bool system_install() const;
+
+ // A convenience method returning package_type() == MULTI_PACKAGE.
+ // TODO(grt): Eradicate the bool in favor of the enum.
+ bool is_multi_install() const;
+
+ // The full path to the place where the operand resides.
+ const FilePath& target_path() const { return target_path_; }
+
+ // True if the "msi" preference is set or if a product with the "msi" state
+ // flag is set is to be operated on.
+ bool is_msi() const { return msi_; }
+
+ // True if the --verbose-logging command-line flag is set or if the
+ // verbose_logging master preferences option is true.
+ bool verbose_logging() const { return verbose_logging_; }
+
+#if defined(OS_WIN)
+ HKEY root_key() const { return root_key_; }
+#endif
+
// The ClientState key by which we interact with Google Update.
const std::wstring& state_key() const { return state_key_; }
+ // Returns the BrowserDistribution instance corresponding to the binaries for
+ // this run if we're operating on a multi-package product.
+ BrowserDistribution* multi_package_binaries_distribution() const {
+ DCHECK(package_type_ == MULTI_PACKAGE);
+ DCHECK(multi_package_distribution_ != NULL);
+ return multi_package_distribution_;
+ }
+
+ const Products& products() const { return products_.get(); }
+
+ // Returns the product of the desired type, or NULL if none found.
+ const Product* FindProduct(BrowserDistribution::Type distribution_type) const;
+
+ // Returns the currently installed version in |target_path|, or NULL if no
+ // products are installed. Ownership is passed to the caller.
+ Version* GetCurrentVersion(const InstallationState& machine_state) const;
+
+ // Returns the path to the installer under Chrome version folder
+ // (for example <target_path>\Google\Chrome\Application\<Version>\Installer)
+ FilePath GetInstallerDirectory(const Version& version) const;
+
+ // Try to delete all directories whose versions are lower than
+ // |latest_version|.
+ void RemoveOldVersionDirectories(const Version& latest_version) const;
+
+ // Adds to |com_dll_list| the list of COM DLLs that are to be registered
+ // and/or unregistered. The list may be empty.
+ void AddComDllList(std::vector<FilePath>* com_dll_list) const;
+
+ bool SetChannelFlags(bool set, ChannelInfo* channel_info) const;
+
protected:
+ FilePath GetDefaultProductInstallPath(BrowserDistribution* dist) const;
+ bool CanAddProduct(const Product& product, const FilePath* product_dir) const;
+ Product* AddProductInDirectory(const FilePath* product_dir,
+ scoped_ptr<Product>* product);
+ Product* AddProductFromPreferences(
+ BrowserDistribution::Type distribution_type,
+ const MasterPreferences& prefs,
+ const InstallationState& machine_state);
bool IsMultiInstallUpdate(const MasterPreferences& prefs,
const InstallationState& machine_state);
+ // Sets this object's level and updates the root_key_ accordingly.
+ void set_level(Level level);
+
+ // Sets this object's package type and updates the multi_package_distribution_
+ // accordingly.
+ void set_package_type(PackageType type);
+
Operation operation_;
+ FilePath target_path_;
std::wstring state_key_;
- bool system_install_;
+ ScopedVector<Product> products_;
+ BrowserDistribution* multi_package_distribution_;
+ Level level_;
+ PackageType package_type_;
+#if defined(OS_WIN)
+ HKEY root_key_;
+#endif
+ bool msi_;
+ bool verbose_logging_;
private:
DISALLOW_COPY_AND_ASSIGN(InstallerState);
diff --git a/chrome/installer/util/installer_state_unittest.cc b/chrome/installer/util/installer_state_unittest.cc
new file mode 100644
index 0000000..25efc07
--- /dev/null
+++ b/chrome/installer/util/installer_state_unittest.cc
@@ -0,0 +1,327 @@
+// Copyright (c) 2011 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 <windows.h>
+
+#include <fstream>
+
+#include "base/base_paths.h"
+#include "base/command_line.h"
+#include "base/file_util.h"
+#include "base/path_service.h"
+#include "base/process_util.h"
+#include "base/string_util.h"
+#include "base/utf_string_conversions.h"
+#include "base/version.h"
+#include "base/win/registry.h"
+#include "base/win/scoped_handle.h"
+#include "chrome/installer/util/google_update_constants.h"
+#include "chrome/installer/util/helper.h"
+#include "chrome/installer/util/installation_state.h"
+#include "chrome/installer/util/installer_state.h"
+#include "chrome/installer/util/master_preferences.h"
+#include "chrome/installer/util/product_unittest.h"
+#include "chrome/installer/util/work_item.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+class InstallerStateTest : public TestWithTempDirAndDeleteTempOverrideKeys {
+ protected:
+};
+
+// An installer state on which we can tweak the target path.
+class MockInstallerState : public installer::InstallerState {
+ public:
+ MockInstallerState() : InstallerState() { }
+ void set_target_path(const FilePath& target_path) {
+ target_path_ = target_path;
+ }
+};
+
+// Simple function to dump some text into a new file.
+void CreateTextFile(const std::wstring& filename,
+ const std::wstring& contents) {
+ std::ofstream file;
+ file.open(filename.c_str());
+ ASSERT_TRUE(file.is_open());
+ file << contents;
+ file.close();
+}
+
+void BuildSingleChromeState(const FilePath& target_dir,
+ MockInstallerState* installer_state) {
+ CommandLine cmd_line = CommandLine::FromString(L"setup.exe");
+ installer::MasterPreferences prefs(cmd_line);
+ installer::InstallationState machine_state;
+ machine_state.Initialize();
+ installer_state->Initialize(cmd_line, prefs, machine_state);
+ installer_state->set_target_path(target_dir);
+ EXPECT_TRUE(installer_state->FindProduct(BrowserDistribution::CHROME_BROWSER)
+ != NULL);
+ EXPECT_TRUE(installer_state->FindProduct(BrowserDistribution::CHROME_FRAME)
+ == NULL);
+}
+
+wchar_t text_content_1[] = L"delete me";
+wchar_t text_content_2[] = L"delete me as well";
+
+// Delete version directories. Everything lower than the given version
+// should be deleted.
+TEST_F(InstallerStateTest, Delete) {
+ // TODO(grt): move common stuff into the test fixture.
+ // Create a Chrome dir
+ FilePath chrome_dir(test_dir_.path());
+ chrome_dir = chrome_dir.AppendASCII("chrome");
+ file_util::CreateDirectory(chrome_dir);
+ ASSERT_TRUE(file_util::PathExists(chrome_dir));
+
+ FilePath chrome_dir_1(chrome_dir);
+ chrome_dir_1 = chrome_dir_1.AppendASCII("1.0.1.0");
+ file_util::CreateDirectory(chrome_dir_1);
+ ASSERT_TRUE(file_util::PathExists(chrome_dir_1));
+
+ FilePath chrome_dir_2(chrome_dir);
+ chrome_dir_2 = chrome_dir_2.AppendASCII("1.0.2.0");
+ file_util::CreateDirectory(chrome_dir_2);
+ ASSERT_TRUE(file_util::PathExists(chrome_dir_2));
+
+ FilePath chrome_dir_3(chrome_dir);
+ chrome_dir_3 = chrome_dir_3.AppendASCII("1.0.3.0");
+ file_util::CreateDirectory(chrome_dir_3);
+ ASSERT_TRUE(file_util::PathExists(chrome_dir_3));
+
+ FilePath chrome_dir_4(chrome_dir);
+ chrome_dir_4 = chrome_dir_4.AppendASCII("1.0.4.0");
+ file_util::CreateDirectory(chrome_dir_4);
+ ASSERT_TRUE(file_util::PathExists(chrome_dir_4));
+
+ FilePath chrome_dll_1(chrome_dir_1);
+ chrome_dll_1 = chrome_dll_1.AppendASCII("chrome.dll");
+ CreateTextFile(chrome_dll_1.value(), text_content_1);
+ ASSERT_TRUE(file_util::PathExists(chrome_dll_1));
+
+ FilePath chrome_dll_2(chrome_dir_2);
+ chrome_dll_2 = chrome_dll_2.AppendASCII("chrome.dll");
+ CreateTextFile(chrome_dll_2.value(), text_content_1);
+ ASSERT_TRUE(file_util::PathExists(chrome_dll_2));
+
+ FilePath chrome_dll_3(chrome_dir_3);
+ chrome_dll_3 = chrome_dll_3.AppendASCII("chrome.dll");
+ CreateTextFile(chrome_dll_3.value(), text_content_1);
+ ASSERT_TRUE(file_util::PathExists(chrome_dll_3));
+
+ FilePath chrome_dll_4(chrome_dir_4);
+ chrome_dll_4 = chrome_dll_4.AppendASCII("chrome.dll");
+ CreateTextFile(chrome_dll_4.value(), text_content_1);
+ ASSERT_TRUE(file_util::PathExists(chrome_dll_4));
+
+ MockInstallerState installer_state;
+ BuildSingleChromeState(chrome_dir, &installer_state);
+ scoped_ptr<Version> latest_version(Version::GetVersionFromString("1.0.4.0"));
+ installer_state.RemoveOldVersionDirectories(*latest_version.get());
+
+ // old versions should be gone
+ EXPECT_FALSE(file_util::PathExists(chrome_dir_1));
+ EXPECT_FALSE(file_util::PathExists(chrome_dir_2));
+ EXPECT_FALSE(file_util::PathExists(chrome_dir_3));
+ // the latest version should stay
+ EXPECT_TRUE(file_util::PathExists(chrome_dll_4));
+}
+
+// Delete older version directories, keeping the one in used intact.
+TEST_F(InstallerStateTest, DeleteInUsed) {
+ // Create a Chrome dir
+ FilePath chrome_dir(test_dir_.path());
+ chrome_dir = chrome_dir.AppendASCII("chrome");
+ file_util::CreateDirectory(chrome_dir);
+ ASSERT_TRUE(file_util::PathExists(chrome_dir));
+
+ FilePath chrome_dir_1(chrome_dir);
+ chrome_dir_1 = chrome_dir_1.AppendASCII("1.0.1.0");
+ file_util::CreateDirectory(chrome_dir_1);
+ ASSERT_TRUE(file_util::PathExists(chrome_dir_1));
+
+ FilePath chrome_dir_2(chrome_dir);
+ chrome_dir_2 = chrome_dir_2.AppendASCII("1.0.2.0");
+ file_util::CreateDirectory(chrome_dir_2);
+ ASSERT_TRUE(file_util::PathExists(chrome_dir_2));
+
+ FilePath chrome_dir_3(chrome_dir);
+ chrome_dir_3 = chrome_dir_3.AppendASCII("1.0.3.0");
+ file_util::CreateDirectory(chrome_dir_3);
+ ASSERT_TRUE(file_util::PathExists(chrome_dir_3));
+
+ FilePath chrome_dir_4(chrome_dir);
+ chrome_dir_4 = chrome_dir_4.AppendASCII("1.0.4.0");
+ file_util::CreateDirectory(chrome_dir_4);
+ ASSERT_TRUE(file_util::PathExists(chrome_dir_4));
+
+ FilePath chrome_dll_1(chrome_dir_1);
+ chrome_dll_1 = chrome_dll_1.AppendASCII("chrome.dll");
+ CreateTextFile(chrome_dll_1.value(), text_content_1);
+ ASSERT_TRUE(file_util::PathExists(chrome_dll_1));
+
+ FilePath chrome_dll_2(chrome_dir_2);
+ chrome_dll_2 = chrome_dll_2.AppendASCII("chrome.dll");
+ CreateTextFile(chrome_dll_2.value(), text_content_1);
+ ASSERT_TRUE(file_util::PathExists(chrome_dll_2));
+
+ // Open the file to make it in use.
+ std::ofstream file;
+ file.open(chrome_dll_2.value().c_str());
+
+ FilePath chrome_othera_2(chrome_dir_2);
+ chrome_othera_2 = chrome_othera_2.AppendASCII("othera.dll");
+ CreateTextFile(chrome_othera_2.value(), text_content_2);
+ ASSERT_TRUE(file_util::PathExists(chrome_othera_2));
+
+ FilePath chrome_otherb_2(chrome_dir_2);
+ chrome_otherb_2 = chrome_otherb_2.AppendASCII("otherb.dll");
+ CreateTextFile(chrome_otherb_2.value(), text_content_2);
+ ASSERT_TRUE(file_util::PathExists(chrome_otherb_2));
+
+ FilePath chrome_dll_3(chrome_dir_3);
+ chrome_dll_3 = chrome_dll_3.AppendASCII("chrome.dll");
+ CreateTextFile(chrome_dll_3.value(), text_content_1);
+ ASSERT_TRUE(file_util::PathExists(chrome_dll_3));
+
+ FilePath chrome_dll_4(chrome_dir_4);
+ chrome_dll_4 = chrome_dll_4.AppendASCII("chrome.dll");
+ CreateTextFile(chrome_dll_4.value(), text_content_1);
+ ASSERT_TRUE(file_util::PathExists(chrome_dll_4));
+
+ MockInstallerState installer_state;
+ BuildSingleChromeState(chrome_dir, &installer_state);
+ scoped_ptr<Version> latest_version(Version::GetVersionFromString("1.0.4.0"));
+ installer_state.RemoveOldVersionDirectories(*latest_version.get());
+
+ // old versions not in used should be gone
+ EXPECT_FALSE(file_util::PathExists(chrome_dir_1));
+ EXPECT_FALSE(file_util::PathExists(chrome_dir_3));
+ // every thing under in used version should stay
+ EXPECT_TRUE(file_util::PathExists(chrome_dir_2));
+ EXPECT_TRUE(file_util::PathExists(chrome_dll_2));
+ EXPECT_TRUE(file_util::PathExists(chrome_othera_2));
+ EXPECT_TRUE(file_util::PathExists(chrome_otherb_2));
+ // the latest version should stay
+ EXPECT_TRUE(file_util::PathExists(chrome_dll_4));
+}
+
+// Tests a few basic things of the Package class. Makes sure that the path
+// operations are correct
+TEST_F(InstallerStateTest, Basic) {
+ const bool multi_install = false;
+ const bool system_level = true;
+ CommandLine cmd_line = CommandLine::FromString(
+ std::wstring(L"setup.exe") +
+ (multi_install ? L" --multi-install --chrome" : L"") +
+ (system_level ? L" --system-level" : L""));
+ installer::MasterPreferences prefs(cmd_line);
+ installer::InstallationState machine_state;
+ machine_state.Initialize();
+ MockInstallerState installer_state;
+ installer_state.Initialize(cmd_line, prefs, machine_state);
+ installer_state.set_target_path(test_dir_.path());
+ EXPECT_EQ(test_dir_.path().value(), installer_state.target_path().value());
+ EXPECT_EQ(1U, installer_state.products().size());
+
+ const char kOldVersion[] = "1.2.3.4";
+ const char kNewVersion[] = "2.3.4.5";
+
+ scoped_ptr<Version> new_version(Version::GetVersionFromString(kNewVersion));
+ scoped_ptr<Version> old_version(Version::GetVersionFromString(kOldVersion));
+ ASSERT_TRUE(new_version.get() != NULL);
+ ASSERT_TRUE(old_version.get() != NULL);
+
+ FilePath installer_dir(
+ installer_state.GetInstallerDirectory(*new_version.get()));
+ EXPECT_FALSE(installer_dir.empty());
+
+ FilePath new_version_dir(installer_state.target_path().Append(
+ UTF8ToWide(new_version->GetString())));
+ FilePath old_version_dir(installer_state.target_path().Append(
+ UTF8ToWide(old_version->GetString())));
+
+ EXPECT_FALSE(file_util::PathExists(new_version_dir));
+ EXPECT_FALSE(file_util::PathExists(old_version_dir));
+
+ EXPECT_FALSE(file_util::PathExists(installer_dir));
+ file_util::CreateDirectory(installer_dir);
+ EXPECT_TRUE(file_util::PathExists(new_version_dir));
+
+ file_util::CreateDirectory(old_version_dir);
+ EXPECT_TRUE(file_util::PathExists(old_version_dir));
+
+ // Create a fake chrome.dll key file in the old version directory. This
+ // should prevent the old version directory from getting deleted.
+ FilePath old_chrome_dll(old_version_dir.Append(installer::kChromeDll));
+ EXPECT_FALSE(file_util::PathExists(old_chrome_dll));
+
+ // Hold on to the file exclusively to prevent the directory from
+ // being deleted.
+ base::win::ScopedHandle file(
+ ::CreateFile(old_chrome_dll.value().c_str(), GENERIC_READ,
+ 0, NULL, OPEN_ALWAYS, 0, NULL));
+ EXPECT_TRUE(file.IsValid());
+ EXPECT_TRUE(file_util::PathExists(old_chrome_dll));
+
+ installer_state.RemoveOldVersionDirectories(*new_version.get());
+ // The old directory should still exist.
+ EXPECT_TRUE(file_util::PathExists(old_version_dir));
+ EXPECT_TRUE(file_util::PathExists(new_version_dir));
+
+ // Now close the file handle to make it possible to delete our key file.
+ file.Close();
+
+ installer_state.RemoveOldVersionDirectories(*new_version.get());
+ // The new directory should still exist.
+ EXPECT_TRUE(file_util::PathExists(new_version_dir));
+
+ // Now, the old directory and key file should be gone.
+ EXPECT_FALSE(file_util::PathExists(old_chrome_dll));
+ EXPECT_FALSE(file_util::PathExists(old_version_dir));
+}
+
+TEST_F(InstallerStateTest, WithProduct) {
+ const bool multi_install = false;
+ const bool system_level = true;
+ CommandLine cmd_line = CommandLine::FromString(
+ std::wstring(L"setup.exe") +
+ (multi_install ? L" --multi-install --chrome" : L"") +
+ (system_level ? L" --system-level" : L""));
+ installer::MasterPreferences prefs(cmd_line);
+ installer::InstallationState machine_state;
+ machine_state.Initialize();
+ MockInstallerState installer_state;
+ installer_state.Initialize(cmd_line, prefs, machine_state);
+ installer_state.set_target_path(test_dir_.path());
+ EXPECT_EQ(1U, installer_state.products().size());
+ EXPECT_EQ(system_level, installer_state.system_install());
+
+ const char kCurrentVersion[] = "1.2.3.4";
+ scoped_ptr<Version> current_version(
+ Version::GetVersionFromString(kCurrentVersion));
+
+ HKEY root = system_level ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER;
+ EXPECT_EQ(root, installer_state.root_key());
+ {
+ TempRegKeyOverride override(root, L"root_pit");
+ BrowserDistribution* dist = BrowserDistribution::GetSpecificDistribution(
+ BrowserDistribution::CHROME_BROWSER);
+ base::win::RegKey chrome_key(root, dist->GetVersionKey().c_str(),
+ KEY_ALL_ACCESS);
+ EXPECT_TRUE(chrome_key.Valid());
+ if (chrome_key.Valid()) {
+ chrome_key.WriteValue(google_update::kRegVersionField,
+ UTF8ToWide(current_version->GetString()).c_str());
+ machine_state.Initialize();
+ // TODO(tommi): Also test for when there exists a new_chrome.exe.
+ scoped_ptr<Version> found_version(installer_state.GetCurrentVersion(
+ machine_state));
+ EXPECT_TRUE(found_version.get() != NULL);
+ if (found_version.get()) {
+ EXPECT_TRUE(current_version->Equals(*found_version));
+ }
+ }
+ }
+}
diff --git a/chrome/installer/util/package.cc b/chrome/installer/util/package.cc
deleted file mode 100644
index 3122cef..0000000
--- a/chrome/installer/util/package.cc
+++ /dev/null
@@ -1,188 +0,0 @@
-// Copyright (c) 2010 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/package.h"
-
-#include "base/file_util.h"
-#include "base/logging.h"
-#include "base/string_util.h"
-#include "base/utf_string_conversions.h"
-#include "base/win/registry.h"
-#include "chrome/installer/util/delete_tree_work_item.h"
-#include "chrome/installer/util/google_update_constants.h"
-#include "chrome/installer/util/helper.h"
-#include "chrome/installer/util/master_preferences.h"
-#include "chrome/installer/util/package_properties.h"
-#include "chrome/installer/util/product.h"
-#include "chrome/installer/util/util_constants.h"
-#include "chrome/installer/util/work_item_list.h"
-
-using base::win::RegKey;
-using installer::MasterPreferences;
-
-namespace installer {
-
-Package::Package(bool multi_install, bool system_level, const FilePath& path,
- PackageProperties* properties)
- : multi_install_(multi_install),
- system_level_(system_level),
- path_(path),
- properties_(properties) {
- DCHECK(properties_);
-}
-
-Package::~Package() {
-}
-
-const FilePath& Package::path() const {
- return path_;
-}
-
-const Products& Package::products() const {
- return products_;
-}
-
-PackageProperties* Package::properties() const {
- return properties_;
-}
-
-bool Package::IsEqual(const FilePath& path) const {
- return FilePath::CompareEqualIgnoreCase(path_.value(), path.value());
-}
-
-void Package::AssociateProduct(const Product* product) {
-#ifndef NDEBUG
- for (size_t i = 0; i < products_.size(); ++i) {
- DCHECK_NE(product->distribution()->GetType(),
- products_[i]->distribution()->GetType());
- }
-#endif
- products_.push_back(product);
-}
-
-bool Package::multi_install() const {
- return multi_install_;
-}
-
-bool Package::system_level() const {
- return system_level_;
-}
-
-FilePath Package::GetInstallerDirectory(
- const Version& version) const {
- return path_.Append(UTF8ToWide(version.GetString()))
- .Append(installer::kInstallerDir);
-}
-
-Version* Package::GetCurrentVersion() const {
- scoped_ptr<Version> current_version;
- // Be aware that there might be a pending "new_chrome.exe" already in the
- // installation path.
- FilePath new_chrome_exe(path_.Append(installer::kChromeNewExe));
- bool new_chrome_exists = file_util::PathExists(new_chrome_exe);
-
- HKEY root = system_level_ ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER;
-
- for (size_t i = 0; i < products_.size(); ++i) {
- const Product* product = products_[i];
- RegKey chrome_key(root, product->distribution()->GetVersionKey().c_str(),
- KEY_READ);
- std::wstring version;
- if (new_chrome_exists)
- chrome_key.ReadValue(google_update::kRegOldVersionField, &version);
-
- if (version.empty())
- chrome_key.ReadValue(google_update::kRegVersionField, &version);
-
- if (!version.empty()) {
- scoped_ptr<Version> this_version(Version::GetVersionFromString(
- WideToASCII(version)));
- if (this_version.get()) {
- if (!current_version.get() ||
- (current_version->CompareTo(*this_version) > 0)) {
- current_version.reset(this_version.release());
- } else if (current_version.get()) {
- DCHECK_EQ(current_version->GetString(), this_version->GetString())
- << "found distributions of different versions in the same "
- "installation folder!";
- }
- }
- }
- }
-
- return current_version.release();
-}
-
-void Package::RemoveOldVersionDirectories(
- const Version& latest_version) const {
- file_util::FileEnumerator version_enum(path_, false,
- file_util::FileEnumerator::DIRECTORIES);
- scoped_ptr<Version> version;
-
- // We try to delete all directories whose versions are lower than
- // latest_version.
- FilePath next_version = version_enum.Next();
- while (!next_version.empty()) {
- file_util::FileEnumerator::FindInfo find_data = {0};
- version_enum.GetFindInfo(&find_data);
- VLOG(1) << "directory found: " << find_data.cFileName;
- version.reset(Version::GetVersionFromString(
- WideToASCII(find_data.cFileName)));
- if (version.get() && (latest_version.CompareTo(*version) > 0)) {
- std::vector<FilePath> key_files;
- for (Products::const_iterator it = products_.begin();
- it != products_.end(); ++it) {
- BrowserDistribution* dist = it->get()->distribution();
- std::vector<FilePath> dist_key_files(dist->GetKeyFiles());
- std::vector<FilePath>::const_iterator key_file_iter(
- dist_key_files.begin());
- for (; key_file_iter != dist_key_files.end(); ++key_file_iter) {
- key_files.push_back(next_version.Append(*key_file_iter));
- }
- }
-
- VLOG(1) << "Deleting directory: " << next_version.value();
-
- scoped_ptr<DeleteTreeWorkItem> item(
- WorkItem::CreateDeleteTreeWorkItem(next_version, key_files));
- if (!item->Do())
- item->Rollback();
- }
-
- next_version = version_enum.Next();
- }
-}
-
-size_t Package::GetMultiInstallDependencyCount() const {
- BrowserDistribution::Type product_types[] = {
- BrowserDistribution::CHROME_BROWSER,
- BrowserDistribution::CHROME_FRAME,
- };
-
- const MasterPreferences& prefs = MasterPreferences::ForCurrentProcess();
- HKEY root_key = system_level_ ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER;
-
- size_t ret = 0;
-
- for (int i = 0; i < arraysize(product_types); ++i) {
- BrowserDistribution* dist =
- BrowserDistribution::GetSpecificDistribution(product_types[i], prefs);
- // First see if the product is installed by checking its version key.
- // If the key doesn't exist, the product isn't installed.
- RegKey version_key(root_key, dist->GetVersionKey().c_str(), KEY_READ);
- if (!version_key.Valid()) {
- VLOG(1) << "Product not installed: " << dist->GetApplicationName();
- } else {
- if (installer::IsInstalledAsMulti(system_level_, dist)) {
- VLOG(1) << "Product dependency: " << dist->GetApplicationName();
- ++ret;
- }
- }
- }
-
- return ret;
-}
-
-} // namespace installer
-
diff --git a/chrome/installer/util/package.h b/chrome/installer/util/package.h
deleted file mode 100644
index d523fc2..0000000
--- a/chrome/installer/util/package.h
+++ /dev/null
@@ -1,90 +0,0 @@
-// Copyright (c) 2010 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_PACKAGE_H_
-#define CHROME_INSTALLER_UTIL_PACKAGE_H_
-#pragma once
-
-#include <vector>
-
-#include "base/file_path.h"
-#include "base/ref_counted.h"
-
-class CommandLine;
-class Version;
-
-namespace installer {
-
-enum InstallStatus;
-class Product;
-class PackageProperties;
-
-typedef std::vector<scoped_refptr<const Product> > Products;
-
-// Represents a physical installation. An instance of this class is associated
-// with one or more Product instances. Product objects can share a Package but
-// not vice versa.
-class Package : public base::RefCounted<Package> {
- public:
- Package(bool multi_install, bool system_level, const FilePath& path,
- PackageProperties* properties);
-
- // Returns the path of the installation folder.
- const FilePath& path() const;
-
- const Products& products() const;
-
- PackageProperties* properties() const;
-
- bool multi_install() const;
-
- bool system_level() const;
-
- bool IsEqual(const FilePath& path) const;
-
- void AssociateProduct(const Product* product);
-
- // Get path to the installer under Chrome version folder
- // (for example <path>\Google\Chrome\Application\<Version>\Installer)
- FilePath GetInstallerDirectory(const Version& version) const;
-
- // Figure out the oldest currently installed version for this package
- // Returns NULL if none is found. Caller is responsible for freeing
- // the returned Version object if valid.
- // The function DCHECKs if it finds that not all products in this
- // folder have the same current version.
- Version* GetCurrentVersion() const;
-
- // Tries to remove all previous version directories (after a new Chrome
- // update). If an instance of Chrome with older version is still running
- // on the system, its corresponding version directory will be left intact.
- // (The version directory is subject for removal again during next update.)
- //
- // latest_version: the latest version of Chrome installed.
- void RemoveOldVersionDirectories(const Version& latest_version) const;
-
- // Returns how many installed products depend on the binaries currently
- // in the installation path.
- // Note: The function counts only products that are installed as part of
- // a multi install installation and only products that have the same
- // system_level() value.
- size_t GetMultiInstallDependencyCount() const;
-
- protected:
- bool multi_install_;
- bool system_level_;
- FilePath path_;
- Products products_;
- PackageProperties* properties_; // Weak reference.
-
- private:
- friend class base::RefCounted<Package>;
- ~Package();
-
- DISALLOW_COPY_AND_ASSIGN(Package);
-};
-
-} // namespace installer
-
-#endif // CHROME_INSTALLER_UTIL_PACKAGE_H_
diff --git a/chrome/installer/util/package_properties.cc b/chrome/installer/util/package_properties.cc
deleted file mode 100644
index e33c2f9..0000000
--- a/chrome/installer/util/package_properties.cc
+++ /dev/null
@@ -1,94 +0,0 @@
-// Copyright (c) 2011 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/package_properties.h"
-
-#include "base/basictypes.h"
-#include "base/string_util.h"
-#include "chrome/installer/util/browser_distribution.h"
-#include "chrome/installer/util/google_update_constants.h"
-#include "chrome/installer/util/google_update_settings.h"
-#include "chrome/installer/util/install_util.h"
-#include "chrome/installer/util/util_constants.h"
-
-namespace {
-
-const wchar_t kChromePackageGuid[] =
- L"{4DC8B4CA-1BDA-483e-B5FA-D3C12E15B62D}";
-
-std::wstring GetKeyForGuid(const wchar_t* base_key, const wchar_t* guid) {
- std::wstring key(base_key);
- key.append(L"\\");
- key.append(guid);
- return key;
-}
-
-} // end namespace
-
-namespace installer {
-
-const char PackageProperties::kPackageProductName[] = "Chrome binaries";
-
-PackagePropertiesImpl::PackagePropertiesImpl(
- const wchar_t* guid,
- const std::wstring& state_key,
- const std::wstring& state_medium_key,
- const std::wstring& version_key)
- : guid_(guid), state_key_(state_key), state_medium_key_(state_medium_key),
- version_key_(version_key) {
-}
-
-PackagePropertiesImpl::~PackagePropertiesImpl() {
-}
-
-const std::wstring& PackagePropertiesImpl::GetAppGuid() {
- return guid_;
-}
-
-const std::wstring& PackagePropertiesImpl::GetStateKey() {
- return state_key_;
-}
-
-const std::wstring& PackagePropertiesImpl::GetStateMediumKey() {
- return state_medium_key_;
-}
-
-const std::wstring& PackagePropertiesImpl::GetVersionKey() {
- return version_key_;
-}
-
-void PackagePropertiesImpl::UpdateInstallStatus(bool system_level,
- bool incremental_install,
- bool multi_install,
- InstallStatus status) {
- if (ReceivesUpdates()) {
- GoogleUpdateSettings::UpdateInstallStatus(system_level,
- incremental_install, multi_install,
- InstallUtil::GetInstallReturnCode(status), guid_);
- }
-}
-
-ChromiumPackageProperties::ChromiumPackageProperties()
- : PackagePropertiesImpl(L"", L"Software\\Chromium", L"Software\\Chromium",
- L"Software\\Chromium") {
-}
-
-ChromiumPackageProperties::~ChromiumPackageProperties() {
-}
-
-ChromePackageProperties::ChromePackageProperties()
- : PackagePropertiesImpl(
- kChromePackageGuid,
- GetKeyForGuid(google_update::kRegPathClientState,
- kChromePackageGuid),
- GetKeyForGuid(google_update::kRegPathClientStateMedium,
- kChromePackageGuid),
- GetKeyForGuid(google_update::kRegPathClients,
- kChromePackageGuid)) {
-}
-
-ChromePackageProperties::~ChromePackageProperties() {
-}
-
-} // namespace installer
diff --git a/chrome/installer/util/package_properties.h b/chrome/installer/util/package_properties.h
deleted file mode 100644
index 5fd5e5f5..0000000
--- a/chrome/installer/util/package_properties.h
+++ /dev/null
@@ -1,109 +0,0 @@
-// Copyright (c) 2011 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_PACKAGE_PROPERTIES_H_
-#define CHROME_INSTALLER_UTIL_PACKAGE_PROPERTIES_H_
-#pragma once
-
-#include <windows.h>
-
-#include <string>
-
-#include "base/basictypes.h"
-
-namespace installer {
-enum InstallStatus;
-};
-
-namespace installer {
-
-// Pure virtual interface that exposes properties of a package installation.
-// A package represents a set of binaries on disk that can be shared by two or
-// more products. Also see the Package class for further details.
-// PackageProperties is comparable to the BrowserDistribution class but the
-// difference is that the BrowserDistribution class represents a product
-// installation whereas PackageProperties represents a package
-// (horizontal vs vertical).
-class PackageProperties {
- public:
- PackageProperties() {}
- virtual ~PackageProperties() {}
-
- static const char kPackageProductName[];
-
- // Returns true iff this package will be updated by Google Update.
- virtual bool ReceivesUpdates() const = 0;
-
- // Equivalent to BrowserDistribution::GetAppGuid()
- virtual const std::wstring& GetAppGuid() = 0;
- virtual const std::wstring& GetStateKey() = 0;
- virtual const std::wstring& GetStateMediumKey() = 0;
- virtual const std::wstring& GetVersionKey() = 0;
- virtual void UpdateInstallStatus(bool system_level, bool incremental_install,
- bool multi_install, installer::InstallStatus status) = 0;
-
- private:
- DISALLOW_COPY_AND_ASSIGN(PackageProperties);
-}; // class PackageProperties
-
-class PackagePropertiesImpl : public PackageProperties {
- public:
- explicit PackagePropertiesImpl(const wchar_t* guid,
- const std::wstring& state_key,
- const std::wstring& state_medium_key,
- const std::wstring& version_key);
- virtual ~PackagePropertiesImpl();
-
- virtual const std::wstring& GetAppGuid();
- virtual const std::wstring& GetStateKey();
- virtual const std::wstring& GetStateMediumKey();
- virtual const std::wstring& GetVersionKey();
- virtual void UpdateInstallStatus(bool system_level, bool incremental_install,
- bool multi_install, installer::InstallStatus status);
-
- protected:
- std::wstring guid_;
- std::wstring state_key_;
- std::wstring state_medium_key_;
- std::wstring version_key_;
-
- private:
- DISALLOW_COPY_AND_ASSIGN(PackagePropertiesImpl);
-}; // class PackagePropertiesImpl
-
-class ChromiumPackageProperties : public PackagePropertiesImpl {
- public:
- ChromiumPackageProperties();
- virtual ~ChromiumPackageProperties();
-
- virtual bool ReceivesUpdates() const {
- return false;
- }
-
- private:
- DISALLOW_COPY_AND_ASSIGN(ChromiumPackageProperties);
-}; // class ChromiumPackageProperties
-
-class ChromePackageProperties : public PackagePropertiesImpl {
- public:
- ChromePackageProperties();
- virtual ~ChromePackageProperties();
-
- virtual bool ReceivesUpdates() const {
- return true;
- }
-
- private:
- DISALLOW_COPY_AND_ASSIGN(ChromePackageProperties);
-}; // class ChromePackageProperties
-
-#if defined(GOOGLE_CHROME_BUILD)
-typedef ChromePackageProperties ActivePackageProperties;
-#else
-typedef ChromiumPackageProperties ActivePackageProperties;
-#endif
-
-} // namespace installer
-
-#endif // CHROME_INSTALLER_UTIL_PACKAGE_PROPERTIES_H_
diff --git a/chrome/installer/util/package_properties_unittest.cc b/chrome/installer/util/package_properties_unittest.cc
deleted file mode 100644
index 000cc72..0000000
--- a/chrome/installer/util/package_properties_unittest.cc
+++ /dev/null
@@ -1,40 +0,0 @@
-// Copyright (c) 2010 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 "base/logging.h"
-#include "base/win/registry.h"
-#include "chrome/installer/util/google_update_constants.h"
-#include "chrome/installer/util/package_properties.h"
-#include "chrome/installer/util/product_unittest.h"
-#include "chrome/installer/util/util_constants.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-using base::win::RegKey;
-using installer::PackageProperties;
-using installer::ChromePackageProperties;
-using installer::ChromiumPackageProperties;
-
-class PackagePropertiesTest : public testing::Test {
- protected:
-};
-
-TEST_F(PackagePropertiesTest, Basic) {
- TempRegKeyOverride::DeleteAllTempKeys();
- ChromePackageProperties chrome_props;
- ChromiumPackageProperties chromium_props;
- PackageProperties* props[] = { &chrome_props, &chromium_props };
- for (size_t i = 0; i < arraysize(props); ++i) {
- std::wstring state_key(props[i]->GetStateKey());
- EXPECT_FALSE(state_key.empty());
- std::wstring version_key(props[i]->GetVersionKey());
- EXPECT_FALSE(version_key.empty());
- if (!props[i]->ReceivesUpdates()) {
- TempRegKeyOverride override(HKEY_CURRENT_USER, L"props");
- RegKey key;
- EXPECT_EQ(ERROR_SUCCESS,
- key.Create(HKEY_CURRENT_USER, state_key.c_str(), KEY_ALL_ACCESS));
- }
- TempRegKeyOverride::DeleteAllTempKeys();
- }
-}
diff --git a/chrome/installer/util/package_unittest.cc b/chrome/installer/util/package_unittest.cc
deleted file mode 100644
index ea696a7..0000000
--- a/chrome/installer/util/package_unittest.cc
+++ /dev/null
@@ -1,190 +0,0 @@
-// Copyright (c) 2011 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 "base/command_line.h"
-#include "base/logging.h"
-#include "base/utf_string_conversions.h"
-#include "base/win/scoped_handle.h"
-#include "chrome/installer/util/browser_distribution.h"
-#include "chrome/installer/util/google_update_constants.h"
-#include "chrome/installer/util/master_preferences.h"
-#include "chrome/installer/util/package.h"
-#include "chrome/installer/util/package_properties.h"
-#include "chrome/installer/util/product.h"
-#include "chrome/installer/util/product_unittest.h"
-#include "chrome/installer/util/util_constants.h"
-
-using base::win::RegKey;
-using installer::ChromePackageProperties;
-using installer::ChromiumPackageProperties;
-using installer::Package;
-using installer::Product;
-using installer::MasterPreferences;
-
-class PackageTest : public TestWithTempDirAndDeleteTempOverrideKeys {
- protected:
-};
-
-// Tests a few basic things of the Package class. Makes sure that the path
-// operations are correct
-TEST_F(PackageTest, Basic) {
- const bool multi_install = false;
- const bool system_level = true;
- ChromiumPackageProperties properties;
- scoped_refptr<Package> package(new Package(multi_install, system_level,
- test_dir_.path(), &properties));
- EXPECT_EQ(test_dir_.path().value(), package->path().value());
- EXPECT_TRUE(package->IsEqual(test_dir_.path()));
- EXPECT_EQ(0U, package->products().size());
-
- const char kOldVersion[] = "1.2.3.4";
- const char kNewVersion[] = "2.3.4.5";
-
- scoped_ptr<Version> new_version(Version::GetVersionFromString(kNewVersion));
- scoped_ptr<Version> old_version(Version::GetVersionFromString(kOldVersion));
- ASSERT_TRUE(new_version.get() != NULL);
- ASSERT_TRUE(old_version.get() != NULL);
-
- FilePath installer_dir(package->GetInstallerDirectory(*new_version.get()));
- EXPECT_FALSE(installer_dir.empty());
-
- FilePath new_version_dir(package->path().Append(
- UTF8ToWide(new_version->GetString())));
- FilePath old_version_dir(package->path().Append(
- UTF8ToWide(old_version->GetString())));
-
- EXPECT_FALSE(file_util::PathExists(new_version_dir));
- EXPECT_FALSE(file_util::PathExists(old_version_dir));
-
- EXPECT_FALSE(file_util::PathExists(installer_dir));
- file_util::CreateDirectory(installer_dir);
- EXPECT_TRUE(file_util::PathExists(new_version_dir));
-
- file_util::CreateDirectory(old_version_dir);
- EXPECT_TRUE(file_util::PathExists(old_version_dir));
-
- // Create a fake chrome.dll key file in the old version directory. This
- // should prevent the old version directory from getting deleted.
- FilePath old_chrome_dll(old_version_dir.Append(installer::kChromeDll));
- EXPECT_FALSE(file_util::PathExists(old_chrome_dll));
-
- // Hold on to the file exclusively to prevent the directory from
- // being deleted.
- base::win::ScopedHandle file(
- ::CreateFile(old_chrome_dll.value().c_str(), GENERIC_READ,
- 0, NULL, OPEN_ALWAYS, 0, NULL));
- EXPECT_TRUE(file.IsValid());
- EXPECT_TRUE(file_util::PathExists(old_chrome_dll));
-
- package->RemoveOldVersionDirectories(*new_version.get());
- // The old directory should still exist.
- EXPECT_TRUE(file_util::PathExists(old_version_dir));
- EXPECT_TRUE(file_util::PathExists(new_version_dir));
-
- // Now close the file handle to make it possible to delete our key file.
- file.Close();
-
- package->RemoveOldVersionDirectories(*new_version.get());
- // The new directory should still exist.
- EXPECT_TRUE(file_util::PathExists(new_version_dir));
-
- // Now, the old directory and key file should be gone.
- EXPECT_FALSE(file_util::PathExists(old_chrome_dll));
- EXPECT_FALSE(file_util::PathExists(old_version_dir));
-}
-
-TEST_F(PackageTest, WithProduct) {
- const MasterPreferences& prefs = MasterPreferences::ForCurrentProcess();
-
- // TODO(tommi): We should mock this and use our mocked distribution.
- const bool multi_install = false;
- const bool system_level = true;
- BrowserDistribution* distribution =
- BrowserDistribution::GetSpecificDistribution(
- BrowserDistribution::CHROME_BROWSER, prefs);
- ChromePackageProperties properties;
- scoped_refptr<Package> package(new Package(multi_install, system_level,
- test_dir_.path(), &properties));
- scoped_refptr<Product> product(new Product(distribution, package.get()));
- EXPECT_EQ(1U, package->products().size());
- EXPECT_EQ(system_level, package->system_level());
-
- const char kCurrentVersion[] = "1.2.3.4";
- scoped_ptr<Version> current_version(
- Version::GetVersionFromString(kCurrentVersion));
-
- HKEY root = system_level ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER;
- {
- TempRegKeyOverride override(root, L"root_pit");
- RegKey chrome_key(root, distribution->GetVersionKey().c_str(),
- KEY_ALL_ACCESS);
- EXPECT_TRUE(chrome_key.Valid());
- if (chrome_key.Valid()) {
- chrome_key.WriteValue(google_update::kRegVersionField,
- UTF8ToWide(current_version->GetString()).c_str());
- // TODO(tommi): Also test for when there exists a new_chrome.exe.
- scoped_ptr<Version> found_version(package->GetCurrentVersion());
- EXPECT_TRUE(found_version.get() != NULL);
- if (found_version.get()) {
- EXPECT_TRUE(current_version->Equals(*found_version));
- }
- }
- }
-}
-
-namespace {
-bool SetUninstallArguments(HKEY root, BrowserDistribution* dist,
- const CommandLine& args) {
- RegKey key(root, dist->GetStateKey().c_str(), KEY_ALL_ACCESS);
- return (key.WriteValue(installer::kUninstallArgumentsField,
- args.command_line_string().c_str()) == ERROR_SUCCESS);
-}
-
-bool SetInstalledVersion(HKEY root, BrowserDistribution* dist,
- const std::wstring& version) {
- RegKey key(root, dist->GetVersionKey().c_str(), KEY_ALL_ACCESS);
- return (key.WriteValue(google_update::kRegVersionField, version.c_str()) ==
- ERROR_SUCCESS);
-}
-} // end namespace
-
-TEST_F(PackageTest, Dependency) {
- const bool multi_install = false;
- const bool system_level = true;
- HKEY root = system_level ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER;
- TempRegKeyOverride override(root, L"root_dep");
-
- ChromePackageProperties properties;
- scoped_refptr<Package> package(new Package(multi_install, system_level,
- test_dir_.path(), &properties));
- EXPECT_EQ(0U, package->GetMultiInstallDependencyCount());
-
- const MasterPreferences& prefs = MasterPreferences::ForCurrentProcess();
-
- BrowserDistribution* chrome = BrowserDistribution::GetSpecificDistribution(
- BrowserDistribution::CHROME_BROWSER, prefs);
- BrowserDistribution* cf = BrowserDistribution::GetSpecificDistribution(
- BrowserDistribution::CHROME_FRAME, prefs);
-
- CommandLine multi_uninstall_cmd(CommandLine::NO_PROGRAM);
- multi_uninstall_cmd.AppendSwitch(installer::switches::kUninstall);
- multi_uninstall_cmd.AppendSwitch(installer::switches::kMultiInstall);
-
- CommandLine single_uninstall_cmd(CommandLine::NO_PROGRAM);
- single_uninstall_cmd.AppendSwitch(installer::switches::kUninstall);
-
- // "install" Chrome.
- SetUninstallArguments(root, chrome, multi_uninstall_cmd);
- SetInstalledVersion(root, chrome, L"1.2.3.4");
- EXPECT_EQ(1U, package->GetMultiInstallDependencyCount());
-
- // "install" Chrome Frame without multi-install.
- SetUninstallArguments(root, cf, single_uninstall_cmd);
- SetInstalledVersion(root, cf, L"1.2.3.4");
- EXPECT_EQ(1U, package->GetMultiInstallDependencyCount());
-
- // "install" Chrome Frame with multi-install.
- SetUninstallArguments(root, cf, multi_uninstall_cmd);
- EXPECT_EQ(2U, package->GetMultiInstallDependencyCount());
-}
diff --git a/chrome/installer/util/product.cc b/chrome/installer/util/product.cc
index de56027..a1e99f6 100644
--- a/chrome/installer/util/product.cc
+++ b/chrome/installer/util/product.cc
@@ -10,74 +10,70 @@
#include "base/logging.h"
#include "base/process_util.h"
#include "base/win/registry.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"
#include "chrome/installer/util/google_update_constants.h"
#include "chrome/installer/util/helper.h"
#include "chrome/installer/util/install_util.h"
#include "chrome/installer/util/master_preferences.h"
#include "chrome/installer/util/master_preferences_constants.h"
-#include "chrome/installer/util/package_properties.h"
+#include "chrome/installer/util/product_operations.h"
using base::win::RegKey;
using installer::MasterPreferences;
-namespace {
-class ProductIsOfType {
- public:
- explicit ProductIsOfType(BrowserDistribution::Type type)
- : type_(type) { }
- bool operator()(
- const scoped_refptr<const installer::Product>& pi) const {
- return pi->distribution()->GetType() == type_;
- }
- private:
- BrowserDistribution::Type type_;
-}; // class ProductIsOfType
-} // end namespace
-
namespace installer {
-const Product* FindProduct(const Products& products,
- BrowserDistribution::Type type) {
- Products::const_iterator i =
- std::find_if(products.begin(), products.end(), ProductIsOfType(type));
- return i == products.end() ? NULL : *i;
+Product::Product(BrowserDistribution* distribution)
+ : distribution_(distribution) {
+ switch (distribution->GetType()) {
+ case BrowserDistribution::CHROME_BROWSER:
+ operations_.reset(InstallUtil::IsChromeSxSProcess() ?
+ new ChromeBrowserSxSOperations() :
+ new ChromeBrowserOperations());
+ break;
+ case BrowserDistribution::CHROME_FRAME:
+ operations_.reset(new ChromeFrameOperations());
+ break;
+ default:
+ NOTREACHED() << "Unsupported BrowserDistribution::Type: "
+ << distribution->GetType();
+ }
}
-////////////////////////////////////////////////////////////////////////////////
+Product::~Product() {
+}
-Product::Product(BrowserDistribution* distribution, Package* package)
- : distribution_(distribution),
- package_(package),
- msi_(false),
- cache_state_(0) {
- package_->AssociateProduct(this);
+void Product::InitializeFromPreferences(const MasterPreferences& prefs) {
+ operations_->ReadOptions(prefs, &options_);
}
-const Package& Product::package() const {
- return *package_.get();
+void Product::InitializeFromUninstallCommand(
+ const CommandLine& uninstall_command) {
+ operations_->ReadOptions(uninstall_command, &options_);
}
FilePath Product::GetUserDataPath() const {
return GetChromeUserDataPath(distribution_);
}
-bool Product::LaunchChrome() const {
- const FilePath& install_package = package_->path();
- bool success = !install_package.empty();
+bool Product::LaunchChrome(const FilePath& application_path) const {
+ bool success = !application_path.empty();
if (success) {
- CommandLine cmd(install_package.Append(installer::kChromeExe));
+ CommandLine cmd(application_path.Append(installer::kChromeExe));
success = base::LaunchApp(cmd, false, false, NULL);
}
return success;
}
-bool Product::LaunchChromeAndWait(const CommandLine& options,
+bool Product::LaunchChromeAndWait(const FilePath& application_path,
+ const CommandLine& options,
int32* exit_code) const {
- const FilePath& install_package = package_->path();
- if (install_package.empty())
+ if (application_path.empty())
return false;
- CommandLine cmd(install_package.Append(installer::kChromeExe));
+ CommandLine cmd(application_path.Append(installer::kChromeExe));
cmd.AppendArguments(options, false);
bool success = false;
@@ -113,36 +109,8 @@ bool Product::LaunchChromeAndWait(const CommandLine& options,
return success;
}
-bool Product::IsMsi() const {
- if ((cache_state_ & MSI_STATE) == 0) {
- msi_ = false; // Covers failure cases below.
-
- const MasterPreferences& prefs = MasterPreferences::ForCurrentProcess();
-
- bool is_msi = false;
- prefs.GetBool(installer::master_preferences::kMsi, &is_msi);
-
- if (!is_msi) {
- // We didn't find it in the preferences, try looking in the registry.
- HKEY reg_root = system_level() ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER;
- RegKey key;
- if (key.Open(reg_root, distribution_->GetStateKey().c_str(),
- KEY_READ) == ERROR_SUCCESS) {
- DWORD msi_value = 0;
- key.ReadValueDW(google_update::kRegMSIField, &msi_value);
- msi_ = msi_value != 0;
- }
- } else {
- msi_ = true;
- }
- cache_state_ |= MSI_STATE;
- }
-
- return msi_;
-}
-
-bool Product::SetMsiMarker(bool set) const {
- HKEY reg_root = system_level() ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER;
+bool Product::SetMsiMarker(bool system_install, bool set) const {
+ HKEY reg_root = system_install ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER;
RegKey client_state_key;
LONG result = client_state_key.Open(reg_root,
distribution_->GetStateKey().c_str(), KEY_READ | KEY_WRITE);
@@ -158,92 +126,23 @@ bool Product::SetMsiMarker(bool set) const {
}
bool Product::ShouldCreateUninstallEntry() const {
- if (IsMsi()) {
- // MSI installations will manage their own uninstall shortcuts.
- return false;
- }
-
- return distribution_->ShouldCreateUninstallEntry();
-}
-
-///////////////////////////////////////////////////////////////////////////////
-ProductPackageMapping::ProductPackageMapping(bool multi_install,
- bool system_level)
- : package_properties_(new ActivePackageProperties()),
- multi_install_(multi_install),
- system_level_(system_level) {
+ return operations_->ShouldCreateUninstallEntry(options_);
}
-const Packages& ProductPackageMapping::packages() const {
- return packages_;
+void Product::AddKeyFiles(std::vector<FilePath>* key_files) const {
+ operations_->AddKeyFiles(options_, key_files);
}
-const Products& ProductPackageMapping::products() const {
- return products_;
+void Product::AddComDllList(std::vector<FilePath>* com_dll_list) const {
+ operations_->AddComDllList(options_, com_dll_list);
}
-bool ProductPackageMapping::AddDistribution(BrowserDistribution* distribution) {
- DCHECK(distribution);
- // Each product type can be added exactly once.
- DCHECK(FindProduct(products_, distribution->GetType()) == NULL);
-
- FilePath install_package;
- if (distribution->GetType() == BrowserDistribution::CHROME_BROWSER) {
- install_package = GetChromeInstallPath(system_level_, distribution);
- } else {
- DCHECK_EQ(BrowserDistribution::CHROME_FRAME, distribution->GetType());
- install_package = GetChromeFrameInstallPath(multi_install_, system_level_,
- distribution);
- }
-
- if (install_package.empty()) {
- LOG(ERROR) << "Got an empty installation path for "
- << distribution->GetApplicationName()
- << ". It's likely that there's a conflicting "
- "installation present";
- return false;
- }
-
- scoped_refptr<Package> target_package;
- for (size_t i = 0; i < packages_.size(); ++i) {
- if (packages_[i]->IsEqual(install_package)) {
- // Use an existing Package.
- target_package = packages_[i];
- break;
- }
- }
-
- if (!target_package.get()) {
- DCHECK(packages_.empty()) << "Multiple packages per run unsupported.";
- // create new one and add.
- target_package = new Package(multi_install_, system_level_, install_package,
- package_properties_.get());
- packages_.push_back(target_package);
- }
-
- scoped_refptr<Product> product(new Product(distribution, target_package));
-#ifndef NDEBUG
- for (size_t i = 0; i < products_.size(); ++i) {
- DCHECK_EQ(product->IsMsi(), products_[i]->IsMsi());
- }
-#endif
- products_.push_back(product);
-
- return true;
+void Product::AppendProductFlags(CommandLine* command_line) const {
+ operations_->AppendProductFlags(options_, command_line);
}
-bool ProductPackageMapping::AddDistribution(
- BrowserDistribution::Type type,
- const MasterPreferences& prefs) {
- BrowserDistribution* distribution =
- BrowserDistribution::GetSpecificDistribution(type, prefs);
- if (!distribution) {
- NOTREACHED();
- return false;
- }
-
- return AddDistribution(distribution);
+bool Product::SetChannelFlags(bool set, ChannelInfo* channel_info) const {
+ return operations_->SetChannelFlags(options_, set, channel_info);
}
} // namespace installer
-
diff --git a/chrome/installer/util/product.h b/chrome/installer/util/product.h
index 28361df..86d3fca 100644
--- a/chrome/installer/util/product.h
+++ b/chrome/installer/util/product.h
@@ -6,30 +6,20 @@
#define CHROME_INSTALLER_UTIL_PRODUCT_H_
#pragma once
+#include <set>
+#include <string>
#include <vector>
-#include "base/ref_counted.h"
#include "base/scoped_ptr.h"
#include "chrome/installer/util/browser_distribution.h"
-#include "chrome/installer/util/package.h"
class CommandLine;
namespace installer {
-class MasterPreferences;
-}
-
-namespace installer {
+class MasterPreferences;
class Product;
-class Package;
-class PackageProperties;
-
-typedef std::vector<scoped_refptr<Package> > Packages;
-typedef std::vector<scoped_refptr<const Product> > Products;
-
-const Product* FindProduct(const Products& products,
- BrowserDistribution::Type type);
+class ProductOperations;
// Represents an installation of a specific product which has a one-to-one
// relation to a BrowserDistribution. A product has registry settings, related
@@ -40,23 +30,22 @@ const Product* FindProduct(const Products& products,
// the future, as we move away from global functions and towards a data driven
// installation, each distribution could derive from this class and provide
// distribution specific functionality.
-class Product : public base::RefCounted<Product> {
+class Product {
public:
- Product(BrowserDistribution* distribution, Package* installation_package);
+ explicit Product(BrowserDistribution* distribution);
+
+ ~Product();
+
+ void InitializeFromPreferences(const MasterPreferences& prefs);
+
+ void InitializeFromUninstallCommand(const CommandLine& uninstall_command);
BrowserDistribution* distribution() const {
return distribution_;
}
- // Returns the install package object for the installation of this product.
- // If the product is installed at system level,the function returns a system
- // wide location (ProgramFiles\Google). Otherwise it returns a package in a
- // user specific location (Users\<user>\Local Settings...)
- const Package& package() const;
-
- // Convenience getter for package().system_level().
- bool system_level() const {
- return package().system_level();
+ bool is_type(BrowserDistribution::Type type) const {
+ return distribution_->GetType() == type;
}
bool is_chrome() const {
@@ -67,6 +56,18 @@ class Product : public base::RefCounted<Product> {
return distribution_->GetType() == BrowserDistribution::CHROME_FRAME;
}
+ bool HasOption(const std::wstring& option) const {
+ return options_.find(option) != options_.end();
+ }
+
+ // Returns true if the set of options is mutated by this operation.
+ bool SetOption(const std::wstring& option, bool set) {
+ if (set)
+ return options_.insert(option).second;
+ else
+ return options_.erase(option) != 0;
+ }
+
// Returns the path to the directory that holds the user data. This is always
// inside "Users\<user>\Local Settings". Note that this is the default user
// data directory and does not take into account that it can be overriden with
@@ -74,7 +75,7 @@ class Product : public base::RefCounted<Product> {
FilePath GetUserDataPath() const;
// Launches Chrome without waiting for it to exit.
- bool LaunchChrome() const;
+ bool LaunchChrome(const FilePath& application_path) const;
// Launches Chrome with given command line, waits for Chrome indefinitely
// (until it terminates), and gets the process exit code if available.
@@ -82,77 +83,44 @@ class Product : public base::RefCounted<Product> {
// The status of Chrome at the return of the function is given by exit_code.
// NOTE: The 'options' CommandLine object should only contain parameters.
// The program part will be ignored.
- bool LaunchChromeAndWait(const CommandLine& options, int32* exit_code) const;
-
- // Returns true if this setup process is running as an install managed by an
- // MSI wrapper. There are three things that are checked:
- // 1) the presence of --msi on the command line
- // 2) the presence of "msi": true in the master preferences file
- // 3) the presence of a DWORD value in the ClientState key called msi with
- // value 1
- bool IsMsi() const;
+ bool LaunchChromeAndWait(const FilePath& application_path,
+ const CommandLine& options,
+ int32* exit_code) const;
// Sets the boolean MSI marker for this installation if set is true or clears
// it otherwise. The MSI marker is stored in the registry under the
// ClientState key.
- bool SetMsiMarker(bool set) const;
+ bool SetMsiMarker(bool system_install, bool set) const;
// Returns true if setup should create an entry in the Add/Remove list
// of installed applications.
bool ShouldCreateUninstallEntry() const;
+ // See ProductOperations::AddKeyFiles.
+ void AddKeyFiles(std::vector<FilePath>* key_files) const;
+
+ // See ProductOperations::AddComDllList.
+ void AddComDllList(std::vector<FilePath>* com_dll_list) const;
+
+ // See ProductOperations::AppendProductFlags.
+ void AppendProductFlags(CommandLine* command_line) const;
+
+ // See Productoperations::SetChannelFlags.
+ bool SetChannelFlags(bool set, ChannelInfo* channel_info) const;
+
protected:
enum CacheStateFlags {
MSI_STATE = 0x01
};
BrowserDistribution* distribution_;
- scoped_refptr<Package> package_;
- mutable bool msi_;
- mutable uint8 cache_state_;
+ scoped_ptr<ProductOperations> operations_;
+ std::set<std::wstring> options_;
private:
- friend class base::RefCounted<Product>;
- ~Product() {
- }
DISALLOW_COPY_AND_ASSIGN(Product);
};
-// A collection of Product objects and related physical installation
-// packages. Each Product is associated with a single installation
-// package object, and each package object is associated with one or more
-// Product objects.
-class ProductPackageMapping {
- public:
- explicit ProductPackageMapping(bool multi_install, bool system_level);
-
- bool multi_install() const {
- return multi_install_;
- }
-
- bool system_level() const {
- return system_level_;
- }
-
- const Packages& packages() const;
-
- const Products& products() const;
-
- bool AddDistribution(BrowserDistribution::Type type,
- const installer::MasterPreferences& prefs);
- bool AddDistribution(BrowserDistribution* distribution);
-
- protected:
- bool multi_install_;
- bool system_level_;
- Packages packages_;
- Products products_;
- scoped_ptr<PackageProperties> package_properties_;
-
- private:
- DISALLOW_COPY_AND_ASSIGN(ProductPackageMapping);
-};
-
} // namespace installer
#endif // CHROME_INSTALLER_UTIL_PRODUCT_H_
diff --git a/chrome/installer/util/product_operations.h b/chrome/installer/util/product_operations.h
new file mode 100644
index 0000000..0874d3d
--- /dev/null
+++ b/chrome/installer/util/product_operations.h
@@ -0,0 +1,74 @@
+// Copyright (c) 2011 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_PRODUCT_OPERATIONS_H_
+#define CHROME_INSTALLER_UTIL_PRODUCT_OPERATIONS_H_
+#pragma once
+
+#include <set>
+#include <string>
+#include <vector>
+
+#include "base/file_path.h"
+
+class CommandLine;
+
+namespace installer {
+
+class ChannelInfo;
+class MasterPreferences;
+
+// An interface to product-specific operations that depend on product
+// configuration. Implementations are expected to be stateless. Configuration
+// can be read from a MasterPreferences instance or from a product's uninstall
+// command.
+class ProductOperations {
+ public:
+ virtual ~ProductOperations() {}
+
+ // Reads product-specific options from |prefs|, adding them to |options|.
+ virtual void ReadOptions(const MasterPreferences& prefs,
+ std::set<std::wstring>* options) const = 0;
+
+ // Reads product-specific options from |command|, adding them to |options|.
+ virtual void ReadOptions(const CommandLine& command,
+ std::set<std::wstring>* options) const = 0;
+
+ // A key-file is a file such as a DLL on Windows that is expected to be in use
+ // when the product is being used. For example "chrome.dll" for Chrome.
+ // Before attempting to delete an installation directory during an
+ // uninstallation, the uninstaller will check if any one of a potential set of
+ // key files is in use and if they are, abort the delete operation. Only if
+ // none of the key files are in use, can the folder be deleted. Note that
+ // this function does not return a full path to the key file(s), only (a) file
+ // name(s).
+ virtual void AddKeyFiles(const std::set<std::wstring>& options,
+ std::vector<FilePath>* key_files) const = 0;
+
+ // Adds to |com_dll_list| the list of COM DLLs that are to be registered
+ // and/or unregistered. The list may be empty.
+ virtual void AddComDllList(const std::set<std::wstring>& options,
+ std::vector<FilePath>* com_dll_list) const = 0;
+
+ // Given a command line, appends the set of uninstall flags the uninstaller
+ // for this product will require.
+ virtual void AppendProductFlags(const std::set<std::wstring>& options,
+ CommandLine* uninstall_command) const = 0;
+
+ // Adds or removes product-specific flags in |channel_info|. Returns true if
+ // |channel_info| is modified.
+ virtual bool SetChannelFlags(const std::set<std::wstring>& options,
+ bool set,
+ ChannelInfo* channel_info) const = 0;
+
+ // Returns true if setup should create an entry in the Add/Remove list
+ // of installed applications for this product. This does not test for use of
+ // MSI; see InstallerState::is_msi.
+ virtual bool ShouldCreateUninstallEntry(
+ const std::set<std::wstring>& options) const = 0;
+};
+
+} // namespace installer
+
+#endif // CHROME_INSTALLER_UTIL_PRODUCT_OPERATIONS_H_
diff --git a/chrome/installer/util/product_state_unittest.cc b/chrome/installer/util/product_state_unittest.cc
new file mode 100644
index 0000000..c6031359
--- /dev/null
+++ b/chrome/installer/util/product_state_unittest.cc
@@ -0,0 +1,416 @@
+// Copyright (c) 2011 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 <windows.h>
+
+#include "base/utf_string_conversions.h"
+#include "base/version.h"
+#include "base/win/registry.h"
+#include "chrome/installer/util/browser_distribution.h"
+#include "chrome/installer/util/google_update_constants.h"
+#include "chrome/installer/util/installation_state.h"
+#include "chrome/installer/util/product_unittest.h"
+#include "chrome/installer/util/util_constants.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using base::win::RegKey;
+using installer::ProductState;
+
+class ProductStateTest : public testing::Test {
+ protected:
+ static void SetUpTestCase();
+ static void TearDownTestCase();
+
+ virtual void SetUp();
+ virtual void TearDown();
+
+ void ApplyUninstallCommand(const wchar_t* exe_path, const wchar_t* args);
+ void MinimallyInstallProduct(const wchar_t* version);
+
+ static BrowserDistribution* dist_;
+ static std::wstring temp_key_path_;
+ bool system_install_;
+ HKEY overridden_;
+ RegKey clients_;
+ RegKey client_state_;
+};
+
+BrowserDistribution* ProductStateTest::dist_;
+std::wstring ProductStateTest::temp_key_path_;
+
+// static
+void ProductStateTest::SetUpTestCase() {
+ testing::Test::SetUpTestCase();
+
+ // We'll use Chrome as our test subject.
+ dist_ = BrowserDistribution::GetSpecificDistribution(
+ BrowserDistribution::CHROME_BROWSER);
+
+ // And we'll play in HKCU here:
+ temp_key_path_.assign(TempRegKeyOverride::kTempTestKeyPath)
+ .append(1, L'\\')
+ .append(L"ProductStateTest");
+}
+
+// static
+void ProductStateTest::TearDownTestCase() {
+ temp_key_path_.clear();
+ dist_ = NULL;
+
+ testing::Test::TearDownTestCase();
+}
+
+void ProductStateTest::SetUp() {
+ testing::Test::SetUp();
+
+ // Create/open the keys for the product we'll test.
+ system_install_ = true;
+ overridden_ = (system_install_ ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER);
+
+ // Override for test purposes. We don't use TempRegKeyOverride
+ // directly because it doesn't suit itself to our use here.
+ RegKey temp_key;
+ EXPECT_EQ(ERROR_SUCCESS,
+ temp_key.Create(HKEY_CURRENT_USER, temp_key_path_.c_str(),
+ KEY_ALL_ACCESS));
+ EXPECT_EQ(ERROR_SUCCESS,
+ ::RegOverridePredefKey(overridden_, temp_key.Handle()));
+
+ EXPECT_EQ(ERROR_SUCCESS,
+ clients_.Create(overridden_, dist_->GetVersionKey().c_str(),
+ KEY_ALL_ACCESS));
+ EXPECT_EQ(ERROR_SUCCESS,
+ client_state_.Create(overridden_, dist_->GetStateKey().c_str(),
+ KEY_ALL_ACCESS));
+}
+
+void ProductStateTest::TearDown() {
+ // Done with the keys.
+ client_state_.Close();
+ clients_.Close();
+ EXPECT_EQ(ERROR_SUCCESS, ::RegOverridePredefKey(overridden_, NULL));
+ overridden_ = NULL;
+ system_install_ = false;
+
+ // Shotgun approach to clearing out data we may have written.
+ TempRegKeyOverride::DeleteAllTempKeys();
+
+ testing::Test::TearDown();
+}
+
+void ProductStateTest::MinimallyInstallProduct(const wchar_t* version) {
+ EXPECT_EQ(ERROR_SUCCESS,
+ clients_.WriteValue(google_update::kRegVersionField, version));
+}
+
+void ProductStateTest::ApplyUninstallCommand(const wchar_t* exe_path,
+ const wchar_t* args) {
+ if (exe_path == NULL) {
+ LONG result = client_state_.DeleteValue(installer::kUninstallStringField);
+ EXPECT_TRUE(result == ERROR_SUCCESS || result == ERROR_FILE_NOT_FOUND);
+ } else {
+ EXPECT_EQ(ERROR_SUCCESS,
+ client_state_.WriteValue(installer::kUninstallStringField,
+ exe_path));
+ }
+
+ if (args == NULL) {
+ LONG result =
+ client_state_.DeleteValue(installer::kUninstallArgumentsField);
+ EXPECT_TRUE(result == ERROR_SUCCESS || result == ERROR_FILE_NOT_FOUND);
+ } else {
+ EXPECT_EQ(ERROR_SUCCESS,
+ client_state_.WriteValue(installer::kUninstallArgumentsField,
+ args));
+ }
+}
+
+TEST_F(ProductStateTest, InitializeInstalled) {
+ // Not installed.
+ {
+ ProductState state;
+ LONG result = clients_.DeleteValue(google_update::kRegVersionField);
+ EXPECT_TRUE(result == ERROR_SUCCESS || result == ERROR_FILE_NOT_FOUND);
+ EXPECT_FALSE(state.Initialize(system_install_, dist_));
+ }
+
+ // Empty version.
+ {
+ ProductState state;
+ LONG result = clients_.WriteValue(google_update::kRegVersionField, L"");
+ EXPECT_TRUE(result == ERROR_SUCCESS || result == ERROR_FILE_NOT_FOUND);
+ EXPECT_FALSE(state.Initialize(system_install_, dist_));
+ }
+
+ // Bogus version.
+ {
+ ProductState state;
+ LONG result = clients_.WriteValue(google_update::kRegVersionField,
+ L"goofy");
+ EXPECT_TRUE(result == ERROR_SUCCESS || result == ERROR_FILE_NOT_FOUND);
+ EXPECT_FALSE(state.Initialize(system_install_, dist_));
+ }
+
+ // Valid "pv" value.
+ {
+ ProductState state;
+ LONG result = clients_.WriteValue(google_update::kRegVersionField,
+ L"10.0.47.0");
+ EXPECT_TRUE(result == ERROR_SUCCESS || result == ERROR_FILE_NOT_FOUND);
+ EXPECT_TRUE(state.Initialize(system_install_, dist_));
+ EXPECT_EQ("10.0.47.0", state.version().GetString());
+ }
+}
+
+// Test extraction of the "opv" value from the Clients key.
+TEST_F(ProductStateTest, InitializeOldVersion) {
+ MinimallyInstallProduct(L"10.0.1.1");
+
+ // No "opv" value.
+ {
+ ProductState state;
+ LONG result = clients_.DeleteValue(google_update::kRegOldVersionField);
+ EXPECT_TRUE(result == ERROR_SUCCESS || result == ERROR_FILE_NOT_FOUND);
+ EXPECT_TRUE(state.Initialize(system_install_, dist_));
+ EXPECT_TRUE(state.old_version() == NULL);
+ }
+
+ // Empty "opv" value.
+ {
+ ProductState state;
+ LONG result = clients_.WriteValue(google_update::kRegOldVersionField, L"");
+ EXPECT_TRUE(result == ERROR_SUCCESS || result == ERROR_FILE_NOT_FOUND);
+ EXPECT_TRUE(state.Initialize(system_install_, dist_));
+ EXPECT_TRUE(state.old_version() == NULL);
+ }
+
+ // Bogus "opv" value.
+ {
+ ProductState state;
+ LONG result = clients_.WriteValue(google_update::kRegOldVersionField,
+ L"coming home");
+ EXPECT_TRUE(result == ERROR_SUCCESS || result == ERROR_FILE_NOT_FOUND);
+ EXPECT_TRUE(state.Initialize(system_install_, dist_));
+ EXPECT_TRUE(state.old_version() == NULL);
+ }
+
+ // Valid "opv" value.
+ {
+ ProductState state;
+ LONG result = clients_.WriteValue(google_update::kRegOldVersionField,
+ L"10.0.47.0");
+ EXPECT_TRUE(result == ERROR_SUCCESS || result == ERROR_FILE_NOT_FOUND);
+ EXPECT_TRUE(state.Initialize(system_install_, dist_));
+ EXPECT_TRUE(state.old_version() != NULL);
+ EXPECT_EQ("10.0.47.0", state.old_version()->GetString());
+ }
+}
+
+// Test extraction of the "cmd" value from the Clients key.
+TEST_F(ProductStateTest, InitializeRenameCmd) {
+ MinimallyInstallProduct(L"10.0.1.1");
+
+ // No "cmd" value.
+ {
+ ProductState state;
+ LONG result = clients_.DeleteValue(google_update::kRegRenameCmdField);
+ EXPECT_TRUE(result == ERROR_SUCCESS || result == ERROR_FILE_NOT_FOUND);
+ EXPECT_TRUE(state.Initialize(system_install_, dist_));
+ EXPECT_TRUE(state.rename_cmd().empty());
+ }
+
+ // Empty "cmd" value.
+ {
+ ProductState state;
+ LONG result = clients_.WriteValue(google_update::kRegRenameCmdField, L"");
+ EXPECT_TRUE(result == ERROR_SUCCESS || result == ERROR_FILE_NOT_FOUND);
+ EXPECT_TRUE(state.Initialize(system_install_, dist_));
+ EXPECT_TRUE(state.rename_cmd().empty());
+ }
+
+ // Valid "cmd" value.
+ {
+ ProductState state;
+ LONG result = clients_.WriteValue(google_update::kRegRenameCmdField,
+ L"spam.exe --spamalot");
+ EXPECT_TRUE(result == ERROR_SUCCESS || result == ERROR_FILE_NOT_FOUND);
+ EXPECT_TRUE(state.Initialize(system_install_, dist_));
+ EXPECT_EQ(L"spam.exe --spamalot", state.rename_cmd());
+ }
+}
+
+// Test extraction of the "ap" value from the ClientState key.
+TEST_F(ProductStateTest, InitializeChannelInfo) {
+ MinimallyInstallProduct(L"10.0.1.1");
+
+ // No "ap" value.
+ {
+ ProductState state;
+ LONG result = client_state_.DeleteValue(google_update::kRegApField);
+ EXPECT_TRUE(result == ERROR_SUCCESS || result == ERROR_FILE_NOT_FOUND);
+ EXPECT_TRUE(state.Initialize(system_install_, dist_));
+ EXPECT_TRUE(state.channel().value().empty());
+ }
+
+ // Empty "ap" value.
+ {
+ ProductState state;
+ LONG result = client_state_.WriteValue(google_update::kRegApField, L"");
+ EXPECT_TRUE(result == ERROR_SUCCESS || result == ERROR_FILE_NOT_FOUND);
+ EXPECT_TRUE(state.Initialize(system_install_, dist_));
+ EXPECT_TRUE(state.channel().value().empty());
+ }
+
+ // Valid "ap" value.
+ {
+ ProductState state;
+ LONG result = client_state_.WriteValue(google_update::kRegApField, L"spam");
+ EXPECT_TRUE(result == ERROR_SUCCESS || result == ERROR_FILE_NOT_FOUND);
+ EXPECT_TRUE(state.Initialize(system_install_, dist_));
+ EXPECT_EQ(L"spam", state.channel().value());
+ }
+}
+
+// Test extraction of the uninstall command and arguments from the ClientState
+// key.
+TEST_F(ProductStateTest, InitializeUninstallCommand) {
+ MinimallyInstallProduct(L"10.0.1.1");
+
+ // No uninstall command.
+ {
+ ProductState state;
+ ApplyUninstallCommand(NULL, NULL);
+ EXPECT_TRUE(state.Initialize(system_install_, dist_));
+ EXPECT_TRUE(state.GetSetupPath().empty());
+ EXPECT_TRUE(state.uninstall_command().command_line_string().empty());
+ EXPECT_EQ(0U, state.uninstall_command().GetSwitchCount());
+ }
+
+ // Empty values.
+ {
+ ProductState state;
+ ApplyUninstallCommand(L"", L"");
+ EXPECT_TRUE(state.Initialize(system_install_, dist_));
+ EXPECT_TRUE(state.GetSetupPath().empty());
+ EXPECT_TRUE(state.uninstall_command().command_line_string().empty());
+ EXPECT_EQ(0U, state.uninstall_command().GetSwitchCount());
+ }
+
+ // Uninstall command without exe.
+ {
+ ProductState state;
+ ApplyUninstallCommand(NULL, L"--uninstall");
+ EXPECT_TRUE(state.Initialize(system_install_, dist_));
+ EXPECT_TRUE(state.GetSetupPath().empty());
+ EXPECT_EQ(L"\"\" --uninstall",
+ state.uninstall_command().command_line_string());
+ EXPECT_EQ(1U, state.uninstall_command().GetSwitchCount());
+ }
+
+ // Uninstall command without args.
+ {
+ ProductState state;
+ ApplyUninstallCommand(L"setup.exe", NULL);
+ EXPECT_TRUE(state.Initialize(system_install_, dist_));
+ EXPECT_EQ(L"setup.exe", state.GetSetupPath().value());
+ EXPECT_EQ(L"\"setup.exe\"",
+ state.uninstall_command().command_line_string());
+ EXPECT_EQ(0U, state.uninstall_command().GetSwitchCount());
+ }
+
+ // Uninstall command with both exe and args.
+ {
+ ProductState state;
+ ApplyUninstallCommand(L"setup.exe", L"--uninstall");
+ EXPECT_TRUE(state.Initialize(system_install_, dist_));
+ EXPECT_EQ(L"setup.exe", state.GetSetupPath().value());
+ EXPECT_EQ(L"\"setup.exe\" --uninstall",
+ state.uninstall_command().command_line_string());
+ EXPECT_EQ(1U, state.uninstall_command().GetSwitchCount());
+ }
+}
+
+// Test extraction of the msi marker from the ClientState key.
+TEST_F(ProductStateTest, InitializeMsi) {
+ MinimallyInstallProduct(L"10.0.1.1");
+
+ // No msi marker.
+ {
+ ProductState state;
+ LONG result = client_state_.DeleteValue(google_update::kRegMSIField);
+ EXPECT_TRUE(result == ERROR_SUCCESS || result == ERROR_FILE_NOT_FOUND);
+ EXPECT_TRUE(state.Initialize(system_install_, dist_));
+ EXPECT_FALSE(state.is_msi());
+ }
+
+ // Msi marker set to zero.
+ {
+ ProductState state;
+ EXPECT_EQ(ERROR_SUCCESS,
+ client_state_.WriteValue(google_update::kRegMSIField,
+ static_cast<DWORD>(0)));
+ EXPECT_TRUE(state.Initialize(system_install_, dist_));
+ EXPECT_FALSE(state.is_msi());
+ }
+
+ // Msi marker set to one.
+ {
+ ProductState state;
+ EXPECT_EQ(ERROR_SUCCESS,
+ client_state_.WriteValue(google_update::kRegMSIField,
+ static_cast<DWORD>(1)));
+ EXPECT_TRUE(state.Initialize(system_install_, dist_));
+ EXPECT_TRUE(state.is_msi());
+ }
+
+ // Msi marker set to a bogus DWORD.
+ {
+ ProductState state;
+ EXPECT_EQ(ERROR_SUCCESS,
+ client_state_.WriteValue(google_update::kRegMSIField,
+ static_cast<DWORD>(47)));
+ EXPECT_TRUE(state.Initialize(system_install_, dist_));
+ EXPECT_TRUE(state.is_msi());
+ }
+
+ // Msi marker set to a bogus string.
+ {
+ ProductState state;
+ EXPECT_EQ(ERROR_SUCCESS,
+ client_state_.WriteValue(google_update::kRegMSIField,
+ L"bogus!"));
+ EXPECT_TRUE(state.Initialize(system_install_, dist_));
+ EXPECT_FALSE(state.is_msi());
+ }
+}
+
+// Test detection of multi-install.
+TEST_F(ProductStateTest, InitializeMultiInstall) {
+ MinimallyInstallProduct(L"10.0.1.1");
+
+ // No uninstall command means single install.
+ {
+ ProductState state;
+ ApplyUninstallCommand(NULL, NULL);
+ EXPECT_TRUE(state.Initialize(system_install_, dist_));
+ EXPECT_FALSE(state.is_multi_install());
+ }
+
+ // Uninstall command without --multi-install is single install.
+ {
+ ProductState state;
+ ApplyUninstallCommand(L"setup.exe", L"--uninstall");
+ EXPECT_TRUE(state.Initialize(system_install_, dist_));
+ EXPECT_FALSE(state.is_multi_install());
+ }
+
+ // Uninstall command with --multi-install is multi install.
+ {
+ ProductState state;
+ ApplyUninstallCommand(L"setup.exe",
+ L"--uninstall --chrome --multi-install");
+ EXPECT_TRUE(state.Initialize(system_install_, dist_));
+ EXPECT_TRUE(state.is_multi_install());
+ }
+}
diff --git a/chrome/installer/util/product_unittest.cc b/chrome/installer/util/product_unittest.cc
index c072dc5..913a6ff 100644
--- a/chrome/installer/util/product_unittest.cc
+++ b/chrome/installer/util/product_unittest.cc
@@ -9,17 +9,12 @@
#include "chrome/installer/util/chrome_frame_distribution.h"
#include "chrome/installer/util/google_update_constants.h"
#include "chrome/installer/util/installation_state.h"
-#include "chrome/installer/util/package.h"
-#include "chrome/installer/util/package_properties.h"
+#include "chrome/installer/util/installer_state.h"
#include "chrome/installer/util/master_preferences.h"
#include "chrome/installer/util/product.h"
using base::win::RegKey;
-using installer::ChromePackageProperties;
-using installer::ChromiumPackageProperties;
-using installer::Package;
using installer::Product;
-using installer::ProductPackageMapping;
using installer::MasterPreferences;
void TestWithTempDir::SetUp() {
@@ -82,15 +77,19 @@ TEST_F(ProductTest, ProductInstallBasic) {
// TODO(tommi): We should mock this and use our mocked distribution.
const bool multi_install = false;
const bool system_level = true;
- const installer::MasterPreferences& prefs =
- installer::MasterPreferences::ForCurrentProcess();
- BrowserDistribution* distribution =
- BrowserDistribution::GetSpecificDistribution(
- BrowserDistribution::CHROME_BROWSER, prefs);
- ChromePackageProperties properties;
- scoped_refptr<Package> package(new Package(multi_install, system_level,
- test_dir_.path(), &properties));
- scoped_refptr<Product> product(new Product(distribution, package.get()));
+ CommandLine cmd_line = CommandLine::FromString(
+ std::wstring(L"setup.exe") +
+ (multi_install ? L" --multi-install --chrome" : L"") +
+ (system_level ? L" --system-level" : L""));
+ installer::MasterPreferences prefs(cmd_line);
+ installer::InstallationState machine_state;
+ machine_state.Initialize();
+ installer::InstallerState installer_state;
+ installer_state.Initialize(cmd_line, prefs, machine_state);
+
+ const Product* product = installer_state.products()[0];
+ BrowserDistribution* distribution = product->distribution();
+ EXPECT_EQ(BrowserDistribution::CHROME_BROWSER, distribution->GetType());
FilePath user_data(product->GetUserDataPath());
EXPECT_FALSE(user_data.empty());
@@ -104,35 +103,15 @@ TEST_F(ProductTest, ProductInstallBasic) {
EXPECT_EQ(std::wstring::npos,
user_data.value().find(program_files.value()));
- // We started out with a non-msi product.
- EXPECT_FALSE(product->IsMsi());
+ // There should be no installed version in the registry.
+ machine_state.Initialize();
+ EXPECT_TRUE(machine_state.GetProductState(
+ system_level, distribution->GetType()) == NULL);
- HKEY root = system_level ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER;
+ HKEY root = installer_state.root_key();
{
TempRegKeyOverride override(root, L"root_pit");
- // Create a make-believe client state key.
- RegKey key;
- std::wstring state_key_path(distribution->GetStateKey());
- ASSERT_EQ(ERROR_SUCCESS,
- key.Create(root, state_key_path.c_str(), KEY_ALL_ACCESS));
-
- // Set the MSI marker, delete the objects, create new ones and verify
- // that we now see the MSI marker.
- EXPECT_TRUE(product->SetMsiMarker(true));
- package = new Package(multi_install, system_level, test_dir_.path(),
- &properties);
- product = new Product(distribution, package.get());
- EXPECT_TRUE(product->IsMsi());
-
- // There should be no installed version in the registry.
- {
- installer::InstallationState state;
- state.Initialize(prefs);
- EXPECT_TRUE(state.GetProductState(system_level,
- distribution->GetType()) == NULL);
- }
-
// Let's pretend chrome is installed.
RegKey version_key(root, distribution->GetVersionKey().c_str(),
KEY_ALL_ACCESS);
@@ -144,16 +123,30 @@ TEST_F(ProductTest, ProductInstallBasic) {
version_key.WriteValue(google_update::kRegVersionField,
UTF8ToWide(current_version->GetString()).c_str());
- {
- installer::InstallationState state;
- state.Initialize(prefs);
- const installer::ProductState* prod_state =
- state.GetProductState(system_level, distribution->GetType());
- EXPECT_TRUE(prod_state != NULL);
- if (prod_state != NULL) {
- EXPECT_TRUE(prod_state->version().Equals(*current_version.get()));
- }
+ // We started out with a non-msi product.
+ machine_state.Initialize();
+ const installer::ProductState* chrome_state =
+ machine_state.GetProductState(system_level, distribution->GetType());
+ EXPECT_TRUE(chrome_state != NULL);
+ if (chrome_state != NULL) {
+ EXPECT_TRUE(chrome_state->version().Equals(*current_version.get()));
+ EXPECT_FALSE(chrome_state->is_msi());
}
+
+ // Create a make-believe client state key.
+ RegKey key;
+ std::wstring state_key_path(distribution->GetStateKey());
+ ASSERT_EQ(ERROR_SUCCESS,
+ key.Create(root, state_key_path.c_str(), KEY_ALL_ACCESS));
+
+ // Set the MSI marker, refresh, and verify that we now see the MSI marker.
+ EXPECT_TRUE(product->SetMsiMarker(system_level, true));
+ machine_state.Initialize();
+ chrome_state =
+ machine_state.GetProductState(system_level, distribution->GetType());
+ EXPECT_TRUE(chrome_state != NULL);
+ if (chrome_state != NULL)
+ EXPECT_TRUE(chrome_state->is_msi());
}
}
@@ -162,41 +155,3 @@ TEST_F(ProductTest, LaunchChrome) {
// Product::LaunchChromeAndWait.
LOG(ERROR) << "Test not implemented.";
}
-
-// Overrides ChromeFrameDistribution for the sole purpose of returning
-// the Chrome (not Chrome Frame) installation path.
-class FakeChromeFrameDistribution : public ChromeFrameDistribution {
- public:
- explicit FakeChromeFrameDistribution(
- const installer::MasterPreferences& prefs)
- : ChromeFrameDistribution(prefs) {}
- virtual std::wstring GetInstallSubDir() {
- const MasterPreferences& prefs =
- installer::MasterPreferences::ForCurrentProcess();
- return BrowserDistribution::GetSpecificDistribution(
- BrowserDistribution::CHROME_BROWSER, prefs)->GetInstallSubDir();
- }
-};
-
-TEST_F(ProductTest, ProductInstallsBasic) {
- const bool multi_install = true;
- const bool system_level = true;
- ProductPackageMapping installs(multi_install, system_level);
- EXPECT_EQ(multi_install, installs.multi_install());
- EXPECT_EQ(system_level, installs.system_level());
- EXPECT_EQ(0U, installs.packages().size());
- EXPECT_EQ(0U, installs.products().size());
-
- // TODO(robertshield): Include test that use mock master preferences.
- const MasterPreferences& prefs =
- installer::MasterPreferences::ForCurrentProcess();
-
- installs.AddDistribution(BrowserDistribution::CHROME_BROWSER, prefs);
- FakeChromeFrameDistribution fake_chrome_frame(prefs);
- installs.AddDistribution(&fake_chrome_frame);
- EXPECT_EQ(2U, installs.products().size());
- // Since our fake Chrome Frame distribution class is reporting the same
- // installation directory as Chrome, we should have only one package object.
- EXPECT_EQ(1U, installs.packages().size());
- EXPECT_EQ(multi_install, installs.packages()[0]->multi_install());
-}
diff --git a/chrome/installer/util/util_constants.cc b/chrome/installer/util/util_constants.cc
index f59d6a4..39e47e9 100644
--- a/chrome/installer/util/util_constants.cc
+++ b/chrome/installer/util/util_constants.cc
@@ -177,4 +177,8 @@ const wchar_t kInstallerResultUIString[] = L"InstallerResultUIString";
const wchar_t kInstallerSuccessLaunchCmdLine[] =
L"InstallerSuccessLaunchCmdLine";
+const wchar_t kOptionCeee[] = L"ceee";
+const wchar_t kOptionMultiInstall[] = L"multi-install";
+const wchar_t kOptionReadyMode[] = L"ready-mode";
+
} // namespace installer
diff --git a/chrome/installer/util/util_constants.h b/chrome/installer/util/util_constants.h
index 5b2f230..9ca8900 100644
--- a/chrome/installer/util/util_constants.h
+++ b/chrome/installer/util/util_constants.h
@@ -66,6 +66,9 @@ enum InstallStatus {
// Chrome Frame.
READY_MODE_END_TEMP_OPT_OUT_FAILED, // 38. Failed to end temporary opt-out
// of Chrome Frame.
+ CONFLICTING_CHANNEL_EXISTS, // 39. A multi-install product on a different
+ // update channel exists.
+ READY_MODE_REQUIRES_CHROME, // 40. Chrome Frame in ready-mode requires Chrome
};
namespace switches {
@@ -141,6 +144,11 @@ extern const wchar_t kInstallerError[];
extern const wchar_t kInstallerResultUIString[];
extern const wchar_t kInstallerSuccessLaunchCmdLine[];
+// Product options.
+extern const wchar_t kOptionCeee[];
+extern const wchar_t kOptionMultiInstall[];
+extern const wchar_t kOptionReadyMode[];
+
} // namespace installer
#endif // CHROME_INSTALLER_UTIL_UTIL_CONSTANTS_H_
diff --git a/chrome_frame/ready_mode/ready_mode.cc b/chrome_frame/ready_mode/ready_mode.cc
index 51df76f..21155f3 100644
--- a/chrome_frame/ready_mode/ready_mode.cc
+++ b/chrome_frame/ready_mode/ready_mode.cc
@@ -15,8 +15,8 @@
#include "base/win/scoped_bstr.h"
#include "base/win/scoped_comptr.h"
#include "base/win/win_util.h"
+#include "chrome/installer/util/browser_distribution.h"
#include "net/base/registry_controlled_domain.h"
-#include "chrome/installer/util/package_properties.h"
#include "chrome_frame/infobars/infobar_manager.h"
#include "chrome_frame/ready_mode/internal/ready_mode_web_browser_adapter.h"
#include "chrome_frame/ready_mode/internal/ready_prompt_content.h"
@@ -220,11 +220,13 @@ void BrowserObserver::ShowPrompt() {
scoped_ptr<RegistryReadyModeState::Observer> ready_mode_state_observer(
new StateObserver(weak_ptr_factory_.GetWeakPtr()));
- installer::ActivePackageProperties package_properties;
+ BrowserDistribution* dist =
+ BrowserDistribution::GetSpecificDistribution(
+ BrowserDistribution::CHROME_BINARIES);
// Owned by infobar_content
scoped_ptr<ReadyModeState> ready_mode_state(new RegistryReadyModeState(
- package_properties.GetStateKey(),
+ dist->GetStateKey(),
base::TimeDelta::FromMinutes(kTemporaryDeclineDurationMinutes),
ready_mode_state_observer.release()));
@@ -360,9 +362,12 @@ void Configure(Delegate* chrome_frame, IWebBrowser2* web_browser) {
// Take ownership of the delegate
linked_ptr<Delegate> delegate(chrome_frame);
chrome_frame = NULL;
+ BrowserDistribution* dist =
+ BrowserDistribution::GetSpecificDistribution(
+ BrowserDistribution::CHROME_BINARIES);
RegistryReadyModeState ready_mode_state(
- installer::ActivePackageProperties().GetStateKey(),
+ dist->GetStateKey(),
base::TimeDelta::FromMinutes(kTemporaryDeclineDurationMinutes),
NULL); // NULL => no observer required