diff options
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()); } |