summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--chrome/browser/process_singleton_win.cc4
-rw-r--r--chrome/chrome_installer_util.gypi4
-rw-r--r--chrome/common/chrome_paths_win.cc9
-rw-r--r--chrome/installer/setup/install.cc8
-rw-r--r--chrome/installer/setup/setup_main.cc78
-rw-r--r--chrome/installer/setup/uninstall.cc19
-rw-r--r--chrome/installer/util/browser_distribution.cc14
-rw-r--r--chrome/installer/util/browser_distribution.h2
-rw-r--r--chrome/installer/util/chrome_frame_distribution.cc3
-rw-r--r--chrome/installer/util/google_chrome_distribution.cc2
-rw-r--r--chrome/installer/util/google_update_settings.cc63
-rw-r--r--chrome/installer/util/google_update_settings.h4
-rw-r--r--chrome/installer/util/google_update_settings_unittest.cc46
-rw-r--r--chrome/installer/util/helper_unittest.cc5
-rw-r--r--chrome/installer/util/install_util.cc13
-rw-r--r--chrome/installer/util/install_util.h3
-rw-r--r--chrome/installer/util/package.cc67
-rw-r--r--chrome/installer/util/package.h12
-rw-r--r--chrome/installer/util/package_properties.cc48
-rw-r--r--chrome/installer/util/package_properties.h6
-rw-r--r--chrome/installer/util/package_unittest.cc70
-rw-r--r--chrome/installer/util/product.cc74
-rw-r--r--chrome/installer/util/product.h39
-rw-r--r--chrome/installer/util/product_unittest.cc33
24 files changed, 418 insertions, 208 deletions
diff --git a/chrome/browser/process_singleton_win.cc b/chrome/browser/process_singleton_win.cc
index 4925d24..1e86daa 100644
--- a/chrome/browser/process_singleton_win.cc
+++ b/chrome/browser/process_singleton_win.cc
@@ -23,7 +23,6 @@
#include "chrome/common/chrome_paths.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/result_codes.h"
-#include "chrome/installer/util/browser_distribution.h"
#include "grit/chromium_strings.h"
#include "grit/generated_resources.h"
@@ -53,8 +52,7 @@ ProcessSingleton::ProcessSingleton(const FilePath& user_data_dir)
// access. As documented, it's clearer to NOT request ownership on creation
// since it isn't guaranteed we will get it. It is better to create it
// without ownership and explicitly get the ownership afterward.
- std::wstring mutex_name(L"Local\\ProcessSingletonStartup!");
- mutex_name += BrowserDistribution::GetDistribution()->GetAppGuid();
+ std::wstring mutex_name(L"Local\\ChromeProcessSingletonStartup!");
ScopedHandle only_me(CreateMutex(NULL, FALSE, mutex_name.c_str()));
DCHECK(only_me.Get() != NULL) << "GetLastError = " << GetLastError();
diff --git a/chrome/chrome_installer_util.gypi b/chrome/chrome_installer_util.gypi
index db9ca01..946ce9e 100644
--- a/chrome/chrome_installer_util.gypi
+++ b/chrome/chrome_installer_util.gypi
@@ -43,6 +43,8 @@
'installer/util/master_preferences_constants.h',
'installer/util/move_tree_work_item.cc',
'installer/util/move_tree_work_item.h',
+ 'installer/util/package.h',
+ 'installer/util/package.cc',
'installer/util/self_reg_work_item.cc',
'installer/util/self_reg_work_item.h',
'installer/util/set_reg_value_work_item.cc',
@@ -101,8 +103,6 @@
'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/package_properties.h',
'installer/util/package_properties.cc',
'installer/util/product.h',
diff --git a/chrome/common/chrome_paths_win.cc b/chrome/common/chrome_paths_win.cc
index 74a730d..8207db6 100644
--- a/chrome/common/chrome_paths_win.cc
+++ b/chrome/common/chrome_paths_win.cc
@@ -15,6 +15,7 @@
#include "base/path_service.h"
#include "chrome/common/chrome_constants.h"
#include "chrome/installer/util/browser_distribution.h"
+#include "chrome/installer/util/master_preferences.h"
namespace chrome {
@@ -30,10 +31,10 @@ bool GetDefaultUserDataDirectory(FilePath* result) {
bool GetChromeFrameUserDataDirectory(FilePath* result) {
if (!PathService::Get(base::DIR_LOCAL_APP_DATA, result))
return false;
-#if defined(GOOGLE_CHROME_BUILD)
- *result = result->Append(FILE_PATH_LITERAL("Google"));
-#endif
- *result = result->Append(L"Chrome Frame");
+ BrowserDistribution* dist = BrowserDistribution::GetSpecificDistribution(
+ BrowserDistribution::CHROME_FRAME,
+ installer::MasterPreferences::ForCurrentProcess());
+ *result = result->Append(dist->GetInstallSubDir());
*result = result->Append(chrome::kUserDataDirname);
return true;
}
diff --git a/chrome/installer/setup/install.cc b/chrome/installer/setup/install.cc
index c5faf74..90f7361 100644
--- a/chrome/installer/setup/install.cc
+++ b/chrome/installer/setup/install.cc
@@ -15,7 +15,6 @@
#include "base/string_util.h"
#include "base/utf_string_conversions.h"
#include "base/win/registry.h"
-#include "base/utf_string_conversions.h"
#include "chrome/installer/setup/setup_constants.h"
#include "chrome/installer/util/browser_distribution.h"
#include "chrome/installer/util/chrome_frame_distribution.h"
@@ -450,6 +449,9 @@ bool DoPostInstallTasks(bool multi_install,
if (InstallUtil::IsChromeSxSProcess())
rename.AppendSwitch(installer::switches::kChromeSxS);
+ if (multi_install)
+ rename.AppendSwitch(installer::switches::kMultiInstall);
+
std::wstring version_key;
for (size_t i = 0; i < products.size(); ++i) {
BrowserDistribution* dist = products[i]->distribution();
@@ -767,8 +769,6 @@ installer::InstallStatus InstallOrUpdateChrome(
const FilePath& install_temp_path, const FilePath& prefs_path,
const installer::MasterPreferences& prefs, const Version& new_version,
const Package& install) {
- bool system_install = install.system_level();
-
FilePath src_path(install_temp_path);
src_path = src_path.Append(kInstallSourceDir).Append(kInstallSourceChromeDir);
@@ -777,7 +777,7 @@ installer::InstallStatus InstallOrUpdateChrome(
setup_path, archive_path, src_path, install_temp_path, new_version,
&existing_version, install);
- if (!BrowserDistribution::GetInstallReturnCode(result)) {
+ if (!InstallUtil::GetInstallReturnCode(result)) {
if (result == installer::FIRST_INSTALL_SUCCESS)
CopyPreferenceFileForFirstRun(install, prefs_path);
diff --git a/chrome/installer/setup/setup_main.cc b/chrome/installer/setup/setup_main.cc
index f4b7a8d..cb4ee56 100644
--- a/chrome/installer/setup/setup_main.cc
+++ b/chrome/installer/setup/setup_main.cc
@@ -177,10 +177,9 @@ bool CheckPreInstallConditions(const Package& installation,
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())
+ if (product->IsInstalled())
is_first_install = false;
// Check to avoid simultaneous per-user and per-machine installs.
@@ -199,14 +198,14 @@ bool CheckPreInstallConditions(const Package& installation,
if (chrome_exe.empty()) {
// If we failed to construct install path. Give up.
status = installer::OS_ERROR;
- product->WriteInstallerResult(status, IDS_INSTALL_OS_ERROR_BASE,
- NULL);
+ installation.WriteInstallerResult(status, IDS_INSTALL_OS_ERROR_BASE,
+ NULL);
} else {
status = installer::EXISTING_VERSION_LAUNCHED;
chrome_exe = chrome_exe.Append(installer::kChromeExe);
CommandLine cmd(chrome_exe);
cmd.AppendSwitch(switches::kFirstRun);
- product->WriteInstallerResult(status, 0, NULL);
+ installation.WriteInstallerResult(status, 0, NULL);
VLOG(1) << "Launching existing system-level chrome instead.";
base::LaunchApp(cmd, false, false, NULL);
}
@@ -225,7 +224,7 @@ bool CheckPreInstallConditions(const Package& installation,
installer::SYSTEM_LEVEL_INSTALL_EXISTS;
int str_id = system_level ? IDS_INSTALL_USER_LEVEL_EXISTS_BASE :
IDS_INSTALL_SYSTEM_LEVEL_EXISTS_BASE;
- product->WriteInstallerResult(status, str_id, NULL);
+ installation.WriteInstallerResult(status, str_id, NULL);
return false;
}
}
@@ -240,7 +239,7 @@ bool CheckPreInstallConditions(const Package& installation,
<< " exists and can not be deleted.";
status = installer::INSTALL_DIR_IN_USE;
int str_id = IDS_INSTALL_DIR_IN_USE_BASE;
- WriteInstallerResult(products, status, str_id, NULL);
+ installation.WriteInstallerResult(status, str_id, NULL);
return false;
}
}
@@ -273,7 +272,7 @@ installer::InstallStatus InstallChrome(const CommandLine& cmd_line,
FilePath temp_path;
if (!file_util::CreateNewTempDirectory(L"chrome_", &temp_path)) {
LOG(ERROR) << "Could not create temporary path.";
- WriteInstallerResult(products, installer::TEMP_DIR_FAILED,
+ installation.WriteInstallerResult(installer::TEMP_DIR_FAILED,
IDS_INSTALL_TEMP_DIR_FAILED_BASE, NULL);
return installer::TEMP_DIR_FAILED;
}
@@ -284,7 +283,7 @@ installer::InstallStatus InstallChrome(const CommandLine& cmd_line,
if (UnPackArchive(archive, installation, temp_path, unpack_path,
incremental_install)) {
install_status = installer::UNCOMPRESSION_FAILED;
- WriteInstallerResult(products, install_status,
+ installation.WriteInstallerResult(install_status,
IDS_INSTALL_UNCOMPRESSION_FAILED_BASE, NULL);
} else {
VLOG(1) << "unpacked to " << unpack_path.value();
@@ -294,7 +293,7 @@ installer::InstallStatus InstallChrome(const CommandLine& cmd_line,
if (!installer_version.get()) {
LOG(ERROR) << "Did not find any valid version in installer.";
install_status = installer::INVALID_ARCHIVE;
- WriteInstallerResult(products, install_status,
+ installation.WriteInstallerResult(install_status,
IDS_INSTALL_INVALID_ARCHIVE_BASE, NULL);
} else {
// TODO(tommi): Move towards having only a single version that is common
@@ -306,8 +305,8 @@ installer::InstallStatus InstallChrome(const CommandLine& cmd_line,
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->CompareTo(*installer_version) > 0)) {
+ const Version* v = product->GetInstalledVersion();
+ if (v != NULL && (v->CompareTo(*installer_version) > 0)) {
LOG(ERROR) << "Higher version is already installed.";
higher_version_installed = true;
install_status = installer::HIGHER_VERSION_EXISTS;
@@ -316,10 +315,10 @@ installer::InstallStatus InstallChrome(const CommandLine& cmd_line,
BrowserDistribution::CHROME_BROWSER) {
// TODO(robertshield): We should take the installer result text
// strings from the Product.
- product->WriteInstallerResult(install_status,
+ installation.WriteInstallerResult(install_status,
IDS_INSTALL_HIGHER_VERSION_BASE, NULL);
} else {
- product->WriteInstallerResult(install_status,
+ installation.WriteInstallerResult(install_status,
IDS_INSTALL_HIGHER_VERSION_CF_BASE, NULL);
}
}
@@ -372,8 +371,8 @@ installer::InstallStatus InstallChrome(const CommandLine& cmd_line,
bool write_chrome_launch_string = (!value) &&
(install_status != installer::IN_USE_UPDATED);
- WriteInstallerResult(products, install_status,
- install_msg_base, write_chrome_launch_string ? &chrome_exe : NULL);
+ installation.WriteInstallerResult(install_status, install_msg_base,
+ write_chrome_launch_string ? &chrome_exe : NULL);
if (install_status == installer::FIRST_INSTALL_SUCCESS) {
VLOG(1) << "First install successful.";
@@ -446,17 +445,16 @@ installer::InstallStatus InstallChrome(const CommandLine& cmd_line,
}
installer::InstallStatus UninstallChrome(const CommandLine& cmd_line,
- const Product& product) {
+ 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::switches::kForceUninstall);
- if (!installed_version.get() && !force) {
+ if (product.IsInstalled()) {
+ VLOG(1) << "version on the system: "
+ << product.GetInstalledVersion()->GetString();
+ } else if (!force) {
LOG(ERROR) << "No Chrome installation found for uninstall.";
- product.WriteInstallerResult(installer::CHROME_NOT_INSTALLED,
+ product.package().WriteInstallerResult(installer::CHROME_NOT_INSTALLED,
IDS_UNINSTALL_FAILED_BASE, NULL);
return installer::CHROME_NOT_INSTALLED;
}
@@ -523,16 +521,16 @@ bool HandleNonInstallCmdLineOptions(const CommandLine& cmd_line,
FilePath new_setup_exe = cmd_line.GetSwitchValuePath(
installer::switches::kNewSetupExe);
if (!installer::ApplyDiffPatch(old_setup_exe,
- FilePath(uncompressed_patch),
- new_setup_exe))
+ FilePath(uncompressed_patch),
+ new_setup_exe))
status = installer::NEW_VERSION_UPDATED;
}
}
- exit_code = BrowserDistribution::GetInstallReturnCode(status);
+ exit_code = InstallUtil::GetInstallReturnCode(status);
if (exit_code) {
LOG(WARNING) << "setup.exe patching failed.";
- WriteInstallerResult(installs.products(), status,
+ installs.packages()[0]->WriteInstallerResult(status,
IDS_SETUP_PATCH_FAILED_BASE, NULL);
}
file_util::Delete(temp_path, true);
@@ -544,7 +542,7 @@ bool HandleNonInstallCmdLineOptions(const CommandLine& cmd_line,
cmd_line.GetSwitchValueNative(installer::switches::kShowEula);
exit_code = ShowEULADialog(inner_frame);
if (installer::EULA_REJECTED != exit_code)
- GoogleUpdateSettings::SetEULAConsent(true);
+ GoogleUpdateSettings::SetEULAConsent(*installs.packages()[0].get(), true);
return true;
} else if (cmd_line.HasSwitch(
installer::switches::kRegisterChromeBrowser)) {
@@ -719,35 +717,35 @@ int WINAPI wWinMain(HINSTANCE instance, HINSTANCE prev_instance,
const CommandLine& cmd_line = *CommandLine::ForCurrentProcess();
VLOG(1) << "Command Line: " << cmd_line.command_line_string();
+ VLOG(1) << "multi install is " << prefs.is_multi_install();
bool system_install = false;
- prefs.GetBool(installer::master_preferences::kSystemLevel,
- &system_install);
+ prefs.GetBool(installer::master_preferences::kSystemLevel, &system_install);
VLOG(1) << "system install is " << system_install;
- ProductPackageMapping installations(system_install);
+ ProductPackageMapping installations(prefs.is_multi_install(), 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.";
- WriteInstallerResult(installations.products(),
- installer::OS_NOT_SUPPORTED, IDS_INSTALL_OS_NOT_SUPPORTED_BASE,
- NULL);
+ installations.packages()[0]->WriteInstallerResult(
+ installer::OS_NOT_SUPPORTED, IDS_INSTALL_OS_NOT_SUPPORTED_BASE, NULL);
return installer::OS_NOT_SUPPORTED;
}
// Initialize COM for use later.
AutoCom auto_com;
if (!auto_com.Init(system_install)) {
- WriteInstallerResult(installations.products(),
- installer::OS_ERROR, IDS_INSTALL_OS_ERROR_BASE, NULL);
+ installations.packages()[0]->WriteInstallerResult(installer::OS_ERROR,
+ IDS_INSTALL_OS_ERROR_BASE, NULL);
return installer::OS_ERROR;
}
// Some command line options don't work with SxS install/uninstall
if (InstallUtil::IsChromeSxSProcess()) {
if (system_install ||
+ prefs.is_multi_install() ||
cmd_line.HasSwitch(installer::switches::kForceUninstall) ||
cmd_line.HasSwitch(installer::switches::kMakeChromeDefault) ||
cmd_line.HasSwitch(installer::switches::kRegisterChromeBrowser) ||
@@ -776,9 +774,9 @@ int WINAPI wWinMain(HINSTANCE instance, HINSTANCE prev_instance,
return exit_code;
} else {
LOG(ERROR) << "Non admin user can not install system level Chrome.";
- WriteInstallerResult(installations.products(),
- installer::INSUFFICIENT_RIGHTS,
- IDS_INSTALL_INSUFFICIENT_RIGHTS_BASE, NULL);
+ installations.packages()[0]->WriteInstallerResult(
+ installer::INSUFFICIENT_RIGHTS, IDS_INSTALL_INSUFFICIENT_RIGHTS_BASE,
+ NULL);
return installer::INSUFFICIENT_RIGHTS;
}
}
@@ -832,7 +830,7 @@ int WINAPI wWinMain(HINSTANCE instance, HINSTANCE prev_instance,
// Note that we allow the status installer::UNINSTALL_REQUIRES_REBOOT
// to pass through, since this is only returned on uninstall which is
// never invoked directly by Google Update.
- return_code = BrowserDistribution::GetInstallReturnCode(install_status);
+ return_code = InstallUtil::GetInstallReturnCode(install_status);
}
}
diff --git a/chrome/installer/setup/uninstall.cc b/chrome/installer/setup/uninstall.cc
index c9bca0d..72d6f00 100644
--- a/chrome/installer/setup/uninstall.cc
+++ b/chrome/installer/setup/uninstall.cc
@@ -213,15 +213,8 @@ bool DeleteEmptyParentDir(const FilePath& path) {
}
FilePath GetLocalStateFolder(const Product& product) {
- // 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 (product.distribution()->GetType() == BrowserDistribution::CHROME_FRAME) {
- chrome::GetChromeFrameUserDataDirectory(&local_state_folder);
- } else {
- chrome::GetDefaultUserDataDirectory(&local_state_folder);
- }
-
+ // Obtain the location of the user profile data.
+ FilePath local_state_folder = product.GetUserDataPath();
LOG_IF(ERROR, local_state_folder.empty())
<< "Could not retrieve user's profile directory.";
@@ -254,7 +247,7 @@ DeleteResult DeleteLocalState(const Product& product) {
return DELETE_SUCCEEDED;
DeleteResult result = DELETE_SUCCEEDED;
- VLOG(1) << "Deleting user profile" << user_local_state.value();
+ 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();
@@ -551,7 +544,7 @@ InstallStatus UninstallChrome(const FilePath& setup_path,
}
// Get the version of installed Chrome (if any)
- scoped_ptr<Version> installed_version(product.GetInstalledVersion());
+ const Version* installed_version = product.GetInstalledVersion();
// 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
@@ -610,7 +603,7 @@ InstallStatus UninstallChrome(const FilePath& setup_path,
// 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) {
+ if (installed_version != NULL && !is_chrome) {
RegisterComDllList(product.package().path().Append(
UTF8ToWide(installed_version->GetString())), product.system_level(),
false, false);
@@ -623,7 +616,7 @@ InstallStatus UninstallChrome(const FilePath& setup_path,
CloseChromeFrameHelperProcess();
}
- if (!installed_version.get())
+ if (installed_version == NULL)
return installer::UNINSTALL_SUCCESSFUL;
// Finally delete all the files from Chrome folder after moving setup.exe
diff --git a/chrome/installer/util/browser_distribution.cc b/chrome/installer/util/browser_distribution.cc
index b36e537..3ac4b1c 100644
--- a/chrome/installer/util/browser_distribution.cc
+++ b/chrome/installer/util/browser_distribution.cc
@@ -159,20 +159,6 @@ std::wstring BrowserDistribution::GetLongAppDescription() {
return app_description;
}
-// static
-int BrowserDistribution::GetInstallReturnCode(
- installer::InstallStatus status) {
- switch (status) {
- case installer::FIRST_INSTALL_SUCCESS:
- case installer::INSTALL_REPAIRED:
- case installer::NEW_VERSION_UPDATED:
- case installer::IN_USE_UPDATED:
- return 0;
- default:
- return status;
- }
-}
-
std::string BrowserDistribution::GetSafeBrowsingName() {
return "chromium";
}
diff --git a/chrome/installer/util/browser_distribution.h b/chrome/installer/util/browser_distribution.h
index 1edc73d..5175656 100644
--- a/chrome/installer/util/browser_distribution.h
+++ b/chrome/installer/util/browser_distribution.h
@@ -45,8 +45,6 @@ class BrowserDistribution {
Type GetType() const { return type_; }
- static int GetInstallReturnCode(installer::InstallStatus install_status);
-
virtual void DoPostUninstallOperations(const Version& version,
const FilePath& local_data_path,
const std::wstring& distribution_data);
diff --git a/chrome/installer/util/chrome_frame_distribution.cc b/chrome/installer/util/chrome_frame_distribution.cc
index 20698da..0798366 100644
--- a/chrome/installer/util/chrome_frame_distribution.cc
+++ b/chrome/installer/util/chrome_frame_distribution.cc
@@ -14,6 +14,7 @@
#include "base/string_util.h"
#include "chrome/installer/util/google_update_constants.h"
#include "chrome/installer/util/google_update_settings.h"
+#include "chrome/installer/util/install_util.h"
#include "chrome/installer/util/l10n_string_util.h"
#include "chrome/installer/util/master_preferences.h"
@@ -109,7 +110,7 @@ bool ChromeFrameDistribution::CanSetAsDefault() {
void ChromeFrameDistribution::UpdateDiffInstallStatus(bool system_install,
bool incremental_install, installer::InstallStatus install_status) {
GoogleUpdateSettings::UpdateDiffInstallStatus(system_install,
- incremental_install, GetInstallReturnCode(install_status),
+ incremental_install, InstallUtil::GetInstallReturnCode(install_status),
kChromeFrameGuid);
}
diff --git a/chrome/installer/util/google_chrome_distribution.cc b/chrome/installer/util/google_chrome_distribution.cc
index c2fb5ca..99c47f9 100644
--- a/chrome/installer/util/google_chrome_distribution.cc
+++ b/chrome/installer/util/google_chrome_distribution.cc
@@ -503,7 +503,7 @@ std::wstring GoogleChromeDistribution::GetVersionKey() {
void GoogleChromeDistribution::UpdateDiffInstallStatus(bool system_install,
bool incremental_install, installer::InstallStatus install_status) {
GoogleUpdateSettings::UpdateDiffInstallStatus(system_install,
- incremental_install, GetInstallReturnCode(install_status),
+ incremental_install, InstallUtil::GetInstallReturnCode(install_status),
product_guid().c_str());
}
diff --git a/chrome/installer/util/google_update_settings.cc b/chrome/installer/util/google_update_settings.cc
index 2481cf4..9bf6d01 100644
--- a/chrome/installer/util/google_update_settings.cc
+++ b/chrome/installer/util/google_update_settings.cc
@@ -17,11 +17,22 @@
#include "chrome/installer/util/channel_info.h"
#include "chrome/installer/util/google_update_constants.h"
#include "chrome/installer/util/install_util.h"
+#include "chrome/installer/util/package.h"
+#include "chrome/installer/util/package_properties.h"
+#include "chrome/installer/util/product.h"
using base::win::RegKey;
namespace {
+// An list of search results in increasing order of desirability.
+enum EulaSearchResult {
+ NO_SETTING,
+ FOUND_CLIENT_STATE,
+ FOUND_OPPOSITE_SETTING,
+ FOUND_SAME_SETTING
+};
+
bool ReadGoogleUpdateStrKey(const wchar_t* const name, std::wstring* value) {
// The registry functions below will end up going to disk. Do this on another
// thread to avoid slowing the IO thread. http://crbug.com/62121
@@ -63,6 +74,21 @@ bool RemoveGoogleUpdateStrKey(const wchar_t* const name) {
return key.DeleteValue(name);
}
+EulaSearchResult HasEULASetting(HKEY root, const std::wstring& state_key,
+ bool setting) {
+ RegKey key;
+ DWORD previous_value;
+
+ if (!key.Open(root, state_key.c_str(), KEY_QUERY_VALUE))
+ return NO_SETTING;
+
+ if (!key.ReadValueDW(google_update::kRegEULAAceptedField, &previous_value))
+ return FOUND_CLIENT_STATE;
+
+ return ((previous_value != 0) == setting) ?
+ FOUND_SAME_SETTING : FOUND_OPPOSITE_SETTING;
+}
+
} // namespace.
bool GoogleUpdateSettings::GetCollectStatsConsent() {
@@ -99,11 +125,38 @@ bool GoogleUpdateSettings::SetMetricsId(const std::wstring& metrics_id) {
return WriteGoogleUpdateStrKey(google_update::kRegMetricsId, metrics_id);
}
-bool GoogleUpdateSettings::SetEULAConsent(bool consented) {
- BrowserDistribution* dist = BrowserDistribution::GetDistribution();
- std::wstring reg_path = dist->GetStateMediumKey();
- RegKey key(HKEY_LOCAL_MACHINE, reg_path.c_str(), KEY_READ | KEY_SET_VALUE);
- return key.WriteValue(google_update::kRegEULAAceptedField, consented? 1 : 0);
+bool GoogleUpdateSettings::SetEULAConsent(
+ const installer::Package& package,
+ bool consented) {
+ // If this is a multi install, Google Update will have put eulaaccepted=0 into
+ // the ClientState key of the multi-installer. Conduct a brief search for
+ // this value and store the consent in the corresponding location.
+ HKEY root = package.system_level() ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER;
+
+ std::wstring reg_path = package.properties()->GetStateMediumKey();
+ EulaSearchResult status = HasEULASetting(
+ root, package.properties()->GetStateKey(), !consented);
+ if (status != FOUND_SAME_SETTING) {
+ EulaSearchResult new_status = NO_SETTING;
+ installer::Products::const_iterator scan = package.products().begin();
+ installer::Products::const_iterator end = package.products().end();
+ for (; status != FOUND_SAME_SETTING && scan != end; ++scan) {
+ const installer::Product& product = *(scan->get());
+ new_status = HasEULASetting(root, product.distribution()->GetStateKey(),
+ !consented);
+ if (new_status > status) {
+ status = new_status;
+ reg_path = product.distribution()->GetStateMediumKey();
+ }
+ }
+ if (status == NO_SETTING) {
+ LOG(WARNING)
+ << "eulaaccepted value not found; setting consent on package";
+ reg_path = package.properties()->GetStateMediumKey();
+ }
+ }
+ RegKey key(HKEY_LOCAL_MACHINE, reg_path.c_str(), KEY_SET_VALUE);
+ return key.WriteValue(google_update::kRegEULAAceptedField, consented ? 1 : 0);
}
int GoogleUpdateSettings::GetLastRunTime() {
diff --git a/chrome/installer/util/google_update_settings.h b/chrome/installer/util/google_update_settings.h
index 3f53c5e..0ac8991 100644
--- a/chrome/installer/util/google_update_settings.h
+++ b/chrome/installer/util/google_update_settings.h
@@ -12,6 +12,7 @@
namespace installer {
class ChannelInfo;
+class Package;
}
// This class provides accessors to the Google Update 'ClientState' information
@@ -37,7 +38,8 @@ class GoogleUpdateSettings {
// Sets the machine-wide EULA consented flag required on OEM installs.
// Returns false if the setting could not be recorded.
- static bool SetEULAConsent(bool consented);
+ static bool SetEULAConsent(const installer::Package& package,
+ bool consented);
// Returns the last time chrome was run in days. It uses a recorded value
// set by SetLastRunTime(). Returns -1 if the value was not found or if
diff --git a/chrome/installer/util/google_update_settings_unittest.cc b/chrome/installer/util/google_update_settings_unittest.cc
index 9fe82e9..672e589 100644
--- a/chrome/installer/util/google_update_settings_unittest.cc
+++ b/chrome/installer/util/google_update_settings_unittest.cc
@@ -5,12 +5,17 @@
#include <windows.h>
#include <shlwapi.h> // For SHDeleteKey.
+#include "base/ref_counted.h"
#include "base/scoped_ptr.h"
#include "base/win/registry.h"
#include "chrome/installer/util/browser_distribution.h"
#include "chrome/installer/util/channel_info.h"
#include "chrome/installer/util/google_update_constants.h"
#include "chrome/installer/util/google_update_settings.h"
+#include "chrome/installer/util/master_preferences.h"
+#include "chrome/installer/util/package.h"
+#include "chrome/installer/util/package_properties.h"
+#include "chrome/installer/util/product.h"
#include "chrome/installer/util/work_item_list.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -395,3 +400,44 @@ TEST_F(GoogleUpdateSettingsTest, UpdateDiffInstallStatusTest) {
<< "Failed to restore ap key.";
}
}
+
+TEST_F(GoogleUpdateSettingsTest, SetEULAConsent) {
+ const bool multi_install = false;
+ const bool system_level = true;
+ HKEY root = system_level ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER;
+
+ const installer::MasterPreferences& prefs =
+ installer::MasterPreferences::ForCurrentProcess();
+ installer::ChromePackageProperties properties;
+ BrowserDistribution* distribution =
+ BrowserDistribution::GetSpecificDistribution(
+ BrowserDistribution::CHROME_BROWSER, prefs);
+ scoped_refptr<installer::Package> package(
+ new installer::Package(multi_install, system_level, FilePath(),
+ &properties));
+ scoped_refptr<installer::Product> product(
+ new installer::Product(distribution, package.get()));
+ RegKey key;
+ DWORD value;
+
+ // By default, eulaconsent ends up on the package.
+ EXPECT_TRUE(GoogleUpdateSettings::SetEULAConsent(*package.get(), true));
+ EXPECT_TRUE(key.Open(HKEY_LOCAL_MACHINE,
+ properties.GetStateMediumKey().c_str(),
+ KEY_QUERY_VALUE | KEY_SET_VALUE));
+ EXPECT_TRUE(key.ReadValueDW(google_update::kRegEULAAceptedField, &value));
+ EXPECT_EQ(1U, value);
+ EXPECT_TRUE(key.DeleteValue(google_update::kRegEULAAceptedField));
+
+ // But it will end up on the product if needed
+ EXPECT_TRUE(key.Create(HKEY_LOCAL_MACHINE,
+ distribution->GetStateKey().c_str(), KEY_SET_VALUE));
+ EXPECT_TRUE(key.WriteValue(google_update::kRegEULAAceptedField,
+ static_cast<DWORD>(0)));
+ EXPECT_TRUE(GoogleUpdateSettings::SetEULAConsent(*package.get(), true));
+ EXPECT_TRUE(key.Open(HKEY_LOCAL_MACHINE,
+ distribution->GetStateMediumKey().c_str(),
+ KEY_QUERY_VALUE | KEY_SET_VALUE));
+ EXPECT_TRUE(key.ReadValueDW(google_update::kRegEULAAceptedField, &value));
+ EXPECT_EQ(1U, value);
+}
diff --git a/chrome/installer/util/helper_unittest.cc b/chrome/installer/util/helper_unittest.cc
index 7c1e955..ee92ba56 100644
--- a/chrome/installer/util/helper_unittest.cc
+++ b/chrome/installer/util/helper_unittest.cc
@@ -111,7 +111,8 @@ TEST_F(SetupHelperTest, Delete) {
scoped_ptr<Version> latest_version(Version::GetVersionFromString(L"1.0.4.0"));
ChromePackageProperties properties;
- scoped_refptr<Package> package(new Package(true, chrome_dir, &properties));
+ scoped_refptr<Package> package(new Package(false, true, chrome_dir,
+ &properties));
package->RemoveOldVersionDirectories(*latest_version.get());
// old versions should be gone
@@ -186,7 +187,7 @@ TEST_F(SetupHelperTest, DeleteInUsed) {
scoped_ptr<Version> latest_version(Version::GetVersionFromString(L"1.0.4.0"));
ChromePackageProperties properties;
- scoped_refptr<Package> install_path(new Package(true, chrome_dir,
+ scoped_refptr<Package> install_path(new Package(false, true, chrome_dir,
&properties));
install_path->RemoveOldVersionDirectories(*latest_version.get());
diff --git a/chrome/installer/util/install_util.cc b/chrome/installer/util/install_util.cc
index 6676bae..db5c17d8 100644
--- a/chrome/installer/util/install_util.cc
+++ b/chrome/installer/util/install_util.cc
@@ -188,3 +188,16 @@ bool InstallUtil::DeleteRegistryValue(HKEY reg_root,
}
return true;
}
+
+// static
+int InstallUtil::GetInstallReturnCode(installer::InstallStatus status) {
+ switch (status) {
+ case installer::FIRST_INSTALL_SUCCESS:
+ case installer::INSTALL_REPAIRED:
+ case installer::NEW_VERSION_UPDATED:
+ case installer::IN_USE_UPDATED:
+ return 0;
+ default:
+ return status;
+ }
+}
diff --git a/chrome/installer/util/install_util.h b/chrome/installer/util/install_util.h
index b2ba973..0d20932 100644
--- a/chrome/installer/util/install_util.h
+++ b/chrome/installer/util/install_util.h
@@ -94,6 +94,9 @@ class InstallUtil {
static bool DeleteRegistryValue(HKEY reg_root, const std::wstring& key_path,
const std::wstring& value_name);
+ // Returns zero on install success, or an InstallStatus value otherwise.
+ static int GetInstallReturnCode(installer::InstallStatus install_status);
+
private:
DISALLOW_COPY_AND_ASSIGN(InstallUtil);
};
diff --git a/chrome/installer/util/package.cc b/chrome/installer/util/package.cc
index c2fff7b..5f5ff57 100644
--- a/chrome/installer/util/package.cc
+++ b/chrome/installer/util/package.cc
@@ -11,19 +11,52 @@
#include "chrome/installer/util/channel_info.h"
#include "chrome/installer/util/delete_tree_work_item.h"
#include "chrome/installer/util/google_update_constants.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/package_properties.h"
#include "chrome/installer/util/product.h"
+#include "chrome/installer/util/util_constants.h"
+#include "chrome/installer/util/work_item_list.h"
using base::win::RegKey;
using installer::ChannelInfo;
using installer::MasterPreferences;
+namespace {
+
+void AddInstallerResult(HKEY root,
+ const std::wstring& key,
+ int installer_result,
+ installer::InstallStatus status,
+ const std::wstring& msg,
+ const std::wstring* const launch_cmd,
+ WorkItemList* install_list) {
+ install_list->AddCreateRegKeyWorkItem(root, key);
+ install_list->AddSetRegValueWorkItem(root, key, installer::kInstallerResult,
+ installer_result, true);
+ install_list->AddSetRegValueWorkItem(root, key, installer::kInstallerError,
+ status, true);
+ if (!msg.empty()) {
+ install_list->AddSetRegValueWorkItem(root, key,
+ installer::kInstallerResultUIString, msg, true);
+ }
+ if (launch_cmd != NULL && !launch_cmd->empty()) {
+ install_list->AddSetRegValueWorkItem(root, key,
+ installer::kInstallerSuccessLaunchCmdLine, *launch_cmd, true);
+ }
+}
+
+} // namespace
+
namespace installer {
-Package::Package(bool system_level, const FilePath& path,
+Package::Package(bool multi_install, bool system_level, const FilePath& path,
PackageProperties* properties)
- : system_level_(system_level), path_(path), properties_(properties) {
+ : multi_install_(multi_install),
+ system_level_(system_level),
+ path_(path),
+ properties_(properties) {
DCHECK(properties_);
}
@@ -56,6 +89,10 @@ void Package::AssociateProduct(const Product* product) {
products_.push_back(product);
}
+bool Package::multi_install() const {
+ return multi_install_;
+}
+
bool Package::system_level() const {
return system_level_;
}
@@ -183,5 +220,31 @@ size_t Package::GetMultiInstallDependencyCount() const {
return ret;
}
+void Package::WriteInstallerResult(installer::InstallStatus status,
+ int string_resource_id,
+ const std::wstring* const launch_cmd) const {
+ HKEY root = system_level() ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER;
+ int installer_result = InstallUtil::GetInstallReturnCode(status) == 0 ? 0 : 1;
+ std::wstring msg;
+ scoped_ptr<WorkItemList> install_list(WorkItem::CreateWorkItemList());
+
+ if (string_resource_id != 0)
+ msg = installer::GetLocalizedString(string_resource_id);
+
+ for (Products::const_iterator scan = products_.begin(), end = products_.end();
+ scan != end; ++scan) {
+ const Product& product = *(scan->get());
+ AddInstallerResult(root, product.distribution()->GetStateKey(),
+ installer_result, status, msg, launch_cmd,
+ install_list.get());
+ }
+ if (multi_install_ && properties_->ReceivesUpdates()) {
+ AddInstallerResult(root, properties_->GetStateKey(), installer_result,
+ status, msg, launch_cmd, install_list.get());
+ }
+ if (!install_list->Do())
+ LOG(ERROR) << "Failed to record installer error information in registry.";
+}
+
} // namespace installer
diff --git a/chrome/installer/util/package.h b/chrome/installer/util/package.h
index c673825..c54c13d 100644
--- a/chrome/installer/util/package.h
+++ b/chrome/installer/util/package.h
@@ -16,6 +16,7 @@ class Version;
namespace installer {
+enum InstallStatus;
class Product;
class PackageProperties;
@@ -26,7 +27,7 @@ typedef std::vector<scoped_refptr<const Product> > Products;
// not vice versa.
class Package : public base::RefCounted<Package> {
public:
- Package(bool system_level, const FilePath& path,
+ Package(bool multi_install, bool system_level, const FilePath& path,
PackageProperties* properties);
// Returns the path of the installation folder.
@@ -36,6 +37,8 @@ class Package : public base::RefCounted<Package> {
PackageProperties* properties() const;
+ bool multi_install() const;
+
bool system_level() const;
bool IsEqual(const FilePath& path) const;
@@ -68,7 +71,14 @@ class Package : public base::RefCounted<Package> {
// system_level() value.
size_t GetMultiInstallDependencyCount() const;
+ // Sets installer error information in registry so that Google Update can read
+ // it and display it to the user.
+ void WriteInstallerResult(installer::InstallStatus status,
+ int string_resource_id,
+ const std::wstring* const launch_cmd) const;
+
protected:
+ bool multi_install_;
bool system_level_;
FilePath path_;
Products products_;
diff --git a/chrome/installer/util/package_properties.cc b/chrome/installer/util/package_properties.cc
index 702688e..814fc9e 100644
--- a/chrome/installer/util/package_properties.cc
+++ b/chrome/installer/util/package_properties.cc
@@ -9,24 +9,16 @@
#include "chrome/installer/util/browser_distribution.h"
#include "chrome/installer/util/google_update_constants.h"
#include "chrome/installer/util/google_update_settings.h"
+#include "chrome/installer/util/install_util.h"
#include "chrome/installer/util/util_constants.h"
-using installer::InstallStatus;
-
namespace {
-// TODO(tommi): Use google_update::kMultiInstallAppGuid
+
const wchar_t kChromePackageGuid[] =
L"{4DC8B4CA-1BDA-483e-B5FA-D3C12E15B62D}";
-std::wstring GetStateKeyForGuid(const wchar_t* guid) {
- std::wstring key(google_update::kRegPathClientState);
- key.append(L"\\");
- key.append(guid);
- return key;
-}
-
-std::wstring GetVersionKeyForGuid(const wchar_t* guid) {
- std::wstring key(google_update::kRegPathClients);
+std::wstring GetKeyForGuid(const wchar_t* base_key, const wchar_t* guid) {
+ std::wstring key(base_key);
key.append(L"\\");
key.append(guid);
return key;
@@ -38,10 +30,13 @@ namespace installer {
const char PackageProperties::kPackageProductName[] = "Chrome binaries";
-PackagePropertiesImpl::PackagePropertiesImpl(const wchar_t* guid,
- const std::wstring& state_key,
- const std::wstring& version_key)
- : guid_(guid), state_key_(state_key), version_key_(version_key) {
+PackagePropertiesImpl::PackagePropertiesImpl(
+ const wchar_t* guid,
+ const std::wstring& state_key,
+ const std::wstring& state_medium_key,
+ const std::wstring& version_key)
+ : guid_(guid), state_key_(state_key), state_medium_key_(state_medium_key),
+ version_key_(version_key) {
}
PackagePropertiesImpl::~PackagePropertiesImpl() {
@@ -51,6 +46,10 @@ const std::wstring& PackagePropertiesImpl::GetStateKey() {
return state_key_;
}
+const std::wstring& PackagePropertiesImpl::GetStateMediumKey() {
+ return state_medium_key_;
+}
+
const std::wstring& PackagePropertiesImpl::GetVersionKey() {
return version_key_;
}
@@ -59,21 +58,26 @@ void PackagePropertiesImpl::UpdateDiffInstallStatus(bool system_level,
bool incremental_install,
InstallStatus status) {
GoogleUpdateSettings::UpdateDiffInstallStatus(system_level,
- incremental_install, BrowserDistribution::GetInstallReturnCode(status),
- guid_);
+ incremental_install, InstallUtil::GetInstallReturnCode(status), guid_);
}
ChromiumPackageProperties::ChromiumPackageProperties()
- : PackagePropertiesImpl(L"", L"Software\\Chromium", L"Software\\Chromium") {
+ : PackagePropertiesImpl(L"", L"Software\\Chromium", L"Software\\Chromium",
+ L"Software\\Chromium") {
}
ChromiumPackageProperties::~ChromiumPackageProperties() {
}
ChromePackageProperties::ChromePackageProperties()
- : PackagePropertiesImpl(kChromePackageGuid,
- GetStateKeyForGuid(kChromePackageGuid),
- GetVersionKeyForGuid(kChromePackageGuid)) {
+ : PackagePropertiesImpl(
+ kChromePackageGuid,
+ GetKeyForGuid(google_update::kRegPathClientState,
+ kChromePackageGuid),
+ GetKeyForGuid(google_update::kRegPathClientStateMedium,
+ kChromePackageGuid),
+ GetKeyForGuid(google_update::kRegPathClients,
+ kChromePackageGuid)) {
}
ChromePackageProperties::~ChromePackageProperties() {
diff --git a/chrome/installer/util/package_properties.h b/chrome/installer/util/package_properties.h
index bced0d9..e3444da 100644
--- a/chrome/installer/util/package_properties.h
+++ b/chrome/installer/util/package_properties.h
@@ -32,11 +32,12 @@ class PackageProperties {
static const char kPackageProductName[];
- // Returns true iff this package will be updated by Omaha.
+ // Returns true iff this package will be updated by Google Update.
virtual bool ReceivesUpdates() const = 0;
// Equivalent to BrowserDistribution::GetAppGuid()
virtual const std::wstring& GetStateKey() = 0;
+ virtual const std::wstring& GetStateMediumKey() = 0;
virtual const std::wstring& GetVersionKey() = 0;
virtual void UpdateDiffInstallStatus(bool system_level,
bool incremental_install, installer::InstallStatus status) = 0;
@@ -49,10 +50,12 @@ class PackagePropertiesImpl : public PackageProperties {
public:
explicit PackagePropertiesImpl(const wchar_t* guid,
const std::wstring& state_key,
+ const std::wstring& state_medium_key,
const std::wstring& version_key);
virtual ~PackagePropertiesImpl();
virtual const std::wstring& GetStateKey();
+ virtual const std::wstring& GetStateMediumKey();
virtual const std::wstring& GetVersionKey();
virtual void UpdateDiffInstallStatus(bool system_level,
bool incremental_install, installer::InstallStatus status);
@@ -60,6 +63,7 @@ class PackagePropertiesImpl : public PackageProperties {
protected:
std::wstring guid_;
std::wstring state_key_;
+ std::wstring state_medium_key_;
std::wstring version_key_;
private:
diff --git a/chrome/installer/util/package_unittest.cc b/chrome/installer/util/package_unittest.cc
index f1eda9c..2bfd44aa 100644
--- a/chrome/installer/util/package_unittest.cc
+++ b/chrome/installer/util/package_unittest.cc
@@ -31,10 +31,11 @@ class PackageTest : public TestWithTempDirAndDeleteTempOverrideKeys {
// Tests a few basic things of the Package class. Makes sure that the path
// operations are correct
TEST_F(PackageTest, Basic) {
+ const bool multi_install = false;
const bool system_level = true;
ChromiumPackageProperties properties;
- scoped_refptr<Package> package(new Package(system_level, test_dir_.path(),
- &properties));
+ scoped_refptr<Package> package(new Package(multi_install, system_level,
+ test_dir_.path(), &properties));
EXPECT_EQ(test_dir_.path().value(), package->path().value());
EXPECT_TRUE(package->IsEqual(test_dir_.path()));
EXPECT_EQ(0U, package->products().size());
@@ -98,13 +99,14 @@ TEST_F(PackageTest, WithProduct) {
const MasterPreferences& prefs = MasterPreferences::ForCurrentProcess();
// TODO(tommi): We should mock this and use our mocked distribution.
+ const bool multi_install = false;
const bool system_level = true;
BrowserDistribution* distribution =
BrowserDistribution::GetSpecificDistribution(
BrowserDistribution::CHROME_BROWSER, prefs);
ChromePackageProperties properties;
- scoped_refptr<Package> package(new Package(system_level, test_dir_.path(),
- &properties));
+ scoped_refptr<Package> package(new Package(multi_install, system_level,
+ test_dir_.path(), &properties));
scoped_refptr<Product> product(new Product(distribution, package.get()));
EXPECT_EQ(1U, package->products().size());
EXPECT_EQ(system_level, package->system_level());
@@ -133,13 +135,14 @@ TEST_F(PackageTest, WithProduct) {
}
TEST_F(PackageTest, Dependency) {
+ const bool multi_install = false;
const bool system_level = true;
HKEY root = system_level ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER;
TempRegKeyOverride override(root, L"root_dep");
ChromePackageProperties properties;
- scoped_refptr<Package> package(new Package(system_level, test_dir_.path(),
- &properties));
+ scoped_refptr<Package> package(new Package(multi_install, system_level,
+ test_dir_.path(), &properties));
EXPECT_EQ(0U, package->GetMultiInstallDependencyCount());
const MasterPreferences& prefs = MasterPreferences::ForCurrentProcess();
@@ -171,3 +174,58 @@ TEST_F(PackageTest, Dependency) {
channel.Write(&cf_key);
EXPECT_EQ(2U, package->GetMultiInstallDependencyCount());
}
+
+TEST_F(PackageTest, InstallerResult) {
+ const bool system_level = true;
+ bool multi_install = false;
+ HKEY root = system_level ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER;
+
+ const MasterPreferences& prefs = MasterPreferences::ForCurrentProcess();
+ ChromePackageProperties properties;
+ BrowserDistribution* distribution =
+ BrowserDistribution::GetSpecificDistribution(
+ BrowserDistribution::CHROME_BROWSER, prefs);
+ scoped_refptr<Package> package(new Package(multi_install, system_level,
+ test_dir_.path(), &properties));
+ scoped_refptr<Product> product(new Product(distribution, package.get()));
+ RegKey key;
+ std::wstring launch_cmd = L"hey diddle diddle";
+ std::wstring value;
+
+ // check results for single Chrome
+ {
+ TempRegKeyOverride override(root, L"root_inst_res");
+ package->WriteInstallerResult(installer::FIRST_INSTALL_SUCCESS, 0,
+ &launch_cmd);
+ EXPECT_TRUE(key.Open(root, distribution->GetStateKey().c_str(), KEY_READ));
+ EXPECT_TRUE(key.ReadValue(installer::kInstallerSuccessLaunchCmdLine,
+ &value));
+ EXPECT_EQ(launch_cmd, value);
+ key.Close();
+ }
+ TempRegKeyOverride::DeleteAllTempKeys();
+
+ // check results for multi Chrome
+ multi_install = true;
+ package = new Package(multi_install, system_level, test_dir_.path(),
+ &properties);
+ product = new Product(distribution, package.get());
+ {
+ TempRegKeyOverride override(root, L"root_inst_res");
+ package->WriteInstallerResult(installer::FIRST_INSTALL_SUCCESS, 0,
+ &launch_cmd);
+ EXPECT_TRUE(key.Open(root, distribution->GetStateKey().c_str(), KEY_READ));
+ EXPECT_TRUE(key.ReadValue(installer::kInstallerSuccessLaunchCmdLine,
+ &value));
+ EXPECT_EQ(launch_cmd, value);
+ EXPECT_EQ(properties.ReceivesUpdates(),
+ key.Open(root, properties.GetStateKey().c_str(), KEY_READ));
+ if (properties.ReceivesUpdates()) {
+ EXPECT_TRUE(key.ReadValue(installer::kInstallerSuccessLaunchCmdLine,
+ &value));
+ EXPECT_EQ(launch_cmd, value);
+ }
+ key.Close();
+ }
+ TempRegKeyOverride::DeleteAllTempKeys();
+}
diff --git a/chrome/installer/util/product.cc b/chrome/installer/util/product.cc
index 3525b8e..8d4617a 100644
--- a/chrome/installer/util/product.cc
+++ b/chrome/installer/util/product.cc
@@ -6,18 +6,16 @@
#include <algorithm>
+#include "base/command_line.h"
#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/package_properties.h"
-#include "chrome/installer/util/work_item_list.h"
using base::win::RegKey;
using installer::MasterPreferences;
@@ -45,21 +43,13 @@ const Product* FindProduct(const Products& products,
return i == products.end() ? NULL : *i;
}
-void WriteInstallerResult(const Products& products,
- installer::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, Package* package)
: distribution_(distribution),
package_(package),
- msi_(MSI_NOT_CHECKED) {
+ msi_(false),
+ cache_state_(0) {
package_->AssociateProduct(this);
}
@@ -124,8 +114,8 @@ bool Product::LaunchChromeAndWait(const CommandLine& options,
}
bool Product::IsMsi() const {
- if (msi_ == MSI_NOT_CHECKED) {
- msi_ = NOT_MSI; // Covers failure cases below.
+ if ((cache_state_ & MSI_STATE) == 0) {
+ msi_ = false; // Covers failure cases below.
const MasterPreferences& prefs =
installer::MasterPreferences::ForCurrentProcess();
@@ -139,16 +129,18 @@ bool Product::IsMsi() const {
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;
+ if (key.ReadValueDW(google_update::kRegMSIField, &msi_value) &&
+ msi_value != 0) {
+ msi_ = true;
}
}
} else {
- msi_ = IS_MSI;
+ msi_ = true;
}
+ cache_state_ |= MSI_STATE;
}
- return msi_ == IS_MSI;
+ return msi_;
}
bool Product::SetMsiMarker(bool set) const {
@@ -170,45 +162,30 @@ bool Product::SetMsiMarker(bool set) const {
return success;
}
-void Product::WriteInstallerResult(
- installer::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::kInstallerResult,
- installer_result, true);
- install_list->AddSetRegValueWorkItem(root, key,
- installer::kInstallerError,
- status, true);
- if (string_resource_id != 0) {
- std::wstring msg = installer::GetLocalizedString(string_resource_id);
- install_list->AddSetRegValueWorkItem(root, key,
- installer::kInstallerResultUIString, msg, true);
+const Version* Product::GetInstalledVersion() const {
+ if ((cache_state_ & VERSION) == 0) {
+ DCHECK(installed_version_.get() == NULL);
+ installed_version_.reset(InstallUtil::GetChromeVersion(distribution_,
+ system_level()));
+ cache_state_ |= VERSION;
}
- if (launch_cmd != NULL && !launch_cmd->empty()) {
- install_list->AddSetRegValueWorkItem(root, key,
- installer::kInstallerSuccessLaunchCmdLine, *launch_cmd, true);
- }
- if (!install_list->Do())
- LOG(ERROR) << "Failed to record installer error information in registry.";
+
+ return installed_version_.get();
}
-Version* Product::GetInstalledVersion() const {
- return InstallUtil::GetChromeVersion(distribution_, system_level());
+bool Product::IsInstalled() const {
+ return GetInstalledVersion() != NULL;
}
///////////////////////////////////////////////////////////////////////////////
-ProductPackageMapping::ProductPackageMapping(bool system_level)
+ProductPackageMapping::ProductPackageMapping(bool multi_install,
+ bool system_level)
#if defined(GOOGLE_CHROME_BUILD)
: package_properties_(new ChromePackageProperties()),
#else
: package_properties_(new ChromiumPackageProperties()),
#endif
+ multi_install_(multi_install),
system_level_(system_level) {
}
@@ -237,8 +214,9 @@ bool ProductPackageMapping::AddDistribution(BrowserDistribution* distribution) {
}
if (!target_package.get()) {
+ DCHECK(packages_.empty()) << "Multiple packages per run unsupported.";
// create new one and add.
- target_package = new Package(system_level_, install_package,
+ target_package = new Package(multi_install_, system_level_, install_package,
package_properties_.get());
packages_.push_back(target_package);
}
diff --git a/chrome/installer/util/product.h b/chrome/installer/util/product.h
index cfd1736..4204071 100644
--- a/chrome/installer/util/product.h
+++ b/chrome/installer/util/product.h
@@ -32,12 +32,6 @@ typedef std::vector<scoped_refptr<const Product> > Products;
const Product* FindProduct(const Products& products,
BrowserDistribution::Type type);
-// Calls WriteInstallerResult for each Product object.
-void WriteInstallerResult(const Products& products,
- installer::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
@@ -96,25 +90,25 @@ class Product : public base::RefCounted<Product> {
// 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::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;
+ // found. The returned Version object is owned by |this| Product instance.
+ const Version* GetInstalledVersion() const;
+
+ // Returns true if the product is already installed.
+ bool IsInstalled() const;
protected:
+ enum CacheStateFlags {
+ MSI_STATE = 0x01,
+ VERSION = 0x02
+ };
+
BrowserDistribution* distribution_;
scoped_refptr<Package> package_;
- mutable enum MsiState {
- MSI_NOT_CHECKED,
- IS_MSI,
- NOT_MSI,
- } msi_;
+ mutable scoped_ptr<Version> installed_version_;
+ mutable bool msi_;
+ mutable uint8 cache_state_;
private:
friend class base::RefCounted<Product>;
@@ -129,7 +123,11 @@ class Product : public base::RefCounted<Product> {
// Product objects.
class ProductPackageMapping {
public:
- explicit ProductPackageMapping(bool system_level);
+ explicit ProductPackageMapping(bool multi_install, bool system_level);
+
+ bool multi_install() const {
+ return multi_install_;
+ }
bool system_level() const {
return system_level_;
@@ -144,6 +142,7 @@ class ProductPackageMapping {
bool AddDistribution(BrowserDistribution* distribution);
protected:
+ bool multi_install_;
bool system_level_;
Packages packages_;
Products products_;
diff --git a/chrome/installer/util/product_unittest.cc b/chrome/installer/util/product_unittest.cc
index 64cc1da..bb72fff 100644
--- a/chrome/installer/util/product_unittest.cc
+++ b/chrome/installer/util/product_unittest.cc
@@ -81,6 +81,7 @@ class ProductTest : public TestWithTempDirAndDeleteTempOverrideKeys {
TEST_F(ProductTest, ProductInstallBasic) {
// TODO(tommi): We should mock this and use our mocked distribution.
+ const bool multi_install = false;
const bool system_level = true;
const installer::MasterPreferences& prefs =
installer::MasterPreferences::ForCurrentProcess();
@@ -88,8 +89,8 @@ TEST_F(ProductTest, ProductInstallBasic) {
BrowserDistribution::GetSpecificDistribution(
BrowserDistribution::CHROME_BROWSER, prefs);
ChromePackageProperties properties;
- scoped_refptr<Package> package(new Package(system_level, test_dir_.path(),
- &properties));
+ scoped_refptr<Package> package(new Package(multi_install, system_level,
+ test_dir_.path(), &properties));
scoped_refptr<Product> product(new Product(distribution, package.get()));
FilePath user_data(product->GetUserDataPath());
@@ -119,20 +120,13 @@ TEST_F(ProductTest, ProductInstallBasic) {
// 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(system_level, test_dir_.path(), &properties);
+ package = new Package(multi_install, system_level, test_dir_.path(),
+ &properties);
product = new Product(distribution, 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::TEMP_DIR_FAILED,
- 0, &launch_cmd);
- std::wstring found_launch_cmd;
- key.ReadValue(installer::kInstallerSuccessLaunchCmdLine,
- &found_launch_cmd);
- EXPECT_EQ(launch_cmd, found_launch_cmd);
-
// There should be no installed version in the registry.
+ EXPECT_FALSE(product->IsInstalled());
EXPECT_TRUE(product->GetInstalledVersion() == NULL);
// Let's pretend chrome is installed.
@@ -146,9 +140,13 @@ TEST_F(ProductTest, ProductInstallBasic) {
version_key.WriteValue(google_update::kRegVersionField,
UTF8ToWide(current_version->GetString()).c_str());
- scoped_ptr<Version> installed(product->GetInstalledVersion());
- EXPECT_TRUE(installed.get() != NULL);
- if (installed.get()) {
+ package = new Package(multi_install, system_level, test_dir_.path(),
+ &properties);
+ product = new Product(distribution, package.get());
+ const Version* installed(product->GetInstalledVersion());
+ EXPECT_TRUE(product->IsInstalled());
+ EXPECT_TRUE(installed != NULL);
+ if (installed) {
EXPECT_TRUE(installed->Equals(*current_version.get()));
}
}
@@ -176,8 +174,10 @@ class FakeChromeFrameDistribution : public ChromeFrameDistribution {
};
TEST_F(ProductTest, ProductInstallsBasic) {
+ const bool multi_install = true;
const bool system_level = true;
- ProductPackageMapping installs(system_level);
+ ProductPackageMapping installs(multi_install, system_level);
+ EXPECT_EQ(multi_install, installs.multi_install());
EXPECT_EQ(system_level, installs.system_level());
EXPECT_EQ(0U, installs.packages().size());
EXPECT_EQ(0U, installs.products().size());
@@ -193,4 +193,5 @@ TEST_F(ProductTest, ProductInstallsBasic) {
// Since our fake Chrome Frame distribution class is reporting the same
// installation directory as Chrome, we should have only one package object.
EXPECT_EQ(1U, installs.packages().size());
+ EXPECT_EQ(multi_install, installs.packages()[0]->multi_install());
}