summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorgrt@chromium.org <grt@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-12-22 12:48:25 +0000
committergrt@chromium.org <grt@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-12-22 12:48:25 +0000
commite132804b4f648ab1188041ec6811a09092593bbe (patch)
tree037ccacd7fa668b5f982168ed07ebb35ae7587d0
parent30686097194aebfd4ffb551081d85a26211abd06 (diff)
downloadchromium_src-e132804b4f648ab1188041ec6811a09092593bbe.zip
chromium_src-e132804b4f648ab1188041ec6811a09092593bbe.tar.gz
chromium_src-e132804b4f648ab1188041ec6811a09092593bbe.tar.bz2
- Installation results for use by Google Update are now written at the Package level. Furthermore, such results are placed in the product keys as well as the package key, if there is one. This ensures that the result will be available for Google Update regardless of whether or not a migration from single to unified is taking place.
- The mutex protecting creation of the window used to join chrome processes no longer contains the app_guid. This increases contention for the lock slightly, but ensures that window creation is safe in light of unified installs. - Fixed placement of the user data directory for Chrome Frame. Previously, GetChromeFrameUserDataDirectory contained its own, different, ChromeFrameDistribution::GetInstallSubDir implementation. Now, GetChromeFrameUserDataDirectory delegates to ChromeFrameDistribution. - Product now caches and owns the Version instance returned by is GetInstalledVersion method (msi state is also cached). Also added Product::IsInstalled. - Moved GetInstallReturnCode from BrowserDistribution to InstallUtil because I didn't see why it belonged to the dist class. - SetEULAConsent now writes the consent value to either the product or package key as appropriate. - Disallow --multi-install when operating on a SxS Chrome installation. - Propagate --multi-install when running setup.exe with --rename-chrome-exe so that installer results can get written to the correct place. BUG=61609 TEST=New tests added to installer_util_unittests for WriteInstallerResult and SetEULAConsent changes. Review URL: http://codereview.chromium.org/6061003 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@69944 0039d316-1c4b-4281-b951-d872f2087c98
-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());
}