summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--chrome/browser/browser_main_win.cc23
-rw-r--r--chrome/browser/first_run/first_run_win.cc5
-rw-r--r--chrome/browser/shell_integration_win.cc5
-rw-r--r--chrome/browser/ui/views/about_chrome_view.cc6
-rw-r--r--chrome/browser/ui/views/uninstall_view.cc5
-rw-r--r--chrome/browser/upgrade_detector.cc7
-rw-r--r--chrome/chrome_installer.gypi3
-rw-r--r--chrome/chrome_installer_util.gypi4
-rw-r--r--chrome/installer/setup/install.cc827
-rw-r--r--chrome/installer/setup/install.h31
-rw-r--r--chrome/installer/setup/setup_main.cc598
-rw-r--r--chrome/installer/setup/setup_util.cc14
-rw-r--r--chrome/installer/setup/setup_util.h2
-rw-r--r--chrome/installer/setup/setup_util_unittest.cc10
-rw-r--r--chrome/installer/setup/uninstall.cc374
-rw-r--r--chrome/installer/setup/uninstall.h18
-rw-r--r--chrome/installer/util/browser_distribution.cc83
-rw-r--r--chrome/installer/util/browser_distribution.h50
-rw-r--r--chrome/installer/util/browser_distribution_unittest.cc30
-rw-r--r--chrome/installer/util/chrome_frame_distribution.h6
-rw-r--r--chrome/installer/util/google_chrome_distribution.cc56
-rw-r--r--chrome/installer/util/google_chrome_distribution.h12
-rw-r--r--chrome/installer/util/google_chrome_distribution_dummy.cc12
-rw-r--r--chrome/installer/util/google_chrome_distribution_unittest.cc3
-rw-r--r--chrome/installer/util/helper.cc118
-rw-r--r--chrome/installer/util/helper.h29
-rw-r--r--chrome/installer/util/helper_unittest.cc15
-rw-r--r--chrome/installer/util/install_util.cc105
-rw-r--r--chrome/installer/util/install_util.h30
-rw-r--r--chrome/installer/util/package.cc148
-rw-r--r--chrome/installer/util/package.h73
-rw-r--r--chrome/installer/util/package_unittest.cc124
-rw-r--r--chrome/installer/util/product.cc266
-rw-r--r--chrome/installer/util/product.h151
-rw-r--r--chrome/installer/util/product_unittest.cc179
-rw-r--r--chrome/installer/util/product_unittest.h49
-rw-r--r--chrome/installer/util/shell_util.cc120
-rw-r--r--chrome/installer/util/shell_util.h40
-rw-r--r--chrome/installer/util/shell_util_unittest.cc9
-rw-r--r--chrome/installer/util/util_constants.cc6
-rw-r--r--chrome/installer/util/util_constants.h6
-rw-r--r--chrome/installer/util/version.h5
-rw-r--r--chrome_frame/test/test_with_web_server.cc34
43 files changed, 2414 insertions, 1277 deletions
diff --git a/chrome/browser/browser_main_win.cc b/chrome/browser/browser_main_win.cc
index e4b52da..273a113 100644
--- a/chrome/browser/browser_main_win.cc
+++ b/chrome/browser/browser_main_win.cc
@@ -29,6 +29,7 @@
#include "chrome/common/env_vars.h"
#include "chrome/common/main_function_params.h"
#include "chrome/common/result_codes.h"
+#include "chrome/installer/util/browser_distribution.h"
#include "chrome/installer/util/helper.h"
#include "chrome/installer/util/install_util.h"
#include "chrome/installer/util/shell_util.h"
@@ -99,9 +100,12 @@ int DoUninstallTasks(bool chrome_still_running) {
VLOG(1) << "Failed to delete sentinel file.";
// We want to remove user level shortcuts and we only care about the ones
// created by us and not by the installer so |alternate| is false.
- if (!ShellUtil::RemoveChromeDesktopShortcut(ShellUtil::CURRENT_USER, false))
+ BrowserDistribution* dist = BrowserDistribution::GetDistribution();
+ if (!ShellUtil::RemoveChromeDesktopShortcut(dist, ShellUtil::CURRENT_USER,
+ false))
VLOG(1) << "Failed to delete desktop shortcut.";
- if (!ShellUtil::RemoveChromeQuickLaunchShortcut(ShellUtil::CURRENT_USER))
+ if (!ShellUtil::RemoveChromeQuickLaunchShortcut(dist,
+ ShellUtil::CURRENT_USER))
VLOG(1) << "Failed to delete quick launch shortcut.";
}
return ret;
@@ -176,22 +180,23 @@ int HandleIconsCommands(const CommandLine &parsed_command_line) {
// allow the user level Chrome to run. So we notify the user and uninstall
// user level Chrome.
bool CheckMachineLevelInstall() {
- scoped_ptr<installer::Version> version(InstallUtil::GetChromeVersion(true));
+ // TODO(tommi): Check if using the default distribution is always the right
+ // thing to do.
+ BrowserDistribution* dist = BrowserDistribution::GetDistribution();
+ scoped_ptr<installer::Version> version(InstallUtil::GetChromeVersion(dist,
+ true));
if (version.get()) {
FilePath exe_path;
PathService::Get(base::DIR_EXE, &exe_path);
std::wstring exe = exe_path.value();
- std::transform(exe.begin(), exe.end(), exe.begin(), tolower);
- std::wstring user_exe_path = installer::GetChromeInstallPath(false);
- std::transform(user_exe_path.begin(), user_exe_path.end(),
- user_exe_path.begin(), tolower);
- if (exe == user_exe_path) {
+ FilePath user_exe_path(installer::GetChromeInstallPath(false, dist));
+ if (FilePath::CompareEqualIgnoreCase(exe, user_exe_path.value())) {
const std::wstring text =
l10n_util::GetString(IDS_MACHINE_LEVEL_INSTALL_CONFLICT);
const std::wstring caption = l10n_util::GetString(IDS_PRODUCT_NAME);
const UINT flags = MB_OK | MB_ICONERROR | MB_TOPMOST;
win_util::MessageBox(NULL, text, caption, flags);
- FilePath uninstall_path(InstallUtil::GetChromeUninstallCmd(false));
+ FilePath uninstall_path(InstallUtil::GetChromeUninstallCmd(false, dist));
CommandLine uninstall_cmd(uninstall_path);
if (!uninstall_cmd.GetProgram().value().empty()) {
uninstall_cmd.AppendSwitch(installer_util::switches::kForceUninstall);
diff --git a/chrome/browser/first_run/first_run_win.cc b/chrome/browser/first_run/first_run_win.cc
index bffded1..55016c4 100644
--- a/chrome/browser/first_run/first_run_win.cc
+++ b/chrome/browser/first_run/first_run_win.cc
@@ -224,7 +224,7 @@ bool FirstRun::CreateChromeDesktopShortcut() {
BrowserDistribution *dist = BrowserDistribution::GetDistribution();
if (!dist)
return false;
- return ShellUtil::CreateChromeDesktopShortcut(chrome_exe.value(),
+ return ShellUtil::CreateChromeDesktopShortcut(dist, chrome_exe.value(),
dist->GetAppDescription(), ShellUtil::CURRENT_USER,
false, true); // create if doesn't exist.
}
@@ -233,7 +233,8 @@ bool FirstRun::CreateChromeQuickLaunchShortcut() {
FilePath chrome_exe;
if (!PathService::Get(base::FILE_EXE, &chrome_exe))
return false;
- return ShellUtil::CreateChromeQuickLaunchShortcut(chrome_exe.value(),
+ BrowserDistribution* dist = BrowserDistribution::GetDistribution();
+ return ShellUtil::CreateChromeQuickLaunchShortcut(dist, chrome_exe.value(),
ShellUtil::CURRENT_USER, // create only for current user.
true); // create if doesn't exist.
}
diff --git a/chrome/browser/shell_integration_win.cc b/chrome/browser/shell_integration_win.cc
index 044a787..ad1f653 100644
--- a/chrome/browser/shell_integration_win.cc
+++ b/chrome/browser/shell_integration_win.cc
@@ -272,7 +272,8 @@ bool ShellIntegration::SetAsDefaultBrowser() {
}
// From UI currently we only allow setting default browser for current user.
- if (!ShellUtil::MakeChromeDefault(ShellUtil::CURRENT_USER,
+ BrowserDistribution* dist = BrowserDistribution::GetDistribution();
+ if (!ShellUtil::MakeChromeDefault(dist, ShellUtil::CURRENT_USER,
chrome_exe.value(), true)) {
LOG(ERROR) << "Chrome could not be set as default browser.";
return false;
@@ -315,7 +316,7 @@ ShellIntegration::DefaultBrowserState ShellIntegration::IsDefaultBrowser() {
// app name being default. If not, then default browser is just called
// Google Chrome or Chromium so we do not append suffix to app name.
std::wstring suffix;
- if (ShellUtil::GetUserSpecificDefaultBrowserSuffix(&suffix))
+ if (ShellUtil::GetUserSpecificDefaultBrowserSuffix(dist, &suffix))
app_name += suffix;
for (int i = 0; i < _countof(kChromeProtocols); i++) {
diff --git a/chrome/browser/ui/views/about_chrome_view.cc b/chrome/browser/ui/views/about_chrome_view.cc
index 2808d98..11cede9 100644
--- a/chrome/browser/ui/views/about_chrome_view.cc
+++ b/chrome/browser/ui/views/about_chrome_view.cc
@@ -26,6 +26,7 @@
#include "chrome/common/chrome_version_info.h"
#include "chrome/common/pref_names.h"
#include "chrome/common/url_constants.h"
+#include "chrome/installer/util/browser_distribution.h"
#include "gfx/canvas.h"
#include "grit/chromium_strings.h"
#include "grit/generated_resources.h"
@@ -739,8 +740,11 @@ void AboutChromeView::UpdateStatus(GoogleUpdateUpgradeResult result,
// Google Update reported that Chrome is up-to-date. Now make sure that we
// are running the latest version and if not, notify the user by falling
// into the next case of UPGRADE_SUCCESSFUL.
+ // TODO(tommi): Check if using the default distribution is always the
+ // right thing to do.
+ BrowserDistribution* dist = BrowserDistribution::GetDistribution();
scoped_ptr<installer::Version> installed_version(
- InstallUtil::GetChromeVersion(false));
+ InstallUtil::GetChromeVersion(dist, false));
scoped_ptr<installer::Version> running_version(
installer::Version::GetVersionFromString(current_version_));
if (!installed_version.get() ||
diff --git a/chrome/browser/ui/views/uninstall_view.cc b/chrome/browser/ui/views/uninstall_view.cc
index a7535b0..ecd2ac7 100644
--- a/chrome/browser/ui/views/uninstall_view.cc
+++ b/chrome/browser/ui/views/uninstall_view.cc
@@ -65,10 +65,11 @@ void UninstallView::SetupControls() {
layout->AddView(delete_profile_);
// Set default browser combo box
- if (BrowserDistribution::GetDistribution()->CanSetAsDefault() &&
+ BrowserDistribution* dist = BrowserDistribution::GetDistribution();
+ if (dist->CanSetAsDefault() &&
ShellIntegration::IsDefaultBrowser()) {
browsers_.reset(new BrowsersMap());
- ShellUtil::GetRegisteredBrowsers(browsers_.get());
+ ShellUtil::GetRegisteredBrowsers(dist, browsers_.get());
if (!browsers_->empty()) {
layout->AddPaddingRow(0, kRelatedControlVerticalSpacing);
diff --git a/chrome/browser/upgrade_detector.cc b/chrome/browser/upgrade_detector.cc
index 6a65c7a..56886bf 100644
--- a/chrome/browser/upgrade_detector.cc
+++ b/chrome/browser/upgrade_detector.cc
@@ -86,10 +86,13 @@ class DetectUpgradeTask : public Task {
// Get the version of the currently *installed* instance of Chrome,
// which might be newer than the *running* instance if we have been
// upgraded in the background.
- installed_version.reset(InstallUtil::GetChromeVersion(false));
+ // TODO(tommi): Check if using the default distribution is always the right
+ // thing to do.
+ BrowserDistribution* dist = BrowserDistribution::GetDistribution();
+ installed_version.reset(InstallUtil::GetChromeVersion(dist, false));
if (!installed_version.get()) {
// User level Chrome is not installed, check system level.
- installed_version.reset(InstallUtil::GetChromeVersion(true));
+ installed_version.reset(InstallUtil::GetChromeVersion(dist, true));
}
#elif defined(OS_MACOSX)
installed_version.reset(
diff --git a/chrome/chrome_installer.gypi b/chrome/chrome_installer.gypi
index c431fac..468c95d 100644
--- a/chrome/chrome_installer.gypi
+++ b/chrome/chrome_installer.gypi
@@ -92,6 +92,9 @@
'installer/util/lzma_util_unittest.cc',
'installer/util/master_preferences_unittest.cc',
'installer/util/move_tree_work_item_unittest.cc',
+ 'installer/util/package_unittest.cc',
+ 'installer/util/product_unittest.h',
+ 'installer/util/product_unittest.cc',
'installer/util/run_all_unittests.cc',
'installer/util/set_reg_value_work_item_unittest.cc',
'installer/util/shell_util_unittest.cc',
diff --git a/chrome/chrome_installer_util.gypi b/chrome/chrome_installer_util.gypi
index 02603bf..2c922cd 100644
--- a/chrome/chrome_installer_util.gypi
+++ b/chrome/chrome_installer_util.gypi
@@ -101,6 +101,10 @@
'installer/util/lzma_util.h',
'installer/util/master_preferences.cc',
'installer/util/master_preferences.h',
+ 'installer/util/package.h',
+ 'installer/util/package.cc',
+ 'installer/util/product.h',
+ 'installer/util/product.cc',
'installer/util/shell_util.cc',
'installer/util/shell_util.h',
],
diff --git a/chrome/installer/setup/install.cc b/chrome/installer/setup/install.cc
index 8aefcf3..3817aa1 100644
--- a/chrome/installer/setup/install.cc
+++ b/chrome/installer/setup/install.cc
@@ -22,6 +22,8 @@
#include "chrome/installer/util/helper.h"
#include "chrome/installer/util/install_util.h"
#include "chrome/installer/util/master_preferences_constants.h"
+#include "chrome/installer/util/package.h"
+#include "chrome/installer/util/product.h"
#include "chrome/installer/util/set_reg_value_work_item.h"
#include "chrome/installer/util/shell_util.h"
#include "chrome/installer/util/util_constants.h"
@@ -33,12 +35,10 @@
namespace {
-std::wstring AppendPath(const std::wstring& parent_path,
- const std::wstring& path) {
- std::wstring new_path(parent_path);
- file_util::AppendToPath(&new_path, path);
- return new_path;
-}
+using installer::Products;
+using installer::Product;
+using installer::Package;
+using installer::Version;
void AddChromeToMediaPlayerList() {
std::wstring reg_path(installer::kMediaPlayerRegPath);
@@ -53,87 +53,95 @@ void AddChromeToMediaPlayerList() {
LOG(ERROR) << "Could not add Chrome to media player inclusion list.";
}
-void AddInstallerCopyTasks(const std::wstring& exe_path,
- const std::wstring& archive_path,
- const std::wstring& temp_path,
- const std::wstring& install_path,
- const std::wstring& new_version,
+void AddInstallerCopyTasks(const FilePath& setup_path,
+ const FilePath& archive_path,
+ const FilePath& temp_path,
+ const Version& new_version,
WorkItemList* install_list,
- bool system_level) {
- std::wstring installer_dir(installer::GetInstallerPathUnderChrome(
- install_path, new_version));
- install_list->AddCreateDirWorkItem(
- FilePath::FromWStringHack(installer_dir));
-
- std::wstring exe_dst(installer_dir);
- std::wstring archive_dst(installer_dir);
- file_util::AppendToPath(&exe_dst,
- file_util::GetFilenameFromPath(exe_path));
- file_util::AppendToPath(&archive_dst,
- file_util::GetFilenameFromPath(archive_path));
-
- install_list->AddCopyTreeWorkItem(exe_path, exe_dst, temp_path,
- WorkItem::ALWAYS);
- if (system_level) {
- install_list->AddCopyTreeWorkItem(archive_path, archive_dst, temp_path,
- WorkItem::ALWAYS);
+ const Package& package) {
+ DCHECK(install_list);
+ FilePath installer_dir(package.GetInstallerDirectory(new_version));
+ install_list->AddCreateDirWorkItem(installer_dir);
+
+ FilePath exe_dst(installer_dir.Append(setup_path.BaseName()));
+ FilePath archive_dst(installer_dir.Append(archive_path.BaseName()));
+
+ install_list->AddCopyTreeWorkItem(setup_path.value(), exe_dst.value(),
+ temp_path.value(), WorkItem::ALWAYS);
+ if (package.system_level()) {
+ install_list->AddCopyTreeWorkItem(archive_path.value(), archive_dst.value(),
+ temp_path.value(), WorkItem::ALWAYS);
} else {
- install_list->AddMoveTreeWorkItem(archive_path, archive_dst, temp_path);
+ install_list->AddMoveTreeWorkItem(archive_path.value(), archive_dst.value(),
+ temp_path.value());
}
}
void AppendUninstallCommandLineFlags(CommandLine* uninstall_cmd,
- bool is_system) {
+ const Product& product) {
DCHECK(uninstall_cmd);
+
uninstall_cmd->AppendSwitch(installer_util::switches::kUninstall);
- // TODO(tommi): In case of multiple installations, we need to create multiple
- // uninstall entries, and not one magic one for all.
const installer_util::MasterPreferences& prefs =
InstallUtil::GetMasterPreferencesForCurrentProcess();
- DCHECK(!prefs.is_multi_install());
- if (prefs.install_chrome_frame()) {
+ bool cf_switch_added = false;
+
+ if (prefs.is_multi_install()) {
+ uninstall_cmd->AppendSwitch(installer_util::switches::kMultiInstall);
+ switch (product.distribution()->GetType()) {
+ case BrowserDistribution::CHROME_BROWSER:
+ uninstall_cmd->AppendSwitch(installer_util::switches::kChrome);
+ break;
+ case BrowserDistribution::CHROME_FRAME:
+ uninstall_cmd->AppendSwitch(installer_util::switches::kChromeFrame);
+ cf_switch_added = true;
+ break;
+ case BrowserDistribution::CEEE:
+ uninstall_cmd->AppendSwitch(installer_util::switches::kCeee);
+ break;
+ default:
+ NOTREACHED();
+ break;
+ }
+ }
+
+ if (product.distribution()->GetType() == BrowserDistribution::CHROME_FRAME) {
+ DCHECK(prefs.install_chrome_frame());
uninstall_cmd->AppendSwitch(installer_util::switches::kDeleteProfile);
- uninstall_cmd->AppendSwitch(installer_util::switches::kChromeFrame);
+ if (!cf_switch_added) {
+ uninstall_cmd->AppendSwitch(installer_util::switches::kChromeFrame);
+ }
}
- if (InstallUtil::IsChromeSxSProcess()) {
+ if (InstallUtil::IsChromeSxSProcess())
uninstall_cmd->AppendSwitch(installer_util::switches::kChromeSxS);
- }
- if (InstallUtil::IsMSIProcess(is_system)) {
+ if (product.IsMsi())
uninstall_cmd->AppendSwitch(installer_util::switches::kMsi);
- }
// Propagate the verbose logging switch to uninstalls too.
- const CommandLine& command_line = *CommandLine::ForCurrentProcess();
- if (command_line.HasSwitch(installer_util::switches::kVerboseLogging)) {
+ bool value = false;
+ if (prefs.GetBool(installer_util::master_preferences::kVerboseLogging,
+ &value) && value)
uninstall_cmd->AppendSwitch(installer_util::switches::kVerboseLogging);
- }
- if (is_system) {
+ if (product.system_level())
uninstall_cmd->AppendSwitch(installer_util::switches::kSystemLevel);
- }
}
// 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(HKEY reg_root,
- const std::wstring& exe_path,
- const std::wstring& install_path,
- const std::wstring& product_name,
- const std::wstring& new_version,
- WorkItemList* install_list) {
- BrowserDistribution* dist = BrowserDistribution::GetDistribution();
- const CommandLine& command_line = *CommandLine::ForCurrentProcess();
-
- // TODO(tommi): Support this for multi-install. We need to add work items
- // for each product being installed.
- const installer_util::MasterPreferences& prefs =
- InstallUtil::GetMasterPreferencesForCurrentProcess();
- DCHECK(!prefs.is_multi_install()) << "TODO";
+void AddUninstallShortcutWorkItems(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;
+ BrowserDistribution* browser_dist = product.distribution();
+ DCHECK(browser_dist);
// When we are installed via an MSI, we need to store our uninstall strings
// in the Google Update client state key. We do this even for non-MSI
@@ -141,16 +149,15 @@ void AddUninstallShortcutWorkItems(HKEY reg_root,
// 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 installer_path(installer::GetInstallerPathUnderChrome(install_path,
- new_version));
- installer_path = installer_path.Append(
- file_util::GetFilenameFromPath(exe_path));
+ FilePath install_path(product.package().path());
+ FilePath installer_path(
+ product.package().GetInstallerDirectory(new_version));
+ installer_path = installer_path.Append(setup_path.BaseName());
CommandLine uninstall_arguments(CommandLine::NO_PROGRAM);
- AppendUninstallCommandLineFlags(&uninstall_arguments,
- reg_root == HKEY_LOCAL_MACHINE);
+ AppendUninstallCommandLineFlags(&uninstall_arguments, product);
- std::wstring update_state_key = dist->GetStateKey();
+ std::wstring update_state_key(browser_dist->GetStateKey());
install_list->AddCreateRegKeyWorkItem(reg_root, update_state_key);
install_list->AddSetRegValueWorkItem(reg_root, update_state_key,
installer_util::kUninstallStringField, installer_path.value(), true);
@@ -159,31 +166,32 @@ void AddUninstallShortcutWorkItems(HKEY reg_root,
uninstall_arguments.command_line_string(), true);
// MSI installations will manage their own uninstall shortcuts.
- if (!InstallUtil::IsMSIProcess(reg_root == HKEY_LOCAL_MACHINE)) {
+ if (!product.IsMsi()) {
// 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], '"');
quoted_uninstall_cmd.AppendArguments(uninstall_arguments, false);
- std::wstring uninstall_reg = dist->GetUninstallRegPath();
+ std::wstring uninstall_reg = browser_dist->GetUninstallRegPath();
install_list->AddCreateRegKeyWorkItem(reg_root, uninstall_reg);
install_list->AddSetRegValueWorkItem(reg_root, uninstall_reg,
- installer_util::kUninstallDisplayNameField, product_name, true);
+ installer_util::kUninstallDisplayNameField,
+ browser_dist->GetAppShortCutName(), true);
install_list->AddSetRegValueWorkItem(reg_root,
uninstall_reg, installer_util::kUninstallStringField,
quoted_uninstall_cmd.command_line_string(), true);
install_list->AddSetRegValueWorkItem(reg_root,
uninstall_reg,
L"InstallLocation",
- install_path,
+ install_path.value(),
true);
// DisplayIcon, NoModify and NoRepair
- std::wstring chrome_icon = AppendPath(install_path,
- installer_util::kChromeExe);
- ShellUtil::GetChromeIcon(chrome_icon);
+ FilePath chrome_icon(install_path.Append(installer_util::kChromeExe));
+ ShellUtil::GetChromeIcon(product.distribution(), chrome_icon.value());
install_list->AddSetRegValueWorkItem(reg_root, uninstall_reg,
- L"DisplayIcon", chrome_icon, true);
+ L"DisplayIcon", chrome_icon.value(),
+ true);
install_list->AddSetRegValueWorkItem(reg_root, uninstall_reg,
L"NoModify", 1, true);
install_list->AddSetRegValueWorkItem(reg_root, uninstall_reg,
@@ -191,12 +199,14 @@ void AddUninstallShortcutWorkItems(HKEY reg_root,
install_list->AddSetRegValueWorkItem(reg_root, uninstall_reg,
L"Publisher",
- dist->GetPublisherName(), true);
+ browser_dist->GetPublisherName(),
+ true);
install_list->AddSetRegValueWorkItem(reg_root, uninstall_reg,
- L"Version", new_version.c_str(), true);
+ L"Version", new_version.GetString(),
+ true);
install_list->AddSetRegValueWorkItem(reg_root, uninstall_reg,
L"DisplayVersion",
- new_version.c_str(), true);
+ new_version.GetString(), true);
time_t rawtime = time(NULL);
struct tm timeinfo = {0};
localtime_s(&timeinfo, &rawtime);
@@ -214,31 +224,31 @@ void AddUninstallShortcutWorkItems(HKEY reg_root,
// 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 DeleteUninstallShortcutsForMSI(bool is_system_install) {
- DCHECK(InstallUtil::IsMSIProcess(is_system_install))
- << "This must only be called for MSI installations!";
+void DeleteUninstallShortcutsForMSI(const Product& product) {
+ 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 = is_system_install ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER;
+ HKEY reg_root = product.system_level() ? HKEY_LOCAL_MACHINE :
+ HKEY_CURRENT_USER;
base::win::RegKey root_key(reg_root, L"", KEY_ALL_ACCESS);
- BrowserDistribution* dist = BrowserDistribution::GetDistribution();
- std::wstring uninstall_reg = dist->GetUninstallRegPath();
+ std::wstring uninstall_reg(product.distribution()->GetUninstallRegPath());
InstallUtil::DeleteRegistryKey(root_key, uninstall_reg);
// Then attempt to delete the old installation's start menu shortcut.
FilePath uninstall_link;
- if (is_system_install) {
+ 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 {
- BrowserDistribution* dist = BrowserDistribution::GetDistribution();
- uninstall_link = uninstall_link.Append(dist->GetAppShortCutName());
uninstall_link = uninstall_link.Append(
- dist->GetUninstallLinkName() + L".lnk");
+ product.distribution()->GetAppShortCutName());
+ uninstall_link = uninstall_link.Append(
+ product.distribution()->GetUninstallLinkName() + L".lnk");
VLOG(1) << "Deleting old uninstall shortcut (if present): "
<< uninstall_link.value();
if (!file_util::Delete(uninstall_link, true))
@@ -249,15 +259,14 @@ void DeleteUninstallShortcutsForMSI(bool is_system_install) {
// 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(bool system_level,
- const std::wstring& prefs_source_path) {
- FilePath prefs_dest_path = FilePath::FromWStringHack(
- installer::GetChromeInstallPath(system_level));
- prefs_dest_path = prefs_dest_path.AppendASCII(
- installer_util::kDefaultMasterPrefs);
- if (!file_util::CopyFile(FilePath::FromWStringHack(prefs_source_path),
- prefs_dest_path))
- VLOG(1) << "Failed to copy master preferences.";
+void CopyPreferenceFileForFirstRun(const Package& package,
+ const FilePath& prefs_source_path) {
+ FilePath prefs_dest_path(package.path().AppendASCII(
+ installer_util::kDefaultMasterPrefs));
+ if (!file_util::CopyFile(prefs_source_path, prefs_dest_path)) {
+ VLOG(1) << "Failed to copy master preferences from:"
+ << prefs_source_path.value() << " gle: " << ::GetLastError();
+ }
}
// This method creates Chrome shortcuts in Start->Programs for all users or
@@ -274,25 +283,32 @@ void CopyPreferenceFileForFirstRun(bool system_level,
//
// If the shortcuts do not exist, the function does not recreate them during
// update.
-bool CreateOrUpdateChromeShortcuts(const std::wstring& exe_path,
- const std::wstring& install_path,
- const std::wstring& new_version,
+bool CreateOrUpdateChromeShortcuts(const FilePath& setup_path,
+ const Version& new_version,
installer_util::InstallStatus install_status,
- bool system_install,
+ const Product& product,
bool create_all_shortcut,
bool alt_shortcut) {
+ // TODO(tommi): Change this function to use WorkItemList.
+#ifndef NDEBUG
+ const installer_util::MasterPreferences& prefs =
+ InstallUtil::GetMasterPreferencesForCurrentProcess();
+ DCHECK(prefs.install_chrome());
+#endif
+
FilePath shortcut_path;
- int dir_enum = (system_install) ? base::DIR_COMMON_START_MENU :
- base::DIR_START_MENU;
+ int dir_enum = product.system_level() ? base::DIR_COMMON_START_MENU :
+ base::DIR_START_MENU;
if (!PathService::Get(dir_enum, &shortcut_path)) {
LOG(ERROR) << "Failed to get location for shortcut.";
return false;
}
+ BrowserDistribution* browser_dist = product.distribution();
+
// The location of Start->Programs->Google Chrome folder
- BrowserDistribution* dist = BrowserDistribution::GetDistribution();
- const std::wstring& product_name = dist->GetAppShortCutName();
- const std::wstring& product_desc = dist->GetAppDescription();
+ const std::wstring product_name(browser_dist->GetAppShortCutName());
+ const std::wstring product_desc(browser_dist->GetAppDescription());
shortcut_path = shortcut_path.Append(product_name);
// Create/update Chrome link (points to chrome.exe) & Uninstall Chrome link
@@ -305,151 +321,191 @@ bool CreateOrUpdateChromeShortcuts(const std::wstring& exe_path,
bool ret = true;
FilePath chrome_link(shortcut_path); // Chrome link (launches Chrome)
chrome_link = chrome_link.Append(product_name + L".lnk");
- std::wstring chrome_exe(install_path); // Chrome link target
- file_util::AppendToPath(&chrome_exe, installer_util::kChromeExe);
+ // Chrome link target
+ FilePath chrome_exe(
+ product.package().path().Append(installer_util::kChromeExe));
if ((install_status == installer_util::FIRST_INSTALL_SUCCESS) ||
(install_status == installer_util::INSTALL_REPAIRED)) {
if (!file_util::PathExists(shortcut_path))
file_util::CreateDirectoryW(shortcut_path);
- VLOG(1) << "Creating shortcut to " << chrome_exe << " at "
+ VLOG(1) << "Creating shortcut to " << chrome_exe.value() << " at "
<< chrome_link.value();
- ret = ret && ShellUtil::UpdateChromeShortcut(chrome_exe,
- chrome_link.value(),
- product_desc, true);
+ ret = ShellUtil::UpdateChromeShortcut(browser_dist, chrome_exe.value(),
+ chrome_link.value(), product_desc, true);
} else if (file_util::PathExists(chrome_link)) {
VLOG(1) << "Updating shortcut at " << chrome_link.value()
- << " to point to " << chrome_exe;
- ret = ret && ShellUtil::UpdateChromeShortcut(chrome_exe,
- chrome_link.value(),
- product_desc, false);
+ << " to point to " << chrome_exe.value();
+ ret = ShellUtil::UpdateChromeShortcut(browser_dist, chrome_exe.value(),
+ chrome_link.value(), product_desc, false);
+ } else {
+ VLOG(1)
+ << "not first or repaired install, link file doesn't exist. status: "
+ << install_status;
}
// Create/update uninstall link if we are not an MSI install. MSI
// 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 (!InstallUtil::IsMSIProcess(system_install)) {
+ if (ret && !product.IsMsi()) {
FilePath uninstall_link(shortcut_path); // Uninstall Chrome link
uninstall_link = uninstall_link.Append(
- dist->GetUninstallLinkName() + L".lnk");
+ browser_dist->GetUninstallLinkName() + L".lnk");
if ((install_status == installer_util::FIRST_INSTALL_SUCCESS) ||
(install_status == installer_util::INSTALL_REPAIRED) ||
(file_util::PathExists(uninstall_link))) {
if (!file_util::PathExists(shortcut_path))
- file_util::CreateDirectoryW(shortcut_path);
- std::wstring setup_exe(installer::GetInstallerPathUnderChrome(
- install_path, new_version));
- file_util::AppendToPath(&setup_exe,
- file_util::GetFilenameFromPath(exe_path));
-
- CommandLine arguments(CommandLine::NO_PROGRAM);
- AppendUninstallCommandLineFlags(&arguments, system_install);
- VLOG(1) << "Creating/updating uninstall link at "
- << uninstall_link.value();
- ret = ret && file_util::CreateShortcutLink(setup_exe.c_str(),
- uninstall_link.value().c_str(),
- NULL,
- arguments.command_line_string().c_str(),
- NULL,
- setup_exe.c_str(),
- 0,
- NULL);
+ file_util::CreateDirectory(shortcut_path);
+
+ FilePath setup_exe(
+ product.package().GetInstallerDirectory(new_version)
+ .Append(setup_path.BaseName()));
+
+ CommandLine arguments(CommandLine::NO_PROGRAM);
+ AppendUninstallCommandLineFlags(&arguments, product);
+ VLOG(1) << "Creating/updating uninstall link at "
+ << uninstall_link.value();
+ ret = file_util::CreateShortcutLink(setup_exe.value().c_str(),
+ uninstall_link.value().c_str(),
+ NULL,
+ arguments.command_line_string().c_str(),
+ NULL,
+ setup_exe.value().c_str(),
+ 0,
+ NULL);
}
}
// Update Desktop and Quick Launch shortcuts. If --create-new-shortcuts
// is specified we want to create them, otherwise we update them only if
// they exist.
- if (system_install) {
- ret = ret && ShellUtil::CreateChromeDesktopShortcut(chrome_exe,
- product_desc, ShellUtil::SYSTEM_LEVEL, alt_shortcut,
- create_all_shortcut);
- ret = ret && ShellUtil::CreateChromeQuickLaunchShortcut(chrome_exe,
- ShellUtil::CURRENT_USER | ShellUtil::SYSTEM_LEVEL, create_all_shortcut);
- } else {
- ret = ret && ShellUtil::CreateChromeDesktopShortcut(chrome_exe,
- product_desc, ShellUtil::CURRENT_USER, alt_shortcut,
- create_all_shortcut);
- ret = ret && ShellUtil::CreateChromeQuickLaunchShortcut(chrome_exe,
- ShellUtil::CURRENT_USER, create_all_shortcut);
+ if (ret) {
+ if (product.system_level()) {
+ ret = ShellUtil::CreateChromeDesktopShortcut(product.distribution(),
+ chrome_exe.value(), product_desc, ShellUtil::SYSTEM_LEVEL,
+ alt_shortcut, create_all_shortcut);
+ if (ret) {
+ ret = ShellUtil::CreateChromeQuickLaunchShortcut(
+ product.distribution(), chrome_exe.value(),
+ ShellUtil::CURRENT_USER | ShellUtil::SYSTEM_LEVEL,
+ create_all_shortcut);
+ }
+ } else {
+ ret = ShellUtil::CreateChromeDesktopShortcut(product.distribution(),
+ chrome_exe.value(), product_desc, ShellUtil::CURRENT_USER,
+ alt_shortcut, create_all_shortcut);
+ if (ret) {
+ ret = ShellUtil::CreateChromeQuickLaunchShortcut(
+ product.distribution(), chrome_exe.value(), ShellUtil::CURRENT_USER,
+ create_all_shortcut);
+ }
+ }
}
return ret;
}
+bool RegisterComDlls(const Package& install,
+ const Version* current_version,
+ const Version& new_version) {
+ // TODO(tommi): setup.exe should always have at least one DLL to register.
+ // Currently we rely on scan_server_dlls.py to populate the array for us,
+ // but we might as well use an explicit static array of required components.
+ if (kNumDllsToRegister <= 0) {
+ NOTREACHED() << "no dlls to register";
+ return false;
+ }
+
+ // Unregister DLLs that were left from the old version that is being upgraded.
+ if (current_version) {
+ FilePath old_dll_path(install.path().Append(current_version->GetString()));
+ // Ignore failures to unregister old DLLs.
+ installer::RegisterComDllList(old_dll_path, install.system_level(), false,
+ false);
+ }
+
+ FilePath dll_path(install.path().Append(new_version.GetString()));
+ return installer::RegisterComDllList(dll_path, install.system_level(), true,
+ true);
+}
+
// After a successful copying of all the files, this function is called to
// do a few post install tasks:
-// - Handle the case of in-use-update by updating "opv" key or deleting it if
-// not required.
+// - Handle the case of in-use-update by updating "opv" (old version) key or
+// deleting it if not required.
// - Register any new dlls and unregister old dlls.
// - If this is an MSI install, ensures that the MSI marker is set, and sets
// it if not.
// If these operations are successful, the function returns true, otherwise
// false.
-bool DoPostInstallTasks(HKEY reg_root,
- const std::wstring& exe_path,
- const std::wstring& install_path,
- const std::wstring& new_chrome_exe,
- const std::wstring& current_version,
- const installer::Version& new_version) {
- BrowserDistribution* dist = BrowserDistribution::GetDistribution();
- std::wstring version_key = dist->GetVersionKey();
-
- bool is_system_install = (reg_root == HKEY_LOCAL_MACHINE);
- const installer_util::MasterPreferences& prefs =
- InstallUtil::GetMasterPreferencesForCurrentProcess();
-
- if (file_util::PathExists(FilePath::FromWStringHack(new_chrome_exe))) {
+bool DoPostInstallTasks(const FilePath& setup_path,
+ const FilePath& new_chrome_exe,
+ const Version* current_version,
+ const Version& new_version,
+ const Package& package) {
+ HKEY root = package.system_level() ? HKEY_LOCAL_MACHINE :
+ HKEY_CURRENT_USER;
+ const Products& products = package.products();
+
+ if (file_util::PathExists(new_chrome_exe)) {
// Looks like this was in use update. So make sure we update the 'opv' key
// with the current version that is active and 'cmd' key with the rename
// command to run.
- if (current_version.empty()) {
- LOG(ERROR) << "New chrome.exe exists but current version is empty!";
+ if (!current_version) {
+ LOG(ERROR) << "New chrome.exe exists but current version is NULL!";
return false;
}
- scoped_ptr<WorkItemList> inuse_list(WorkItem::CreateWorkItemList());
- inuse_list->AddSetRegValueWorkItem(reg_root,
- version_key,
- google_update::kRegOldVersionField,
- current_version.c_str(),
- true);
- FilePath installer_path(installer::GetInstallerPathUnderChrome(install_path,
- new_version.GetString()));
- installer_path = installer_path.Append(
- file_util::GetFilenameFromPath(exe_path));
- CommandLine rename_cmd(installer_path);
- rename_cmd.AppendSwitch(installer_util::switches::kRenameChromeExe);
- if (is_system_install)
- rename_cmd.AppendSwitch(installer_util::switches::kSystemLevel);
+ scoped_ptr<WorkItemList> inuse_list(WorkItem::CreateWorkItemList());
+ FilePath installer_path(package.GetInstallerDirectory(new_version)
+ .Append(setup_path.BaseName()));
- if (prefs.install_chrome_frame())
- rename_cmd.AppendSwitch(installer_util::switches::kChromeFrame);
+ CommandLine rename(installer_path);
+ rename.AppendSwitch(installer_util::switches::kRenameChromeExe);
+ if (package.system_level())
+ rename.AppendSwitch(installer_util::switches::kSystemLevel);
if (InstallUtil::IsChromeSxSProcess())
- rename_cmd.AppendSwitch(installer_util::switches::kChromeSxS);
+ rename.AppendSwitch(installer_util::switches::kChromeSxS);
+
+ for (size_t i = 0; i < products.size(); ++i) {
+ BrowserDistribution* dist = products[i]->distribution();
+ std::wstring version_key(dist->GetVersionKey());
+ inuse_list->AddSetRegValueWorkItem(root, version_key,
+ google_update::kRegOldVersionField,
+ current_version->GetString(), true);
+
+ // Adding this registry entry for all products is overkill.
+ // However, as it stands, we don't have a way to know which distribution
+ // will check the key and run the command, so we add it for all.
+ // After the first run, the subsequent runs should just be noops.
+ // (see Upgrade::SwapNewChromeExeIfPresent).
+ inuse_list->AddSetRegValueWorkItem(root, version_key,
+ google_update::kRegRenameCmdField,
+ rename.command_line_string(), true);
+ }
- inuse_list->AddSetRegValueWorkItem(reg_root,
- version_key,
- google_update::kRegRenameCmdField,
- rename_cmd.command_line_string(),
- true);
if (!inuse_list->Do()) {
LOG(ERROR) << "Couldn't write opv/cmd values to registry.";
inuse_list->Rollback();
return false;
}
} else {
- // Since this was not in-use-update, delete 'opv' and 'cmd' keys.
+ // Since this was not an in-use-update, delete 'opv' and 'cmd' keys.
scoped_ptr<WorkItemList> inuse_list(WorkItem::CreateWorkItemList());
- inuse_list->AddDeleteRegValueWorkItem(reg_root, version_key,
- google_update::kRegOldVersionField,
- true);
- inuse_list->AddDeleteRegValueWorkItem(reg_root, version_key,
- google_update::kRegRenameCmdField,
- true);
+ for (size_t i = 0; i < products.size(); ++i) {
+ BrowserDistribution* dist = products[i]->distribution();
+ std::wstring version_key(dist->GetVersionKey());
+ inuse_list->AddDeleteRegValueWorkItem(root, version_key,
+ google_update::kRegOldVersionField,
+ true);
+ inuse_list->AddDeleteRegValueWorkItem(root, version_key,
+ google_update::kRegRenameCmdField,
+ true);
+ }
+
if (!inuse_list->Do()) {
LOG(ERROR) << "Couldn't delete opv/cmd values from registry.";
inuse_list->Rollback();
@@ -457,55 +513,27 @@ bool DoPostInstallTasks(HKEY reg_root,
}
}
- if (prefs.install_chrome_frame()) {
- // TODO(tommi): setup.exe should always have at least one DLL to
- // register. Currently we rely on scan_server_dlls.py to populate
- // the array for us, but we might as well use an explicit static
- // array of required components.
- if (kNumDllsToRegister <= 0) {
- NOTREACHED() << "no dlls to register";
- return false;
- }
-
- // any that were left from the old version that is being upgraded:
- if (!current_version.empty()) {
- std::wstring old_dll_path(install_path);
- file_util::AppendToPath(&old_dll_path, current_version);
- scoped_ptr<WorkItemList> old_dll_list(WorkItem::CreateWorkItemList());
- if (InstallUtil::BuildDLLRegistrationList(old_dll_path, kDllsToRegister,
- kNumDllsToRegister, false,
- !is_system_install,
- old_dll_list.get())) {
- // Don't abort the install as a result of a failure to unregister old
- // DLLs.
- old_dll_list->Do();
- }
- }
-
- std::wstring dll_path(install_path);
- file_util::AppendToPath(&dll_path, new_version.GetString());
- scoped_ptr<WorkItemList> dll_list(WorkItem::CreateWorkItemList());
- if (InstallUtil::BuildDLLRegistrationList(dll_path, kDllsToRegister,
- kNumDllsToRegister, true,
- !is_system_install,
- dll_list.get())) {
- if (!dll_list->Do()) {
- dll_list->Rollback();
- return false;
- }
- }
+ if (FindProduct(products, BrowserDistribution::CHROME_FRAME) ||
+ FindProduct(products, BrowserDistribution::CEEE)) {
+ // TODO(robershield): move the "which DLLs should be registered" policy
+ // into the installer.
+ RegisterComDlls(package, current_version, new_version);
}
// 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 (InstallUtil::IsMSIProcess(is_system_install)) {
- if (!InstallUtil::SetMSIMarker(is_system_install, true))
- return false;
+ for (size_t i = 0; i < products.size(); ++i) {
+ const Product* product = products[i];
+ if (product->IsMsi()) {
+ if (!product->SetMsiMarker(true))
+ return false;
- // 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).
- DeleteUninstallShortcutsForMSI(is_system_install);
+ // 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).
+ DeleteUninstallShortcutsForMSI(*product);
+ }
}
return true;
@@ -529,9 +557,11 @@ bool Is64bit() {
return false;
}
-void RegisterChromeOnMachine(const std::wstring& install_path,
- bool system_level,
+void RegisterChromeOnMachine(const Product& product,
bool make_chrome_default) {
+ DCHECK_EQ(product.distribution()->GetType(),
+ BrowserDistribution::CHROME_BROWSER);
+
// Try to add Chrome to Media Player shim inclusion list. We don't do any
// error checking here because this operation will fail if user doesn't
// have admin rights and we want to ignore the error.
@@ -539,246 +569,229 @@ void RegisterChromeOnMachine(const std::wstring& install_path,
// Is --make-chrome-default option is given we make Chrome default browser
// otherwise we only register it on the machine as a valid browser.
- std::wstring chrome_exe(install_path);
- file_util::AppendToPath(&chrome_exe, installer_util::kChromeExe);
- VLOG(1) << "Registering Chrome as browser";
+ FilePath chrome_exe(
+ product.package().path().Append(installer_util::kChromeExe));
+ VLOG(1) << "Registering Chrome as browser: " << chrome_exe.value();
if (make_chrome_default) {
int level = ShellUtil::CURRENT_USER;
- if (system_level)
+ if (product.system_level())
level = level | ShellUtil::SYSTEM_LEVEL;
- ShellUtil::MakeChromeDefault(level, chrome_exe, true);
+ ShellUtil::MakeChromeDefault(product.distribution(), level,
+ chrome_exe.value(), true);
} else {
- ShellUtil::RegisterChromeBrowser(chrome_exe, L"", false);
+ ShellUtil::RegisterChromeBrowser(product.distribution(), chrome_exe.value(),
+ L"", false);
}
}
// This function installs a new version of Chrome to the specified location.
//
-// exe_path: Path to the executable (setup.exe) as it will be copied
+// setup_path: Path to the executable (setup.exe) as it will be copied
// to Chrome install folder after install is complete
// archive_path: Path to the archive (chrome.7z) as it will be copied
// to Chrome install folder after install is complete
// src_path: the path that contains a complete and unpacked Chrome package
// to be installed.
-// install_path: the destination path for Chrome to be installed to. This
-// path does not need to exist.
// temp_dir: the path of working directory used during installation. This path
// does not need to exist.
-// reg_root: the root of registry where the function applies settings for the
-// new Chrome version. It should be either HKLM or HKCU.
// new_version: new Chrome version that needs to be installed
-// current_version: returns the current active version (if any)
+// oldest_installed_version: returns the oldest active version (if any)
//
// This function makes best effort to do installation in a transactional
// manner. If failed it tries to rollback all changes on the file system
-// and registry. For example, if install_path exists before calling the
+// and registry. For example, if package exists before calling the
// function, it rolls back all new file and directory changes under
-// install_path. If install_path does not exist before calling the function
-// (typical new install), the function creates install_path during install
+// package. If package does not exist before calling the function
+// (typical new install), the function creates package during install
// and removes the whole directory during rollback.
installer_util::InstallStatus InstallNewVersion(
- const std::wstring& exe_path,
- const std::wstring& archive_path,
- const std::wstring& src_path,
- const std::wstring& install_path,
- const std::wstring& temp_dir,
- const HKEY reg_root,
- const installer::Version& new_version,
- std::wstring* current_version) {
- if (reg_root != HKEY_LOCAL_MACHINE && reg_root != HKEY_CURRENT_USER)
- return installer_util::INSTALL_FAILED;
-
- if (InstallUtil::IsChromeFrameProcess()) {
+ 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) {
+ DCHECK(current_version);
+
+ const Products& products = package.products();
+ DCHECK(products.size());
+
+ if (FindProduct(products, BrowserDistribution::CHROME_FRAME)) {
// Make sure that we don't end up deleting installed files on next reboot.
- if (!RemoveFromMovesPendingReboot(install_path.c_str())) {
+ if (!RemoveFromMovesPendingReboot(package.path().value().c_str())) {
LOG(ERROR) << "Error accessing pending moves value.";
}
}
+ // TODO(tommi): See if we can't get rid of this parameter.
+ current_version->reset(package.GetCurrentVersion());
+
scoped_ptr<WorkItemList> install_list(WorkItem::CreateWorkItemList());
// A temp directory that work items need and the actual install directory.
- install_list->AddCreateDirWorkItem(FilePath::FromWStringHack(temp_dir));
- install_list->AddCreateDirWorkItem(FilePath::FromWStringHack(install_path));
+ install_list->AddCreateDirWorkItem(temp_dir);
+ install_list->AddCreateDirWorkItem(package.path());
// Delete any new_chrome.exe if present (we will end up creating a new one
// if required) and then copy chrome.exe
- std::wstring new_chrome_exe = AppendPath(install_path,
- installer_util::kChromeNewExe);
- BrowserDistribution* dist = BrowserDistribution::GetDistribution();
- base::win::RegKey chrome_key(reg_root, dist->GetVersionKey().c_str(),
- KEY_READ);
- if (file_util::PathExists(FilePath::FromWStringHack(new_chrome_exe)))
- chrome_key.ReadValue(google_update::kRegOldVersionField, current_version);
-
- if (current_version->empty())
- chrome_key.ReadValue(google_update::kRegVersionField, current_version);
-
- chrome_key.Close();
+ FilePath new_chrome_exe(
+ package.path().Append(installer_util::kChromeNewExe));
- install_list->AddDeleteTreeWorkItem(new_chrome_exe, std::wstring());
+ install_list->AddDeleteTreeWorkItem(new_chrome_exe.value(), std::wstring());
install_list->AddCopyTreeWorkItem(
- AppendPath(src_path, installer_util::kChromeExe),
- AppendPath(install_path, installer_util::kChromeExe),
- temp_dir, WorkItem::NEW_NAME_IF_IN_USE, new_chrome_exe);
+ src_path.Append(installer_util::kChromeExe).value(),
+ package.path().Append(installer_util::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(
- AppendPath(src_path, installer::kWowHelperExe),
- AppendPath(install_path, installer::kWowHelperExe),
- temp_dir, WorkItem::ALWAYS);
+ src_path.Append(installer::kWowHelperExe).value(),
+ package.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 (reg_root == HKEY_LOCAL_MACHINE) {
+ if (package.system_level()) {
install_list->AddCopyTreeWorkItem(
- AppendPath(src_path, new_version.GetString()),
- AppendPath(install_path, new_version.GetString()),
- temp_dir, WorkItem::ALWAYS);
+ src_path.Append(new_version.GetString()).value(),
+ package.path().Append(new_version.GetString()).value(),
+ temp_dir.value(), WorkItem::ALWAYS);
} else {
install_list->AddMoveTreeWorkItem(
- AppendPath(src_path, new_version.GetString()),
- AppendPath(install_path, new_version.GetString()),
- temp_dir);
+ src_path.Append(new_version.GetString()).value(),
+ package.path().Append(new_version.GetString()).value(),
+ temp_dir.value());
}
- // Copy the default Dictionaries only if the folder doesnt exist already
+ // Copy the default Dictionaries only if the folder doesn't exist already.
install_list->AddCopyTreeWorkItem(
- AppendPath(src_path, installer::kDictionaries),
- AppendPath(install_path, installer::kDictionaries),
- temp_dir, WorkItem::IF_NOT_PRESENT);
-
- // Copy installer in install directory and
- // add shortcut in Control Panel->Add/Remove Programs.
- AddInstallerCopyTasks(exe_path, archive_path, temp_dir, install_path,
- new_version.GetString(), install_list.get(),
- (reg_root == HKEY_LOCAL_MACHINE));
- std::wstring product_name = dist->GetAppShortCutName();
-
- AddUninstallShortcutWorkItems(reg_root, exe_path, install_path,
- product_name, new_version.GetString(), install_list.get());
+ src_path.Append(installer::kDictionaries).value(),
+ package.path().Append(installer::kDictionaries).value(),
+ temp_dir.value(), WorkItem::IF_NOT_PRESENT);
// Delete any old_chrome.exe if present.
install_list->AddDeleteTreeWorkItem(
- AppendPath(install_path, installer_util::kChromeOldExe), std::wstring());
-
- // Create Version key (if not already present) and set the new Chrome
- // version as last step.
- std::wstring version_key = dist->GetVersionKey();
- install_list->AddCreateRegKeyWorkItem(reg_root, version_key);
- install_list->AddSetRegValueWorkItem(reg_root, version_key,
- google_update::kRegNameField,
- product_name,
- true); // overwrite name also
- install_list->AddSetRegValueWorkItem(reg_root, version_key,
- google_update::kRegOopcrashesField,
- 1,
- false); // set during first install
- install_list->AddSetRegValueWorkItem(reg_root, version_key,
- google_update::kRegVersionField,
- new_version.GetString(),
- true); // overwrite version
+ package.path().Append(installer_util::kChromeOldExe).value(),
+ std::wstring());
+
+ // 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.get(), package);
+
+ for (size_t i = 0; i < products.size(); ++i) {
+ const Product* product = products[i];
+
+ AddUninstallShortcutWorkItems(setup_path, new_version, install_list.get(),
+ *product);
+
+ // Create Version key for each distribution (if not already present) and set
+ // the new product version as the last step.
+ HKEY root = product->system_level() ? HKEY_LOCAL_MACHINE :
+ HKEY_CURRENT_USER;
+ std::wstring version_key(product->distribution()->GetVersionKey());
+ install_list->AddCreateRegKeyWorkItem(root, version_key);
+
+ std::wstring product_name(product->distribution()->GetAppShortCutName());
+ install_list->AddSetRegValueWorkItem(root, version_key,
+ google_update::kRegNameField,
+ product_name,
+ true); // overwrite name also
+ install_list->AddSetRegValueWorkItem(root, version_key,
+ google_update::kRegOopcrashesField,
+ 1,
+ false); // set during first install
+ install_list->AddSetRegValueWorkItem(root, version_key,
+ google_update::kRegVersionField,
+ new_version.GetString(),
+ true); // overwrite version
+ }
if (!install_list->Do() ||
- !DoPostInstallTasks(reg_root, exe_path, install_path,
- new_chrome_exe, *current_version, new_version)) {
+ !DoPostInstallTasks(setup_path, new_chrome_exe, current_version->get(),
+ new_version, package)) {
installer_util::InstallStatus result =
- (file_util::PathExists(FilePath::FromWStringHack(new_chrome_exe)) &&
- !current_version->empty() &&
- (new_version.GetString() == *current_version)) ?
+ file_util::PathExists(new_chrome_exe) && current_version->get() &&
+ new_version.IsEqual(*current_version->get()) ?
installer_util::SAME_VERSION_REPAIR_FAILED :
installer_util::INSTALL_FAILED;
- LOG(ERROR) << "Install failed, rolling back... ";
+ LOG(ERROR) << "Install failed, rolling back... result: " << result;
install_list->Rollback();
LOG(ERROR) << "Rollback complete. ";
return result;
}
- scoped_ptr<installer::Version> installed_version;
- if (!current_version->empty())
- installed_version.reset(
- installer::Version::GetVersionFromString(*current_version));
- if (!installed_version.get()) {
+
+ if (!current_version->get()) {
VLOG(1) << "First install of version " << new_version.GetString();
return installer_util::FIRST_INSTALL_SUCCESS;
}
- if (new_version.GetString() == installed_version->GetString()) {
+
+ if (new_version.IsEqual(*current_version->get())) {
VLOG(1) << "Install repaired of version " << new_version.GetString();
return installer_util::INSTALL_REPAIRED;
}
- if (new_version.IsHigherThan(installed_version.get())) {
- if (file_util::PathExists(FilePath::FromWStringHack(new_chrome_exe))) {
+
+ if (new_version.IsHigherThan(current_version->get())) {
+ if (file_util::PathExists(new_chrome_exe)) {
VLOG(1) << "Version updated to " << new_version.GetString()
- << " while running " << installed_version->GetString();
+ << " while running " << (*current_version)->GetString();
return installer_util::IN_USE_UPDATED;
}
VLOG(1) << "Version updated to " << new_version.GetString();
return installer_util::NEW_VERSION_UPDATED;
}
+
LOG(ERROR) << "Not sure how we got here while updating"
<< ", new version: " << new_version.GetString()
- << ", old version: " << installed_version->GetString();
+ << ", old version: " << (*current_version)->GetString();
+
return installer_util::INSTALL_FAILED;
}
-} // namespace
+} // end namespace
-std::wstring installer::GetInstallerPathUnderChrome(
- const std::wstring& install_path, const std::wstring& new_version) {
- std::wstring installer_path(install_path);
- file_util::AppendToPath(&installer_path, new_version);
- file_util::AppendToPath(&installer_path, installer_util::kInstallerDir);
- return installer_path;
-}
+namespace installer {
-installer_util::InstallStatus installer::InstallOrUpdateChrome(
- const std::wstring& exe_path, const std::wstring& archive_path,
- const std::wstring& install_temp_path, const std::wstring& prefs_path,
+installer_util::InstallStatus InstallOrUpdateChrome(
+ const FilePath& setup_path, const FilePath& archive_path,
+ const FilePath& install_temp_path, const FilePath& prefs_path,
const installer_util::MasterPreferences& prefs, const Version& new_version,
- const Version* installed_version) {
- bool system_install = false;
- prefs.GetBool(installer_util::master_preferences::kSystemLevel,
- &system_install);
- std::wstring install_path(GetChromeInstallPath(system_install));
- if (install_path.empty()) {
- LOG(ERROR) << "Could not get installation destination path.";
- return installer_util::INSTALL_FAILED;
- }
- VLOG(1) << "install destination path: " << install_path;
+ const Package& install) {
+ bool system_install = install.system_level();
- std::wstring src_path(install_temp_path);
- file_util::AppendToPath(&src_path, std::wstring(kInstallSourceDir));
- file_util::AppendToPath(&src_path, std::wstring(kInstallSourceChromeDir));
+ FilePath src_path(install_temp_path);
+ src_path = src_path.Append(kInstallSourceDir).Append(kInstallSourceChromeDir);
- HKEY reg_root = (system_install) ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER;
- std::wstring current_version;
- installer_util::InstallStatus result = InstallNewVersion(exe_path,
- archive_path, src_path, install_path, install_temp_path, reg_root,
- new_version, &current_version);
+ scoped_ptr<Version> existing_version;
+ installer_util::InstallStatus result = InstallNewVersion(setup_path,
+ archive_path, src_path, install_temp_path, new_version,
+ &existing_version, install);
- BrowserDistribution* dist = BrowserDistribution::GetDistribution();
- if (!dist->GetInstallReturnCode(result)) {
+ if (!BrowserDistribution::GetInstallReturnCode(result)) {
if (result == installer_util::FIRST_INSTALL_SUCCESS)
- CopyPreferenceFileForFirstRun(system_install, prefs_path);
-
- bool value = false;
- // TODO(tommi): Currently this only creates shortcuts for Chrome, but
- // for other products we might want to create shortcuts.
- if (prefs.install_chrome() &&
- (!prefs.GetBool(
- installer_util::master_preferences::kDoNotCreateShortcuts,
- &value) || !value)) {
+ CopyPreferenceFileForFirstRun(install, prefs_path);
+
+ bool do_not_create_shortcuts = false;
+ prefs.GetBool(installer_util::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);
+ if (chrome_install && !do_not_create_shortcuts) {
bool create_all_shortcut = false;
prefs.GetBool(installer_util::master_preferences::kCreateAllShortcuts,
&create_all_shortcut);
bool alt_shortcut = false;
prefs.GetBool(installer_util::master_preferences::kAltShortcutText,
&alt_shortcut);
- if (!CreateOrUpdateChromeShortcuts(exe_path, install_path,
- new_version.GetString(), result,
- system_install, create_all_shortcut,
+ if (!CreateOrUpdateChromeShortcuts(setup_path, new_version, result,
+ *chrome_install, create_all_shortcut,
alt_shortcut)) {
- LOG(WARNING) << "Failed to create/update start menu shortcut.";
+ PLOG(WARNING) << "Failed to create/update start menu shortcut.";
}
bool make_chrome_default = false;
@@ -797,15 +810,43 @@ installer_util::InstallStatus installer::InstallOrUpdateChrome(
&force_chrome_default_for_user);
}
- RegisterChromeOnMachine(install_path, system_install,
+ RegisterChromeOnMachine(*chrome_install,
make_chrome_default || force_chrome_default_for_user);
}
- std::wstring latest_version_to_keep(new_version.GetString());
- if (!current_version.empty())
- latest_version_to_keep.assign(current_version);
- RemoveOldVersionDirs(install_path, latest_version_to_keep);
+ install.RemoveOldVersionDirectories(existing_version.get() ?
+ *existing_version.get() : new_version);
}
return result;
}
+
+bool RegisterComDllList(const FilePath& dll_folder, bool system_level,
+ bool do_register, bool rollback_on_failure) {
+ bool success = false;
+ scoped_ptr<WorkItemList> work_item_list;
+ if (rollback_on_failure) {
+ work_item_list.reset(WorkItem::CreateWorkItemList());
+ } else {
+ work_item_list.reset(WorkItem::CreateNoRollbackWorkItemList());
+ }
+
+ // TODO(robertshield): What if the list of old dlls and new ones isn't
+ // the same? I (elmo) think we should start storing the list of DLLs
+ // somewhere.
+ if (InstallUtil::BuildDLLRegistrationList(dll_folder.value(), kDllsToRegister,
+ kNumDllsToRegister, do_register,
+ !system_level,
+ work_item_list.get())) {
+ // Ignore failures to unregister old DLLs.
+ success = work_item_list->Do();
+ if (!success && rollback_on_failure) {
+ work_item_list->Rollback();
+ }
+ }
+
+ return success;
+}
+
+} // namespace installer
+
diff --git a/chrome/installer/setup/install.h b/chrome/installer/setup/install.h
index 1c8ccc4..bccb7e2 100644
--- a/chrome/installer/setup/install.h
+++ b/chrome/installer/setup/install.h
@@ -9,7 +9,9 @@
#pragma once
#include <string>
+#include <vector>
+#include "chrome/installer/util/product.h"
#include "chrome/installer/util/master_preferences.h"
#include "chrome/installer/util/util_constants.h"
#include "chrome/installer/util/version.h"
@@ -17,15 +19,13 @@
class DictionaryValue;
namespace installer {
-// Get path to the installer under Chrome version folder
-// (for example <path>\Google\Chrome\<Version>\installer)
-std::wstring GetInstallerPathUnderChrome(const std::wstring& install_path,
- const std::wstring& new_version);
+
+class Package;
// This function installs or updates a new version of Chrome. It returns
// install status (failed, new_install, updated etc).
//
-// exe_path: Path to the executable (setup.exe) as it will be copied
+// setup_path: Path to the executable (setup.exe) as it will be copied
// to Chrome install folder after install is complete
// archive_path: Path to the archive (chrome.7z) as it will be copied
// to Chrome install folder after install is complete
@@ -34,16 +34,25 @@ std::wstring GetInstallerPathUnderChrome(const std::wstring& install_path,
// and unpacked Chrome package.
// prefs: master preferences. See chrome/installer/util/master_preferences.h.
// new_version: new Chrome version that needs to be installed
-// installed_version: currently installed version of Chrome, if any, or
-// NULL otherwise
+// package: Represents the target installation folder and all distributions
+// to be installed in that folder.
//
// Note: since caller unpacks Chrome to install_temp_path\source, the caller
// is responsible for cleaning up install_temp_path.
installer_util::InstallStatus InstallOrUpdateChrome(
- const std::wstring& exe_path, const std::wstring& archive_path,
- const std::wstring& install_temp_path, const std::wstring& prefs_path,
+ const FilePath& setup_path, const FilePath& archive_path,
+ const FilePath& install_temp_path, const FilePath& prefs_path,
const installer_util::MasterPreferences& prefs, const Version& new_version,
- const Version* installed_version);
-}
+ const Package& package);
+
+// Registers or unregisters COM DLLs in a specific folder as declared in
+// kDllsToRegister.
+// TODO(robertshield): What if the list of old dlls and new ones isn't
+// the same? I think we should start storing the list of DLLs somewhere as
+// part of the installation data.
+bool RegisterComDllList(const FilePath& dll_folder, bool system_level,
+ bool do_register, bool rollback_on_failure);
+
+} // namespace installer
#endif // CHROME_INSTALLER_SETUP_INSTALL_H_
diff --git a/chrome/installer/setup/setup_main.cc b/chrome/installer/setup/setup_main.cc
index 7d0725c..d9ace56 100644
--- a/chrome/installer/setup/setup_main.cc
+++ b/chrome/installer/setup/setup_main.cc
@@ -44,6 +44,14 @@
#include "installer_util_strings.h"
+using installer::Product;
+using installer::ProductPackageMapping;
+using installer::Products;
+using installer::Package;
+using installer::Packages;
+using installer::Version;
+using installer_util::MasterPreferences;
+
namespace {
// This method unpacks and uncompresses the given archive file. For Chrome
@@ -55,39 +63,41 @@ namespace {
// (chrome.7z) or uncompressed archive patch file (chrome_patch.diff). If it
// is patch file, it is applied to the old archive file that should be
// present on the system already. As the final step the new archive file
-// is unpacked in the path specified by parameter "path".
-DWORD UnPackArchive(const std::wstring& archive, bool system_install,
- const installer::Version* installed_version,
- const std::wstring& temp_path, const std::wstring& path,
+// is unpacked in the path specified by parameter "output_directory".
+DWORD UnPackArchive(const FilePath& archive,
+ const Package& installation,
+ const FilePath& temp_path,
+ const FilePath& output_directory,
bool& incremental_install) {
// First uncompress the payload. This could be a differential
// update (patch.7z) or full archive (chrome.7z). If this uncompress fails
// return with error.
std::wstring unpacked_file;
- int32 ret = LzmaUtil::UnPackArchive(archive, temp_path, &unpacked_file);
+ int32 ret = LzmaUtil::UnPackArchive(archive.value(), temp_path.value(),
+ &unpacked_file);
if (ret != NO_ERROR)
return ret;
- std::wstring uncompressed_archive(temp_path);
- file_util::AppendToPath(&uncompressed_archive, installer::kChromeArchive);
+ FilePath uncompressed_archive(temp_path.Append(installer::kChromeArchive));
+ scoped_ptr<Version> archive_version(
+ setup_util::GetVersionFromArchiveDir(installation.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
// it is a differential installer if chrome.7z is not found.
- if (!file_util::PathExists(FilePath::FromWStringHack(uncompressed_archive))) {
+ if (!file_util::PathExists(uncompressed_archive)) {
incremental_install = true;
VLOG(1) << "Differential patch found. Applying to existing archive.";
- if (!installed_version) {
+ if (!archive_version.get()) {
LOG(ERROR) << "Can not use differential update when Chrome is not "
<< "installed on the system.";
return installer_util::CHROME_NOT_INSTALLED;
}
- std::wstring existing_archive =
- installer::GetChromeInstallPath(system_install);
- file_util::AppendToPath(&existing_archive,
- installed_version->GetString());
- file_util::AppendToPath(&existing_archive, installer_util::kInstallerDir);
- file_util::AppendToPath(&existing_archive, installer::kChromeArchive);
+
+ FilePath existing_archive(
+ installation.path().Append(archive_version->GetString()));
+ existing_archive = existing_archive.Append(installer_util::kInstallerDir);
+ existing_archive = existing_archive.Append(installer::kChromeArchive);
if (int i = setup_util::ApplyDiffPatch(FilePath(existing_archive),
FilePath(unpacked_file),
FilePath(uncompressed_archive))) {
@@ -97,7 +107,8 @@ DWORD UnPackArchive(const std::wstring& archive, bool system_install,
}
// Unpack the uncompressed archive.
- return LzmaUtil::UnPackArchive(uncompressed_archive, path, &unpacked_file);
+ return LzmaUtil::UnPackArchive(uncompressed_archive.value(),
+ output_directory.value(), &unpacked_file);
}
@@ -106,39 +117,45 @@ DWORD UnPackArchive(const std::wstring& archive, bool system_install,
// for Chrome so there should be a file called new_chrome.exe on the file
// 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_util::InstallStatus RenameChromeExecutables(bool system_install) {
- std::wstring chrome_path(installer::GetChromeInstallPath(system_install));
-
- std::wstring chrome_exe(chrome_path);
- file_util::AppendToPath(&chrome_exe, installer_util::kChromeExe);
- std::wstring chrome_old_exe(chrome_path);
- file_util::AppendToPath(&chrome_old_exe, installer_util::kChromeOldExe);
- std::wstring chrome_new_exe(chrome_path);
- file_util::AppendToPath(&chrome_new_exe, installer_util::kChromeNewExe);
+installer_util::InstallStatus RenameChromeExecutables(
+ const Package& installation) {
+ FilePath chrome_exe(installation.path().Append(installer_util::kChromeExe));
+ FilePath chrome_old_exe(installation.path().Append(
+ installer_util::kChromeOldExe));
+ FilePath chrome_new_exe(installation.path().Append(
+ installer_util::kChromeNewExe));
scoped_ptr<WorkItemList> install_list(WorkItem::CreateWorkItemList());
- install_list->AddDeleteTreeWorkItem(chrome_old_exe, std::wstring());
+ install_list->AddDeleteTreeWorkItem(chrome_old_exe.value(), std::wstring());
FilePath temp_path;
if (!file_util::CreateNewTempDirectory(L"chrome_", &temp_path)) {
LOG(ERROR) << "Failed to create Temp directory " << temp_path.value();
return installer_util::RENAME_FAILED;
}
- install_list->AddCopyTreeWorkItem(chrome_new_exe,
- chrome_exe,
+
+ install_list->AddCopyTreeWorkItem(chrome_new_exe.value(),
+ chrome_exe.value(),
temp_path.ToWStringHack(),
WorkItem::IF_DIFFERENT,
std::wstring());
- HKEY reg_root = system_install ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER;
- BrowserDistribution *dist = BrowserDistribution::GetDistribution();
- install_list->AddDeleteRegValueWorkItem(reg_root,
- dist->GetVersionKey(),
- google_update::kRegOldVersionField,
- true);
- install_list->AddDeleteTreeWorkItem(chrome_new_exe, std::wstring());
- install_list->AddDeleteRegValueWorkItem(reg_root,
- dist->GetVersionKey(),
- google_update::kRegRenameCmdField,
- true);
+ install_list->AddDeleteTreeWorkItem(chrome_new_exe.value(), std::wstring());
+
+ HKEY reg_root = installation.system_level() ? HKEY_LOCAL_MACHINE :
+ HKEY_CURRENT_USER;
+ const Products& products = installation.products();
+ for (size_t i = 0; i < products.size(); ++i) {
+ const Product* product = products[i];
+ BrowserDistribution* browser_dist = product->distribution();
+ std::wstring version_key(browser_dist->GetVersionKey());
+ install_list->AddDeleteRegValueWorkItem(reg_root,
+ version_key,
+ google_update::kRegOldVersionField,
+ true);
+ install_list->AddDeleteRegValueWorkItem(reg_root,
+ version_key,
+ google_update::kRegRenameCmdField,
+ true);
+ }
installer_util::InstallStatus ret = installer_util::RENAME_SUCCESSFUL;
if (!install_list->Do()) {
LOG(ERROR) << "Renaming of executables failed. Rolling back any changes.";
@@ -149,67 +166,82 @@ installer_util::InstallStatus RenameChromeExecutables(bool system_install) {
return ret;
}
-bool CheckPreInstallConditions(const installer::Version* installed_version,
- bool system_install,
+bool CheckPreInstallConditions(const Package& installation,
installer_util::InstallStatus& status) {
- bool is_first_install = (NULL == installed_version);
- // Check to avoid simultaneous per-user and per-machine installs.
- scoped_ptr<installer::Version>
- chrome_version(InstallUtil::GetChromeVersion(!system_install));
- if (chrome_version.get()) {
- LOG(ERROR) << "Already installed version " << chrome_version->GetString()
- << " conflicts with the current install mode.";
- if (!system_install && is_first_install) {
- // 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.
- std::wstring chrome_exe(installer::GetChromeInstallPath(!system_install));
- if (chrome_exe.empty()) {
- // If we failed to construct install path. Give up.
- status = installer_util::OS_ERROR;
- InstallUtil::WriteInstallerResult(system_install, status,
- IDS_INSTALL_OS_ERROR_BASE, NULL);
- return false;
- } else {
- status = installer_util::EXISTING_VERSION_LAUNCHED;
- file_util::AppendToPath(&chrome_exe, installer_util::kChromeExe);
- chrome_exe = L"\"" + chrome_exe + L"\" --"
- + ASCIIToWide(switches::kFirstRun);
- InstallUtil::WriteInstallerResult(system_install, status,
- 0, NULL);
- VLOG(1) << "Launching existing system-level chrome instead.";
- base::LaunchApp(chrome_exe, false, false, NULL);
+ const Products& products = installation.products();
+ DCHECK(products.size());
+
+ bool is_first_install = true;
+
+ for (size_t i = 0; i < products.size(); ++i) {
+ const Product* product = products[i];
+ BrowserDistribution* browser_dist = product->distribution();
+ scoped_ptr<Version> installed_version(product->GetInstalledVersion());
+ // TODO(tommi): If the current install is for a different distribution than
+ // that might already be installed, then this check is incorrect.
+ if (installed_version.get())
+ is_first_install = false;
+
+ // Check to avoid simultaneous per-user and per-machine installs.
+ scoped_ptr<Version> chrome_version(
+ InstallUtil::GetChromeVersion(browser_dist, !product->system_level()));
+
+ if (chrome_version.get()) {
+ LOG(ERROR) << "Already installed version " << chrome_version->GetString()
+ << " conflicts with the current install mode.";
+ if (!product->system_level() && is_first_install) {
+ // 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.
+ FilePath chrome_exe(installer::GetChromeInstallPath(
+ !product->system_level(), browser_dist));
+ if (chrome_exe.empty()) {
+ // If we failed to construct install path. Give up.
+ status = installer_util::OS_ERROR;
+ product->WriteInstallerResult(status, IDS_INSTALL_OS_ERROR_BASE,
+ NULL);
+ } else {
+ status = installer_util::EXISTING_VERSION_LAUNCHED;
+ chrome_exe = chrome_exe.Append(installer_util::kChromeExe);
+ CommandLine cmd(chrome_exe);
+ cmd.AppendSwitch(switches::kFirstRun);
+ product->WriteInstallerResult(status, 0, NULL);
+ VLOG(1) << "Launching existing system-level chrome instead.";
+ base::LaunchApp(cmd, false, false, NULL);
+ }
return false;
}
+
+ // 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_util::SXS_OPTION_NOT_SUPPORTED == 33,
+ dont_change_enum);
+
+ // This is an update, not an install. Omaha should know the difference
+ // and not show a dialog.
+ status = product->system_level() ?
+ installer_util::USER_LEVEL_INSTALL_EXISTS :
+ installer_util::SYSTEM_LEVEL_INSTALL_EXISTS;
+ int str_id = product->system_level() ?
+ IDS_INSTALL_USER_LEVEL_EXISTS_BASE :
+ IDS_INSTALL_SYSTEM_LEVEL_EXISTS_BASE;
+ product->WriteInstallerResult(status, str_id, NULL);
+ return false;
}
- // 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_util::SXS_OPTION_NOT_SUPPORTED == 33,
- dont_change_enum);
-
- // This is an update, not an install. Omaha should know the difference
- // and not show a dialog.
- status = system_install ? installer_util::USER_LEVEL_INSTALL_EXISTS :
- installer_util::SYSTEM_LEVEL_INSTALL_EXISTS;
- int str_id = system_install ? IDS_INSTALL_USER_LEVEL_EXISTS_BASE :
- IDS_INSTALL_SYSTEM_LEVEL_EXISTS_BASE;
- InstallUtil::WriteInstallerResult(system_install, status, str_id, NULL);
- return false;
}
+
// 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) {
- FilePath install_path = FilePath::FromWStringHack(
- installer::GetChromeInstallPath(system_install));
- if (file_util::PathExists(install_path) &&
- !file_util::Delete(install_path, true)) {
- LOG(ERROR) << "Installation directory " << install_path.value()
+ if (file_util::PathExists(installation.path()) &&
+ !file_util::Delete(installation.path(), true)) {
+ LOG(ERROR) << "Installation directory " << installation.path().value()
<< " exists and can not be deleted.";
status = installer_util::INSTALL_DIR_IN_USE;
int str_id = IDS_INSTALL_DIR_IN_USE_BASE;
- InstallUtil::WriteInstallerResult(system_install, status, str_id, NULL);
+ WriteInstallerResult(products, status, str_id, NULL);
return false;
}
}
@@ -218,21 +250,15 @@ bool CheckPreInstallConditions(const installer::Version* installed_version,
}
installer_util::InstallStatus InstallChrome(const CommandLine& cmd_line,
- const installer::Version* installed_version,
- const installer_util::MasterPreferences& prefs) {
- bool system_level = false;
- prefs.GetBool(installer_util::master_preferences::kSystemLevel,
- &system_level);
+ const Package& installation, const MasterPreferences& prefs) {
installer_util::InstallStatus install_status = installer_util::UNKNOWN_STATUS;
- if (!CheckPreInstallConditions(installed_version,
- system_level, install_status))
+ if (!CheckPreInstallConditions(installation, install_status))
return install_status;
// For install the default location for chrome.packed.7z is in current
// folder, so get that value first.
- FilePath archive =
- cmd_line.GetProgram().DirName().Append(
- installer::kChromeCompressedArchive);
+ FilePath archive(cmd_line.GetProgram().DirName().Append(
+ installer::kChromeCompressedArchive));
// If --install-archive is given, get the user specified value
if (cmd_line.HasSwitch(installer_util::switches::kInstallArchive)) {
@@ -240,120 +266,133 @@ installer_util::InstallStatus InstallChrome(const CommandLine& cmd_line,
installer_util::switches::kInstallArchive);
}
VLOG(1) << "Archive found to install Chrome " << archive.value();
+ bool system_level = installation.system_level();
+ const Products& products = installation.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(system_level,
- installer_util::TEMP_DIR_FAILED,
- IDS_INSTALL_TEMP_DIR_FAILED_BASE,
- NULL);
+ WriteInstallerResult(products, installer_util::TEMP_DIR_FAILED,
+ IDS_INSTALL_TEMP_DIR_FAILED_BASE, NULL);
return installer_util::TEMP_DIR_FAILED;
}
VLOG(1) << "created path " << temp_path.value();
- BrowserDistribution* dist = BrowserDistribution::GetDistribution();
- std::wstring unpack_path(temp_path.ToWStringHack());
- file_util::AppendToPath(&unpack_path,
- std::wstring(installer::kInstallSourceDir));
+ FilePath unpack_path(temp_path.Append(installer::kInstallSourceDir));
bool incremental_install = false;
- if (UnPackArchive(archive.value(), system_level, installed_version,
- temp_path.ToWStringHack(), unpack_path,
+ if (UnPackArchive(archive, installation,temp_path, unpack_path,
incremental_install)) {
install_status = installer_util::UNCOMPRESSION_FAILED;
- InstallUtil::WriteInstallerResult(system_level, install_status,
- IDS_INSTALL_UNCOMPRESSION_FAILED_BASE,
- NULL);
+ WriteInstallerResult(products, install_status,
+ IDS_INSTALL_UNCOMPRESSION_FAILED_BASE, NULL);
} else {
- VLOG(1) << "unpacked to " << unpack_path;
- std::wstring src_path(unpack_path);
- file_util::AppendToPath(&src_path,
- std::wstring(installer::kInstallSourceChromeDir));
- scoped_ptr<installer::Version>
- installer_version(setup_util::GetVersionFromDir(FilePath(src_path)));
+ VLOG(1) << "unpacked to " << unpack_path.value();
+ FilePath src_path(unpack_path.Append(installer::kInstallSourceChromeDir));
+ scoped_ptr<Version>
+ installer_version(setup_util::GetVersionFromArchiveDir(src_path));
if (!installer_version.get()) {
LOG(ERROR) << "Did not find any valid version in installer.";
install_status = installer_util::INVALID_ARCHIVE;
- InstallUtil::WriteInstallerResult(system_level, install_status,
- IDS_INSTALL_INVALID_ARCHIVE_BASE, NULL);
+ WriteInstallerResult(products, install_status,
+ IDS_INSTALL_INVALID_ARCHIVE_BASE, NULL);
} else {
+ // TODO(tommi): Move towards having only a single version that is common
+ // to all products. Only the package should have a version since it
+ // represents all the binaries. When a single product is upgraded, all
+ // currently installed product for the shared binary installation, should
+ // (or rather must) be upgraded.
VLOG(1) << "version to install: " << installer_version->GetString();
- if (installed_version &&
- installed_version->IsHigherThan(installer_version.get())) {
- LOG(ERROR) << "Higher version is already installed.";
- install_status = installer_util::HIGHER_VERSION_EXISTS;
-
- int result_resource_id = IDS_INSTALL_HIGHER_VERSION_BASE;
- if (InstallUtil::IsChromeFrameProcess()) {
- result_resource_id = IDS_INSTALL_HIGHER_VERSION_CF_BASE;
+ bool higher_version_installed = false;
+ for (size_t i = 0; i < installation.products().size(); ++i) {
+ const Product* product = installation.products()[i];
+ scoped_ptr<Version> v(product->GetInstalledVersion());
+ if (v.get() && v->IsHigherThan(installer_version.get())) {
+ LOG(ERROR) << "Higher version is already installed.";
+ higher_version_installed = true;
+ install_status = installer_util::HIGHER_VERSION_EXISTS;
+
+ if (product->distribution()->GetType() !=
+ BrowserDistribution::CHROME_BROWSER) {
+ // TODO(robertshield): We should take the installer result text
+ // strings from the Product.
+ product->WriteInstallerResult(install_status,
+ IDS_INSTALL_HIGHER_VERSION_BASE, NULL);
+ } else {
+ product->WriteInstallerResult(install_status,
+ IDS_INSTALL_HIGHER_VERSION_CF_BASE, NULL);
+ }
}
- InstallUtil::WriteInstallerResult(system_level,
- install_status,
- result_resource_id,
- NULL);
- } else {
+ }
+
+ if (!higher_version_installed) {
// We want to keep uncompressed archive (chrome.7z) that we get after
// uncompressing and binary patching. Get the location for this file.
- FilePath archive_to_copy = temp_path.Append(installer::kChromeArchive);
- std::wstring prefs_source_path = cmd_line.GetSwitchValueNative(
- installer_util::switches::kInstallerData);
- install_status = installer::InstallOrUpdateChrome(
- cmd_line.GetProgram().value(), archive_to_copy.value(),
- temp_path.ToWStringHack(),
- prefs_source_path, prefs, *installer_version, installed_version);
+ FilePath archive_to_copy(temp_path.Append(installer::kChromeArchive));
+ FilePath prefs_source_path(cmd_line.GetSwitchValueNative(
+ installer_util::switches::kInstallerData));
+ install_status = installer::InstallOrUpdateChrome(cmd_line.GetProgram(),
+ archive_to_copy, temp_path, prefs_source_path, prefs,
+ *installer_version, installation);
int install_msg_base = IDS_INSTALL_FAILED_BASE;
std::wstring chrome_exe;
if (install_status == installer_util::SAME_VERSION_REPAIR_FAILED) {
- if (InstallUtil::IsChromeFrameProcess()) {
+ if (FindProduct(products, 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_util::INSTALL_FAILED) {
- chrome_exe = installer::GetChromeInstallPath(system_level);
- if (chrome_exe.empty()) {
+ if (installation.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_util::OS_ERROR;
} else {
- file_util::AppendToPath(&chrome_exe, installer_util::kChromeExe);
+ chrome_exe = installation.path()
+ .Append(installer_util::kChromeExe).value();
chrome_exe = L"\"" + chrome_exe + L"\"";
install_msg_base = 0;
}
}
+ const Product* chrome_install =
+ FindProduct(products, BrowserDistribution::CHROME_BROWSER);
+
bool value = false;
- if (prefs.install_chrome()) {
+ if (chrome_install) {
prefs.GetBool(
installer_util::master_preferences::kDoNotRegisterForUpdateLaunch,
&value);
} else {
value = true; // Never register.
}
+
bool write_chrome_launch_string = (!value) &&
(install_status != installer_util::IN_USE_UPDATED);
- InstallUtil::WriteInstallerResult(system_level, install_status,
+ WriteInstallerResult(products, install_status,
install_msg_base, write_chrome_launch_string ? &chrome_exe : NULL);
if (install_status == installer_util::FIRST_INSTALL_SUCCESS) {
VLOG(1) << "First install successful.";
- if (prefs.install_chrome()) {
+ if (chrome_install) {
// We never want to launch Chrome in system level install mode.
bool do_not_launch_chrome = false;
prefs.GetBool(
installer_util::master_preferences::kDoNotLaunchChrome,
&do_not_launch_chrome);
- if (!system_level && !do_not_launch_chrome)
- installer::LaunchChrome(system_level);
+ if (!chrome_install->system_level() && !do_not_launch_chrome)
+ chrome_install->LaunchChrome();
}
} else if ((install_status == installer_util::NEW_VERSION_UPDATED) ||
(install_status == installer_util::IN_USE_UPDATED)) {
- installer_setup::RemoveLegacyRegistryKeys();
+ for (size_t i = 0; i < products.size(); ++i) {
+ installer::RemoveLegacyRegistryKeys(
+ products[i]->distribution());
+ }
}
}
}
@@ -364,8 +403,11 @@ installer_util::InstallStatus InstallChrome(const CommandLine& cmd_line,
//
// There is another way to reach this same function if this is a system
// level install. See HandleNonInstallCmdLineOptions().
- dist->LaunchUserExperiment(install_status, *installer_version,
- system_level);
+ for (size_t i = 0; i < products.size(); ++i) {
+ const Product* product = products[i];
+ product->distribution()->LaunchUserExperiment(install_status,
+ *installer_version, *product, product->system_level());
+ }
}
// Delete temporary files. These include install temporary directory
@@ -395,31 +437,36 @@ installer_util::InstallStatus InstallChrome(const CommandLine& cmd_line,
}
}
- dist->UpdateDiffInstallStatus(system_level, incremental_install,
- install_status);
+ for (size_t i = 0; i < products.size(); ++i) {
+ const Product* product = products[i];
+ product->distribution()->UpdateDiffInstallStatus(system_level,
+ incremental_install, install_status);
+ }
+
return install_status;
}
installer_util::InstallStatus UninstallChrome(const CommandLine& cmd_line,
- const installer::Version* version,
- bool system_install) {
+ const Product& product) {
VLOG(1) << "Uninstalling Chome";
+
+ scoped_ptr<Version> installed_version(product.GetInstalledVersion());
+ if (installed_version.get())
+ VLOG(1) << "version on the system: " << installed_version->GetString();
+
bool force = cmd_line.HasSwitch(installer_util::switches::kForceUninstall);
- if (!version && !force) {
+ if (!installed_version.get() && !force) {
LOG(ERROR) << "No Chrome installation found for uninstall.";
- InstallUtil::WriteInstallerResult(system_install,
- installer_util::CHROME_NOT_INSTALLED,
- IDS_UNINSTALL_FAILED_BASE, NULL);
+ product.WriteInstallerResult(installer_util::CHROME_NOT_INSTALLED,
+ IDS_UNINSTALL_FAILED_BASE, NULL);
return installer_util::CHROME_NOT_INSTALLED;
}
bool remove_all = !cmd_line.HasSwitch(
installer_util::switches::kDoNotRemoveSharedItems);
- return installer_setup::UninstallChrome(cmd_line.GetProgram().value(),
- system_install,
- remove_all, force,
- cmd_line);
+ return installer::UninstallChrome(cmd_line.GetProgram(), product, remove_all,
+ force, cmd_line);
}
installer_util::InstallStatus ShowEULADialog(const std::wstring& inner_frame) {
@@ -454,9 +501,9 @@ installer_util::InstallStatus ShowEULADialog(const std::wstring& inner_frame) {
// 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 CommandLine& cmd_line,
- bool system_install,
- int& exit_code) {
- BrowserDistribution* dist = BrowserDistribution::GetDistribution();
+ int& exit_code,
+ const ProductPackageMapping& installs) {
+ DCHECK(installs.products().size());
if (cmd_line.HasSwitch(installer_util::switches::kUpdateSetupExe)) {
installer_util::InstallStatus status = installer_util::SETUP_PATCH_FAILED;
// If --update-setup-exe command line option is given, we apply the given
@@ -483,11 +530,11 @@ bool HandleNonInstallCmdLineOptions(const CommandLine& cmd_line,
}
}
- exit_code = dist->GetInstallReturnCode(status);
+ exit_code = BrowserDistribution::GetInstallReturnCode(status);
if (exit_code) {
LOG(WARNING) << "setup.exe patching failed.";
- InstallUtil::WriteInstallerResult(system_install, status,
- IDS_SETUP_PATCH_FAILED_BASE, NULL);
+ WriteInstallerResult(installs.products(), status,
+ IDS_SETUP_PATCH_FAILED_BASE, NULL);
}
file_util::Delete(temp_path, true);
return true;
@@ -502,25 +549,37 @@ bool HandleNonInstallCmdLineOptions(const CommandLine& cmd_line,
return true;
} else if (cmd_line.HasSwitch(
installer_util::switches::kRegisterChromeBrowser)) {
- // If --register-chrome-browser option is specified, register all
- // Chrome protocol/file associations as well as register it as a valid
- // browser for Start Menu->Internet shortcut. This option should only
- // be used when setup.exe is launched with admin rights. We do not
- // make any user specific changes in this option.
- std::wstring chrome_exe(cmd_line.GetSwitchValueNative(
- installer_util::switches::kRegisterChromeBrowser));
- std::wstring suffix;
- if (cmd_line.HasSwitch(
- installer_util::switches::kRegisterChromeBrowserSuffix)) {
- suffix = cmd_line.GetSwitchValueNative(
- installer_util::switches::kRegisterChromeBrowserSuffix);
+ const Product* chrome_install =
+ FindProduct(installs.products(), BrowserDistribution::CHROME_BROWSER);
+ DCHECK(chrome_install);
+ if (chrome_install) {
+ // If --register-chrome-browser option is specified, register all
+ // Chrome protocol/file associations as well as register it as a valid
+ // browser for Start Menu->Internet shortcut. This option should only
+ // be used when setup.exe is launched with admin rights. We do not
+ // make any user specific changes in this option.
+ std::wstring chrome_exe(cmd_line.GetSwitchValueNative(
+ installer_util::switches::kRegisterChromeBrowser));
+ std::wstring suffix;
+ if (cmd_line.HasSwitch(
+ installer_util::switches::kRegisterChromeBrowserSuffix)) {
+ suffix = cmd_line.GetSwitchValueNative(
+ installer_util::switches::kRegisterChromeBrowserSuffix);
+ }
+ exit_code = ShellUtil::RegisterChromeBrowser(
+ chrome_install->distribution(), chrome_exe, suffix, false);
+ } else {
+ LOG(ERROR) << "Can't register browser - Chrome distribution not found";
+ exit_code = installer_util::UNKNOWN_STATUS;
}
- exit_code = ShellUtil::RegisterChromeBrowser(chrome_exe, suffix, false);
return true;
} else if (cmd_line.HasSwitch(installer_util::switches::kRenameChromeExe)) {
// If --rename-chrome-exe is specified, we want to rename the executables
// and exit.
- exit_code = RenameChromeExecutables(system_install);
+ 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());
return true;
} else if (cmd_line.HasSwitch(
installer_util::switches::kRemoveChromeRegistration)) {
@@ -535,26 +594,44 @@ bool HandleNonInstallCmdLineOptions(const CommandLine& cmd_line,
installer_util::switches::kRegisterChromeBrowserSuffix);
}
installer_util::InstallStatus tmp = installer_util::UNKNOWN_STATUS;
- installer_setup::DeleteChromeRegistrationKeys(HKEY_LOCAL_MACHINE,
- suffix, tmp);
+ const Product* chrome_install =
+ FindProduct(installs.products(), BrowserDistribution::CHROME_BROWSER);
+ DCHECK(chrome_install);
+ if (chrome_install) {
+ installer::DeleteChromeRegistrationKeys(chrome_install->distribution(),
+ HKEY_LOCAL_MACHINE, suffix, tmp);
+ }
exit_code = tmp;
return true;
} else if (cmd_line.HasSwitch(installer_util::switches::kInactiveUserToast)) {
// Launch the inactive user toast experiment.
- std::string flavor = cmd_line.GetSwitchValueASCII(
- installer_util::switches::kInactiveUserToast);
- int flavor_int;
- base::StringToInt(flavor, &flavor_int);
- dist->InactiveUserToastExperiment(flavor_int,
- cmd_line.HasSwitch(installer_util::switches::kSystemLevelToast));
+ int flavor = -1;
+ base::StringToInt(cmd_line.GetSwitchValueNative(
+ installer_util::switches::kInactiveUserToast), &flavor);
+ DCHECK_NE(-1, flavor);
+ if (flavor == -1) {
+ exit_code = installer_util::UNKNOWN_STATUS;
+ } else {
+ const Products& products = installs.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);
+ }
+ }
return true;
} else if (cmd_line.HasSwitch(installer_util::switches::kSystemLevelToast)) {
- // We started as system-level and have been re-launched as user level
- // to continue with the toast experiment.
- scoped_ptr<installer::Version>
- installed_version(InstallUtil::GetChromeVersion(system_install));
- dist->LaunchUserExperiment(installer_util::REENTRY_SYS_UPDATE,
- *installed_version, true);
+ const Products& products = installs.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()));
+ browser_dist->LaunchUserExperiment(installer_util::REENTRY_SYS_UPDATE,
+ *installed_version, *product, true);
+ }
return true;
}
return false;
@@ -604,9 +681,6 @@ class AutoCom {
bool Init(bool system_install) {
if (CoInitializeEx(NULL, COINIT_APARTMENTTHREADED) != S_OK) {
LOG(ERROR) << "COM initialization failed.";
- InstallUtil::WriteInstallerResult(system_install,
- installer_util::OS_ERROR,
- IDS_INSTALL_OS_ERROR_BASE, NULL);
return false;
}
initialized_ = true;
@@ -617,6 +691,25 @@ class AutoCom {
bool initialized_;
};
+void PopulateInstallations(const MasterPreferences& prefs,
+ ProductPackageMapping* installations) {
+ DCHECK(installations);
+ if (prefs.install_chrome()) {
+ VLOG(1) << "Install distribution: Chrome";
+ installations->AddDistribution(BrowserDistribution::CHROME_BROWSER);
+ }
+
+ if (prefs.install_chrome_frame()) {
+ VLOG(1) << "Install distribution: Chrome Frame";
+ installations->AddDistribution(BrowserDistribution::CHROME_FRAME);
+ }
+
+ if (prefs.install_ceee()) {
+ VLOG(1) << "Install distribution: CEEE";
+ installations->AddDistribution(BrowserDistribution::CHROME_FRAME);
+ }
+}
+
} // namespace
int WINAPI wWinMain(HINSTANCE instance, HINSTANCE prev_instance,
@@ -625,63 +718,62 @@ int WINAPI wWinMain(HINSTANCE instance, HINSTANCE prev_instance,
base::AtExitManager exit_manager;
CommandLine::Init(0, NULL);
- const installer_util::MasterPreferences& prefs =
+ const MasterPreferences& prefs =
InstallUtil::GetMasterPreferencesForCurrentProcess();
installer::InitInstallerLogging(prefs);
- const CommandLine& parsed_command_line = *CommandLine::ForCurrentProcess();
- VLOG(1) << "Command Line: " << parsed_command_line.command_line_string();
+ const CommandLine& cmd_line = *CommandLine::ForCurrentProcess();
+ VLOG(1) << "Command Line: " << cmd_line.command_line_string();
bool system_install = false;
prefs.GetBool(installer_util::master_preferences::kSystemLevel,
&system_install);
VLOG(1) << "system install is " << system_install;
+ ProductPackageMapping installations(system_install);
+ PopulateInstallations(prefs, &installations);
+
// Check to make sure current system is WinXP or later. If not, log
// error message and get out.
if (!InstallUtil::IsOSSupported()) {
LOG(ERROR) << "Chrome only supports Windows XP or later.";
- InstallUtil::WriteInstallerResult(system_install,
- installer_util::OS_NOT_SUPPORTED,
- IDS_INSTALL_OS_NOT_SUPPORTED_BASE, NULL);
+ WriteInstallerResult(installations.products(),
+ installer_util::OS_NOT_SUPPORTED, IDS_INSTALL_OS_NOT_SUPPORTED_BASE,
+ NULL);
return installer_util::OS_NOT_SUPPORTED;
}
// Initialize COM for use later.
AutoCom auto_com;
if (!auto_com.Init(system_install)) {
+ WriteInstallerResult(installations.products(),
+ installer_util::OS_ERROR, IDS_INSTALL_OS_ERROR_BASE, NULL);
return installer_util::OS_ERROR;
}
// Some command line options don't work with SxS install/uninstall
if (InstallUtil::IsChromeSxSProcess()) {
if (system_install ||
- parsed_command_line.HasSwitch(
- installer_util::switches::kForceUninstall) ||
- parsed_command_line.HasSwitch(
- installer_util::switches::kMakeChromeDefault) ||
- parsed_command_line.HasSwitch(
- installer_util::switches::kRegisterChromeBrowser) ||
- parsed_command_line.HasSwitch(
+ cmd_line.HasSwitch(installer_util::switches::kForceUninstall) ||
+ cmd_line.HasSwitch(installer_util::switches::kMakeChromeDefault) ||
+ cmd_line.HasSwitch(installer_util::switches::kRegisterChromeBrowser) ||
+ cmd_line.HasSwitch(
installer_util::switches::kRemoveChromeRegistration) ||
- parsed_command_line.HasSwitch(
- installer_util::switches::kInactiveUserToast) ||
- parsed_command_line.HasSwitch(
- installer_util::switches::kSystemLevelToast)) {
+ cmd_line.HasSwitch(installer_util::switches::kInactiveUserToast) ||
+ cmd_line.HasSwitch(installer_util::switches::kSystemLevelToast)) {
return installer_util::SXS_OPTION_NOT_SUPPORTED;
}
}
int exit_code = 0;
- if (HandleNonInstallCmdLineOptions(parsed_command_line, system_install,
- exit_code))
+ if (HandleNonInstallCmdLineOptions(cmd_line, exit_code, installations))
return exit_code;
if (system_install && !IsUserAnAdmin()) {
if (base::win::GetVersion() >= base::win::VERSION_VISTA &&
- !parsed_command_line.HasSwitch(installer_util::switches::kRunAsAdmin)) {
+ !cmd_line.HasSwitch(installer_util::switches::kRunAsAdmin)) {
CommandLine new_cmd(CommandLine::NO_PROGRAM);
- new_cmd.AppendArguments(parsed_command_line, true);
+ new_cmd.AppendArguments(cmd_line, true);
// Append --run-as-admin flag to let the new instance of setup.exe know
// that we already tried to launch ourselves as admin.
new_cmd.AppendSwitch(installer_util::switches::kRunAsAdmin);
@@ -690,45 +782,46 @@ int WINAPI wWinMain(HINSTANCE instance, HINSTANCE prev_instance,
return exit_code;
} else {
LOG(ERROR) << "Non admin user can not install system level Chrome.";
- InstallUtil::WriteInstallerResult(system_install,
- installer_util::INSUFFICIENT_RIGHTS,
- IDS_INSTALL_INSUFFICIENT_RIGHTS_BASE,
- NULL);
+ WriteInstallerResult(installations.products(),
+ installer_util::INSUFFICIENT_RIGHTS,
+ IDS_INSTALL_INSUFFICIENT_RIGHTS_BASE, NULL);
return installer_util::INSUFFICIENT_RIGHTS;
}
}
- // Check the existing version installed.
- scoped_ptr<installer::Version>
- installed_version(InstallUtil::GetChromeVersion(system_install));
- if (installed_version.get())
- VLOG(1) << "version on the system: " << installed_version->GetString();
+ bool is_uninstall = cmd_line.HasSwitch(installer_util::switches::kUninstall);
installer_util::InstallStatus install_status = installer_util::UNKNOWN_STATUS;
// If --uninstall option is given, uninstall chrome
- if (parsed_command_line.HasSwitch(installer_util::switches::kUninstall)) {
- install_status = UninstallChrome(parsed_command_line,
- installed_version.get(),
- system_install);
- // If --uninstall option is not specified, we assume it is install case.
+ if (is_uninstall) {
+ DCHECK_EQ(1U, installations.products().size()) <<
+ "We currently really only support uninstalling one distribution "
+ "at a time";
+ for (size_t i = 0; i < installations.products().size(); ++i) {
+ install_status = UninstallChrome(cmd_line,
+ *installations.products()[i]);
+ }
} else {
- install_status = InstallChrome(parsed_command_line, installed_version.get(),
- prefs);
+ // 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(cmd_line, *packages[i].get(), prefs);
+ }
}
- BrowserDistribution* dist = BrowserDistribution::GetDistribution();
+ const Product* cf_install =
+ FindProduct(installations.products(), BrowserDistribution::CHROME_FRAME);
- if (InstallUtil::IsChromeFrameProcess() &&
- !parsed_command_line.HasSwitch(
- installer_util::switches::kForceUninstall)) {
+ if (cf_install &&
+ !cmd_line.HasSwitch(installer_util::switches::kForceUninstall)) {
if (install_status == installer_util::UNINSTALL_REQUIRES_REBOOT) {
ShowRebootDialog();
- } else if (parsed_command_line.HasSwitch(
- installer_util::switches::kUninstall)) {
+ } else if (is_uninstall) {
::MessageBoxW(NULL,
installer_util::GetLocalizedString(
IDS_UNINSTALL_COMPLETE_BASE).c_str(),
- dist->GetApplicationName().c_str(),
+ cf_install->distribution()->GetApplicationName().c_str(),
MB_OK);
}
}
@@ -737,14 +830,19 @@ 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.
- if (!(InstallUtil::IsMSIProcess(system_install) &&
- parsed_command_line.HasSwitch(installer_util::switches::kUninstall))) {
- // Note that we allow the status installer_util::UNINSTALL_REQUIRES_REBOOT
- // to pass through, since this is only returned on uninstall which is never
- // invoked directly by Google Update.
- return_code = dist->GetInstallReturnCode(install_status);
+ // 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_util::UNINSTALL_REQUIRES_REBOOT
+ // to pass through, since this is only returned on uninstall which is
+ // never invoked directly by Google Update.
+ return_code = BrowserDistribution::GetInstallReturnCode(install_status);
+ }
}
VLOG(1) << "Installation complete, returning: " << return_code;
+
return return_code;
}
diff --git a/chrome/installer/setup/setup_util.cc b/chrome/installer/setup/setup_util.cc
index d4fbed1..08ea157 100644
--- a/chrome/installer/setup/setup_util.cc
+++ b/chrome/installer/setup/setup_util.cc
@@ -33,20 +33,26 @@ int setup_util::ApplyDiffPatch(const FilePath& src,
dest.value().c_str());
}
-installer::Version* setup_util::GetVersionFromDir(
+installer::Version* setup_util::GetVersionFromArchiveDir(
const FilePath& chrome_path) {
VLOG(1) << "Looking for Chrome version folder under " << chrome_path.value();
FilePath root_path = chrome_path.Append(L"*");
- WIN32_FIND_DATA find_data;
+ // TODO(tommi): The version directory really should match the version of
+ // setup.exe. To begin with, we should at least DCHECK that that's true.
+
+ // TODO(tommi): use file_util::FileEnumerator.
+ WIN32_FIND_DATA find_data = {0};
HANDLE file_handle = FindFirstFile(root_path.value().c_str(), &find_data);
BOOL ret = TRUE;
- installer::Version *version = NULL;
+ installer::Version* version = NULL;
// Here we are assuming that the installer we have is really valid so there
// can not be two version directories. We exit as soon as we find a valid
// version directory.
while (ret) {
- if (find_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
+ if (find_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY &&
+ lstrcmpW(find_data.cFileName, L"..") != 0 &&
+ lstrcmpW(find_data.cFileName, L".") != 0) {
VLOG(1) << "directory found: " << find_data.cFileName;
version = installer::Version::GetVersionFromString(find_data.cFileName);
if (version)
diff --git a/chrome/installer/setup/setup_util.h b/chrome/installer/setup/setup_util.h
index 61aed71..0858070 100644
--- a/chrome/installer/setup/setup_util.h
+++ b/chrome/installer/setup/setup_util.h
@@ -23,7 +23,7 @@ namespace setup_util {
// Find the version of Chrome from an install source directory.
// Chrome_path should contain a version folder.
// Returns the first version found or NULL if no version is found.
- installer::Version* GetVersionFromDir(const FilePath& chrome_path);
+ installer::Version* GetVersionFromArchiveDir(const FilePath& chrome_path);
} // namespace setup_util
#endif // CHROME_INSTALLER_SETUP_SETUP_UTIL_H_
diff --git a/chrome/installer/setup/setup_util_unittest.cc b/chrome/installer/setup/setup_util_unittest.cc
index 0e74de9..8161173 100644
--- a/chrome/installer/setup/setup_util_unittest.cc
+++ b/chrome/installer/setup/setup_util_unittest.cc
@@ -57,27 +57,27 @@ TEST_F(SetupUtilTest, ApplyDiffPatchTest) {
}
// Test that we are parsing Chrome version correctly.
-TEST_F(SetupUtilTest, GetVersionFromDirTest) {
+TEST_F(SetupUtilTest, GetVersionFromArchiveDirTest) {
// Create a version dir
FilePath chrome_dir = test_dir_.path().AppendASCII("1.0.0.0");
file_util::CreateDirectory(chrome_dir);
ASSERT_TRUE(file_util::PathExists(chrome_dir));
scoped_ptr<installer::Version> version(
- setup_util::GetVersionFromDir(test_dir_.path()));
+ setup_util::GetVersionFromArchiveDir(test_dir_.path()));
ASSERT_TRUE(version->GetString() == L"1.0.0.0");
file_util::Delete(chrome_dir, true);
ASSERT_FALSE(file_util::PathExists(chrome_dir));
- ASSERT_TRUE(setup_util::GetVersionFromDir(test_dir_.path()) == NULL);
+ ASSERT_TRUE(setup_util::GetVersionFromArchiveDir(test_dir_.path()) == NULL);
chrome_dir = test_dir_.path().AppendASCII("ABC");
file_util::CreateDirectory(chrome_dir);
ASSERT_TRUE(file_util::PathExists(chrome_dir));
- ASSERT_TRUE(setup_util::GetVersionFromDir(test_dir_.path()) == NULL);
+ ASSERT_TRUE(setup_util::GetVersionFromArchiveDir(test_dir_.path()) == NULL);
chrome_dir = test_dir_.path().AppendASCII("2.3.4.5");
file_util::CreateDirectory(chrome_dir);
ASSERT_TRUE(file_util::PathExists(chrome_dir));
- version.reset(setup_util::GetVersionFromDir(test_dir_.path()));
+ version.reset(setup_util::GetVersionFromArchiveDir(test_dir_.path()));
ASSERT_TRUE(version->GetString() == L"2.3.4.5");
}
diff --git a/chrome/installer/setup/uninstall.cc b/chrome/installer/setup/uninstall.cc
index 4b3ddee..1dee62d 100644
--- a/chrome/installer/setup/uninstall.cc
+++ b/chrome/installer/setup/uninstall.cc
@@ -32,8 +32,9 @@
#include "registered_dlls.h" // NOLINT
using base::win::RegKey;
+using installer_util::InstallStatus;
-namespace {
+namespace installer {
// This functions checks for any Chrome instances that are
// running and first asks them to close politely by sending a Windows message.
@@ -90,7 +91,7 @@ void CloseChromeFrameHelperProcess() {
DWORD wait = ::WaitForSingleObject(process, kWaitMs);
if (wait != WAIT_OBJECT_0) {
LOG(WARNING) << "Wait for " << installer_util::kChromeFrameHelperExe
- << " to exit failed or timed out.";
+ << " to exit failed or timed out.";
} else {
kill = false;
VLOG(1) << installer_util::kChromeFrameHelperExe << " exited normally.";
@@ -108,19 +109,18 @@ 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(bool system_uninstall) {
+bool CurrentUserHasDefaultBrowser(const Product& product) {
std::wstring reg_key(ShellUtil::kRegStartMenuInternet);
- BrowserDistribution* dist = BrowserDistribution::GetDistribution();
- reg_key.append(L"\\" + dist->GetApplicationName() + ShellUtil::kRegShellOpen);
+ reg_key.append(L"\\" + product.distribution()->GetApplicationName() +
+ ShellUtil::kRegShellOpen);
RegKey key(HKEY_LOCAL_MACHINE, reg_key.c_str(), KEY_READ);
std::wstring reg_exe;
if (key.ReadValue(L"", &reg_exe) && reg_exe.length() > 2) {
- std::wstring chrome_exe = installer::GetChromeInstallPath(system_uninstall);
- file_util::AppendToPath(&chrome_exe, installer_util::kChromeExe);
+ FilePath chrome_exe(product.package().path()
+ .Append(installer_util::kChromeExe));
+ // The path in the registry will always have quotes.
reg_exe = reg_exe.substr(1, reg_exe.length() - 2);
- if ((reg_exe.size() == chrome_exe.size()) &&
- (std::equal(chrome_exe.begin(), chrome_exe.end(),
- reg_exe.begin(), base::CaseInsensitiveCompare<wchar_t>())))
+ if (FilePath::CompareEqualIgnoreCase(reg_exe, chrome_exe.value()))
return true;
}
@@ -133,29 +133,40 @@ bool CurrentUserHasDefaultBrowser(bool system_uninstall) {
// 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(bool system_uninstall) {
+void DeleteChromeShortcuts(const Product& product) {
+ if (product.distribution()->GetType() !=
+ BrowserDistribution::CHROME_BROWSER) {
+ VLOG(1) << __FUNCTION__ " called for non-CHROME distribution";
+ return;
+ }
+
FilePath shortcut_path;
- if (system_uninstall) {
+ if (product.system_level()) {
PathService::Get(base::DIR_COMMON_START_MENU, &shortcut_path);
- if (!ShellUtil::RemoveChromeDesktopShortcut(ShellUtil::CURRENT_USER |
- ShellUtil::SYSTEM_LEVEL, false))
- ShellUtil::RemoveChromeDesktopShortcut(ShellUtil::CURRENT_USER |
- ShellUtil::SYSTEM_LEVEL, true);
+ if (!ShellUtil::RemoveChromeDesktopShortcut(product.distribution(),
+ ShellUtil::CURRENT_USER | ShellUtil::SYSTEM_LEVEL, false)) {
+ ShellUtil::RemoveChromeDesktopShortcut(product.distribution(),
+ ShellUtil::CURRENT_USER | ShellUtil::SYSTEM_LEVEL, true);
+ }
- ShellUtil::RemoveChromeQuickLaunchShortcut(ShellUtil::CURRENT_USER |
- ShellUtil::SYSTEM_LEVEL);
+ ShellUtil::RemoveChromeQuickLaunchShortcut(product.distribution(),
+ ShellUtil::CURRENT_USER | ShellUtil::SYSTEM_LEVEL);
} else {
PathService::Get(base::DIR_START_MENU, &shortcut_path);
- if (!ShellUtil::RemoveChromeDesktopShortcut(ShellUtil::CURRENT_USER, false))
- ShellUtil::RemoveChromeDesktopShortcut(ShellUtil::CURRENT_USER, true);
+ if (!ShellUtil::RemoveChromeDesktopShortcut(product.distribution(),
+ ShellUtil::CURRENT_USER, false)) {
+ ShellUtil::RemoveChromeDesktopShortcut(product.distribution(),
+ ShellUtil::CURRENT_USER, true);
+ }
- ShellUtil::RemoveChromeQuickLaunchShortcut(ShellUtil::CURRENT_USER);
+ ShellUtil::RemoveChromeQuickLaunchShortcut(product.distribution(),
+ ShellUtil::CURRENT_USER);
}
if (shortcut_path.empty()) {
LOG(ERROR) << "Failed to get location for shortcut.";
} else {
- BrowserDistribution* dist = BrowserDistribution::GetDistribution();
- shortcut_path = shortcut_path.Append(dist->GetAppShortCutName());
+ shortcut_path = shortcut_path.Append(
+ product.distribution()->GetAppShortCutName());
VLOG(1) << "Deleting shortcut " << shortcut_path.value();
if (!file_util::Delete(shortcut_path, true))
LOG(ERROR) << "Failed to delete folder: " << shortcut_path.value();
@@ -206,124 +217,134 @@ enum DeleteResult {
DELETE_REQUIRES_REBOOT
};
-// Deletes all installed files of Chromium and Folders or schedules them for
-// deletion on reboot if they are in use. Before deleting it
-// needs to move setup.exe in a temp folder because the current process
-// is using that file.
-// Returns DELETE_SUCCEEDED if all files were successfully delete.
-// Returns DELETE_FAILED if it could not get the path to the install dir.
-// Returns DELETE_REQUIRES_REBOOT if the files were in use and so were
-// scheduled for deletion on next reboot.
-DeleteResult DeleteFilesAndFolders(const std::wstring& exe_path,
- bool system_uninstall, const installer::Version& installed_version,
- std::wstring* local_state_path, bool delete_profile) {
- std::wstring install_path(installer::GetChromeInstallPath(system_uninstall));
- if (install_path.empty()) {
- LOG(ERROR) << "Could not get installation destination path.";
- return DELETE_FAILED; // Nothing else we can do to uninstall, so we return.
+FilePath GetLocalStateFolder(const Product& product) {
+ // chrome_frame will be true for CHROME_FRAME and CEEE.
+ bool chrome_frame = (product.distribution()->GetType() !=
+ BrowserDistribution::CHROME_BROWSER);
+ // Obtain the location of the user profile data. Chrome Frame needs to
+ // build this path manually since it doesn't use the Chrome default dir.
+ FilePath local_state_folder;
+ if (chrome_frame) {
+ chrome::GetChromeFrameUserDataDirectory(&local_state_folder);
+ } else {
+ chrome::GetDefaultUserDataDirectory(&local_state_folder);
}
- VLOG(1) << "install destination path: " << install_path;
- // Move setup.exe to the temp path.
- std::wstring setup_exe(installer::GetInstallerPathUnderChrome(
- install_path, installed_version.GetString()));
- file_util::AppendToPath(&setup_exe, file_util::GetFilenameFromPath(exe_path));
+ LOG_IF(ERROR, local_state_folder.empty())
+ << "Could not retrieve user's profile directory.";
- FilePath temp_file;
- if (!file_util::CreateTemporaryFile(&temp_file)) {
- LOG(ERROR) << "Failed to create temporary file for setup.exe.";
- } else {
- FilePath setup_exe_path = FilePath::FromWStringHack(setup_exe);
- file_util::Move(setup_exe_path, temp_file);
- }
+ return local_state_folder;
+}
- // Obtain the location of the user profile data. Chrome Frame needs to
- // build this path manually since it doesn't use the Chrome default dir.
- FilePath user_local_state;
- bool got_local_state = false;
- if (InstallUtil::IsChromeFrameProcess()) {
- got_local_state =
- chrome::GetChromeFrameUserDataDirectory(&user_local_state);
+// Creates a copy of the local state file and returns a path to the copy.
+FilePath BackupLocalStateFile(const FilePath& local_state_folder) {
+ FilePath backup;
+ FilePath state_file(local_state_folder.Append(chrome::kLocalStateFilename));
+ if (!file_util::CreateTemporaryFile(&backup)) {
+ LOG(ERROR) << "Failed to create temporary file for Local State.";
} else {
- got_local_state = chrome::GetDefaultUserDataDirectory(&user_local_state);
+ file_util::CopyFile(state_file, backup);
}
+ return backup;
+}
- // Move the browser's persisted local state
- if (got_local_state) {
- FilePath user_local_file(
- user_local_state.Append(chrome::kLocalStateFilename));
- FilePath path;
- if (!file_util::CreateTemporaryFile(&path)) {
- LOG(ERROR) << "Failed to create temporary file for Local State.";
+// Copies the local state to the temp folder and then deletes it.
+// The path to the copy is returned via the local_state_copy parameter.
+DeleteResult DeleteLocalState(const Product& product) {
+ FilePath user_local_state(GetLocalStateFolder(product));
+ if (user_local_state.empty())
+ return DELETE_SUCCEEDED;
+
+ DeleteResult result = DELETE_SUCCEEDED;
+ VLOG(1) << "Deleting user profile" << user_local_state.value();
+ if (!file_util::Delete(user_local_state, true)) {
+ LOG(ERROR) << "Failed to delete user profile dir: "
+ << user_local_state.value();
+ if (product.distribution()->GetType() ==
+ BrowserDistribution::CHROME_FRAME) {
+ ScheduleDirectoryForDeletion(user_local_state.value().c_str());
+ result = DELETE_REQUIRES_REBOOT;
} else {
- *local_state_path = path.value();
- file_util::CopyFile(user_local_file, path);
+ result = DELETE_FAILED;
}
+ }
+
+ if (result == DELETE_REQUIRES_REBOOT) {
+ ScheduleParentAndGrandparentForDeletion(user_local_state);
} else {
- LOG(ERROR) << "Could not retrieve user's profile directory.";
+ DeleteEmptyParentDir(user_local_state);
+ }
+
+ return result;
+}
+
+bool MoveSetupOutOfInstallFolder(const Package& package,
+ const FilePath& setup_path,
+ const Version& installed_version) {
+ bool ret = false;
+ FilePath setup_exe(package.GetInstallerDirectory(installed_version)
+ .Append(setup_path.BaseName()));
+ FilePath temp_file;
+ if (!file_util::CreateTemporaryFile(&temp_file)) {
+ LOG(ERROR) << "Failed to create temporary file for setup.exe.";
+ } else {
+ ret = file_util::Move(setup_exe, temp_file);
+ }
+ return ret;
+}
+
+DeleteResult DeleteFilesAndFolders(const Package& package,
+ const installer::Version& installed_version) {
+ VLOG(1) << "DeleteFilesAndFolders: " << package.path().value();
+ if (package.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 " << install_path;
- if (!file_util::Delete(install_path, true)) {
- LOG(ERROR) << "Failed to delete folder (1st try): " << install_path;
- if (InstallUtil::IsChromeFrameProcess()) {
+ VLOG(1) << "Deleting install path " << package.path().value();
+ if (!file_util::Delete(package.path(), true)) {
+ LOG(ERROR) << "Failed to delete folder (1st try): "
+ << package.path().value();
+ if (FindProduct(package.products(),
+ 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(install_path.c_str());
+ ScheduleDirectoryForDeletion(package.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(install_path, true)) {
- LOG(ERROR) << "Failed to delete folder (2nd try): " << install_path;
- result = DELETE_FAILED;
- }
- }
- }
-
- if (delete_profile && got_local_state) {
- VLOG(1) << "Deleting user profile" << user_local_state.value();
- if (!file_util::Delete(user_local_state, true)) {
- LOG(ERROR) << "Failed to delete user profile dir: "
- << user_local_state.value();
- if (InstallUtil::IsChromeFrameProcess()) {
- ScheduleDirectoryForDeletion(user_local_state.value().c_str());
- result = DELETE_REQUIRES_REBOOT;
- } else {
+ if (!file_util::Delete(package.path(), true)) {
+ LOG(ERROR) << "Failed to delete folder (2nd try): "
+ << package.path().value();
result = DELETE_FAILED;
}
}
- if (result == DELETE_REQUIRES_REBOOT) {
- ScheduleParentAndGrandparentForDeletion(user_local_state);
- } else {
- DeleteEmptyParentDir(user_local_state);
- }
}
if (result == DELETE_REQUIRES_REBOOT) {
// 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(FilePath(install_path));
+ ScheduleParentAndGrandparentForDeletion(package.path());
} else {
// Now check and delete if the parent directories are empty
// For example Google\Chrome or Chromium
- DeleteEmptyParentDir(FilePath(install_path));
+ DeleteEmptyParentDir(package.path());
}
return result;
}
-
// 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.
-installer_util::InstallStatus IsChromeActiveOrUserCancelled(
- bool system_uninstall) {
- static const std::wstring kCmdLineOptions(L" --uninstall");
+InstallStatus IsChromeActiveOrUserCancelled(const Product& product) {
int32 exit_code = ResultCodes::NORMAL_EXIT;
+ CommandLine options(CommandLine::NO_PROGRAM);
+ options.AppendSwitch(installer_util::switches::kUninstall);
// Here we want to save user from frustration (in case of Chrome crashes)
// and continue with the uninstallation as long as chrome.exe process exit
@@ -334,35 +355,33 @@ installer_util::InstallStatus IsChromeActiveOrUserCancelled(
// 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 (installer::LaunchChromeAndWaitForResult(system_uninstall,
- kCmdLineOptions,
- &exit_code)) {
+ if (product.LaunchChromeAndWait(options, &exit_code)) {
VLOG(1) << "chrome.exe launched for uninstall confirmation returned: "
<< exit_code;
if ((exit_code == ResultCodes::UNINSTALL_CHROME_ALIVE) ||
(exit_code == ResultCodes::UNINSTALL_USER_CANCEL) ||
(exit_code == ResultCodes::HUNG))
return installer_util::UNINSTALL_CANCELLED;
+
if (exit_code == ResultCodes::UNINSTALL_DELETE_PROFILE)
return installer_util::UNINSTALL_DELETE_PROFILE;
} else {
- LOG(ERROR) << "Failed to launch chrome.exe for uninstall confirmation.";
+ PLOG(ERROR) << "Failed to launch chrome.exe for uninstall confirmation.";
}
return installer_util::UNINSTALL_CONFIRMED;
}
-bool ShouldDeleteProfile(const CommandLine& cmd_line,
- installer_util::InstallStatus status,
- bool system_uninstall) {
+bool ShouldDeleteProfile(const CommandLine& cmd_line, InstallStatus status,
+ const Product& product) {
bool should_delete = false;
// Chrome Frame uninstallations always want to delete the profile (we have no
// 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 (InstallUtil::IsChromeFrameProcess() &&
- !InstallUtil::IsMSIProcess(system_uninstall)) {
+ if (product.distribution()->GetType() !=
+ BrowserDistribution::CHROME_BROWSER && !product.IsMsi()) {
should_delete = true;
} else {
should_delete =
@@ -373,18 +392,18 @@ bool ShouldDeleteProfile(const CommandLine& cmd_line,
return should_delete;
}
-} // namespace
-
-
-bool installer_setup::DeleteChromeRegistrationKeys(HKEY root,
- const std::wstring& browser_entry_suffix,
- installer_util::InstallStatus& exit_code) {
- if (!BrowserDistribution::GetDistribution()->CanSetAsDefault()) {
+bool DeleteChromeRegistrationKeys(BrowserDistribution* dist, HKEY root,
+ const std::wstring& browser_entry_suffix,
+ InstallStatus& exit_code) {
+ if (!dist->CanSetAsDefault()) {
// We should have never set those keys.
return true;
}
RegKey key(root, L"", KEY_ALL_ACCESS);
+ if (!key.Valid()) {
+ PLOG(ERROR) << "DeleteChromeRegistrationKeys: failed to open root key";
+ }
// Delete Software\Classes\ChromeHTML,
std::wstring html_prog_id(ShellUtil::kRegClasses);
@@ -393,7 +412,6 @@ bool installer_setup::DeleteChromeRegistrationKeys(HKEY root,
InstallUtil::DeleteRegistryKey(key, html_prog_id);
// Delete Software\Clients\StartMenuInternet\Chromium
- BrowserDistribution* dist = BrowserDistribution::GetDistribution();
std::wstring set_access_key(ShellUtil::kRegStartMenuInternet);
file_util::AppendToPath(&set_access_key, dist->GetApplicationName());
set_access_key.append(browser_entry_suffix);
@@ -435,7 +453,7 @@ bool installer_setup::DeleteChromeRegistrationKeys(HKEY root,
return true;
}
-void installer_setup::RemoveLegacyRegistryKeys() {
+void RemoveLegacyRegistryKeys(BrowserDistribution* dist) {
// We used to register Chrome to handle crx files, but this turned out
// to be not worth the hassle. Remove these old registry entries if
// they exist. See: http://codereview.chromium.org/210007
@@ -452,7 +470,7 @@ const wchar_t kChromeExtProgId[] = L"ChromiumExt";
std::wstring suffix;
if (roots[i] == HKEY_LOCAL_MACHINE &&
- !ShellUtil::GetUserSpecificDefaultBrowserSuffix(&suffix))
+ !ShellUtil::GetUserSpecificDefaultBrowserSuffix(dist, &suffix))
suffix = L"";
// Delete Software\Classes\ChromeExt,
@@ -469,23 +487,32 @@ const wchar_t kChromeExtProgId[] = L"ChromiumExt";
}
}
-installer_util::InstallStatus installer_setup::UninstallChrome(
- const std::wstring& exe_path, bool system_uninstall,
- bool remove_all, bool force_uninstall,
- const CommandLine& cmd_line) {
- installer_util::InstallStatus status = installer_util::UNINSTALL_CONFIRMED;
+InstallStatus UninstallChrome(const FilePath& setup_path,
+ const Product& product,
+ bool remove_all,
+ bool force_uninstall,
+ const CommandLine& cmd_line) {
+ InstallStatus status = installer_util::UNINSTALL_CONFIRMED;
std::wstring suffix;
- if (!ShellUtil::GetUserSpecificDefaultBrowserSuffix(&suffix))
+ if (!ShellUtil::GetUserSpecificDefaultBrowserSuffix(product.distribution(),
+ &suffix))
suffix = L"";
+ BrowserDistribution* browser_dist = product.distribution();
+ bool is_chrome = (browser_dist->GetType() ==
+ BrowserDistribution::CHROME_BROWSER);
+
+ VLOG(1) << "UninstallChrome: " << browser_dist->GetApplicationName();
+
if (force_uninstall) {
// Since --force-uninstall command line option is used, we are going to
// do silent uninstall. Try to close all running Chrome instances.
- if (!InstallUtil::IsChromeFrameProcess())
+ // NOTE: We don't do this for Chrome Frame or CEEE.
+ if (is_chrome)
CloseAllChromeProcesses();
- } else if (!InstallUtil::IsChromeFrameProcess()) {
+ } else if (is_chrome) {
// no --force-uninstall so lets show some UI dialog boxes.
- status = IsChromeActiveOrUserCancelled(system_uninstall);
+ status = IsChromeActiveOrUserCancelled(product);
if (status != installer_util::UNINSTALL_CONFIRMED &&
status != installer_util::UNINSTALL_DELETE_PROFILE)
return status;
@@ -494,9 +521,9 @@ installer_util::InstallStatus installer_setup::UninstallChrome(
// 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(system_uninstall)) &&
+ (!suffix.empty() || CurrentUserHasDefaultBrowser(product)) &&
!::IsUserAnAdmin() &&
- (base::win::GetVersion() >= base::win::VERSION_VISTA) &&
+ base::win::GetVersion() >= base::win::VERSION_VISTA &&
!cmd_line.HasSwitch(installer_util::switches::kRunAsAdmin)) {
CommandLine new_cmd(CommandLine::NO_PROGRAM);
new_cmd.AppendArguments(cmd_line, true);
@@ -516,49 +543,51 @@ installer_util::InstallStatus installer_setup::UninstallChrome(
// Get the version of installed Chrome (if any)
scoped_ptr<installer::Version>
- installed_version(InstallUtil::GetChromeVersion(system_uninstall));
+ installed_version(InstallUtil::GetChromeVersion(browser_dist,
+ product.system_level()));
// Chrome is not in use so lets uninstall Chrome by deleting various files
// and registry entries. Here we will just make best effort and keep going
// in case of errors.
// First delete shortcuts from Start->Programs, Desktop & Quick Launch.
- DeleteChromeShortcuts(system_uninstall);
+ DeleteChromeShortcuts(product);
// Delete the registry keys (Uninstall key and Version key).
- HKEY reg_root = system_uninstall ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER;
+ HKEY reg_root = product.system_level() ? HKEY_LOCAL_MACHINE :
+ HKEY_CURRENT_USER;
RegKey key(reg_root, L"", KEY_ALL_ACCESS);
- BrowserDistribution* dist = BrowserDistribution::GetDistribution();
// Note that we must retrieve the distribution-specific data before deleting
- // dist->GetVersionKey().
- std::wstring distribution_data(dist->GetDistributionData(&key));
+ // product.GetVersionKey().
+ std::wstring distribution_data(browser_dist->GetDistributionData(reg_root));
// Remove Control Panel uninstall link and Omaha product key.
- InstallUtil::DeleteRegistryKey(key, dist->GetUninstallRegPath());
- InstallUtil::DeleteRegistryKey(key, dist->GetVersionKey());
+ InstallUtil::DeleteRegistryKey(key, browser_dist->GetUninstallRegPath());
+ InstallUtil::DeleteRegistryKey(key, browser_dist->GetVersionKey());
// Also try to delete the MSI value in the ClientState key (it might not be
// 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.
- InstallUtil::SetMSIMarker(system_uninstall, false);
+ product.SetMsiMarker(false);
// Remove all Chrome registration keys.
- installer_util::InstallStatus ret = installer_util::UNKNOWN_STATUS;
- DeleteChromeRegistrationKeys(reg_root, suffix, ret);
+ InstallStatus ret = installer_util::UNKNOWN_STATUS;
+ DeleteChromeRegistrationKeys(product.distribution(), reg_root, suffix, ret);
// 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 && !system_uninstall &&
- (!suffix.empty() || CurrentUserHasDefaultBrowser(system_uninstall)))
- DeleteChromeRegistrationKeys(HKEY_LOCAL_MACHINE, suffix, ret);
+ if (remove_all && !product.system_level() &&
+ (!suffix.empty() || CurrentUserHasDefaultBrowser(product))) {
+ DeleteChromeRegistrationKeys(product.distribution(), HKEY_LOCAL_MACHINE,
+ suffix, ret);
+ }
// Delete shared registry keys as well (these require admin rights) if
// remove_all option is specified.
if (remove_all) {
- if (!InstallUtil::IsChromeSxSProcess() &&
- !InstallUtil::IsChromeFrameProcess()) {
+ if (!InstallUtil::IsChromeSxSProcess() && is_chrome) {
// Delete media player registry key that exists only in HKLM.
// We don't delete this key in SxS uninstall or Chrome Frame uninstall
// as we never set the key for those products.
@@ -570,18 +599,14 @@ installer_util::InstallStatus installer_setup::UninstallChrome(
}
// Unregister any dll servers that we may have registered for Chrome Frame
- // builds only.
- if (installed_version.get() && InstallUtil::IsChromeFrameProcess()) {
- std::wstring dll_path(installer::GetChromeInstallPath(system_uninstall));
- file_util::AppendToPath(&dll_path, installed_version->GetString());
-
- scoped_ptr<WorkItemList> dll_list(WorkItem::CreateWorkItemList());
- if (InstallUtil::BuildDLLRegistrationList(dll_path, kDllsToRegister,
- kNumDllsToRegister, false,
- !system_uninstall,
- dll_list.get())) {
- dll_list->Do();
- }
+ // and CEEE builds only.
+ // TODO(tommi): We should only do this when the folder itself is
+ // being removed and we know that the DLLs were previously registered.
+ // Simplest would be to always register them.
+ if (installed_version.get() && !is_chrome) {
+ RegisterComDllList(product.package().path().Append(
+ installed_version->GetString()),
+ product.system_level(), false, false);
}
}
@@ -596,12 +621,26 @@ installer_util::InstallStatus installer_setup::UninstallChrome(
// 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, system_uninstall);
- std::wstring local_state_path;
+ bool delete_profile = ShouldDeleteProfile(cmd_line, status, product);
ret = installer_util::UNINSTALL_SUCCESSFUL;
- DeleteResult delete_result = DeleteFilesAndFolders(exe_path,
- system_uninstall, *installed_version, &local_state_path, delete_profile);
+ // 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,
+ *installed_version);
+
+ FilePath backup_state_file(BackupLocalStateFile(
+ GetLocalStateFolder(product)));
+
+ // TODO(tommi): We should only do this when the last distribution is being
+ // uninstalled.
+ DeleteResult delete_result = DeleteFilesAndFolders(product.package(),
+ *installed_version);
+
+ if (delete_profile)
+ DeleteLocalState(product);
+
if (delete_result == DELETE_FAILED) {
ret = installer_util::UNINSTALL_FAILED;
} else if (delete_result == DELETE_REQUIRES_REBOOT) {
@@ -610,14 +649,17 @@ installer_util::InstallStatus installer_setup::UninstallChrome(
if (!force_uninstall) {
VLOG(1) << "Uninstallation complete. Launching Uninstall survey.";
- dist->DoPostUninstallOperations(*installed_version, local_state_path,
- distribution_data);
+ browser_dist->DoPostUninstallOperations(*installed_version,
+ backup_state_file, distribution_data);
}
// Try and delete the preserved local state once the post-install
// operations are complete.
- if (!local_state_path.empty())
- file_util::Delete(local_state_path, false);
+ if (!backup_state_file.empty())
+ file_util::Delete(backup_state_file, false);
return ret;
}
+
+} // namespace installer
+
diff --git a/chrome/installer/setup/uninstall.h b/chrome/installer/setup/uninstall.h
index d0dc8c3..9165091 100644
--- a/chrome/installer/setup/uninstall.h
+++ b/chrome/installer/setup/uninstall.h
@@ -13,39 +13,37 @@
#include <shlobj.h>
#include "base/command_line.h"
+#include "chrome/installer/util/product.h"
#include "chrome/installer/util/util_constants.h"
#include "chrome/installer/util/version.h"
-namespace installer_setup {
+namespace installer {
// This function removes all Chrome registration related keys. It returns true
// if successful, otherwise false. The error code is set in |exit_code|.
// |root| is the registry root (HKLM|HKCU) and |browser_entry_suffix| is the
// suffix for default browser entry name in the registry (optional).
-bool DeleteChromeRegistrationKeys(HKEY root,
+bool DeleteChromeRegistrationKeys(BrowserDistribution* dist, HKEY root,
const std::wstring& browser_entry_suffix,
installer_util::InstallStatus& exit_code);
// Removes any legacy registry keys from earlier versions of Chrome that are no
// longer needed. This is used during autoupdate since we don't do full
// uninstalls/reinstalls to update.
-void RemoveLegacyRegistryKeys();
+void RemoveLegacyRegistryKeys(BrowserDistribution* dist);
// This function uninstalls Chrome.
//
-// exe_path: Path to the executable (setup.exe) as it will be copied
+// setup_path: Path to the executable (setup.exe) as it will be copied
// to temp folder before deleting Chrome folder.
-// system_uninstall: if true, the function uninstalls Chrome installed system
-// wise. otherwise, it uninstalls Chrome installed for the
-// current user.
+// dist: Represents the distribution to be uninstalled.
// remove_all: Remove all shared files, registry entries as well.
// force_uninstall: Uninstall without prompting for user confirmation or
// any checks for Chrome running.
// cmd_line: CommandLine that contains information about the command that
// was used to launch current uninstaller.
installer_util::InstallStatus UninstallChrome(
- const std::wstring& exe_path, bool system_uninstall,
- bool remove_all, bool force_uninstall,
- const CommandLine& cmd_line);
+ const FilePath& setup_path, const Product& dist, bool remove_all,
+ bool force_uninstall, const CommandLine& cmd_line);
} // namespace installer_setup
diff --git a/chrome/installer/util/browser_distribution.cc b/chrome/installer/util/browser_distribution.cc
index 2e2ccf2..db98298 100644
--- a/chrome/installer/util/browser_distribution.cc
+++ b/chrome/installer/util/browser_distribution.cc
@@ -9,10 +9,12 @@
#include "chrome/installer/util/browser_distribution.h"
+#include "base/atomicops.h"
#include "base/command_line.h"
#include "base/file_path.h"
#include "base/path_service.h"
#include "base/lock.h"
+#include "base/logging.h"
#include "base/win/registry.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/env_vars.h"
@@ -25,6 +27,11 @@
#include "installer_util_strings.h"
namespace {
+// The BrowserDistribution objects are never freed.
+BrowserDistribution* g_browser_distribution = NULL;
+BrowserDistribution* g_chrome_frame_distribution = NULL;
+BrowserDistribution* g_ceee_distribution = NULL;
+
// Returns true if currently running in npchrome_frame.dll
bool IsChromeFrameModule() {
FilePath module_path;
@@ -41,40 +48,69 @@ bool IsCeeeBrokerProcess() {
installer_util::kCeeeBrokerExe);
}
+BrowserDistribution::DistributionType GetCurrentDistributionType() {
+ static BrowserDistribution::DistributionType type =
+ (InstallUtil::IsChromeFrameProcess() || IsChromeFrameModule()) ?
+ BrowserDistribution::CHROME_FRAME :
+ (IsCeeeBrokerProcess() ? BrowserDistribution::CEEE :
+ BrowserDistribution::CHROME_BROWSER);
+ return type;
+}
+
} // end namespace
+template<class DistributionClass>
+BrowserDistribution* BrowserDistribution::GetOrCreateBrowserDistribution(
+ BrowserDistribution** dist) {
+ if (!*dist) {
+ DistributionClass* temp = new DistributionClass();
+ if (base::subtle::NoBarrier_CompareAndSwap(
+ reinterpret_cast<base::subtle::AtomicWord*>(dist), NULL,
+ reinterpret_cast<base::subtle::AtomicWord>(temp)) != NULL)
+ delete temp;
+ }
+
+ return *dist;
+}
+
BrowserDistribution* BrowserDistribution::GetDistribution() {
- return GetDistribution(InstallUtil::IsChromeFrameProcess() ||
- IsChromeFrameModule() ||
- IsCeeeBrokerProcess());
-}
-
-BrowserDistribution* BrowserDistribution::GetDistribution(bool chrome_frame) {
- static BrowserDistribution* dist = NULL;
- static Lock dist_lock;
- AutoLock lock(dist_lock);
- if (dist == NULL) {
- if (chrome_frame) {
- // TODO(robertshield): Make one of these for Google Chrome vs
- // non Google Chrome builds?
- dist = new ChromeFrameDistribution();
- } else {
+ return GetSpecificDistribution(GetCurrentDistributionType());
+}
+
+// static
+BrowserDistribution* BrowserDistribution::GetSpecificDistribution(
+ BrowserDistribution::DistributionType type) {
+ BrowserDistribution* dist = NULL;
+
+ // TODO(tommi): initialize g_ceee_distribution when appropriate. Right now
+ // we treat CEEE as Chrome Frame.
+
+ if (type == CHROME_FRAME || type == CEEE) {
+ // TODO(robertshield): Make one of these for Google Chrome vs
+ // non Google Chrome builds?
+ dist = GetOrCreateBrowserDistribution<ChromeFrameDistribution>(
+ &g_chrome_frame_distribution);
+ } else {
+ DCHECK_EQ(CHROME_BROWSER, type);
#if defined(GOOGLE_CHROME_BUILD)
if (InstallUtil::IsChromeSxSProcess()) {
- dist = new GoogleChromeSxSDistribution();
+ dist = GetOrCreateBrowserDistribution<GoogleChromeSxSDistribution>(
+ &g_browser_distribution);
} else {
- dist = new GoogleChromeDistribution();
+ dist = GetOrCreateBrowserDistribution<GoogleChromeDistribution>(
+ &g_browser_distribution);
}
#else
- dist = new BrowserDistribution();
+ dist = GetOrCreateBrowserDistribution<BrowserDistribution>(
+ &g_browser_distribution);
#endif
- }
}
+
return dist;
}
void BrowserDistribution::DoPostUninstallOperations(
- const installer::Version& version, const std::wstring& local_data_path,
+ const installer::Version& version, const FilePath& local_data_path,
const std::wstring& distribution_data) {
}
@@ -116,6 +152,7 @@ std::wstring BrowserDistribution::GetLongAppDescription() {
return app_description;
}
+// static
int BrowserDistribution::GetInstallReturnCode(
installer_util::InstallStatus status) {
switch (status) {
@@ -145,7 +182,7 @@ std::wstring BrowserDistribution::GetStatsServerURL() {
return L"";
}
-std::wstring BrowserDistribution::GetDistributionData(base::win::RegKey* key) {
+std::wstring BrowserDistribution::GetDistributionData(HKEY root_key) {
return L"";
}
@@ -183,10 +220,10 @@ void BrowserDistribution::UpdateDiffInstallStatus(bool system_install,
void BrowserDistribution::LaunchUserExperiment(
installer_util::InstallStatus status, const installer::Version& version,
- bool system_install) {
+ const installer::Product& installation, bool system_level) {
}
void BrowserDistribution::InactiveUserToastExperiment(int flavor,
- bool system_install) {
+ const installer::Product& installation) {
}
diff --git a/chrome/installer/util/browser_distribution.h b/chrome/installer/util/browser_distribution.h
index 39eecdd..749d6af 100644
--- a/chrome/installer/util/browser_distribution.h
+++ b/chrome/installer/util/browser_distribution.h
@@ -9,23 +9,38 @@
#pragma once
#include "base/basictypes.h"
+#include "base/file_path.h"
#include "chrome/installer/util/util_constants.h"
#include "chrome/installer/util/version.h"
-namespace base {
-namespace win {
-class RegKey;
-} // namespace win
-} // namespace base
+#if defined(OS_WIN)
+#include <windows.h>
+#endif
+
+namespace installer {
+class Product;
+}
class BrowserDistribution {
public:
virtual ~BrowserDistribution() {}
+ typedef enum DistributionType {
+ CHROME_BROWSER,
+ CHROME_FRAME,
+ CEEE,
+ };
+
static BrowserDistribution* GetDistribution();
+ static BrowserDistribution* GetSpecificDistribution(DistributionType type);
+
+ DistributionType GetType() const { return type_; }
+
+ static int GetInstallReturnCode(installer_util::InstallStatus install_status);
+
virtual void DoPostUninstallOperations(const installer::Version& version,
- const std::wstring& local_data_path,
+ const FilePath& local_data_path,
const std::wstring& distribution_data);
virtual std::wstring GetAppGuid();
@@ -46,9 +61,6 @@ class BrowserDistribution {
virtual std::wstring GetLongAppDescription();
- virtual int GetInstallReturnCode(
- installer_util::InstallStatus install_status);
-
virtual std::string GetSafeBrowsingName();
virtual std::wstring GetStateKey();
@@ -57,7 +69,9 @@ class BrowserDistribution {
virtual std::wstring GetStatsServerURL();
- virtual std::wstring GetDistributionData(base::win::RegKey* key);
+#if defined(OS_WIN)
+ virtual std::wstring GetDistributionData(HKEY root_key);
+#endif
virtual std::wstring GetUninstallLinkName();
@@ -80,17 +94,23 @@ class BrowserDistribution {
// experiment. This function determines if the user qualifies and if so it
// sets the wheels in motion or in simple cases does the experiment itself.
virtual void LaunchUserExperiment(installer_util::InstallStatus status,
- const installer::Version& version,
- bool system_install);
+ const installer::Version& version,
+ const installer::Product& installation,
+ bool system_level);
// The user has qualified for the inactive user toast experiment and this
// function just performs it.
- virtual void InactiveUserToastExperiment(int flavor, bool system_install);
+ virtual void InactiveUserToastExperiment(int flavor,
+ const installer::Product& installation);
protected:
- BrowserDistribution() {}
+ BrowserDistribution() : type_(CHROME_BROWSER) {}
+
+ template<class DistributionClass>
+ static BrowserDistribution* GetOrCreateBrowserDistribution(
+ BrowserDistribution** dist);
- static BrowserDistribution* GetDistribution(bool chrome_frame);
+ DistributionType type_;
private:
DISALLOW_COPY_AND_ASSIGN(BrowserDistribution);
diff --git a/chrome/installer/util/browser_distribution_unittest.cc b/chrome/installer/util/browser_distribution_unittest.cc
index 55d0d8f..2733d1f 100644
--- a/chrome/installer/util/browser_distribution_unittest.cc
+++ b/chrome/installer/util/browser_distribution_unittest.cc
@@ -24,14 +24,23 @@ 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) {
- BrowserDistribution *dist = BrowserDistribution::GetDistribution();
- ASSERT_TRUE(dist != NULL);
- std::wstring name = dist->GetApplicationName();
- EXPECT_FALSE(name.empty());
- std::wstring desc = dist->GetAppDescription();
- EXPECT_FALSE(desc.empty());
- std::wstring alt_name = dist->GetAlternateApplicationName();
- EXPECT_FALSE(alt_name.empty());
+ BrowserDistribution::DistributionType types[] = {
+ BrowserDistribution::CHROME_BROWSER,
+ BrowserDistribution::CHROME_FRAME,
+ // TODO(tommi): Also include CEEE.
+ };
+
+ for (int i = 0; i < arraysize(types); ++i) {
+ BrowserDistribution* dist =
+ BrowserDistribution::GetSpecificDistribution(types[i]);
+ ASSERT_TRUE(dist != NULL);
+ std::wstring name = dist->GetApplicationName();
+ EXPECT_FALSE(name.empty());
+ std::wstring desc = dist->GetAppDescription();
+ EXPECT_FALSE(desc.empty());
+ std::wstring alt_name = dist->GetAlternateApplicationName();
+ EXPECT_FALSE(alt_name.empty());
+ }
}
// The shortcut strings obtained by the shell utility functions should not
@@ -39,8 +48,9 @@ TEST(BrowserDistributionTest, StringsTest) {
TEST(BrowserDistributionTest, AlternateAndNormalShortcutName) {
std::wstring normal_name;
std::wstring alternate_name;
- EXPECT_TRUE(ShellUtil::GetChromeShortcutName(&normal_name, false));
- EXPECT_TRUE(ShellUtil::GetChromeShortcutName(&alternate_name, true));
+ BrowserDistribution* dist = BrowserDistribution::GetDistribution();
+ EXPECT_TRUE(ShellUtil::GetChromeShortcutName(dist, &normal_name, false));
+ EXPECT_TRUE(ShellUtil::GetChromeShortcutName(dist, &alternate_name, true));
EXPECT_NE(normal_name, alternate_name);
EXPECT_FALSE(normal_name.empty());
EXPECT_FALSE(alternate_name.empty());
diff --git a/chrome/installer/util/chrome_frame_distribution.h b/chrome/installer/util/chrome_frame_distribution.h
index f42d41f..6b071ae 100644
--- a/chrome/installer/util/chrome_frame_distribution.h
+++ b/chrome/installer/util/chrome_frame_distribution.h
@@ -54,11 +54,13 @@ class ChromeFrameDistribution : public BrowserDistribution {
virtual void UpdateDiffInstallStatus(bool system_install,
bool incremental_install, installer_util::InstallStatus install_status);
- private:
+ protected:
friend class BrowserDistribution;
// Disallow construction from non-friends.
- ChromeFrameDistribution() {}
+ ChromeFrameDistribution() {
+ type_ = BrowserDistribution::CHROME_FRAME;
+ }
};
diff --git a/chrome/installer/util/google_chrome_distribution.cc b/chrome/installer/util/google_chrome_distribution.cc
index 34a6333..375a4e1 100644
--- a/chrome/installer/util/google_chrome_distribution.cc
+++ b/chrome/installer/util/google_chrome_distribution.cc
@@ -26,6 +26,7 @@
#include "chrome/common/json_value_serializer.h"
#include "chrome/common/pref_names.h"
#include "chrome/common/result_codes.h"
+#include "chrome/installer/util/product.h"
#include "chrome/installer/util/install_util.h"
#include "chrome/installer/util/l10n_string_util.h"
#include "chrome/installer/util/google_update_constants.h"
@@ -324,7 +325,7 @@ bool GoogleChromeDistribution::ExtractUninstallMetrics(
#endif
void GoogleChromeDistribution::DoPostUninstallOperations(
- const installer::Version& version, const std::wstring& local_data_path,
+ const installer::Version& version, const FilePath& local_data_path,
const std::wstring& distribution_data) {
// Send the Chrome version and OS version as params to the form.
// It would be nice to send the locale, too, but I don't see an
@@ -357,7 +358,8 @@ void GoogleChromeDistribution::DoPostUninstallOperations(
os_version;
std::wstring uninstall_metrics;
- if (ExtractUninstallMetricsFromFile(local_data_path, &uninstall_metrics)) {
+ if (ExtractUninstallMetricsFromFile(local_data_path.value(),
+ &uninstall_metrics)) {
// The user has opted into anonymous usage data collection, so append
// metrics and distribution data.
command += uninstall_metrics;
@@ -436,14 +438,12 @@ std::wstring GoogleChromeDistribution::GetStatsServerURL() {
return L"https://clients4.google.com/firefox/metrics/collect";
}
-std::wstring GoogleChromeDistribution::GetDistributionData(
- base::win::RegKey* key) {
- DCHECK(NULL != key);
+std::wstring GoogleChromeDistribution::GetDistributionData(HKEY root_key) {
std::wstring sub_key(google_update::kRegPathClientState);
sub_key.append(L"\\");
sub_key.append(product_guid());
- base::win::RegKey client_state_key(key->Handle(), sub_key.c_str(), KEY_READ);
+ base::win::RegKey client_state_key(root_key, sub_key.c_str(), KEY_READ);
std::wstring result;
std::wstring brand_value;
if (client_state_key.ReadValue(google_update::kRegRLZBrandField,
@@ -557,8 +557,8 @@ void SetClient(std::wstring experiment_group, bool last_write) {
// this function with |system_install| true and a REENTRY_SYS_UPDATE status.
void GoogleChromeDistribution::LaunchUserExperiment(
installer_util::InstallStatus status, const installer::Version& version,
- bool system_install) {
- if (system_install) {
+ const installer::Product& installation, bool system_level) {
+ if (system_level) {
if (installer_util::NEW_VERSION_UPDATED == status) {
// We need to relaunch as the interactive user.
RelaunchSetupAsConsoleUser(installer_util::switches::kSystemLevelToast);
@@ -586,10 +586,12 @@ void GoogleChromeDistribution::LaunchUserExperiment(
} else {
// Check browser usage inactivity by the age of the last-write time of the
// chrome user data directory.
- std::wstring user_data_dir = installer::GetChromeUserDataPath();
+ FilePath user_data_dir(installation.GetUserDataPath());
+
// TODO(cpu): re-enable experiment.
const int kThirtyDays = 3000 * 24;
- int dir_age_hours = GetDirectoryWriteAgeInHours(user_data_dir.c_str());
+ int dir_age_hours = GetDirectoryWriteAgeInHours(
+ user_data_dir.value().c_str());
if (dir_age_hours < 0) {
// This means that we failed to find the user data dir. The most likely
// cause is that this user has not ever used chrome at all which can
@@ -617,26 +619,32 @@ void GoogleChromeDistribution::LaunchUserExperiment(
// System level: We have already been relaunched, so we don't need to be
// quick, but we relaunch to follow the exact same codepath.
RelaunchSetup(installer_util::switches::kInactiveUserToast, flavor,
- system_install);
+ system_level);
}
// User qualifies for the experiment. Launch chrome with --try-chrome=flavor.
void GoogleChromeDistribution::InactiveUserToastExperiment(int flavor,
- bool system_install) {
+ const installer::Product& installation) {
bool has_welcome_url = (flavor == 0);
// Possibly add a url to launch depending on the experiment flavor.
- std::wstring options(StringPrintf(L"--%ls=%d",
- ASCIIToUTF16(switches::kTryChromeAgain).c_str(), flavor));
+ CommandLine options(CommandLine::NO_PROGRAM);
+ options.AppendSwitchNative(switches::kTryChromeAgain,
+ base::IntToString16(flavor));
if (has_welcome_url) {
- const std::wstring url(GetWelcomeBackUrl());
- options.append(L" -- ");
- options.append(url);
+ // Prepend the url with a space.
+ std::wstring url(GetWelcomeBackUrl());
+ options.AppendArg("--");
+ options.AppendArgNative(url);
+ // The command line should now have the url added as:
+ // "chrome.exe -- <url>"
+ DCHECK_NE(std::wstring::npos,
+ options.command_line_string().find(L" -- " + url));
}
// Launch chrome now. It will show the toast UI.
int32 exit_code = 0;
- if (!installer::LaunchChromeAndWaitForResult(system_install,
- options, &exit_code))
+ if (!installation.LaunchChromeAndWait(options, &exit_code))
return;
+
// The chrome process has exited, figure out what happened.
const wchar_t* outcome = NULL;
switch (exit_code) {
@@ -658,10 +666,16 @@ void GoogleChromeDistribution::InactiveUserToastExperiment(int flavor,
if (outcome != kToastExpUninstallGroup)
return;
+
// The user wants to uninstall. This is a best effort operation. Note that
// we waited for chrome to exit so the uninstall would not detect chrome
// running.
- base::LaunchApp(InstallUtil::GetChromeUninstallCmd(system_install),
- false, false, NULL);
+ bool system_level_toast = CommandLine::ForCurrentProcess()->HasSwitch(
+ installer_util::switches::kSystemLevelToast);
+
+ std::wstring cmd(InstallUtil::GetChromeUninstallCmd(
+ system_level_toast, this));
+
+ base::LaunchApp(cmd, false, false, NULL);
}
#endif
diff --git a/chrome/installer/util/google_chrome_distribution.h b/chrome/installer/util/google_chrome_distribution.h
index 53d754b..d6fa281 100644
--- a/chrome/installer/util/google_chrome_distribution.h
+++ b/chrome/installer/util/google_chrome_distribution.h
@@ -27,7 +27,7 @@ class GoogleChromeDistribution : public BrowserDistribution {
// concatenated to the survey url if the file in local_data_path indicates
// the user has opted in to providing anonymous usage data.
virtual void DoPostUninstallOperations(const installer::Version& version,
- const std::wstring& local_data_path,
+ const FilePath& local_data_path,
const std::wstring& distribution_data);
virtual std::wstring GetAppGuid();
@@ -55,7 +55,7 @@ class GoogleChromeDistribution : public BrowserDistribution {
// This method reads data from the Google Update ClientState key for
// potential use in the uninstall survey. It must be called before the
// key returned by GetVersionKey() is deleted.
- virtual std::wstring GetDistributionData(base::win::RegKey* key);
+ virtual std::wstring GetDistributionData(HKEY root_key);
virtual std::wstring GetUninstallLinkName();
@@ -69,13 +69,15 @@ class GoogleChromeDistribution : public BrowserDistribution {
bool incremental_install, installer_util::InstallStatus install_status);
virtual void LaunchUserExperiment(installer_util::InstallStatus status,
- const installer::Version& version,
- bool system_install);
+ const installer::Version& version,
+ const installer::Product& installation,
+ bool system_level);
// Assuming that the user qualifies, this function performs the inactive user
// toast experiment. It will use chrome to show the UI and it will record the
// outcome in the registry.
- virtual void InactiveUserToastExperiment(int flavor, bool system_install);
+ virtual void InactiveUserToastExperiment(int flavor,
+ const installer::Product& installation);
std::wstring product_guid() { return product_guid_; }
diff --git a/chrome/installer/util/google_chrome_distribution_dummy.cc b/chrome/installer/util/google_chrome_distribution_dummy.cc
index a50dd11..0cb540c 100644
--- a/chrome/installer/util/google_chrome_distribution_dummy.cc
+++ b/chrome/installer/util/google_chrome_distribution_dummy.cc
@@ -19,7 +19,7 @@ GoogleChromeDistribution::GoogleChromeDistribution() {
void GoogleChromeDistribution::DoPostUninstallOperations(
const installer::Version& version,
- const std::wstring& local_data_path,
+ const FilePath& local_data_path,
const std::wstring& distribution_data) {
}
@@ -78,8 +78,7 @@ std::wstring GoogleChromeDistribution::GetStatsServerURL() {
return std::wstring();
}
-std::wstring GoogleChromeDistribution::GetDistributionData(
- base::win::RegKey* key) {
+std::wstring GoogleChromeDistribution::GetDistributionData(HKEY root_key) {
NOTREACHED();
return std::wstring();
}
@@ -111,13 +110,12 @@ void GoogleChromeDistribution::UpdateDiffInstallStatus(bool system_install,
void GoogleChromeDistribution::LaunchUserExperiment(
installer_util::InstallStatus status, const installer::Version& version,
- bool system_install) {
+ const installer::Product& installation, bool system_level) {
NOTREACHED();
}
-void GoogleChromeDistribution::InactiveUserToastExperiment(
- int flavor,
- bool system_install) {
+void GoogleChromeDistribution::InactiveUserToastExperiment(int flavor,
+ const installer::Product& installation) {
NOTREACHED();
}
diff --git a/chrome/installer/util/google_chrome_distribution_unittest.cc b/chrome/installer/util/google_chrome_distribution_unittest.cc
index 1e0ede8..10c2022 100644
--- a/chrome/installer/util/google_chrome_distribution_unittest.cc
+++ b/chrome/installer/util/google_chrome_distribution_unittest.cc
@@ -51,7 +51,8 @@ TEST(GoogleChromeDistTest, TestExtractUninstallMetrics) {
ASSERT_TRUE(root.get());
std::wstring uninstall_metrics_string;
GoogleChromeDistribution* dist = static_cast<GoogleChromeDistribution*>(
- BrowserDistribution::GetDistribution());
+ BrowserDistribution::GetSpecificDistribution(
+ BrowserDistribution::CHROME_BROWSER));
EXPECT_TRUE(
dist->ExtractUninstallMetrics(*static_cast<DictionaryValue*>(root.get()),
diff --git a/chrome/installer/util/helper.cc b/chrome/installer/util/helper.cc
index 551b9c6..4da09a8 100644
--- a/chrome/installer/util/helper.cc
+++ b/chrome/installer/util/helper.cc
@@ -2,126 +2,40 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include <windows.h>
+#include "chrome/installer/util/helper.h"
-#include "base/file_util.h"
-#include "base/logging.h"
#include "base/path_service.h"
-#include "base/process_util.h"
-#include "base/scoped_ptr.h"
#include "chrome/installer/util/browser_distribution.h"
-#include "chrome/installer/util/delete_tree_work_item.h"
-#include "chrome/installer/util/helper.h"
-#include "chrome/installer/util/logging_installer.h"
-#include "chrome/installer/util/util_constants.h"
-#include "chrome/installer/util/version.h"
-#include "chrome/installer/util/work_item_list.h"
namespace {
-std::wstring GetChromeInstallBasePath(bool system_install,
- const wchar_t* subpath) {
+FilePath GetChromeInstallBasePath(bool system,
+ BrowserDistribution* distribution,
+ const wchar_t* sub_path) {
FilePath install_path;
- if (system_install) {
+ if (system) {
PathService::Get(base::DIR_PROGRAM_FILES, &install_path);
} else {
PathService::Get(base::DIR_LOCAL_APP_DATA, &install_path);
}
+
if (!install_path.empty()) {
- BrowserDistribution* dist = BrowserDistribution::GetDistribution();
- install_path = install_path.Append(dist->GetInstallSubDir());
- install_path = install_path.Append(subpath);
+ install_path = install_path.Append(distribution->GetInstallSubDir());
+ install_path = install_path.Append(sub_path);
}
- return install_path.ToWStringHack();
+
+ return install_path;
}
} // namespace
-std::wstring installer::GetChromeInstallPath(bool system_install) {
- return GetChromeInstallBasePath(system_install,
+FilePath installer::GetChromeInstallPath(bool system_install,
+ BrowserDistribution* dist) {
+ return GetChromeInstallBasePath(system_install, dist,
installer_util::kInstallBinaryDir);
}
-std::wstring installer::GetChromeUserDataPath() {
- return GetChromeInstallBasePath(false, installer_util::kInstallUserDataDir);
-}
-
-bool installer::LaunchChrome(bool system_install) {
- std::wstring chrome_exe(L"\"");
- chrome_exe.append(installer::GetChromeInstallPath(system_install));
- file_util::AppendToPath(&chrome_exe, installer_util::kChromeExe);
- chrome_exe.append(L"\"");
- return base::LaunchApp(chrome_exe, false, false, NULL);
-}
-
-bool installer::LaunchChromeAndWaitForResult(bool system_install,
- const std::wstring& options,
- int32* exit_code) {
- std::wstring chrome_exe(installer::GetChromeInstallPath(system_install));
- if (chrome_exe.empty())
- return false;
- file_util::AppendToPath(&chrome_exe, installer_util::kChromeExe);
-
- std::wstring command_line(L"\"" + chrome_exe + L"\"");
- command_line.append(options);
- STARTUPINFOW si = {sizeof(si)};
- PROCESS_INFORMATION pi = {0};
- if (!::CreateProcessW(chrome_exe.c_str(),
- const_cast<wchar_t*>(command_line.c_str()),
- NULL, NULL, FALSE, CREATE_NO_WINDOW, NULL, NULL,
- &si, &pi)) {
- return false;
- }
-
- DWORD wr = ::WaitForSingleObject(pi.hProcess, INFINITE);
- DWORD ret;
- if (::GetExitCodeProcess(pi.hProcess, &ret) == 0)
- return false;
-
- if (exit_code)
- *exit_code = ret;
-
- ::CloseHandle(pi.hProcess);
- ::CloseHandle(pi.hThread);
- return true;
-}
-
-void installer::RemoveOldVersionDirs(const std::wstring& chrome_path,
- const std::wstring& latest_version_str) {
- std::wstring search_path(chrome_path);
- file_util::AppendToPath(&search_path, L"*");
-
- WIN32_FIND_DATA find_file_data;
- HANDLE file_handle = FindFirstFile(search_path.c_str(), &find_file_data);
- if (file_handle == INVALID_HANDLE_VALUE)
- return;
-
- BOOL ret = TRUE;
- scoped_ptr<installer::Version> version;
- scoped_ptr<installer::Version> latest_version(
- installer::Version::GetVersionFromString(latest_version_str));
-
- // We try to delete all directories whose versions are lower than
- // latest_version.
- while (ret) {
- if (find_file_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
- VLOG(1) << "directory found: " << find_file_data.cFileName;
- version.reset(
- installer::Version::GetVersionFromString(find_file_data.cFileName));
- if (version.get() && latest_version->IsHigherThan(version.get())) {
- std::wstring remove_dir(chrome_path);
- file_util::AppendToPath(&remove_dir, find_file_data.cFileName);
- std::wstring chrome_dll_path(remove_dir);
- file_util::AppendToPath(&chrome_dll_path, installer_util::kChromeDll);
- VLOG(1) << "deleting directory " << remove_dir;
- scoped_ptr<DeleteTreeWorkItem> item;
- item.reset(WorkItem::CreateDeleteTreeWorkItem(remove_dir,
- chrome_dll_path));
- item->Do();
- }
- }
- ret = FindNextFile(file_handle, &find_file_data);
- }
-
- FindClose(file_handle);
+FilePath installer::GetChromeUserDataPath(BrowserDistribution* dist) {
+ return GetChromeInstallBasePath(false, dist,
+ installer_util::kInstallUserDataDir);
}
diff --git a/chrome/installer/util/helper.h b/chrome/installer/util/helper.h
index dd4c3b8..747e11b 100644
--- a/chrome/installer/util/helper.h
+++ b/chrome/installer/util/helper.h
@@ -8,7 +8,9 @@
#define CHROME_INSTALLER_UTIL_HELPER_H_
#pragma once
-#include <string>
+#include "base/file_path.h"
+
+class BrowserDistribution;
namespace installer {
@@ -17,34 +19,13 @@ namespace installer {
// system_install: if true, the function returns system wide location
// (ProgramFiles\Google). Otherwise it returns user specific
// location (Document And Settings\<user>\Local Settings...)
-std::wstring GetChromeInstallPath(bool system_install);
+FilePath GetChromeInstallPath(bool system_install, BrowserDistribution* dist);
// This function returns the path to the directory that holds the user data,
// this is always inside "Document And Settings\<user>\Local Settings.". Note
// that this is the default user data directory and does not take into account
// that it can be overriden with a command line parameter.
-std::wstring GetChromeUserDataPath();
-
-// Launches Chrome without waiting for its exit.
-bool LaunchChrome(bool system_install);
-
-// Launches Chrome with given command line, waits for Chrome indefinitely
-// (until it terminates), and gets the process exit code if available.
-// The function returns true as long as Chrome is successfully launched.
-// The status of Chrome at the return of the function is given by exit_code.
-bool LaunchChromeAndWaitForResult(bool system_install,
- const std::wstring& options,
- int32* exit_code);
-
-// This function 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.)
-//
-// chrome_path: the root path of Chrome installation.
-// latest_version_str: the latest version of Chrome installed.
-void RemoveOldVersionDirs(const std::wstring& chrome_path,
- const std::wstring& latest_version_str);
+FilePath GetChromeUserDataPath(BrowserDistribution* dist);
} // namespace installer
diff --git a/chrome/installer/util/helper_unittest.cc b/chrome/installer/util/helper_unittest.cc
index 7604e49..e9133bf 100644
--- a/chrome/installer/util/helper_unittest.cc
+++ b/chrome/installer/util/helper_unittest.cc
@@ -11,10 +11,15 @@
#include "base/path_service.h"
#include "base/process_util.h"
#include "base/string_util.h"
+#include "chrome/installer/util/package.h"
#include "chrome/installer/util/helper.h"
+#include "chrome/installer/util/version.h"
#include "chrome/installer/util/work_item.h"
#include "testing/gtest/include/gtest/gtest.h"
+using installer::Version;
+using installer::Package;
+
namespace {
class SetupHelperTest : public testing::Test {
protected:
@@ -103,8 +108,9 @@ TEST_F(SetupHelperTest, Delete) {
CreateTextFile(chrome_dll_4.value(), text_content_1);
ASSERT_TRUE(file_util::PathExists(chrome_dll_4));
- std::wstring latest_version(L"1.0.4.0");
- installer::RemoveOldVersionDirs(chrome_dir.value(), latest_version);
+ scoped_ptr<Version> latest_version(Version::GetVersionFromString(L"1.0.4.0"));
+ scoped_refptr<Package> package(new Package(chrome_dir));
+ package->RemoveOldVersionDirectories(*latest_version.get());
// old versions should be gone
EXPECT_FALSE(file_util::PathExists(chrome_dir_1));
@@ -176,8 +182,9 @@ TEST_F(SetupHelperTest, DeleteInUsed) {
CreateTextFile(chrome_dll_4.value(), text_content_1);
ASSERT_TRUE(file_util::PathExists(chrome_dll_4));
- std::wstring latest_version(L"1.0.4.0");
- installer::RemoveOldVersionDirs(chrome_dir.value(), latest_version);
+ scoped_ptr<Version> latest_version(Version::GetVersionFromString(L"1.0.4.0"));
+ scoped_refptr<Package> install_path(new Package(chrome_dir));
+ install_path->RemoveOldVersionDirectories(*latest_version.get());
// old versions not in used should be gone
EXPECT_FALSE(file_util::PathExists(chrome_dir_1));
diff --git a/chrome/installer/util/install_util.cc b/chrome/installer/util/install_util.cc
index 6c11f99..ae9c67d 100644
--- a/chrome/installer/util/install_util.cc
+++ b/chrome/installer/util/install_util.cc
@@ -73,21 +73,23 @@ bool InstallUtil::ExecuteExeAsAdmin(const CommandLine& cmd, DWORD* exit_code) {
return true;
}
-std::wstring InstallUtil::GetChromeUninstallCmd(bool system_install) {
+std::wstring InstallUtil::GetChromeUninstallCmd(bool system_install,
+ BrowserDistribution* dist) {
+ DCHECK(dist);
HKEY root = system_install ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER;
- BrowserDistribution* dist = BrowserDistribution::GetDistribution();
RegKey key(root, dist->GetUninstallRegPath().c_str(), KEY_READ);
std::wstring uninstall_cmd;
key.ReadValue(installer_util::kUninstallStringField, &uninstall_cmd);
return uninstall_cmd;
}
-installer::Version* InstallUtil::GetChromeVersion(bool system_install) {
+installer::Version* InstallUtil::GetChromeVersion(BrowserDistribution* dist,
+ bool system_install) {
+ DCHECK(dist);
RegKey key;
std::wstring version_str;
HKEY reg_root = (system_install) ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER;
- BrowserDistribution* dist = BrowserDistribution::GetDistribution();
if (!key.Open(reg_root, dist->GetVersionKey().c_str(), KEY_READ) ||
!key.ReadValue(google_update::kRegVersionField, &version_str)) {
VLOG(1) << "No existing Chrome install found.";
@@ -111,34 +113,6 @@ bool InstallUtil::IsOSSupported() {
(version == base::win::VERSION_XP && major >= 2);
}
-void InstallUtil::WriteInstallerResult(bool system_install,
- installer_util::InstallStatus status,
- int string_resource_id,
- const std::wstring* const launch_cmd) {
- HKEY root = system_install ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER;
- BrowserDistribution* dist = BrowserDistribution::GetDistribution();
- std::wstring key = dist->GetStateKey();
- int installer_result = (dist->GetInstallReturnCode(status) == 0) ? 0 : 1;
- scoped_ptr<WorkItemList> install_list(WorkItem::CreateWorkItemList());
- install_list->AddCreateRegKeyWorkItem(root, key);
- install_list->AddSetRegValueWorkItem(root, key, L"InstallerResult",
- installer_result, true);
- install_list->AddSetRegValueWorkItem(root, key, L"InstallerError",
- status, true);
- if (string_resource_id != 0) {
- std::wstring msg = installer_util::GetLocalizedString(string_resource_id);
- install_list->AddSetRegValueWorkItem(root, key, L"InstallerResultUIString",
- msg, true);
- }
- if (launch_cmd != NULL && !launch_cmd->empty()) {
- install_list->AddSetRegValueWorkItem(root, key,
- L"InstallerSuccessLaunchCmdLine",
- *launch_cmd, true);
- }
- if (!install_list->Do())
- LOG(ERROR) << "Failed to record installer error information in registry.";
-}
-
bool InstallUtil::IsPerUserInstall(const wchar_t* const exe_path) {
wchar_t program_files_path[MAX_PATH] = {0};
if (SUCCEEDED(SHGetFolderPath(NULL, CSIDL_PROGRAM_FILES, NULL,
@@ -155,7 +129,7 @@ bool InstallUtil::IsChromeFrameProcess() {
return prefs.install_chrome_frame();
}
-bool InstallUtil::IsChromeSxSProcess() {
+bool CheckIsChromeSxSProcess() {
CommandLine* command_line = CommandLine::ForCurrentProcess();
CHECK(command_line);
@@ -173,64 +147,9 @@ bool InstallUtil::IsChromeSxSProcess() {
chrome_sxs_dir);
}
-bool InstallUtil::IsMSIProcess(bool system_level) {
- // Initialize the static msi flags.
- static bool is_msi_ = false;
- static bool msi_checked_ = false;
-
- if (!msi_checked_) {
- msi_checked_ = true;
-
- const MasterPreferences& prefs = GetMasterPreferencesForCurrentProcess();
-
- bool is_msi = false;
- prefs.GetBool(installer_util::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;
- DWORD msi_value;
-
- BrowserDistribution* dist = BrowserDistribution::GetDistribution();
- DCHECK(dist);
-
- bool success = false;
- std::wstring reg_key(dist->GetStateKey());
- if (key.Open(reg_root, reg_key.c_str(), KEY_READ | KEY_WRITE)) {
- if (key.ReadValueDW(google_update::kRegMSIField, &msi_value)) {
- is_msi = (msi_value == 1);
- }
- }
- }
-
- is_msi_ = is_msi;
- }
-
- return is_msi_;
-}
-
-bool InstallUtil::SetMSIMarker(bool system_level, bool set) {
- BrowserDistribution* dist = BrowserDistribution::GetDistribution();
- DCHECK(dist);
- std::wstring client_state_path(dist->GetStateKey());
-
- bool success = false;
- HKEY reg_root = system_level ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER;
- RegKey client_state_key;
- if (client_state_key.Open(reg_root, client_state_path.c_str(),
- KEY_READ | KEY_WRITE)) {
- DWORD msi_value = set ? 1 : 0;
- if (client_state_key.WriteValue(google_update::kRegMSIField, msi_value)) {
- success = true;
- } else {
- LOG(ERROR) << "Could not write msi value to client state key.";
- }
- } else {
- LOG(ERROR) << "Could not open client state key!";
- }
-
- return success;
+bool InstallUtil::IsChromeSxSProcess() {
+ static bool sxs = CheckIsChromeSxSProcess();
+ return sxs;
}
bool InstallUtil::BuildDLLRegistrationList(const std::wstring& install_path,
@@ -257,8 +176,8 @@ bool InstallUtil::DeleteRegistryKey(RegKey& root_key,
const std::wstring& key_path) {
VLOG(1) << "Deleting registry key " << key_path;
if (!root_key.DeleteKey(key_path.c_str()) &&
- ::GetLastError() != ERROR_MOD_NOT_FOUND) {
- LOG(ERROR) << "Failed to delete registry key: " << key_path;
+ ::GetLastError() != ERROR_FILE_NOT_FOUND) {
+ PLOG(ERROR) << "Failed to delete registry key: " << key_path;
return false;
}
return true;
diff --git a/chrome/installer/util/install_util.h b/chrome/installer/util/install_util.h
index 027a8ee..5fd87be 100644
--- a/chrome/installer/util/install_util.h
+++ b/chrome/installer/util/install_util.h
@@ -21,6 +21,7 @@
#include "chrome/installer/util/version.h"
class WorkItemList;
+class BrowserDistribution;
namespace base {
namespace win {
@@ -39,24 +40,20 @@ class InstallUtil {
// Reads the uninstall command for Chromium from registry and returns it.
// If system_install is true the command is read from HKLM, otherwise
// from HKCU.
- static std::wstring GetChromeUninstallCmd(bool system_install);
+ static std::wstring GetChromeUninstallCmd(bool system_install,
+ BrowserDistribution* dist);
+
// Find the version of Chrome installed on the system by checking the
// Google Update registry key. Returns the version or NULL if no version is
// found.
// system_install: if true, looks for version number under the HKLM root,
// otherwise looks under the HKCU.
- static installer::Version* GetChromeVersion(bool system_install);
+ static installer::Version* GetChromeVersion(BrowserDistribution* dist,
+ bool system_install);
// This function checks if the current OS is supported for Chromium.
static bool IsOSSupported();
- // This function sets installer error information in registry so that Google
- // Update can read it and display to the user.
- static void WriteInstallerResult(bool system_install,
- installer_util::InstallStatus status,
- int string_resource_id,
- const std::wstring* const launch_cmd);
-
// Returns true if this installation path is per user, otherwise returns
// false (per machine install, meaning: the exe_path contains path to
// Program Files).
@@ -74,21 +71,6 @@ class InstallUtil {
// by either --chrome-sxs or the executable path).
static bool IsChromeSxSProcess();
- // 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
- // NOTE: This method is NOT thread safe.
- static bool IsMSIProcess(bool system_level);
-
-
- // 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.
- static bool SetMSIMarker(bool system_level, bool set);
-
// Adds all DLLs in install_path whose names are given by dll_names to a
// work item list containing registration or unregistration actions.
//
diff --git a/chrome/installer/util/package.cc b/chrome/installer/util/package.cc
new file mode 100644
index 0000000..37dc97c
--- /dev/null
+++ b/chrome/installer/util/package.cc
@@ -0,0 +1,148 @@
+// 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/win/registry.h"
+#include "chrome/installer/util/delete_tree_work_item.h"
+#include "chrome/installer/util/google_update_constants.h"
+#include "chrome/installer/util/product.h"
+
+using base::win::RegKey;
+
+namespace installer {
+
+Package::Package(const FilePath& path) : path_(path) {
+}
+
+Package::~Package() {
+}
+
+const FilePath& Package::path() const {
+ return path_;
+}
+
+const Products& Package::products() const {
+ return products_;
+}
+
+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_EQ(product->system_level(), products_[i]->system_level());
+ DCHECK_NE(product->distribution()->GetType(),
+ products_[i]->distribution()->GetType());
+ }
+#endif
+ products_.push_back(product);
+}
+
+bool Package::system_level() const {
+ // Convenience getter that returns the system_level value of the first
+ // product for this folder. All distributions must have the same
+ // value, so the function also checks this in debug builds.
+ if (!products_.size()) {
+ NOTREACHED() << "this should not be possible";
+ return false;
+ }
+ return products_[0]->system_level();
+}
+
+FilePath Package::GetInstallerDirectory(
+ const Version& version) const {
+ return path_.Append(version.GetString())
+ .Append(installer_util::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_util::kChromeNewExe));
+ bool new_chrome_exists = file_util::PathExists(new_chrome_exe);
+
+ for (size_t i = 0; i < products_.size(); ++i) {
+ const Product* product = products_[i];
+ HKEY root = product->system_level() ? HKEY_LOCAL_MACHINE :
+ HKEY_CURRENT_USER;
+ 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(version));
+ if (this_version.get()) {
+ if (!current_version.get() ||
+ current_version->IsHigherThan(this_version.get())) {
+ 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 {
+ std::wstring search_path(path_.value());
+ file_util::AppendToPath(&search_path, L"*");
+
+ // TODO(tommi): use file_util::FileEnumerator.
+ WIN32_FIND_DATA find_file_data;
+ HANDLE file_handle = FindFirstFile(search_path.c_str(), &find_file_data);
+ if (file_handle == INVALID_HANDLE_VALUE) {
+ VLOG(1) << "No directories found under: " << search_path;
+ return;
+ }
+
+ BOOL ret = TRUE;
+ scoped_ptr<Version> version;
+
+ // We try to delete all directories whose versions are lower than
+ // latest_version.
+ while (ret) {
+ if (find_file_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY &&
+ lstrcmpW(find_file_data.cFileName, L"..") != 0 &&
+ lstrcmpW(find_file_data.cFileName, L".") != 0) {
+ VLOG(1) << "directory found: " << find_file_data.cFileName;
+ version.reset(Version::GetVersionFromString(find_file_data.cFileName));
+ if (version.get() && latest_version.IsHigherThan(version.get())) {
+ std::wstring remove_dir(path_.value());
+ file_util::AppendToPath(&remove_dir, find_file_data.cFileName);
+ std::wstring chrome_dll_path(remove_dir);
+ file_util::AppendToPath(&chrome_dll_path, installer_util::kChromeDll);
+ VLOG(1) << "Deleting directory: " << remove_dir;
+ // TODO(tommi): We should support more "key files". One for each
+ // associated Product. Maybe the relative key file path should
+ // be a property of BrowserDistribution.
+ scoped_ptr<DeleteTreeWorkItem> item(
+ WorkItem::CreateDeleteTreeWorkItem(remove_dir, chrome_dll_path));
+ if (!item->Do())
+ item->Rollback();
+ }
+ }
+ ret = FindNextFile(file_handle, &find_file_data);
+ }
+
+ FindClose(file_handle);
+}
+
+} // namespace installer
+
diff --git a/chrome/installer/util/package.h b/chrome/installer/util/package.h
new file mode 100644
index 0000000..c7318e1
--- /dev/null
+++ b/chrome/installer/util/package.h
@@ -0,0 +1,73 @@
+// 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;
+
+namespace installer {
+
+class Product;
+class Version;
+
+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:
+ explicit Package(const FilePath& path);
+
+ // Returns the path of the installation folder.
+ const FilePath& path() const;
+
+ const Products& products() const;
+
+ bool system_level() const;
+
+ bool IsEqual(const FilePath& path) const;
+
+ void AssociateProduct(const Product* distribution);
+
+ // Get path to the installer under Chrome version folder
+ // (for example <path>\Google\Chrome\<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;
+
+ protected:
+ FilePath path_;
+ Products products_;
+
+ 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_unittest.cc b/chrome/installer/util/package_unittest.cc
new file mode 100644
index 0000000..575716d
--- /dev/null
+++ b/chrome/installer/util/package_unittest.cc
@@ -0,0 +1,124 @@
+// 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/scoped_handle.h"
+#include "chrome/installer/util/browser_distribution.h"
+#include "chrome/installer/util/google_update_constants.h"
+#include "chrome/installer/util/package.h"
+#include "chrome/installer/util/product.h"
+#include "chrome/installer/util/product_unittest.h"
+#include "chrome/installer/util/util_constants.h"
+#include "chrome/installer/util/version.h"
+
+using base::win::RegKey;
+using base::win::ScopedHandle;
+using installer::Package;
+using installer::Product;
+using installer::Version;
+
+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) {
+ scoped_refptr<Package> package(new Package(test_dir_.path()));
+ EXPECT_EQ(test_dir_.path().value(), package->path().value());
+ EXPECT_TRUE(package->IsEqual(test_dir_.path()));
+ EXPECT_EQ(0U, package->products().size());
+
+ const wchar_t kOldVersion[] = L"1.2.3.4";
+ const wchar_t kNewVersion[] = L"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(new_version->GetString()));
+ FilePath old_version_dir(package->path().Append(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_util::kChromeDll));
+ EXPECT_FALSE(file_util::PathExists(old_chrome_dll));
+
+ // Hold on to the file exclusively to prevent the directory from
+ // being deleted.
+ 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) {
+ TempRegKeyOverride::DeleteAllTempKeys();
+
+ // TODO(tommi): We should mock this and use our mocked distribution.
+ const bool system_level = true;
+ BrowserDistribution* distribution =
+ BrowserDistribution::GetSpecificDistribution(
+ BrowserDistribution::CHROME_BROWSER);
+ scoped_refptr<Package> package(new Package(test_dir_.path()));
+ scoped_refptr<Product> product(new Product(distribution,
+ system_level,
+ package.get()));
+ EXPECT_EQ(1U, package->products().size());
+ EXPECT_EQ(system_level, package->system_level());
+
+ const wchar_t kCurrentVersion[] = L"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,
+ 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->IsEqual(*found_version.get()));
+ }
+ }
+ }
+
+ TempRegKeyOverride::DeleteAllTempKeys();
+}
diff --git a/chrome/installer/util/product.cc b/chrome/installer/util/product.cc
new file mode 100644
index 0000000..60846e3
--- /dev/null
+++ b/chrome/installer/util/product.cc
@@ -0,0 +1,266 @@
+// 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/product.h"
+
+#include <algorithm>
+
+#include "base/logging.h"
+#include "base/process_util.h"
+#include "base/win/registry.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/l10n_string_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/work_item_list.h"
+
+using base::win::RegKey;
+using installer_util::MasterPreferences;
+
+namespace {
+class ProductIsOfType {
+ public:
+ explicit ProductIsOfType(BrowserDistribution::DistributionType type)
+ : type_(type) { }
+ bool operator()(
+ const scoped_refptr<const installer::Product>& pi) const {
+ return pi->distribution()->GetType() == type_;
+ }
+ private:
+ BrowserDistribution::DistributionType type_;
+}; // class ProductIsOfType
+} // end namespace
+
+namespace installer {
+
+const Product* FindProduct(const Products& products,
+ BrowserDistribution::DistributionType type) {
+ Products::const_iterator i =
+ std::find_if(products.begin(), products.end(), ProductIsOfType(type));
+ return i == products.end() ? NULL : *i;
+}
+
+void WriteInstallerResult(const Products& products,
+ installer_util::InstallStatus status,
+ int string_resource_id,
+ const std::wstring* const launch_cmd) {
+ Products::const_iterator end = products.end();
+ for (Products::const_iterator i = products.begin(); i != end; ++i)
+ (*i)->WriteInstallerResult(status, string_resource_id, launch_cmd);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+Product::Product(BrowserDistribution* distribution, bool system_level,
+ Package* package)
+ : distribution_(distribution),
+ system_level_(system_level),
+ package_(package),
+ msi_(MSI_NOT_CHECKED) {
+ package_->AssociateProduct(this);
+}
+
+const Package& Product::package() const {
+ return *package_.get();
+}
+
+FilePath Product::GetUserDataPath() const {
+ return GetChromeUserDataPath(distribution_);
+}
+
+bool Product::LaunchChrome() const {
+ const FilePath& install_package = package_->path();
+ bool success = !install_package.empty();
+ if (success) {
+ CommandLine cmd(install_package.Append(installer_util::kChromeExe));
+ success = base::LaunchApp(cmd, false, false, NULL);
+ }
+ return success;
+}
+
+bool Product::LaunchChromeAndWait(const CommandLine& options,
+ int32* exit_code) const {
+ const FilePath& install_package = package_->path();
+ if (install_package.empty())
+ return false;
+
+ CommandLine cmd(install_package.Append(installer_util::kChromeExe));
+ cmd.AppendArguments(options, false);
+
+ bool success = false;
+ STARTUPINFOW si = { sizeof(si) };
+ PROCESS_INFORMATION pi = {0};
+ // Cast away constness of the command_line_string() since CreateProcess
+ // might modify the string (insert \0 to separate the program from the
+ // arguments). Since we're not using the cmd variable beyond this point
+ // we don't care.
+ if (!::CreateProcess(cmd.GetProgram().value().c_str(),
+ const_cast<wchar_t*>(cmd.command_line_string().c_str()),
+ NULL, NULL, FALSE, CREATE_NO_WINDOW, NULL, NULL,
+ &si, &pi)) {
+ PLOG(ERROR) << "Failed to launch: " << cmd.command_line_string();
+ } else {
+ ::CloseHandle(pi.hThread);
+
+ DWORD ret = ::WaitForSingleObject(pi.hProcess, INFINITE);
+ DLOG_IF(ERROR, ret != WAIT_OBJECT_0)
+ << "Unexpected return value from WaitForSingleObject: " << ret;
+ if (::GetExitCodeProcess(pi.hProcess, &ret)) {
+ DCHECK(ret != STILL_ACTIVE);
+ success = true;
+ if (exit_code)
+ *exit_code = ret;
+ } else {
+ PLOG(ERROR) << "GetExitCodeProcess failed";
+ }
+
+ ::CloseHandle(pi.hProcess);
+ }
+
+ return success;
+}
+
+bool Product::IsMsi() const {
+ if (msi_ == MSI_NOT_CHECKED) {
+ msi_ = NOT_MSI; // Covers failure cases below.
+
+ const MasterPreferences& prefs =
+ InstallUtil::GetMasterPreferencesForCurrentProcess();
+
+ bool is_msi = false;
+ prefs.GetBool(installer_util::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)) {
+ DWORD msi_value;
+ if (key.ReadValueDW(google_update::kRegMSIField, &msi_value)) {
+ msi_ = (msi_value == 1) ? IS_MSI : NOT_MSI;
+ }
+ }
+ } else {
+ msi_ = IS_MSI;
+ }
+ }
+
+ return msi_ == IS_MSI;
+}
+
+bool Product::SetMsiMarker(bool set) const {
+ bool success = false;
+ HKEY reg_root = system_level_ ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER;
+ RegKey client_state_key;
+ if (client_state_key.Open(reg_root, distribution_->GetStateKey().c_str(),
+ KEY_READ | KEY_WRITE)) {
+ DWORD msi_value = set ? 1 : 0;
+ if (client_state_key.WriteValue(google_update::kRegMSIField, msi_value)) {
+ success = true;
+ } else {
+ LOG(ERROR) << "Could not write MSI value to client state key.";
+ }
+ } else {
+ LOG(ERROR) << "SetMsiMarker: Could not open client state key!";
+ }
+
+ return success;
+}
+
+void Product::WriteInstallerResult(
+ installer_util::InstallStatus status, int string_resource_id,
+ const std::wstring* const launch_cmd) const {
+ HKEY root = system_level_ ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER;
+ std::wstring key(distribution_->GetStateKey());
+ int installer_result = distribution_->GetInstallReturnCode(status) == 0 ?
+ 0 : 1;
+ scoped_ptr<WorkItemList> install_list(WorkItem::CreateWorkItemList());
+ install_list->AddCreateRegKeyWorkItem(root, key);
+ install_list->AddSetRegValueWorkItem(root, key,
+ installer_util::kInstallerResult,
+ installer_result, true);
+ install_list->AddSetRegValueWorkItem(root, key,
+ installer_util::kInstallerError,
+ status, true);
+ if (string_resource_id != 0) {
+ std::wstring msg = installer_util::GetLocalizedString(string_resource_id);
+ install_list->AddSetRegValueWorkItem(root, key,
+ installer_util::kInstallerResultUIString, msg, true);
+ }
+ if (launch_cmd != NULL && !launch_cmd->empty()) {
+ install_list->AddSetRegValueWorkItem(root, key,
+ installer_util::kInstallerSuccessLaunchCmdLine, *launch_cmd, true);
+ }
+ if (!install_list->Do())
+ LOG(ERROR) << "Failed to record installer error information in registry.";
+}
+
+Version* Product::GetInstalledVersion() const {
+ return InstallUtil::GetChromeVersion(distribution_, system_level_);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+ProductPackageMapping::ProductPackageMapping(bool system_level)
+ : system_level_(system_level) {
+}
+
+const Packages& ProductPackageMapping::packages() const {
+ return packages_;
+}
+
+const Products& ProductPackageMapping::products() const {
+ return products_;
+}
+
+bool ProductPackageMapping::AddDistribution(BrowserDistribution* distribution) {
+ DCHECK(distribution);
+ // Each product type can be added exactly once.
+ DCHECK(FindProduct(products_, distribution->GetType()) == NULL);
+
+ FilePath install_package(GetChromeInstallPath(system_level_, distribution));
+
+ 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()) {
+ // create new one and add.
+ target_package = new Package(install_package);
+ packages_.push_back(target_package);
+ }
+
+ scoped_refptr<Product> product(
+ new Product(distribution, system_level_, 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;
+}
+
+bool ProductPackageMapping::AddDistribution(
+ BrowserDistribution::DistributionType type) {
+ BrowserDistribution* distribution =
+ BrowserDistribution::GetSpecificDistribution(type);
+ if (!distribution) {
+ NOTREACHED();
+ return false;
+ }
+
+ return AddDistribution(distribution);
+}
+
+} // namespace installer
+
diff --git a/chrome/installer/util/product.h b/chrome/installer/util/product.h
new file mode 100644
index 0000000..639e48a
--- /dev/null
+++ b/chrome/installer/util/product.h
@@ -0,0 +1,151 @@
+// 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_PRODUCT_H_
+#define CHROME_INSTALLER_UTIL_PRODUCT_H_
+#pragma once
+
+#include <vector>
+
+#include "base/ref_counted.h"
+#include "chrome/installer/util/browser_distribution.h"
+#include "chrome/installer/util/package.h"
+
+class CommandLine;
+
+namespace installer {
+
+class Product;
+class Package;
+class Version;
+
+typedef std::vector<scoped_refptr<Package> > Packages;
+typedef std::vector<scoped_refptr<const Product> > Products;
+
+const Product* FindProduct(const Products& products,
+ BrowserDistribution::DistributionType type);
+
+// Calls WriteInstallerResult for each Product object.
+void WriteInstallerResult(const Products& products,
+ installer_util::InstallStatus status,
+ int string_resource_id,
+ const std::wstring* const launch_cmd);
+
+// Represents an installation of a specific product which has a one-to-one
+// relation to a BrowserDistribution. A product has registry settings, related
+// installation/uninstallation actions and exactly one Package that represents
+// the files on disk. The Package may be shared with other Product instances,
+// so only the last Product to be uninstalled should remove the package.
+// Right now there are no classes that derive from Product, but in
+// 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> {
+ public:
+ Product(BrowserDistribution* distribution, bool system_level,
+ Package* installation_package);
+
+ BrowserDistribution* distribution() const {
+ return distribution_;
+ }
+
+ bool system_level() const {
+ return system_level_;
+ }
+
+ // 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;
+
+ // 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
+ // a command line parameter.
+ FilePath GetUserDataPath() const;
+
+ // Launches Chrome without waiting for it to exit.
+ bool LaunchChrome() const;
+
+ // Launches Chrome with given command line, waits for Chrome indefinitely
+ // (until it terminates), and gets the process exit code if available.
+ // The function returns true as long as Chrome is successfully launched.
+ // 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;
+
+ // 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;
+
+ // Sets installer error information in registry so that Google Update can read
+ // it and display to the user.
+ void WriteInstallerResult(installer_util::InstallStatus status,
+ int string_resource_id,
+ const std::wstring* const launch_cmd) const;
+
+ // Find the version of this product installed on the system by checking the
+ // Google Update registry key. Returns the version or NULL if no version is
+ // found. Caller must free the returned Version object.
+ Version* GetInstalledVersion() const;
+
+ protected:
+ BrowserDistribution* distribution_;
+ scoped_refptr<Package> package_;
+ bool system_level_;
+ mutable enum MsiState {
+ MSI_NOT_CHECKED,
+ IS_MSI,
+ NOT_MSI,
+ } msi_;
+
+ 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 system_level);
+
+ bool system_level() const {
+ return system_level_;
+ }
+
+ const Packages& packages() const;
+
+ const Products& products() const;
+
+ bool AddDistribution(BrowserDistribution::DistributionType type);
+ bool AddDistribution(BrowserDistribution* distribution);
+
+ protected:
+ bool system_level_;
+ Packages packages_;
+ Products products_;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(ProductPackageMapping);
+};
+
+} // namespace installer
+
+#endif // CHROME_INSTALLER_UTIL_PRODUCT_H_
diff --git a/chrome/installer/util/product_unittest.cc b/chrome/installer/util/product_unittest.cc
new file mode 100644
index 0000000..7dab702
--- /dev/null
+++ b/chrome/installer/util/product_unittest.cc
@@ -0,0 +1,179 @@
+// 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/product_unittest.h"
+
+#include "base/logging.h"
+#include "base/scoped_handle.h"
+#include "chrome/installer/util/chrome_frame_distribution.h"
+#include "chrome/installer/util/google_update_constants.h"
+#include "chrome/installer/util/product.h"
+
+using base::win::RegKey;
+using base::win::ScopedHandle;
+using installer::Package;
+using installer::Product;
+using installer::ProductPackageMapping;
+using installer::Version;
+
+void TestWithTempDir::SetUp() {
+ // Name a subdirectory of the user temp directory.
+ ASSERT_TRUE(test_dir_.CreateUniqueTempDir());
+}
+
+void TestWithTempDir::TearDown() {
+ logging::CloseLogFile();
+ ASSERT_TRUE(test_dir_.Delete());
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+void TestWithTempDirAndDeleteTempOverrideKeys::SetUp() {
+ TempRegKeyOverride::DeleteAllTempKeys();
+ TestWithTempDir::SetUp();
+}
+
+void TestWithTempDirAndDeleteTempOverrideKeys::TearDown() {
+ TestWithTempDir::TearDown();
+ TempRegKeyOverride::DeleteAllTempKeys();
+}
+
+////////////////////////////////////////////////////////////////////////////////
+const wchar_t TempRegKeyOverride::kTempTestKeyPath[] =
+ L"Software\\Chromium\\TempTestKeys";
+
+TempRegKeyOverride::TempRegKeyOverride(HKEY override, const wchar_t* temp_name)
+ : override_(override), temp_name_(temp_name) {
+ DCHECK(temp_name && lstrlenW(temp_name));
+ std::wstring key_path(kTempTestKeyPath);
+ key_path += L"\\" + temp_name_;
+ EXPECT_TRUE(temp_key_.Create(HKEY_CURRENT_USER, key_path.c_str(),
+ KEY_ALL_ACCESS));
+ EXPECT_EQ(ERROR_SUCCESS,
+ ::RegOverridePredefKey(override_, temp_key_.Handle()));
+}
+
+TempRegKeyOverride::~TempRegKeyOverride() {
+ ::RegOverridePredefKey(override_, NULL);
+ // The temp key will be deleted via a call to DeleteAllTempKeys().
+}
+
+// static
+void TempRegKeyOverride::DeleteAllTempKeys() {
+ RegKey key;
+ if (key.Open(HKEY_CURRENT_USER, L"", KEY_ALL_ACCESS)) {
+ key.DeleteKey(kTempTestKeyPath);
+ }
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+class ProductTest : public TestWithTempDirAndDeleteTempOverrideKeys {
+ protected:
+};
+
+TEST_F(ProductTest, ProductInstallBasic) {
+ // TODO(tommi): We should mock this and use our mocked distribution.
+ const bool system_level = true;
+ BrowserDistribution* distribution =
+ BrowserDistribution::GetSpecificDistribution(
+ BrowserDistribution::CHROME_BROWSER);
+ scoped_refptr<Package> package(new Package(test_dir_.path()));
+ scoped_refptr<Product> product(new Product(distribution, system_level,
+ package.get()));
+
+ EXPECT_EQ(system_level, product->system_level());
+ FilePath user_data(product->GetUserDataPath());
+ EXPECT_FALSE(user_data.empty());
+ EXPECT_NE(std::wstring::npos,
+ user_data.value().find(installer_util::kInstallUserDataDir));
+
+ FilePath program_files;
+ PathService::Get(base::DIR_PROGRAM_FILES, &program_files);
+ // The User Data path should never be under program files, even though
+ // system_level is true.
+ EXPECT_EQ(std::wstring::npos,
+ user_data.value().find(program_files.value()));
+
+ // We started out with a non-msi product.
+ EXPECT_FALSE(product->IsMsi());
+
+ HKEY root = system_level ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER;
+ {
+ TempRegKeyOverride override(root, L"root_pit");
+
+ // Create a make-believe client state key.
+ RegKey key;
+ std::wstring state_key_path(distribution->GetStateKey());
+ ASSERT_TRUE(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(test_dir_.path());
+ product = new Product(distribution, system_level, package.get());
+ EXPECT_TRUE(product->IsMsi());
+
+ // See if WriteInstallerResult writes anything.
+ std::wstring launch_cmd(L"chrome.exe --this-is-a-test");
+ product->WriteInstallerResult(installer_util::TEMP_DIR_FAILED,
+ 0, &launch_cmd);
+ std::wstring found_launch_cmd;
+ key.ReadValue(installer_util::kInstallerSuccessLaunchCmdLine,
+ &found_launch_cmd);
+ EXPECT_EQ(launch_cmd, found_launch_cmd);
+
+ // There should be no installed version in the registry.
+ EXPECT_TRUE(product->GetInstalledVersion() == NULL);
+
+ // Let's pretend chrome is installed.
+ RegKey version_key(root, distribution->GetVersionKey().c_str(),
+ KEY_ALL_ACCESS);
+ ASSERT_TRUE(version_key.Valid());
+
+ const wchar_t kCurrentVersion[] = L"1.2.3.4";
+ scoped_ptr<Version> current_version(
+ Version::GetVersionFromString(kCurrentVersion));
+ version_key.WriteValue(google_update::kRegVersionField,
+ current_version->GetString().c_str());
+
+ scoped_ptr<Version> installed(product->GetInstalledVersion());
+ EXPECT_TRUE(installed.get() != NULL);
+ if (installed.get()) {
+ EXPECT_TRUE(installed->IsEqual(*current_version.get()));
+ }
+ }
+}
+
+TEST_F(ProductTest, LaunchChrome) {
+ // TODO(tommi): Test Product::LaunchChrome and
+ // 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:
+ virtual std::wstring GetInstallSubDir() {
+ return BrowserDistribution::GetSpecificDistribution(
+ BrowserDistribution::CHROME_BROWSER)->GetInstallSubDir();
+ }
+};
+
+TEST_F(ProductTest, ProductInstallsBasic) {
+ const bool system_level = true;
+ ProductPackageMapping installs(system_level);
+ EXPECT_EQ(system_level, installs.system_level());
+ EXPECT_EQ(0U, installs.packages().size());
+ EXPECT_EQ(0U, installs.products().size());
+
+ installs.AddDistribution(BrowserDistribution::CHROME_BROWSER);
+ FakeChromeFrameDistribution fake_chrome_frame;
+ 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());
+}
diff --git a/chrome/installer/util/product_unittest.h b/chrome/installer/util/product_unittest.h
new file mode 100644
index 0000000..31f630c
--- /dev/null
+++ b/chrome/installer/util/product_unittest.h
@@ -0,0 +1,49 @@
+// 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_PRODUCT_UNITTEST_H_
+#define CHROME_INSTALLER_UTIL_PRODUCT_UNITTEST_H_
+#pragma once
+
+#include <windows.h>
+
+#include "base/file_path.h"
+#include "base/file_util.h"
+#include "base/path_service.h"
+#include "base/scoped_temp_dir.h"
+#include "base/win/registry.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+class TestWithTempDir : public testing::Test {
+ protected:
+ virtual void SetUp();
+ virtual void TearDown();
+
+ ScopedTempDir test_dir_;
+};
+
+class TestWithTempDirAndDeleteTempOverrideKeys : public TestWithTempDir {
+ protected:
+ virtual void SetUp();
+ virtual void TearDown();
+};
+
+// TODO(tommi): This is "borrowed" from Chrome Frame test code. It should be
+// moved to some common test utility file.
+class TempRegKeyOverride {
+ public:
+ static const wchar_t kTempTestKeyPath[];
+
+ TempRegKeyOverride(HKEY override, const wchar_t* temp_name);
+ ~TempRegKeyOverride();
+
+ static void DeleteAllTempKeys();
+
+ protected:
+ HKEY override_;
+ base::win::RegKey temp_key_;
+ std::wstring temp_name_;
+};
+
+#endif // CHROME_INSTALLER_UTIL_PRODUCT_UNITTEST_H_
diff --git a/chrome/installer/util/shell_util.cc b/chrome/installer/util/shell_util.cc
index b82bbf8..734c90d9 100644
--- a/chrome/installer/util/shell_util.cc
+++ b/chrome/installer/util/shell_util.cc
@@ -47,10 +47,11 @@ class RegistryEntry {
public:
// This method returns a list of all the registry entries that
// are needed to register Chromium ProgIds.
- static bool GetProgIdEntries(const std::wstring& chrome_exe,
+ static bool GetProgIdEntries(BrowserDistribution* dist,
+ const std::wstring& chrome_exe,
const std::wstring& suffix,
std::list<RegistryEntry*>* entries) {
- std::wstring icon_path = ShellUtil::GetChromeIcon(chrome_exe);
+ std::wstring icon_path = ShellUtil::GetChromeIcon(dist, chrome_exe);
std::wstring open_cmd = ShellUtil::GetChromeShellOpenCmd(chrome_exe);
// File association ProgId
@@ -71,13 +72,13 @@ class RegistryEntry {
// This method returns a list of all the system level registry entries that
// are needed to register Chromium on the machine.
- static bool GetSystemEntries(const std::wstring& chrome_exe,
+ static bool GetSystemEntries(BrowserDistribution* dist,
+ const std::wstring& chrome_exe,
const std::wstring& suffix,
std::list<RegistryEntry*>* entries) {
- std::wstring icon_path = ShellUtil::GetChromeIcon(chrome_exe);
+ std::wstring icon_path = ShellUtil::GetChromeIcon(dist, chrome_exe);
std::wstring quoted_exe_path = L"\"" + chrome_exe + L"\"";
- BrowserDistribution* dist = BrowserDistribution::GetDistribution();
std::wstring app_name = dist->GetApplicationName() + suffix;
std::wstring start_menu_entry(ShellUtil::kRegStartMenuInternet);
start_menu_entry.append(L"\\" + app_name);
@@ -137,7 +138,8 @@ class RegistryEntry {
// This method returns a list of all the user level registry entries that
// are needed to make Chromium default browser.
- static bool GetUserEntries(const std::wstring& chrome_exe,
+ static bool GetUserEntries(BrowserDistribution* dist,
+ const std::wstring& chrome_exe,
const std::wstring& suffix,
std::list<RegistryEntry*>* entries) {
// File extension associations.
@@ -151,7 +153,7 @@ class RegistryEntry {
// Protocols associations.
std::wstring chrome_open = ShellUtil::GetChromeShellOpenCmd(chrome_exe);
- std::wstring chrome_icon = ShellUtil::GetChromeIcon(chrome_exe);
+ std::wstring chrome_icon = ShellUtil::GetChromeIcon(dist, chrome_exe);
for (int i = 0; ShellUtil::kProtocolAssociations[i] != NULL; i++) {
std::wstring url_key(ShellUtil::kRegClasses);
file_util::AppendToPath(&url_key, ShellUtil::kProtocolAssociations[i]);
@@ -175,7 +177,6 @@ class RegistryEntry {
// start->Internet shortcut.
std::wstring start_menu(ShellUtil::kRegStartMenuInternet);
- BrowserDistribution* dist = BrowserDistribution::GetDistribution();
std::wstring app_name = dist->GetApplicationName() + suffix;
entries->push_front(new RegistryEntry(start_menu, app_name));
return true;
@@ -279,13 +280,14 @@ bool AddRegistryEntries(HKEY root, const std::list<RegistryEntry*>& entries) {
// This method checks if Chrome is already registered on the local machine.
// It gets all the required registry entries for Chrome and then checks if
// they exist in HKLM. Returns true if all the entries exist, otherwise false.
-bool IsChromeRegistered(const std::wstring& chrome_exe,
+bool IsChromeRegistered(BrowserDistribution* dist,
+ const std::wstring& chrome_exe,
const std::wstring& suffix) {
bool registered = true;
std::list<RegistryEntry*> entries;
STLElementDeleter<std::list<RegistryEntry*>> entries_deleter(&entries);
- RegistryEntry::GetProgIdEntries(chrome_exe, suffix, &entries);
- RegistryEntry::GetSystemEntries(chrome_exe, suffix, &entries);
+ RegistryEntry::GetProgIdEntries(dist, chrome_exe, suffix, &entries);
+ RegistryEntry::GetSystemEntries(dist, chrome_exe, suffix, &entries);
for (std::list<RegistryEntry*>::const_iterator itr = entries.begin();
itr != entries.end() && registered; ++itr) {
// We do not need registered = registered && ... since the loop condition
@@ -299,13 +301,13 @@ bool IsChromeRegistered(const std::wstring& chrome_exe,
// That will show the user the standard Vista elevation prompt. If the user
// accepts it the new process will make the necessary changes and return SUCCESS
// that we capture and return.
-bool ElevateAndRegisterChrome(const std::wstring& chrome_exe,
+bool ElevateAndRegisterChrome(BrowserDistribution* dist,
+ const std::wstring& chrome_exe,
const std::wstring& suffix) {
FilePath exe_path =
FilePath::FromWStringHack(chrome_exe).DirName()
.Append(installer_util::kSetupExe);
if (!file_util::PathExists(exe_path)) {
- BrowserDistribution* dist = BrowserDistribution::GetDistribution();
HKEY reg_root = InstallUtil::IsPerUserInstall(chrome_exe.c_str()) ?
HKEY_CURRENT_USER : HKEY_LOCAL_MACHINE;
RegKey key(reg_root, dist->GetUninstallRegPath().c_str(), KEY_READ);
@@ -348,9 +350,9 @@ bool ElevateAndRegisterChrome(const std::wstring& chrome_exe,
// - Finally to handle the default install path (C:\Document and Settings\
// <user>\Local Settings\Application Data\Chromium\Application) the value
// of the above key should differ from |chrome_exe| only in user name.
-bool AnotherUserHasDefaultBrowser(const std::wstring& chrome_exe) {
+bool AnotherUserHasDefaultBrowser(BrowserDistribution* dist,
+ const std::wstring& chrome_exe) {
std::wstring reg_key(ShellUtil::kRegStartMenuInternet);
- BrowserDistribution* dist = BrowserDistribution::GetDistribution();
reg_key.append(L"\\" + dist->GetApplicationName() + ShellUtil::kRegShellOpen);
RegKey key(HKEY_LOCAL_MACHINE, reg_key.c_str(), KEY_READ);
std::wstring registry_chrome_exe;
@@ -424,12 +426,13 @@ const wchar_t* ShellUtil::kProtocolAssociations[] = {L"ftp", L"http", L"https",
NULL};
const wchar_t* ShellUtil::kRegUrlProtocol = L"URL Protocol";
-bool ShellUtil::AdminNeededForRegistryCleanup(const std::wstring& suffix) {
+bool ShellUtil::AdminNeededForRegistryCleanup(BrowserDistribution* dist,
+ const std::wstring& suffix) {
bool cleanup_needed = false;
std::list<RegistryEntry*> entries;
STLElementDeleter<std::list<RegistryEntry*>> entries_deleter(&entries);
- RegistryEntry::GetProgIdEntries(L"chrome.exe", suffix, &entries);
- RegistryEntry::GetSystemEntries(L"chrome.exe", suffix, &entries);
+ RegistryEntry::GetProgIdEntries(dist, L"chrome.exe", suffix, &entries);
+ RegistryEntry::GetSystemEntries(dist, L"chrome.exe", suffix, &entries);
for (std::list<RegistryEntry*>::const_iterator itr = entries.begin();
itr != entries.end() && !cleanup_needed; ++itr) {
cleanup_needed = (*itr)->NameExistsInHKLM();
@@ -437,12 +440,13 @@ bool ShellUtil::AdminNeededForRegistryCleanup(const std::wstring& suffix) {
return cleanup_needed;
}
-bool ShellUtil::CreateChromeDesktopShortcut(const std::wstring& chrome_exe,
+bool ShellUtil::CreateChromeDesktopShortcut(BrowserDistribution* dist,
+ const std::wstring& chrome_exe,
const std::wstring& description,
int shell_change, bool alternate,
bool create_new) {
std::wstring shortcut_name;
- if (!ShellUtil::GetChromeShortcutName(&shortcut_name, alternate))
+ if (!ShellUtil::GetChromeShortcutName(dist, &shortcut_name, alternate))
return false;
bool ret = true;
@@ -450,7 +454,7 @@ bool ShellUtil::CreateChromeDesktopShortcut(const std::wstring& chrome_exe,
std::wstring shortcut_path;
if (ShellUtil::GetDesktopPath(false, &shortcut_path)) {
file_util::AppendToPath(&shortcut_path, shortcut_name);
- ret = ShellUtil::UpdateChromeShortcut(chrome_exe, shortcut_path,
+ ret = ShellUtil::UpdateChromeShortcut(dist, chrome_exe, shortcut_path,
description, create_new);
} else {
ret = false;
@@ -462,7 +466,7 @@ bool ShellUtil::CreateChromeDesktopShortcut(const std::wstring& chrome_exe,
file_util::AppendToPath(&shortcut_path, shortcut_name);
// Note we need to call the create operation and then AND the result
// with the create operation of user level shortcut.
- ret = ShellUtil::UpdateChromeShortcut(chrome_exe, shortcut_path,
+ ret = ShellUtil::UpdateChromeShortcut(dist, chrome_exe, shortcut_path,
description, create_new) && ret;
} else {
ret = false;
@@ -471,11 +475,12 @@ bool ShellUtil::CreateChromeDesktopShortcut(const std::wstring& chrome_exe,
return ret;
}
-bool ShellUtil::CreateChromeQuickLaunchShortcut(const std::wstring& chrome_exe,
+bool ShellUtil::CreateChromeQuickLaunchShortcut(BrowserDistribution* dist,
+ const std::wstring& chrome_exe,
int shell_change,
bool create_new) {
std::wstring shortcut_name;
- if (!ShellUtil::GetChromeShortcutName(&shortcut_name, false))
+ if (!ShellUtil::GetChromeShortcutName(dist, &shortcut_name, false))
return false;
bool ret = true;
@@ -484,7 +489,7 @@ bool ShellUtil::CreateChromeQuickLaunchShortcut(const std::wstring& chrome_exe,
std::wstring user_ql_path;
if (ShellUtil::GetQuickLaunchPath(false, &user_ql_path)) {
file_util::AppendToPath(&user_ql_path, shortcut_name);
- ret = ShellUtil::UpdateChromeShortcut(chrome_exe, user_ql_path,
+ ret = ShellUtil::UpdateChromeShortcut(dist, chrome_exe, user_ql_path,
L"", create_new);
} else {
ret = false;
@@ -497,7 +502,7 @@ bool ShellUtil::CreateChromeQuickLaunchShortcut(const std::wstring& chrome_exe,
std::wstring default_ql_path;
if (ShellUtil::GetQuickLaunchPath(true, &default_ql_path)) {
file_util::AppendToPath(&default_ql_path, shortcut_name);
- ret = ShellUtil::UpdateChromeShortcut(chrome_exe, default_ql_path,
+ ret = ShellUtil::UpdateChromeShortcut(dist, chrome_exe, default_ql_path,
L"", create_new) && ret;
} else {
ret = false;
@@ -507,8 +512,8 @@ bool ShellUtil::CreateChromeQuickLaunchShortcut(const std::wstring& chrome_exe,
return ret;
}
-std::wstring ShellUtil::GetChromeIcon(const std::wstring& chrome_exe) {
- BrowserDistribution* dist = BrowserDistribution::GetDistribution();
+std::wstring ShellUtil::GetChromeIcon(BrowserDistribution* dist,
+ const std::wstring& chrome_exe) {
std::wstring chrome_icon(chrome_exe);
chrome_icon.append(L",");
chrome_icon.append(base::IntToString16(dist->GetIconIndex()));
@@ -519,8 +524,8 @@ std::wstring ShellUtil::GetChromeShellOpenCmd(const std::wstring& chrome_exe) {
return L"\"" + chrome_exe + L"\" -- \"%1\"";
}
-bool ShellUtil::GetChromeShortcutName(std::wstring* shortcut, bool alternate) {
- BrowserDistribution* dist = BrowserDistribution::GetDistribution();
+bool ShellUtil::GetChromeShortcutName(BrowserDistribution* dist,
+ std::wstring* shortcut, bool alternate) {
shortcut->assign(alternate ? dist->GetAlternateApplicationName() :
dist->GetAppShortCutName());
shortcut->append(L".lnk");
@@ -567,7 +572,8 @@ bool ShellUtil::GetQuickLaunchPath(bool system_level, std::wstring* path) {
return true;
}
-void ShellUtil::GetRegisteredBrowsers(std::map<std::wstring,
+void ShellUtil::GetRegisteredBrowsers(BrowserDistribution* dist,
+ std::map<std::wstring,
std::wstring>* browsers) {
std::wstring base_key(ShellUtil::kRegStartMenuInternet);
HKEY root = HKEY_LOCAL_MACHINE;
@@ -587,14 +593,14 @@ void ShellUtil::GetRegisteredBrowsers(std::map<std::wstring,
if (!install_info.Valid() ||
!install_info.ReadValue(L"ReinstallCommand", &command))
continue;
- BrowserDistribution* dist = BrowserDistribution::GetDistribution();
if (!name.empty() && !command.empty() &&
name.find(dist->GetApplicationName()) == std::wstring::npos)
(*browsers)[name] = command;
}
}
-bool ShellUtil::GetUserSpecificDefaultBrowserSuffix(std::wstring* entry) {
+bool ShellUtil::GetUserSpecificDefaultBrowserSuffix(BrowserDistribution* dist,
+ std::wstring* entry) {
wchar_t user_name[256];
DWORD size = _countof(user_name);
if (::GetUserName(user_name, &size) == 0)
@@ -603,19 +609,19 @@ bool ShellUtil::GetUserSpecificDefaultBrowserSuffix(std::wstring* entry) {
entry->append(user_name);
std::wstring start_menu_entry(ShellUtil::kRegStartMenuInternet);
- BrowserDistribution* dist = BrowserDistribution::GetDistribution();
start_menu_entry.append(L"\\" + dist->GetApplicationName() + *entry);
RegKey key(HKEY_LOCAL_MACHINE, start_menu_entry.c_str(), KEY_READ);
return key.Valid();
}
-bool ShellUtil::MakeChromeDefault(int shell_change,
+bool ShellUtil::MakeChromeDefault(BrowserDistribution* dist,
+ int shell_change,
const std::wstring& chrome_exe,
bool elevate_if_not_admin) {
- if (!BrowserDistribution::GetDistribution()->CanSetAsDefault())
+ if (!dist->CanSetAsDefault())
return false;
- ShellUtil::RegisterChromeBrowser(chrome_exe, L"", elevate_if_not_admin);
+ ShellUtil::RegisterChromeBrowser(dist, chrome_exe, L"", elevate_if_not_admin);
bool ret = true;
// First use the new "recommended" way on Vista to make Chrome default
@@ -627,10 +633,9 @@ bool ShellUtil::MakeChromeDefault(int shell_change,
NULL, CLSCTX_INPROC, __uuidof(IApplicationAssociationRegistration),
(void**)&pAAR);
if (SUCCEEDED(hr)) {
- BrowserDistribution* dist = BrowserDistribution::GetDistribution();
std::wstring app_name = dist->GetApplicationName();
std::wstring suffix;
- if (ShellUtil::GetUserSpecificDefaultBrowserSuffix(&suffix))
+ if (ShellUtil::GetUserSpecificDefaultBrowserSuffix(dist, &suffix))
app_name += suffix;
hr = pAAR->SetAppAsDefaultAll(app_name.c_str());
@@ -650,9 +655,9 @@ bool ShellUtil::MakeChromeDefault(int shell_change,
std::list<RegistryEntry*> entries;
STLElementDeleter<std::list<RegistryEntry*>> entries_deleter(&entries);
std::wstring suffix;
- if (!GetUserSpecificDefaultBrowserSuffix(&suffix))
+ if (!GetUserSpecificDefaultBrowserSuffix(dist, &suffix))
suffix = L"";
- RegistryEntry::GetUserEntries(chrome_exe, suffix, &entries);
+ RegistryEntry::GetUserEntries(dist, chrome_exe, suffix, &entries);
// Change the default browser for current user.
if ((shell_change & ShellUtil::CURRENT_USER) &&
!AddRegistryEntries(HKEY_CURRENT_USER, entries))
@@ -669,10 +674,11 @@ bool ShellUtil::MakeChromeDefault(int shell_change,
return ret;
}
-bool ShellUtil::RegisterChromeBrowser(const std::wstring& chrome_exe,
+bool ShellUtil::RegisterChromeBrowser(BrowserDistribution* dist,
+ const std::wstring& chrome_exe,
const std::wstring& unique_suffix,
bool elevate_if_not_admin) {
- if (!BrowserDistribution::GetDistribution()->CanSetAsDefault())
+ if (!dist->CanSetAsDefault())
return false;
// First figure out we need to append a suffix to the registry entries to
@@ -681,41 +687,42 @@ bool ShellUtil::RegisterChromeBrowser(const std::wstring& chrome_exe,
if (!unique_suffix.empty()) {
suffix = unique_suffix;
} else if (InstallUtil::IsPerUserInstall(chrome_exe.c_str()) &&
- !GetUserSpecificDefaultBrowserSuffix(&suffix) &&
- !AnotherUserHasDefaultBrowser(chrome_exe)) {
+ !GetUserSpecificDefaultBrowserSuffix(dist, &suffix) &&
+ !AnotherUserHasDefaultBrowser(dist, chrome_exe)) {
suffix = L"";
}
// Check if Chromium is already registered with this suffix.
- if (IsChromeRegistered(chrome_exe, suffix))
+ if (IsChromeRegistered(dist, chrome_exe, suffix))
return true;
// If user is an admin try to register and return the status.
if (IsUserAnAdmin()) {
std::list<RegistryEntry*> entries;
STLElementDeleter<std::list<RegistryEntry*>> entries_deleter(&entries);
- RegistryEntry::GetProgIdEntries(chrome_exe, suffix, &entries);
- RegistryEntry::GetSystemEntries(chrome_exe, suffix, &entries);
+ RegistryEntry::GetProgIdEntries(dist, chrome_exe, suffix, &entries);
+ RegistryEntry::GetSystemEntries(dist, chrome_exe, suffix, &entries);
return AddRegistryEntries(HKEY_LOCAL_MACHINE, entries);
}
// If user is not an admin and OS is Vista, try to elevate and register.
if (elevate_if_not_admin &&
base::win::GetVersion() >= base::win::VERSION_VISTA &&
- ElevateAndRegisterChrome(chrome_exe, suffix))
+ ElevateAndRegisterChrome(dist, chrome_exe, suffix))
return true;
// If we got to this point then all we can do is create ProgIds under HKCU
// on XP as well as Vista.
std::list<RegistryEntry*> entries;
STLElementDeleter<std::list<RegistryEntry*>> entries_deleter(&entries);
- RegistryEntry::GetProgIdEntries(chrome_exe, L"", &entries);
+ RegistryEntry::GetProgIdEntries(dist, chrome_exe, L"", &entries);
return AddRegistryEntries(HKEY_CURRENT_USER, entries);
}
-bool ShellUtil::RemoveChromeDesktopShortcut(int shell_change, bool alternate) {
+bool ShellUtil::RemoveChromeDesktopShortcut(BrowserDistribution* dist,
+ int shell_change, bool alternate) {
std::wstring shortcut_name;
- if (!ShellUtil::GetChromeShortcutName(&shortcut_name, alternate))
+ if (!ShellUtil::GetChromeShortcutName(dist, &shortcut_name, alternate))
return false;
bool ret = true;
@@ -741,9 +748,10 @@ bool ShellUtil::RemoveChromeDesktopShortcut(int shell_change, bool alternate) {
return ret;
}
-bool ShellUtil::RemoveChromeQuickLaunchShortcut(int shell_change) {
+bool ShellUtil::RemoveChromeQuickLaunchShortcut(BrowserDistribution* dist,
+ int shell_change) {
std::wstring shortcut_name;
- if (!ShellUtil::GetChromeShortcutName(&shortcut_name, false))
+ if (!ShellUtil::GetChromeShortcutName(dist, &shortcut_name, false))
return false;
bool ret = true;
@@ -772,11 +780,11 @@ bool ShellUtil::RemoveChromeQuickLaunchShortcut(int shell_change) {
return ret;
}
-bool ShellUtil::UpdateChromeShortcut(const std::wstring& chrome_exe,
+bool ShellUtil::UpdateChromeShortcut(BrowserDistribution* dist,
+ const std::wstring& chrome_exe,
const std::wstring& shortcut,
const std::wstring& description,
bool create_new) {
- BrowserDistribution* dist = BrowserDistribution::GetDistribution();
std::wstring chrome_path = file_util::GetDirectoryFromPath(chrome_exe);
FilePath prefs_path(chrome_path);
diff --git a/chrome/installer/util/shell_util.h b/chrome/installer/util/shell_util.h
index ad72f64..5df73c6 100644
--- a/chrome/installer/util/shell_util.h
+++ b/chrome/installer/util/shell_util.h
@@ -17,6 +17,8 @@
#include "base/basictypes.h"
#include "chrome/installer/util/work_item_list.h"
+class BrowserDistribution;
+
// This is a utility class that provides common shell integration methods
// that can be used by installer as well as Chrome.
class ShellUtil {
@@ -74,7 +76,8 @@ class ShellUtil {
// Checks if we need Admin rights for registry cleanup by checking if any
// entry exists in HKLM.
- static bool AdminNeededForRegistryCleanup(const std::wstring& suffix);
+ static bool AdminNeededForRegistryCleanup(BrowserDistribution* dist,
+ const std::wstring& suffix);
// Create Chrome shortcut on Desktop
// If shell_change is CURRENT_USER, the shortcut is created in the
@@ -84,7 +87,8 @@ class ShellUtil {
// If alternate is true, an alternate text for the shortcut is used.
// create_new: If false, will only update the shortcut. If true, the function
// will create a new shortcut if it doesn't exist already.
- static bool CreateChromeDesktopShortcut(const std::wstring& chrome_exe,
+ static bool CreateChromeDesktopShortcut(BrowserDistribution* dist,
+ const std::wstring& chrome_exe,
const std::wstring& description,
int shell_change, bool alternate,
bool create_new);
@@ -98,7 +102,8 @@ class ShellUtil {
// system.
// create_new: If false, will only update the shortcut. If true, the function
// will create a new shortcut if it doesn't exist already.
- static bool CreateChromeQuickLaunchShortcut(const std::wstring& chrome_exe,
+ static bool CreateChromeQuickLaunchShortcut(BrowserDistribution* dist,
+ const std::wstring& chrome_exe,
int shell_change,
bool create_new);
@@ -106,7 +111,8 @@ class ShellUtil {
// chrome.exe path passed in as input, to generate the full path for
// Chrome icon that can be used as value for Windows registry keys.
// |chrome_exe| full path to chrome.exe.
- static std::wstring GetChromeIcon(const std::wstring& chrome_exe);
+ static std::wstring GetChromeIcon(BrowserDistribution* dist,
+ const std::wstring& chrome_exe);
// This method returns the command to open URLs/files using chrome. Typically
// this command is written to the registry under shell\open\command key.
@@ -116,7 +122,8 @@ class ShellUtil {
// Returns the localized name of Chrome shortcut. If |alternate| is true
// it returns a second localized text that is better suited for certain
// scenarios.
- static bool GetChromeShortcutName(std::wstring* shortcut, bool alternate);
+ static bool GetChromeShortcutName(BrowserDistribution* dist,
+ std::wstring* shortcut, bool alternate);
// Gets the desktop path for the current user or all users (if system_level
// is true) and returns it in 'path' argument. Return true if successful,
@@ -131,8 +138,9 @@ class ShellUtil {
static bool GetQuickLaunchPath(bool system_level, std::wstring* path);
// Gets a mapping of all registered browser (on local machine) names and
- // thier reinstall command (which usually sets browser as default).
- static void GetRegisteredBrowsers(std::map<std::wstring,
+ // their reinstall command (which usually sets browser as default).
+ static void GetRegisteredBrowsers(BrowserDistribution* dist,
+ std::map<std::wstring,
std::wstring>* browsers);
// This function gets a suffix (user's login name) that can be added
@@ -142,7 +150,8 @@ class ShellUtil {
// This suffix value is assigned to |entry|. The function also checks for
// existence of Default Browser registry key with this suffix and
// returns true if it exists. In all other cases it returns false.
- static bool GetUserSpecificDefaultBrowserSuffix(std::wstring* entry);
+ static bool GetUserSpecificDefaultBrowserSuffix(BrowserDistribution* dist,
+ std::wstring* entry);
// Make Chrome default browser.
// shell_change: Defined whether to register as default browser at system
@@ -151,7 +160,8 @@ class ShellUtil {
// chrome_exe: The chrome.exe path to register as default browser.
// elevate_if_not_admin: On Vista if user is not admin, try to elevate for
// Chrome registration.
- static bool MakeChromeDefault(int shell_change,
+ static bool MakeChromeDefault(BrowserDistribution* dist,
+ int shell_change,
const std::wstring& chrome_exe,
bool elevate_if_not_admin);
@@ -176,7 +186,8 @@ class ShellUtil {
// to default browser entries names that it creates in the registry.
// |elevate_if_not_admin| if true will make this method try alternate methods
// as described above.
- static bool RegisterChromeBrowser(const std::wstring& chrome_exe,
+ static bool RegisterChromeBrowser(BrowserDistribution* dist,
+ const std::wstring& chrome_exe,
const std::wstring& unique_suffix,
bool elevate_if_not_admin);
@@ -187,21 +198,24 @@ class ShellUtil {
// Desktop folder of "All Users" profile.
// If alternate is true, the shortcut with the alternate name is removed. See
// CreateChromeDesktopShortcut() for more information.
- static bool RemoveChromeDesktopShortcut(int shell_change, bool alternate);
+ static bool RemoveChromeDesktopShortcut(BrowserDistribution* dist,
+ int shell_change, bool alternate);
// Remove Chrome shortcut from Quick Launch Bar.
// If shell_change is CURRENT_USER, the shortcut is removed from
// the Quick Launch folder of current user's profile.
// If shell_change is SYSTEM_LEVEL, the shortcut is removed from
// the Quick Launch folder of "Default User" profile.
- static bool RemoveChromeQuickLaunchShortcut(int shell_change);
+ static bool RemoveChromeQuickLaunchShortcut(BrowserDistribution* dist,
+ int shell_change);
// Updates shortcut (or creates a new shortcut) at destination given by
// shortcut to a target given by chrome_exe. The arguments is left NULL
// for the target and icon is set as icon at index 0 from exe.
// If create_new is set to true, the function will create a new shortcut if
// if doesn't exist.
- static bool UpdateChromeShortcut(const std::wstring& chrome_exe,
+ static bool UpdateChromeShortcut(BrowserDistribution* dist,
+ const std::wstring& chrome_exe,
const std::wstring& shortcut,
const std::wstring& description,
bool create_new);
diff --git a/chrome/installer/util/shell_util_unittest.cc b/chrome/installer/util/shell_util_unittest.cc
index ae74556..a5d917e 100644
--- a/chrome/installer/util/shell_util_unittest.cc
+++ b/chrome/installer/util/shell_util_unittest.cc
@@ -11,6 +11,7 @@
#include "base/file_util.h"
#include "base/path_service.h"
#include "base/scoped_comptr_win.h"
+#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"
@@ -108,6 +109,8 @@ class ShellUtilTest : public testing::Test {
// Test that we can open archives successfully.
TEST_F(ShellUtilTest, UpdateChromeShortcutTest) {
+ BrowserDistribution* dist = BrowserDistribution::GetDistribution();
+ ASSERT_TRUE(dist != NULL);
// Create an executable in test path by copying ourself to it.
wchar_t exe_full_path_str[MAX_PATH];
EXPECT_FALSE(::GetModuleFileName(NULL, exe_full_path_str, MAX_PATH) == 0);
@@ -118,7 +121,7 @@ TEST_F(ShellUtilTest, UpdateChromeShortcutTest) {
FilePath shortcut_path = test_dir_.AppendASCII("shortcut.lnk");
const std::wstring description(L"dummy description");
- EXPECT_TRUE(ShellUtil::UpdateChromeShortcut(exe_path.value(),
+ EXPECT_TRUE(ShellUtil::UpdateChromeShortcut(dist, exe_path.value(),
shortcut_path.value(),
description, true));
EXPECT_TRUE(VerifyChromeShortcut(exe_path.value(),
@@ -139,7 +142,7 @@ TEST_F(ShellUtilTest, UpdateChromeShortcutTest) {
"}";
file.close();
ASSERT_TRUE(file_util::Delete(shortcut_path, false));
- EXPECT_TRUE(ShellUtil::UpdateChromeShortcut(exe_path.value(),
+ EXPECT_TRUE(ShellUtil::UpdateChromeShortcut(dist, exe_path.value(),
shortcut_path.value(),
description, true));
EXPECT_TRUE(VerifyChromeShortcut(exe_path.value(),
@@ -149,7 +152,7 @@ TEST_F(ShellUtilTest, UpdateChromeShortcutTest) {
// Now change only description to update shortcut and make sure icon index
// doesn't change.
const std::wstring description2(L"dummy description 2");
- EXPECT_TRUE(ShellUtil::UpdateChromeShortcut(exe_path.value(),
+ EXPECT_TRUE(ShellUtil::UpdateChromeShortcut(dist, exe_path.value(),
shortcut_path.value(),
description2, false));
EXPECT_TRUE(VerifyChromeShortcut(exe_path.value(),
diff --git a/chrome/installer/util/util_constants.cc b/chrome/installer/util/util_constants.cc
index 66a0636..3b1d651 100644
--- a/chrome/installer/util/util_constants.cc
+++ b/chrome/installer/util/util_constants.cc
@@ -153,4 +153,10 @@ const wchar_t kUninstallArgumentsField[] = L"UninstallArguments";
const wchar_t kUninstallDisplayNameField[] = L"DisplayName";
const char kUninstallMetricsName[] = "uninstall_metrics";
const wchar_t kUninstallInstallationDate[] = L"installation_date";
+const wchar_t kInstallerResult[] = L"InstallerResult";
+const wchar_t kInstallerError[] = L"InstallerError";
+const wchar_t kInstallerResultUIString[] = L"InstallerResultUIString";
+const wchar_t kInstallerSuccessLaunchCmdLine[] =
+ L"InstallerSuccessLaunchCmdLine";
+
} // namespace installer_util
diff --git a/chrome/installer/util/util_constants.h b/chrome/installer/util/util_constants.h
index 7cc4042..3cd21b0 100644
--- a/chrome/installer/util/util_constants.h
+++ b/chrome/installer/util/util_constants.h
@@ -110,6 +110,12 @@ extern const wchar_t kUninstallInstallationDate[];
extern const char kUninstallMetricsName[];
extern const wchar_t kUninstallStringField[];
+// Used by ProductInstall::WriteInstallerResult.
+extern const wchar_t kInstallerResult[];
+extern const wchar_t kInstallerError[];
+extern const wchar_t kInstallerResultUIString[];
+extern const wchar_t kInstallerSuccessLaunchCmdLine[];
+
} // namespace installer_util
#endif // CHROME_INSTALLER_UTIL_UTIL_CONSTANTS_H_
diff --git a/chrome/installer/util/version.h b/chrome/installer/util/version.h
index 72e8271..e237260 100644
--- a/chrome/installer/util/version.h
+++ b/chrome/installer/util/version.h
@@ -11,6 +11,7 @@
namespace installer {
+// TODO(tommi): We should be using the Version class from base.
class Version {
public:
virtual ~Version();
@@ -24,6 +25,10 @@ class Version {
return version_str_;
}
+ bool IsEqual(const Version& other) const {
+ return version_str_ == other.GetString();
+ }
+
// Assume that the version string is specified by four integers separated
// by character '.'. Return NULL if string is not of this format.
// Caller is responsible for freeing the Version object once done.
diff --git a/chrome_frame/test/test_with_web_server.cc b/chrome_frame/test/test_with_web_server.cc
index a030a76..8d4e3ba 100644
--- a/chrome_frame/test/test_with_web_server.cc
+++ b/chrome_frame/test/test_with_web_server.cc
@@ -8,9 +8,11 @@
#include "base/file_version_info.h"
#include "base/path_service.h"
#include "base/stringprintf.h"
+#include "base/test/test_timeouts.h"
#include "base/utf_string_conversions.h"
#include "base/win/windows_version.h"
#include "chrome/common/chrome_switches.h"
+#include "chrome/installer/util/product.h"
#include "chrome/installer/util/install_util.h"
#include "chrome/installer/util/helper.h"
#include "chrome_frame/html_utils.h"
@@ -26,8 +28,6 @@ using testing::_;
using testing::StrCaseEq;
const wchar_t kDocRoot[] = L"chrome_frame\\test\\data";
-const int kLongWaitTimeout = 15 * 1000;
-const int kShortWaitTimeout = 5 * 1000;
namespace {
@@ -92,7 +92,7 @@ void ChromeFrameTestWithWebServer::SetUp() {
// Make sure our playground is clean before we start.
CloseAllBrowsers();
- // Make sure that we are not accidently enabling gcf protocol.
+ // Make sure that we are not accidentally enabling gcf protocol.
SetConfigBool(kAllowUnsafeURLs, false);
FilePath chrome_frame_source_path;
@@ -220,7 +220,7 @@ void ChromeFrameTestWithWebServer::SimpleBrowserTestExpectedResult(
ASSERT_TRUE(LaunchBrowser(browser, page));
server_mock_.ExpectAndHandlePostedResult(CFInvocation(CFInvocation::NONE),
kPostedResultSubstring);
- WaitForTestToComplete(kLongWaitTimeout);
+ WaitForTestToComplete(TestTimeouts::action_max_timeout_ms());
ASSERT_EQ(result, server_mock_.posted_result());
}
@@ -237,7 +237,7 @@ void ChromeFrameTestWithWebServer::OptionalBrowserTest(BrowserKind browser,
} else {
server_mock_.ExpectAndHandlePostedResult(CFInvocation(CFInvocation::NONE),
kPostedResultSubstring);
- WaitForTestToComplete(kLongWaitTimeout);
+ WaitForTestToComplete(TestTimeouts::action_max_timeout_ms());
ASSERT_EQ("OK", server_mock_.posted_result());
}
}
@@ -259,15 +259,17 @@ void ChromeFrameTestWithWebServer::VersionTest(BrowserKind browser,
// If we can't find the Chrome Frame DLL in the src tree, we turn to
// the directory where chrome is installed.
if (!version_info) {
- installer::Version* ver_system = InstallUtil::GetChromeVersion(true);
- installer::Version* ver_user = InstallUtil::GetChromeVersion(false);
- ASSERT_TRUE(ver_system || ver_user);
-
- bool system_install = ver_system ? true : false;
- FilePath cf_dll_path = FilePath::FromWStringHack(
- installer::GetChromeInstallPath(system_install));
+ BrowserDistribution* dist = BrowserDistribution::GetDistribution();
+ scoped_ptr<installer::Version> ver_system(
+ InstallUtil::GetChromeVersion(dist, true));
+ scoped_ptr<installer::Version> ver_user(
+ InstallUtil::GetChromeVersion(dist, false));
+ ASSERT_TRUE(ver_system.get() || ver_user.get());
+
+ bool system_install = ver_system.get() ? true : false;
+ FilePath cf_dll_path(installer::GetChromeInstallPath(system_install, dist));
cf_dll_path = cf_dll_path.Append(
- ver_system ? ver_system->GetString() : ver_user->GetString());
+ ver_system.get() ? ver_system->GetString() : ver_user->GetString());
cf_dll_path = cf_dll_path.Append(kChromeFrameDllName);
version_info = FileVersionInfo::CreateFileVersionInfo(cf_dll_path);
if (version_info)
@@ -281,7 +283,7 @@ void ChromeFrameTestWithWebServer::VersionTest(BrowserKind browser,
EXPECT_TRUE(LaunchBrowser(browser, page));
server_mock_.ExpectAndHandlePostedResult(CFInvocation(CFInvocation::NONE),
kPostedResultSubstring);
- WaitForTestToComplete(kLongWaitTimeout);
+ WaitForTestToComplete(TestTimeouts::action_max_timeout_ms());
ASSERT_EQ(version, UTF8ToWide(server_mock_.posted_result()));
}
@@ -294,7 +296,7 @@ void ChromeFrameTestWithWebServer::SessionIdTest(BrowserKind browser,
server_mock_.set_expected_result(expected_result);
server_mock_.ExpectAndHandlePostedResult(CFInvocation(CFInvocation::NONE),
kPostedResultSubstring);
- WaitForTestToComplete(kLongWaitTimeout);
+ WaitForTestToComplete(TestTimeouts::action_max_timeout_ms());
ASSERT_EQ(expected_result, server_mock_.posted_result());
}
@@ -489,7 +491,7 @@ TEST_F(ChromeFrameTestWithWebServer, DISABLED_WidgetModeOpera_ObjectFocus) {
if (!LaunchBrowser(OPERA, kNavigateSimpleObjectFocus)) {
LOG(ERROR) << "Failed to launch browser " << ToString(OPERA);
} else {
- ASSERT_TRUE(WaitForOnLoad(kLongWaitTimeout));
+ ASSERT_TRUE(WaitForOnLoad(TestTimeouts::action_max_timeout_ms()));
server_mock_.ExpectAndHandlePostedResult(CFInvocation(CFInvocation::NONE),
kPostedResultSubstring);
BringBrowserToTop();