diff options
author | grt@chromium.org <grt@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-01-05 03:13:33 +0000 |
---|---|---|
committer | grt@chromium.org <grt@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-01-05 03:13:33 +0000 |
commit | a6ea126034ade23d94df94e2b105538152f6d86e (patch) | |
tree | 24b3059668f27f4a2e29fca025f77eefe14987a5 | |
parent | 269bb3a69e402a893bc8d01a99347c7ef6a5a38a (diff) | |
download | chromium_src-a6ea126034ade23d94df94e2b105538152f6d86e.zip chromium_src-a6ea126034ade23d94df94e2b105538152f6d86e.tar.gz chromium_src-a6ea126034ade23d94df94e2b105538152f6d86e.tar.bz2 |
- WriteInstallerResult is now back in InstallUtil and only writes the result where it is needed
- WriteInstallerResult is no longer called on uninstall (Google Update doesn't check it on uninstall)
- Introduced the poorly named InstallationState (state of the system based on registry inspection) and InstallerState (state of the current operation) classes
- Product::GetInstalledVersion and Product::IsInstalled are gone; use InstallationState instead
- A few cleanups to make the code comply with the style guide
- UpdateDiffInstallStatus has been renamed to UpdateInstallStatus
- Chromium builds noop in UpdateInstallStatus (this was always the case for the browser, but now also is for GCF and the multi-installer package).
- The -multifail suffixes is now added to/removed from the Google Update "ap" value by UpdateInstallStatus on the basis of multi-install success/failure.
- Added code to update the Google Update "ap" value based on the set up products/options installed
- ChannelInfo is now an ordered list of modifiers and suffixes. We're careful to keep -full at the end since that was an operating assumption previously.
- ActivePackageProperties is a typedef to either the Chrome or Chromium PackageProperties class
TEST=Some existing unit tests updated; more new unit tests to follow.
BUG=61609
Review URL: http://codereview.chromium.org/5988007
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@70483 0039d316-1c4b-4281-b951-d872f2087c98
38 files changed, 1370 insertions, 570 deletions
diff --git a/chrome/chrome_installer.gypi b/chrome/chrome_installer.gypi index 764b7f8e..5430e69 100644 --- a/chrome/chrome_installer.gypi +++ b/chrome/chrome_installer.gypi @@ -87,6 +87,7 @@ 'installer/util/google_chrome_distribution_unittest.cc', 'installer/util/google_update_settings_unittest.cc', 'installer/util/helper_unittest.cc', + 'installer/util/install_util_unittest.cc', 'installer/util/installer_util_unittests.rc', 'installer/util/installer_util_unittests_resource.h', 'installer/util/language_selector_unittest.cc', diff --git a/chrome/chrome_installer_util.gypi b/chrome/chrome_installer_util.gypi index b581c41..72601bb 100644 --- a/chrome/chrome_installer_util.gypi +++ b/chrome/chrome_installer_util.gypi @@ -41,6 +41,10 @@ 'installer/util/helper.h', 'installer/util/install_util.cc', 'installer/util/install_util.h', + 'installer/util/installation_state.h', + 'installer/util/installation_state.cc', + 'installer/util/installer_state.h', + 'installer/util/installer_state.cc', 'installer/util/l10n_string_util.cc', 'installer/util/l10n_string_util.h', 'installer/util/language_selector.cc', @@ -51,6 +55,8 @@ 'installer/util/move_tree_work_item.h', 'installer/util/package.h', 'installer/util/package.cc', + 'installer/util/package_properties.h', + 'installer/util/package_properties.cc', 'installer/util/self_reg_work_item.cc', 'installer/util/self_reg_work_item.h', 'installer/util/set_reg_value_work_item.cc', @@ -107,8 +113,6 @@ 'installer/util/lzma_util.h', 'installer/util/master_preferences.cc', 'installer/util/master_preferences.h', - 'installer/util/package_properties.h', - 'installer/util/package_properties.cc', 'installer/util/product.h', 'installer/util/product.cc', 'installer/util/shell_util.cc', diff --git a/chrome/installer/mini_installer/mini_installer.cc b/chrome/installer/mini_installer/mini_installer.cc index bbbcf65..760a70c 100644 --- a/chrome/installer/mini_installer/mini_installer.cc +++ b/chrome/installer/mini_installer/mini_installer.cc @@ -649,6 +649,7 @@ int WMain(HMODULE module) { // any errors here and we try to set the suffix for user level unless // --system-level is on the command line in which case we set it for system // level instead. This only applies to the Google Chrome distribution. + // TODO(grt): also add -multifail if --multi-install. SetFullInstallerFlag(); #endif diff --git a/chrome/installer/setup/install.cc b/chrome/installer/setup/install.cc index 0403257e..ec36f79 100644 --- a/chrome/installer/setup/install.cc +++ b/chrome/installer/setup/install.cc @@ -27,6 +27,8 @@ #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/installation_state.h" +#include "chrome/installer/util/installer_state.h" #include "chrome/installer/util/master_preferences.h" #include "chrome/installer/util/master_preferences_constants.h" #include "chrome/installer/util/package.h" @@ -43,6 +45,8 @@ using base::win::RegKey; using installer::ChannelInfo; +using installer::InstallerState; +using installer::InstallationState; using installer::MasterPreferences; using installer::Products; using installer::Product; @@ -219,6 +223,89 @@ void AddUninstallShortcutWorkItems(const FilePath& setup_path, } } +// Adds work items that make registry adjustments for Google Update. When a +// product is installed (including overinstall), Google Update will write the +// channel ("ap") value into either Chrome or Chrome Frame's ClientState key. +// In the multi-install case, this value is used as the basis upon which the +// package's channel value is built (by adding the ordered list of installed +// products and their options). +void AddGoogleUpdateWorkItems(const InstallationState& original_state, + const InstallerState& installer_state, + const Package& package, + WorkItemList* install_list) { + // Is a multi-install product being installed or over-installed? + if (installer_state.operation() != InstallerState::MULTI_INSTALL) + return; + + const HKEY reg_root = package.system_level() ? HKEY_LOCAL_MACHINE : + HKEY_CURRENT_USER; + const std::wstring key_path = installer_state.state_key(); + ChannelInfo channel_info; + + // Update the "ap" value for the product being installed/updated. + // It is completely acceptable for there to be no "ap" value or even no + // ClientState key. Note that we check the registry rather than + // original_state since on a fresh install the "ap" value will be present + // sans "pv" value. + channel_info.Initialize(RegKey(reg_root, key_path.c_str(), KEY_QUERY_VALUE)); + + // This is a multi-install product. + bool modified = channel_info.SetMultiInstall(true); + + // Add the appropriate modifiers for all products and their options. + Products::const_iterator scan = package.products().begin(); + const Products::const_iterator end = package.products().end(); + for (; scan != end; ++scan) { + modified |= scan->get()->distribution()->SetChannelFlags(true, + &channel_info); + } + + // Write the results if needed. + if (modified) { + install_list->AddSetRegValueWorkItem(reg_root, key_path, + google_update::kRegApField, + channel_info.value(), true); + } + + // Synchronize the other products and the package with this one. + std::wstring other_key; + std::vector<std::wstring> keys; + + keys.reserve(package.products().size()); + other_key = package.properties()->GetStateKey(); + if (other_key != key_path) + keys.push_back(other_key); + scan = package.products().begin(); + for (; scan != end; ++scan) { + other_key = scan->get()->distribution()->GetStateKey(); + if (other_key != key_path) + keys.push_back(other_key); + } + + RegKey key; + ChannelInfo other_info; + std::vector<std::wstring>::const_iterator kscan = keys.begin(); + std::vector<std::wstring>::const_iterator kend = keys.end(); + for (; kscan != kend; ++kscan) { + // Handle the case where the ClientState key doesn't exist by creating it. + // This takes care of the multi-installer's package key, which is not + // created by Google Update for us. + if (!key.Open(reg_root, kscan->c_str(), KEY_QUERY_VALUE) || + !other_info.Initialize(key)) { + other_info.set_value(std::wstring()); + } + if (!other_info.Equals(channel_info)) { + if (!key.Valid()) + install_list->AddCreateRegKeyWorkItem(reg_root, *kscan); + install_list->AddSetRegValueWorkItem(reg_root, *kscan, + google_update::kRegApField, + channel_info.value(), true); + } + } + // TODO(grt): check for other keys/values we should put in the package's + // ClientState and/or Clients key. +} + // This is called when an MSI installation is run. It may be that a user is // attempting to install the MSI on top of a non-MSI managed installation. // If so, try and remove any existing uninstallation shortcuts, as we want the @@ -693,6 +780,8 @@ void AddProductSpecificWorkItems(bool install, // (typical new install), the function creates package during install // and removes the whole directory during rollback. installer::InstallStatus InstallNewVersion( + const InstallationState& original_state, + const InstallerState& installer_state, bool multi_install, const FilePath& setup_path, const FilePath& archive_path, @@ -799,6 +888,10 @@ installer::InstallStatus InstallNewVersion( // each product. AddProductSpecificWorkItems(true, setup_path, new_version, package, install_list.get()); + + AddGoogleUpdateWorkItems(original_state, installer_state, package, + install_list.get()); + // Append the tasks that run after the installation. AppendPostInstallTasks(multi_install, setup_path, @@ -852,6 +945,8 @@ installer::InstallStatus InstallNewVersion( namespace installer { installer::InstallStatus InstallOrUpdateProduct( + const InstallationState& original_state, + const InstallerState& installer_state, const FilePath& setup_path, const FilePath& archive_path, const FilePath& install_temp_path, const FilePath& prefs_path, const installer::MasterPreferences& prefs, const Version& new_version, @@ -860,9 +955,9 @@ installer::InstallStatus InstallOrUpdateProduct( src_path = src_path.Append(kInstallSourceDir).Append(kInstallSourceChromeDir); scoped_ptr<Version> existing_version; - installer::InstallStatus result = InstallNewVersion(prefs.is_multi_install(), - setup_path, archive_path, src_path, install_temp_path, new_version, - &existing_version, install); + installer::InstallStatus result = InstallNewVersion(original_state, + installer_state, prefs.is_multi_install(), setup_path, archive_path, + src_path, install_temp_path, new_version, &existing_version, install); if (!InstallUtil::GetInstallReturnCode(result)) { if (result == installer::FIRST_INSTALL_SUCCESS && !prefs_path.empty()) @@ -1007,9 +1102,12 @@ void AddChromeFrameWorkItems(bool install, // uninstallation command line does not include the --chrome-frame switch // so that uninstalling Chrome will no longer uninstall Chrome Frame. - list->AddDeleteRegValueWorkItem(root, - product.package().properties()->GetStateKey(), - installer::kChromeFrameReadyModeField, false); + if (RegKey(root, product.package().properties()->GetStateKey().c_str(), + KEY_QUERY_VALUE).Valid()) { + list->AddDeleteRegValueWorkItem(root, + product.package().properties()->GetStateKey(), + installer::kChromeFrameReadyModeField, false); + } const Product* chrome = installer::FindProduct(product.package().products(), BrowserDistribution::CHROME_BROWSER); @@ -1045,7 +1143,8 @@ void AddChromeFrameWorkItems(bool install, } } -InstallStatus ChromeFrameReadyModeOptIn(const CommandLine& cmd_line) { +InstallStatus ChromeFrameReadyModeOptIn(const InstallerState& installer_state, + const CommandLine& cmd_line) { VLOG(1) << "Opting into Chrome Frame"; InstallStatus status = INSTALL_REPAIRED; @@ -1059,11 +1158,7 @@ InstallStatus ChromeFrameReadyModeOptIn(const CommandLine& cmd_line) { BrowserDistribution* chrome = BrowserDistribution::GetSpecificDistribution( BrowserDistribution::CHROME_BROWSER, prefs); -#if defined(GOOGLE_CHROME_BUILD) - ChromePackageProperties package_properties; -#else - ChromiumPackageProperties package_properties; -#endif + ActivePackageProperties package_properties; // Remove ChromeFrameReadyMode, update Chrome's uninstallation commands to // only uninstall Chrome, and add an entry to the Add/Remove Programs @@ -1074,21 +1169,28 @@ InstallStatus ChromeFrameReadyModeOptIn(const CommandLine& cmd_line) { LOG(ERROR) << "Conflicting installations"; status = NON_MULTI_INSTALLATION_EXISTS; } else { + InstallationState original_state; + original_state.Initialize(prefs); + scoped_refptr<Package> package(new Package(prefs.is_multi_install(), system_install, path, &package_properties)); scoped_refptr<Product> cf_product(new Product(cf, package)); DCHECK(cf_product->ShouldCreateUninstallEntry() || cf_product->IsMsi()); scoped_refptr<Product> chrome_product(new Product(chrome, package)); - - const Version* version = cf_product->GetInstalledVersion(); + const ProductState* product_state = + original_state.GetProductState(system_install, cf->GetType()); + if (product_state == NULL) { + LOG(ERROR) << "No Chrome Frame installation found for opt-in."; + return CHROME_NOT_INSTALLED; + } scoped_ptr<WorkItemList> item_list(WorkItem::CreateWorkItemList()); // This creates the uninstallation entry for GCF. - AddUninstallShortcutWorkItems(cmd_line.GetProgram(), *version, - item_list.get(), *cf_product.get()); + AddUninstallShortcutWorkItems(cmd_line.GetProgram(), + product_state->version(), item_list.get(), *cf_product.get()); // This updates the Chrome uninstallation entries. - AddUninstallShortcutWorkItems(cmd_line.GetProgram(), *version, - item_list.get(), *chrome_product.get()); + AddUninstallShortcutWorkItems(cmd_line.GetProgram(), + product_state->version(), item_list.get(), *chrome_product.get()); // Add a work item to delete the ChromeFrameReadyMode registry value. HKEY root = system_install ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER; diff --git a/chrome/installer/setup/install.h b/chrome/installer/setup/install.h index 7d21a24..40225c0 100644 --- a/chrome/installer/setup/install.h +++ b/chrome/installer/setup/install.h @@ -22,6 +22,8 @@ class WorkItemList; namespace installer { +class InstallationState; +class InstallerState; class Package; // This function installs or updates a new version of Chrome. It returns @@ -41,7 +43,9 @@ class Package; // // Note: since caller unpacks Chrome to install_temp_path\source, the caller // is responsible for cleaning up install_temp_path. -installer::InstallStatus InstallOrUpdateProduct( +InstallStatus InstallOrUpdateProduct( + const InstallationState& original_state, + const InstallerState& installer_state, const FilePath& setup_path, const FilePath& archive_path, const FilePath& install_temp_path, const FilePath& prefs_path, const installer::MasterPreferences& prefs, const Version& new_version, @@ -77,7 +81,8 @@ void AddChromeFrameWorkItems(bool install, const FilePath& setup_path, // Removes the ChromeFrameReadyMode flag from the registry, updates Chrome's // uninstallation commands to only uninstall Chrome, and adds an entry to the // Add/Remove Programs list for GCF. -InstallStatus ChromeFrameReadyModeOptIn(const CommandLine& cmd_line); +InstallStatus ChromeFrameReadyModeOptIn(const InstallerState& installer_state, + const CommandLine& cmd_line); } // namespace installer diff --git a/chrome/installer/setup/setup_main.cc b/chrome/installer/setup/setup_main.cc index 48f0f1c..cc47f7b 100644 --- a/chrome/installer/setup/setup_main.cc +++ b/chrome/installer/setup/setup_main.cc @@ -37,6 +37,8 @@ #include "chrome/installer/util/helper.h" #include "chrome/installer/util/html_dialog.h" #include "chrome/installer/util/install_util.h" +#include "chrome/installer/util/installer_state.h" +#include "chrome/installer/util/installation_state.h" #include "chrome/installer/util/l10n_string_util.h" #include "chrome/installer/util/logging_installer.h" #include "chrome/installer/util/lzma_util.h" @@ -48,8 +50,11 @@ #include "installer_util_strings.h" // NOLINT +using installer::InstallerState; +using installer::InstallationState; using installer::Product; using installer::ProductPackageMapping; +using installer::ProductState; using installer::Products; using installer::Package; using installer::Packages; @@ -178,28 +183,32 @@ installer::InstallStatus RenameChromeExecutables( return ret; } -bool CheckPreInstallConditions(const Package& installation, - installer::InstallStatus& status) { +bool CheckPreInstallConditions(const InstallationState& original_state, + const InstallerState& installer_state, + const Package& installation, + const MasterPreferences& prefs, + installer::InstallStatus* status) { const Products& products = installation.products(); DCHECK(products.size()); - bool is_first_install = true; - bool system_level = installation.system_level(); + bool is_first_install; + const bool system_level = installation.system_level(); for (size_t i = 0; i < products.size(); ++i) { const Product* product = products[i]; BrowserDistribution* browser_dist = product->distribution(); - // TODO(tommi): If the current install is for a different distribution than - // that might already be installed, then this check is incorrect. - if (product->IsInstalled()) + const ProductState* product_state = + original_state.GetProductState(system_level, browser_dist->GetType()); + if (product_state != NULL) is_first_install = false; // Check to avoid simultaneous per-user and per-machine installs. - scoped_ptr<Version> chrome_version( - InstallUtil::GetChromeVersion(browser_dist, !system_level)); + const ProductState* other_state = + original_state.GetProductState(!system_level, browser_dist->GetType()); - if (chrome_version.get()) { - LOG(ERROR) << "Already installed version " << chrome_version->GetString() + if (other_state != NULL) { + LOG(ERROR) << "Already installed version " + << other_state->version().GetString() << " conflicts with the current install mode."; if (!system_level && is_first_install && product->is_chrome()) { // This is user-level install and there is a system-level chrome @@ -209,15 +218,17 @@ bool CheckPreInstallConditions(const Package& installation, browser_dist)); if (chrome_exe.empty()) { // If we failed to construct install path. Give up. - status = installer::OS_ERROR; - installation.WriteInstallerResult(status, IDS_INSTALL_OS_ERROR_BASE, - NULL); + *status = installer::OS_ERROR; + InstallUtil::WriteInstallerResult(system_level, + installer_state.state_key(), *status, IDS_INSTALL_OS_ERROR_BASE, + NULL); } else { - status = installer::EXISTING_VERSION_LAUNCHED; + *status = installer::EXISTING_VERSION_LAUNCHED; chrome_exe = chrome_exe.Append(installer::kChromeExe); CommandLine cmd(chrome_exe); cmd.AppendSwitch(switches::kFirstRun); - installation.WriteInstallerResult(status, 0, NULL); + InstallUtil::WriteInstallerResult(system_level, + installer_state.state_key(), *status, 0, NULL); VLOG(1) << "Launching existing system-level chrome instead."; base::LaunchApp(cmd, false, false, NULL); } @@ -232,11 +243,12 @@ bool CheckPreInstallConditions(const Package& installation, // This is an update, not an install. Omaha should know the difference // and not show a dialog. - status = system_level ? installer::USER_LEVEL_INSTALL_EXISTS : - installer::SYSTEM_LEVEL_INSTALL_EXISTS; + *status = system_level ? installer::USER_LEVEL_INSTALL_EXISTS : + installer::SYSTEM_LEVEL_INSTALL_EXISTS; int str_id = system_level ? IDS_INSTALL_USER_LEVEL_EXISTS_BASE : IDS_INSTALL_SYSTEM_LEVEL_EXISTS_BASE; - installation.WriteInstallerResult(status, str_id, NULL); + InstallUtil::WriteInstallerResult(system_level, + installer_state.state_key(), *status, str_id, NULL); return false; } } @@ -249,9 +261,10 @@ bool CheckPreInstallConditions(const Package& installation, !file_util::Delete(installation.path(), true)) { LOG(ERROR) << "Installation directory " << installation.path().value() << " exists and can not be deleted."; - status = installer::INSTALL_DIR_IN_USE; + *status = installer::INSTALL_DIR_IN_USE; int str_id = IDS_INSTALL_DIR_IN_USE_BASE; - installation.WriteInstallerResult(status, str_id, NULL); + InstallUtil::WriteInstallerResult(system_level, + installer_state.state_key(), *status, str_id, NULL); return false; } } @@ -259,10 +272,13 @@ bool CheckPreInstallConditions(const Package& installation, return true; } -installer::InstallStatus InstallChrome(const CommandLine& cmd_line, - const Package& installation, const MasterPreferences& prefs) { +installer::InstallStatus InstallChrome(const InstallationState& original_state, + const InstallerState& installer_state, + const CommandLine& cmd_line, const Package& installation, + const MasterPreferences& prefs) { installer::InstallStatus install_status = installer::UNKNOWN_STATUS; - if (!CheckPreInstallConditions(installation, install_status)) + if (!CheckPreInstallConditions(original_state, installer_state, installation, + prefs, &install_status)) return install_status; // For install the default location for chrome.packed.7z is in current @@ -276,7 +292,6 @@ installer::InstallStatus InstallChrome(const CommandLine& cmd_line, installer::switches::kInstallArchive); } VLOG(1) << "Archive found to install Chrome " << archive.value(); - bool system_level = installation.system_level(); const Products& products = installation.products(); // Create a temp folder where we will unpack Chrome archive. If it fails, @@ -284,7 +299,8 @@ 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."; - installation.WriteInstallerResult(installer::TEMP_DIR_FAILED, + InstallUtil::WriteInstallerResult(installer_state.system_install(), + installer_state.state_key(), installer::TEMP_DIR_FAILED, IDS_INSTALL_TEMP_DIR_FAILED_BASE, NULL); return installer::TEMP_DIR_FAILED; } @@ -295,7 +311,8 @@ installer::InstallStatus InstallChrome(const CommandLine& cmd_line, if (UnPackArchive(archive, installation, temp_path, unpack_path, incremental_install)) { install_status = installer::UNCOMPRESSION_FAILED; - installation.WriteInstallerResult(install_status, + InstallUtil::WriteInstallerResult(installer_state.system_install(), + installer_state.state_key(), install_status, IDS_INSTALL_UNCOMPRESSION_FAILED_BASE, NULL); } else { VLOG(1) << "unpacked to " << unpack_path.value(); @@ -305,7 +322,8 @@ 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; - installation.WriteInstallerResult(install_status, + InstallUtil::WriteInstallerResult(installer_state.system_install(), + installer_state.state_key(), install_status, IDS_INSTALL_INVALID_ARCHIVE_BASE, NULL); } else { // TODO(tommi): Move towards having only a single version that is common @@ -317,8 +335,11 @@ 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]; - const Version* v = product->GetInstalledVersion(); - if (v != NULL && (v->CompareTo(*installer_version) > 0)) { + const ProductState* product_state = + original_state.GetProductState(installer_state.system_install(), + product->distribution()->GetType()); + if (product_state != NULL && + (product_state->version().CompareTo(*installer_version) > 0)) { LOG(ERROR) << "Higher version is already installed."; higher_version_installed = true; install_status = installer::HIGHER_VERSION_EXISTS; @@ -326,10 +347,12 @@ installer::InstallStatus InstallChrome(const CommandLine& cmd_line, if (product->is_chrome()) { // TODO(robertshield): We should take the installer result text // strings from the Product. - installation.WriteInstallerResult(install_status, + InstallUtil::WriteInstallerResult(installer_state.system_install(), + installer_state.state_key(), install_status, IDS_INSTALL_HIGHER_VERSION_BASE, NULL); } else { - installation.WriteInstallerResult(install_status, + InstallUtil::WriteInstallerResult(installer_state.system_install(), + installer_state.state_key(), install_status, IDS_INSTALL_HIGHER_VERSION_CF_BASE, NULL); } } @@ -341,8 +364,8 @@ installer::InstallStatus InstallChrome(const CommandLine& cmd_line, FilePath archive_to_copy(temp_path.Append(installer::kChromeArchive)); FilePath prefs_source_path(cmd_line.GetSwitchValueNative( installer::switches::kInstallerData)); - install_status = installer::InstallOrUpdateProduct( - cmd_line.GetProgram(), archive_to_copy, temp_path, + install_status = installer::InstallOrUpdateProduct(original_state, + installer_state, cmd_line.GetProgram(), archive_to_copy, temp_path, prefs_source_path, prefs, *installer_version, installation); int install_msg_base = IDS_INSTALL_FAILED_BASE; @@ -382,7 +405,8 @@ installer::InstallStatus InstallChrome(const CommandLine& cmd_line, bool write_chrome_launch_string = (!value) && (install_status != installer::IN_USE_UPDATED); - installation.WriteInstallerResult(install_status, install_msg_base, + InstallUtil::WriteInstallerResult(installer_state.system_install(), + installer_state.state_key(), install_status, install_msg_base, write_chrome_launch_string ? &chrome_exe : NULL); if (install_status == installer::FIRST_INSTALL_SUCCESS) { @@ -448,31 +472,41 @@ installer::InstallStatus InstallChrome(const CommandLine& cmd_line, for (size_t i = 0; i < products.size(); ++i) { const Product* product = products[i]; - product->distribution()->UpdateDiffInstallStatus(system_level, - incremental_install, install_status); + product->distribution()->UpdateInstallStatus( + installer_state.system_install(), incremental_install, + prefs.is_multi_install(), install_status); + } + if (prefs.is_multi_install()) { + installation.properties()->UpdateInstallStatus( + installer_state.system_install(), incremental_install, true, + install_status); } return install_status; } -installer::InstallStatus UninstallProduct(const CommandLine& cmd_line, - const Product& product) { +installer::InstallStatus UninstallProduct( + const InstallationState& original_state, + const InstallerState& installer_state, + const CommandLine& cmd_line, + const Product& product) { bool force = cmd_line.HasSwitch(installer::switches::kForceUninstall); - if (product.IsInstalled()) { + const ProductState* product_state = + original_state.GetProductState(installer_state.system_install(), + product.distribution()->GetType()); + if (product_state != NULL) { VLOG(1) << "version on the system: " - << product.GetInstalledVersion()->GetString(); + << product_state->version().GetString(); } else if (!force) { LOG(ERROR) << "No Chrome installation found for uninstall."; - product.package().WriteInstallerResult(installer::CHROME_NOT_INSTALLED, - IDS_UNINSTALL_FAILED_BASE, NULL); return installer::CHROME_NOT_INSTALLED; } bool remove_all = !cmd_line.HasSwitch( installer::switches::kDoNotRemoveSharedItems); - return installer::UninstallProduct(cmd_line.GetProgram(), product, remove_all, - force, cmd_line); + return installer::UninstallProduct(original_state, installer_state, + cmd_line.GetProgram(), product, remove_all, force, cmd_line); } installer::InstallStatus ShowEULADialog(const std::wstring& inner_frame) { @@ -506,9 +540,10 @@ installer::InstallStatus ShowEULADialog(const std::wstring& inner_frame) { // various tasks other than installation (renaming chrome.exe, showing eula // among others). This function returns true if any such command line option // has been found and processed (so setup.exe should exit at that point). -bool HandleNonInstallCmdLineOptions(const CommandLine& cmd_line, - int& exit_code, - const ProductPackageMapping& installs) { +bool HandleNonInstallCmdLineOptions(const InstallerState& installer_state, + const CommandLine& cmd_line, + const ProductPackageMapping& installs, + int* exit_code) { DCHECK(installs.products().size()); bool handled = true; // TODO(tommi): Split these checks up into functions and use a data driven @@ -539,11 +574,12 @@ bool HandleNonInstallCmdLineOptions(const CommandLine& cmd_line, } } - exit_code = InstallUtil::GetInstallReturnCode(status); - if (exit_code) { + *exit_code = InstallUtil::GetInstallReturnCode(status); + if (*exit_code) { LOG(WARNING) << "setup.exe patching failed."; - installs.packages()[0]->WriteInstallerResult(status, - IDS_SETUP_PATCH_FAILED_BASE, NULL); + InstallUtil::WriteInstallerResult(installer_state.system_install(), + installer_state.state_key(), status, IDS_SETUP_PATCH_FAILED_BASE, + NULL); } file_util::Delete(temp_path, true); } else if (cmd_line.HasSwitch(installer::switches::kShowEula)) { @@ -551,8 +587,8 @@ bool HandleNonInstallCmdLineOptions(const CommandLine& cmd_line, // then the dialog is shown and regardless of the outcome setup exits here. std::wstring inner_frame = cmd_line.GetSwitchValueNative(installer::switches::kShowEula); - exit_code = ShowEULADialog(inner_frame); - if (installer::EULA_REJECTED != exit_code) + *exit_code = ShowEULADialog(inner_frame); + if (installer::EULA_REJECTED != *exit_code) GoogleUpdateSettings::SetEULAConsent(*installs.packages()[0].get(), true); } else if (cmd_line.HasSwitch( installer::switches::kRegisterChromeBrowser)) { @@ -573,11 +609,11 @@ bool HandleNonInstallCmdLineOptions(const CommandLine& cmd_line, suffix = cmd_line.GetSwitchValueNative( installer::switches::kRegisterChromeBrowserSuffix); } - exit_code = ShellUtil::RegisterChromeBrowser( + *exit_code = ShellUtil::RegisterChromeBrowser( chrome_install->distribution(), chrome_exe, suffix, false); } else { LOG(ERROR) << "Can't register browser - Chrome distribution not found"; - exit_code = installer::UNKNOWN_STATUS; + *exit_code = installer::UNKNOWN_STATUS; } } else if (cmd_line.HasSwitch(installer::switches::kRenameChromeExe)) { // If --rename-chrome-exe is specified, we want to rename the executables @@ -585,7 +621,7 @@ bool HandleNonInstallCmdLineOptions(const CommandLine& cmd_line, const Packages& packages = installs.packages(); DCHECK_EQ(1U, packages.size()); for (size_t i = 0; i < packages.size(); ++i) - exit_code = RenameChromeExecutables(*packages[i].get()); + *exit_code = RenameChromeExecutables(*packages[i].get()); } else if (cmd_line.HasSwitch( installer::switches::kRemoveChromeRegistration)) { // This is almost reverse of --register-chrome-browser option above. @@ -606,7 +642,7 @@ bool HandleNonInstallCmdLineOptions(const CommandLine& cmd_line, installer::DeleteChromeRegistrationKeys(chrome_install->distribution(), HKEY_LOCAL_MACHINE, suffix, tmp); } - exit_code = tmp; + *exit_code = tmp; } else if (cmd_line.HasSwitch(installer::switches::kInactiveUserToast)) { // Launch the inactive user toast experiment. int flavor = -1; @@ -614,7 +650,7 @@ bool HandleNonInstallCmdLineOptions(const CommandLine& cmd_line, installer::switches::kInactiveUserToast), &flavor); DCHECK_NE(-1, flavor); if (flavor == -1) { - exit_code = installer::UNKNOWN_STATUS; + *exit_code = installer::UNKNOWN_STATUS; } else { const Products& products = installs.products(); for (size_t i = 0; i < products.size(); ++i) { @@ -637,8 +673,8 @@ bool HandleNonInstallCmdLineOptions(const CommandLine& cmd_line, } } else if (cmd_line.HasSwitch( installer::switches::kChromeFrameReadyModeOptIn)) { - exit_code = InstallUtil::GetInstallReturnCode( - installer::ChromeFrameReadyModeOptIn(cmd_line)); + *exit_code = InstallUtil::GetInstallReturnCode( + installer::ChromeFrameReadyModeOptIn(installer_state, cmd_line)); } else { handled = false; } @@ -835,17 +871,27 @@ int WINAPI wWinMain(HINSTANCE instance, HINSTANCE prev_instance, google_breakpad::scoped_ptr<google_breakpad::ExceptionHandler> breakpad( InitializeCrashReporting(system_install)); + InstallationState original_state; + original_state.Initialize(prefs); + + InstallerState installer_state; + installer_state.Initialize(prefs, original_state); + ProductPackageMapping installations(prefs.is_multi_install(), system_install); if (!PopulateInstallations(prefs, &installations)) { // Currently this can only fail if one of the installations is a multi and // a pre-existing single installation exists or vice versa. installer::InstallStatus status; if (prefs.is_multi_install()) { + // TODO(grt): create a new string for this condition. status = installer::NON_MULTI_INSTALLATION_EXISTS; } else { + // TODO(grt): create a new string for this condition. status = installer::MULTI_INSTALLATION_EXISTS; } LOG(ERROR) << "Failed to populate installations: " << status; + InstallUtil::WriteInstallerResult(system_install, + installer_state.state_key(), status, NULL, NULL); return status; } @@ -853,15 +899,17 @@ int WINAPI wWinMain(HINSTANCE instance, HINSTANCE prev_instance, // error message and get out. if (!InstallUtil::IsOSSupported()) { LOG(ERROR) << "Chrome only supports Windows XP or later."; - installations.packages()[0]->WriteInstallerResult( - installer::OS_NOT_SUPPORTED, IDS_INSTALL_OS_NOT_SUPPORTED_BASE, NULL); + InstallUtil::WriteInstallerResult(system_install, + installer_state.state_key(), 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)) { - installations.packages()[0]->WriteInstallerResult(installer::OS_ERROR, + InstallUtil::WriteInstallerResult(system_install, + installer_state.state_key(), installer::OS_ERROR, IDS_INSTALL_OS_ERROR_BASE, NULL); return installer::OS_ERROR; } @@ -882,7 +930,8 @@ int WINAPI wWinMain(HINSTANCE instance, HINSTANCE prev_instance, } int exit_code = 0; - if (HandleNonInstallCmdLineOptions(cmd_line, exit_code, installations)) + if (HandleNonInstallCmdLineOptions(installer_state, cmd_line, installations, + &exit_code)) return exit_code; if (system_install && !IsUserAnAdmin()) { @@ -898,9 +947,9 @@ int WINAPI wWinMain(HINSTANCE instance, HINSTANCE prev_instance, return exit_code; } else { LOG(ERROR) << "Non admin user can not install system level Chrome."; - installations.packages()[0]->WriteInstallerResult( - installer::INSUFFICIENT_RIGHTS, IDS_INSTALL_INSUFFICIENT_RIGHTS_BASE, - NULL); + InstallUtil::WriteInstallerResult(system_install, + installer_state.state_key(), installer::INSUFFICIENT_RIGHTS, + IDS_INSTALL_INSUFFICIENT_RIGHTS_BASE, NULL); return installer::INSUFFICIENT_RIGHTS; } } @@ -911,14 +960,16 @@ int WINAPI wWinMain(HINSTANCE instance, HINSTANCE prev_instance, // If --uninstall option is given, uninstall chrome if (is_uninstall) { for (size_t i = 0; i < installations.products().size(); ++i) { - install_status = UninstallProduct(cmd_line, *installations.products()[i]); + install_status = UninstallProduct(original_state, installer_state, + cmd_line, *installations.products()[i]); } } else { // If --uninstall option is not specified, we assume it is install case. const Packages& packages = installations.packages(); VLOG(1) << "Installing to " << packages.size() << " target paths"; for (size_t i = 0; i < packages.size(); ++i) { - install_status = InstallChrome(cmd_line, *packages[i].get(), prefs); + install_status = InstallChrome(original_state, installer_state, cmd_line, + *packages[i].get(), prefs); } } diff --git a/chrome/installer/setup/uninstall.cc b/chrome/installer/setup/uninstall.cc index 0b1aa79..0d3d193 100644 --- a/chrome/installer/setup/uninstall.cc +++ b/chrome/installer/setup/uninstall.cc @@ -20,9 +20,13 @@ #include "chrome/installer/setup/install.h" #include "chrome/installer/setup/setup_constants.h" #include "chrome/installer/util/browser_distribution.h" +#include "chrome/installer/util/channel_info.h" #include "chrome/installer/util/delete_after_reboot_helper.h" +#include "chrome/installer/util/google_update_constants.h" #include "chrome/installer/util/helper.h" #include "chrome/installer/util/install_util.h" +#include "chrome/installer/util/installation_state.h" +#include "chrome/installer/util/installer_state.h" #include "chrome/installer/util/logging_installer.h" #include "chrome/installer/util/package_properties.h" #include "chrome/installer/util/shell_util.h" @@ -34,6 +38,67 @@ using base::win::RegKey; using installer::InstallStatus; +namespace { + +// Makes appropriate changes to the Google Update "ap" value in the registry. +// Specifically, removes the flags associated with this product ("-chrome" or +// "-chromeframe[-CEEE][-readymode]") from the "ap" values for all other +// installed products and for the multi-installer package. +void ProcessGoogleUpdateItems( + const installer::InstallationState& original_state, + const installer::Product& product) { + const bool system_level = product.system_level(); + BrowserDistribution* distribution = product.distribution(); + const HKEY reg_root = system_level ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER; + const installer::ProductState* product_state = + original_state.GetProductState(system_level, distribution->GetType()); + DCHECK(product_state != NULL); + installer::ChannelInfo channel_info; + + // Remove product's flags from the channel value. + channel_info.set_value(product_state->channel().value()); + const bool modified = distribution->SetChannelFlags(false, &channel_info); + + // Apply the new channel value to all other products and to the multi package. + if (modified) { + BrowserDistribution::Type other_dist_type = + (distribution->GetType() == BrowserDistribution::CHROME_BROWSER) ? + BrowserDistribution::CHROME_FRAME : + BrowserDistribution::CHROME_BROWSER; + BrowserDistribution* other_dist = + BrowserDistribution::GetSpecificDistribution(other_dist_type, + installer::MasterPreferences::ForCurrentProcess()); + scoped_ptr<WorkItemList> + update_list(WorkItem::CreateNoRollbackWorkItemList()); + + product_state = original_state.GetProductState(system_level, + other_dist_type); + if (installer::IsInstalledAsMulti(system_level, other_dist) && + !product_state->channel().Equals(channel_info)) { + update_list->AddSetRegValueWorkItem(reg_root, other_dist->GetStateKey(), + google_update::kRegApField, channel_info.value(), true); + } else { + VLOG(1) << other_dist->GetApplicationName() + << "'s ap value is unexpectedly up to date."; + } + + product_state = original_state.GetMultiPackageState(system_level); + DCHECK(product_state != NULL); + if (!product_state->channel().Equals(channel_info)) { + update_list->AddSetRegValueWorkItem(reg_root, + product.package().properties()->GetStateKey(), + google_update::kRegApField, channel_info.value(), true); + } else { + VLOG(1) << "Multi-install package's ap value is unexpectedly up to date."; + } + + bool success = update_list->Do(); + LOG_IF(ERROR, !success) << "Failed updating channel values."; + } +} + +} // namespace + namespace installer { // This functions checks for any Chrome instances that are @@ -477,18 +542,21 @@ const wchar_t kChromeExtProgId[] = L"ChromiumExt"; } bool ProcessChromeFrameWorkItems(const FilePath& setup_path, - const Product& product) { + const Product& product, + const ProductState* product_state) { if (!product.is_chrome_frame()) return false; - const Version* version = product.GetInstalledVersion(); + DCHECK(product_state != NULL); scoped_ptr<WorkItemList> item_list(WorkItem::CreateWorkItemList()); - AddChromeFrameWorkItems(false, setup_path, *version, product, + AddChromeFrameWorkItems(false, setup_path, product_state->version(), product, item_list.get()); return item_list->Do(); } -InstallStatus UninstallProduct(const FilePath& setup_path, +InstallStatus UninstallProduct(const InstallationState& original_state, + const InstallerState& installer_state, + const FilePath& setup_path, const Product& product, bool remove_all, bool force_uninstall, @@ -571,8 +639,16 @@ InstallStatus UninstallProduct(const FilePath& setup_path, InstallStatus ret = installer::UNKNOWN_STATUS; DeleteChromeRegistrationKeys(product.distribution(), reg_root, suffix, ret); + // Get the state of the installed product (if any) + const ProductState* product_state = + original_state.GetProductState(installer_state.system_install(), + browser_dist->GetType()); + if (!is_chrome) - ProcessChromeFrameWorkItems(setup_path, product); + ProcessChromeFrameWorkItems(setup_path, product, product_state); + + if (product.package().multi_install()) + ProcessGoogleUpdateItems(original_state, product); // For user level install also we end up creating some keys in HKLM if user // sets Chrome as default browser. So delete those as well (needs admin). @@ -582,9 +658,6 @@ InstallStatus UninstallProduct(const FilePath& setup_path, suffix, ret); } - // Get the version of the installed product (if any) - const Version* installed_version = product.GetInstalledVersion(); - // Delete shared registry keys as well (these require admin rights) if // remove_all option is specified. if (remove_all) { @@ -596,15 +669,14 @@ InstallStatus UninstallProduct(const FilePath& setup_path, std::wstring reg_path(installer::kMediaPlayerRegPath); file_util::AppendToPath(®_path, installer::kChromeExe); InstallUtil::DeleteRegistryKey(hklm_key, reg_path); - hklm_key.Close(); } // Unregister any dll servers that we may have registered for this // product. - if (installed_version != NULL) { + if (product_state != NULL) { std::vector<FilePath> com_dll_list(browser_dist->GetComDllList()); FilePath dll_folder = product.package().path().Append( - UTF8ToWide(installed_version->GetString())); + UTF8ToWide(product_state->version().GetString())); scoped_ptr<WorkItemList> unreg_work_item_list( WorkItem::CreateWorkItemList()); @@ -626,7 +698,7 @@ InstallStatus UninstallProduct(const FilePath& setup_path, CloseChromeFrameHelperProcess(); } - if (installed_version == NULL) + if (product_state == NULL) return installer::UNINSTALL_SUCCESSFUL; // Finally delete all the files from Chrome folder after moving setup.exe @@ -661,9 +733,9 @@ InstallStatus UninstallProduct(const FilePath& setup_path, // need to move setup.exe out of the install folder. // TODO(tommi): What if the temp folder is on a different volume? MoveSetupOutOfInstallFolder(product.package(), setup_path, - *installed_version); + product_state->version()); delete_result = DeleteFilesAndFolders(product.package(), - *installed_version); + product_state->version()); } if (delete_profile) @@ -677,7 +749,7 @@ InstallStatus UninstallProduct(const FilePath& setup_path, if (!force_uninstall) { VLOG(1) << "Uninstallation complete. Launching Uninstall survey."; - browser_dist->DoPostUninstallOperations(*installed_version, + browser_dist->DoPostUninstallOperations(product_state->version(), backup_state_file, distribution_data); } diff --git a/chrome/installer/setup/uninstall.h b/chrome/installer/setup/uninstall.h index 274f55e..a3f1ec1 100644 --- a/chrome/installer/setup/uninstall.h +++ b/chrome/installer/setup/uninstall.h @@ -8,22 +8,26 @@ #define CHROME_INSTALLER_SETUP_UNINSTALL_H_ #pragma once -#include <string> - #include <shlobj.h> +#include <string> + #include "base/command_line.h" #include "chrome/installer/util/product.h" #include "chrome/installer/util/util_constants.h" namespace installer { + +class InstallationState; +class InstallerState; + // This function removes all Chrome registration related keys. It returns true // if successful, otherwise false. The error code is set in |exit_code|. // |root| is the registry root (HKLM|HKCU) and |browser_entry_suffix| is the // suffix for default browser entry name in the registry (optional). bool DeleteChromeRegistrationKeys(BrowserDistribution* dist, HKEY root, const std::wstring& browser_entry_suffix, - installer::InstallStatus& exit_code); + InstallStatus& exit_code); // Removes any legacy registry keys from earlier versions of Chrome that are no // longer needed. This is used during autoupdate since we don't do full @@ -33,6 +37,8 @@ void RemoveLegacyRegistryKeys(BrowserDistribution* dist); // This function uninstalls a product. Hence we came up with this awesome // name for it. // +// original_state: The installation state of all products on the system. +// installer_state: State associated with this operation. // setup_path: Path to the executable (setup.exe) as it will be copied // to temp folder before deleting Chrome folder. // dist: Represents the distribution to be uninstalled. @@ -42,8 +48,13 @@ void RemoveLegacyRegistryKeys(BrowserDistribution* dist); // cmd_line: CommandLine that contains information about the command that // was used to launch current uninstaller. installer::InstallStatus UninstallProduct( - const FilePath& setup_path, const Product& dist, bool remove_all, - bool force_uninstall, const CommandLine& cmd_line); + const InstallationState& original_state, + const InstallerState& installer_state, + const FilePath& setup_path, + const Product& dist, + bool remove_all, + bool force_uninstall, + const CommandLine& cmd_line); } // namespace installer_setup diff --git a/chrome/installer/util/browser_distribution.cc b/chrome/installer/util/browser_distribution.cc index d684c97..05f3c04 100644 --- a/chrome/installer/util/browser_distribution.cc +++ b/chrome/installer/util/browser_distribution.cc @@ -33,7 +33,6 @@ namespace { // The BrowserDistribution objects are never freed. BrowserDistribution* g_browser_distribution = NULL; BrowserDistribution* g_chrome_frame_distribution = NULL; -BrowserDistribution* g_ceee_distribution = NULL; // Returns true if currently running in npchrome_frame.dll bool IsChromeFrameModule() { @@ -203,8 +202,9 @@ bool BrowserDistribution::GetChromeChannel(std::wstring* channel) { return false; } -void BrowserDistribution::UpdateDiffInstallStatus(bool system_install, - bool incremental_install, installer::InstallStatus install_status) { +void BrowserDistribution::UpdateInstallStatus(bool system_install, + bool incremental_install, bool multi_install, + installer::InstallStatus install_status) { } void BrowserDistribution::LaunchUserExperiment( @@ -236,3 +236,9 @@ void BrowserDistribution::AppendUninstallCommandLineFlags( bool BrowserDistribution::ShouldCreateUninstallEntry() { return true; } + +bool BrowserDistribution::SetChannelFlags( + bool set, + installer::ChannelInfo* channel_info) { + return false; +} diff --git a/chrome/installer/util/browser_distribution.h b/chrome/installer/util/browser_distribution.h index a967116..1f6a1c9 100644 --- a/chrome/installer/util/browser_distribution.h +++ b/chrome/installer/util/browser_distribution.h @@ -23,10 +23,9 @@ class CommandLine; namespace installer { -class Product; -} -namespace installer { +class ChannelInfo; class MasterPreferences; +class Product; } class BrowserDistribution { @@ -91,8 +90,9 @@ class BrowserDistribution { virtual bool GetChromeChannel(std::wstring* channel); - virtual void UpdateDiffInstallStatus(bool system_install, - bool incremental_install, installer::InstallStatus install_status); + virtual void UpdateInstallStatus(bool system_install, + bool incremental_install, bool multi_install, + installer::InstallStatus install_status); // After an install or upgrade the user might qualify to participate in an // experiment. This function determines if the user qualifies and if so it @@ -128,6 +128,10 @@ class BrowserDistribution { // Add/Remove Programs dialog for this distribution. virtual bool ShouldCreateUninstallEntry(); + // Adds or removes product-specific flags in |channel_info|. Returns true if + // |channel_info| is modified. + virtual bool SetChannelFlags(bool set, installer::ChannelInfo* channel_info); + protected: explicit BrowserDistribution(const installer::MasterPreferences& prefs); diff --git a/chrome/installer/util/channel_info.cc b/chrome/installer/util/channel_info.cc index 4acc4d4..fd8c6b5 100644 --- a/chrome/installer/util/channel_info.cc +++ b/chrome/installer/util/channel_info.cc @@ -15,8 +15,12 @@ namespace { const wchar_t kChannelBeta[] = L"beta"; const wchar_t kChannelDev[] = L"dev"; const wchar_t kModCeee[] = L"-CEEE"; -const wchar_t kModFullInstall[] = L"-full"; +const wchar_t kModChrome[] = L"-chrome"; +const wchar_t kModChromeFrame[] = L"-chromeframe"; const wchar_t kModMultiInstall[] = L"-multi"; +const wchar_t kModReadyMode[] = L"-readymode"; +const wchar_t kSfxFull[] = L"-full"; +const wchar_t kSfxMultiFail[] = L"-multifail"; const wchar_t* const kChannels[] = { kChannelBeta, @@ -24,44 +28,93 @@ const wchar_t* const kChannels[] = { }; const wchar_t* const kModifiers[] = { + kModMultiInstall, + kModChrome, + kModChromeFrame, kModCeee, - kModFullInstall, - kModMultiInstall + kModReadyMode, + kSfxMultiFail, + kSfxFull }; -} // namespace +enum ModifierIndex { + MOD_MULTI_INSTALL, + MOD_CHROME, + MOD_CHROME_FRAME, + MOD_CEEE, + MOD_READY_MODE, + SFX_MULTI_FAIL, + SFX_FULL, + NUM_MODIFIERS +}; -namespace installer { +COMPILE_ASSERT(NUM_MODIFIERS == arraysize(kModifiers), + kModifiers_disagrees_with_ModifierIndex_comma_they_must_match_bang); + +// Returns true if the modifier is found, in which case |position| holds the +// location at which the modifier was found. +bool FindModifier(ModifierIndex index, + const std::wstring& ap_value, + std::wstring::size_type* position) { + DCHECK(position != NULL); + std::wstring::size_type mod_length = + std::wstring::traits_type::length(kModifiers[index]); + for (std::wstring::size_type pos = 0; ; ) { + *position = ap_value.find(kModifiers[index], pos, mod_length); + if (*position == std::wstring::npos) + break; + // The modifier must be either at the end of the string or followed by -. + pos = *position + mod_length; + if (pos == ap_value.size() || ap_value[pos] == L'-') + return true; + } + return false; +} -// static -bool ChannelInfo::HasModifier(const wchar_t* modifier, - const std::wstring& ap_value) { - DCHECK(modifier); - return ap_value.find(modifier) != std::wstring::npos; +bool HasModifier(ModifierIndex index, const std::wstring& ap_value) { + DCHECK(index >= 0 && index < NUM_MODIFIERS); + std::wstring::size_type position; + return FindModifier(index, ap_value, &position); +} + +std::wstring::size_type FindInsertionPoint(ModifierIndex index, + const std::wstring& ap_value) { + // Return the location of the next modifier. + std::wstring::size_type result; + + for (int scan = index + 1; scan < NUM_MODIFIERS; ++scan) { + if (FindModifier(static_cast<ModifierIndex>(scan), ap_value, &result)) + return result; + } + + return ap_value.size(); } // Returns true if |ap_value| is modified. -// static -bool ChannelInfo::SetModifier(const wchar_t* modifier, - bool set, - std::wstring* ap_value) { - DCHECK(modifier); +bool SetModifier(ModifierIndex index, bool set, std::wstring* ap_value) { + DCHECK(index >= 0 && index < NUM_MODIFIERS); DCHECK(ap_value); - std::wstring::size_type position = ap_value->find(modifier); + std::wstring::size_type position; + bool have_modifier = FindModifier(index, *ap_value, &position); if (set) { - if (position == std::wstring::npos) { - ap_value->append(modifier); + if (!have_modifier) { + ap_value->insert(FindInsertionPoint(index, *ap_value), kModifiers[index]); return true; } } else { - if (position != std::wstring::npos) { - ap_value->erase(position, std::wstring::traits_type::length(modifier)); + if (have_modifier) { + ap_value->erase(position, + std::wstring::traits_type::length(kModifiers[index])); return true; } } return false; } +} // namespace + +namespace installer { + bool ChannelInfo::Initialize(const RegKey& key) { return key.ReadValue(google_update::kRegApField, &value_); } @@ -87,10 +140,8 @@ bool ChannelInfo::GetChannelName(std::wstring* channel_name) const { // There may be modifiers present. Strip them off and see if we're left // with the empty string (stable channel). std::wstring tmp_value = value_; - for (const wchar_t* const* scan = &kModifiers[0], - *const *end = &kModifiers[arraysize(kModifiers)]; scan != end; - ++scan) { - SetModifier(*scan, false, &tmp_value); + for (int i = 0; i != NUM_MODIFIERS; ++i) { + SetModifier(static_cast<ModifierIndex>(i), false, &tmp_value); } if (tmp_value.empty()) { channel_name->erase(); @@ -102,27 +153,59 @@ bool ChannelInfo::GetChannelName(std::wstring* channel_name) const { } bool ChannelInfo::IsCeee() const { - return HasModifier(kModCeee, value_); + return HasModifier(MOD_CEEE, value_); } bool ChannelInfo::SetCeee(bool value) { - return SetModifier(kModCeee, value, &value_); + return SetModifier(MOD_CEEE, value, &value_); } -bool ChannelInfo::IsFullInstall() const { - return HasModifier(kModFullInstall, value_); +bool ChannelInfo::IsChrome() const { + return HasModifier(MOD_CHROME, value_); } -bool ChannelInfo::SetFullInstall(bool value) { - return SetModifier(kModFullInstall, value, &value_); +bool ChannelInfo::SetChrome(bool value) { + return SetModifier(MOD_CHROME, value, &value_); +} + +bool ChannelInfo::IsChromeFrame() const { + return HasModifier(MOD_CHROME_FRAME, value_); +} + +bool ChannelInfo::SetChromeFrame(bool value) { + return SetModifier(MOD_CHROME_FRAME, value, &value_); } bool ChannelInfo::IsMultiInstall() const { - return HasModifier(kModMultiInstall, value_); + return HasModifier(MOD_MULTI_INSTALL, value_); } bool ChannelInfo::SetMultiInstall(bool value) { - return SetModifier(kModMultiInstall, value, &value_); + return SetModifier(MOD_MULTI_INSTALL, value, &value_); +} + +bool ChannelInfo::IsReadyMode() const { + return HasModifier(MOD_READY_MODE, value_); +} + +bool ChannelInfo::SetReadyMode(bool value) { + return SetModifier(MOD_READY_MODE, value, &value_); +} + +bool ChannelInfo::HasFullSuffix() const { + return HasModifier(SFX_FULL, value_); +} + +bool ChannelInfo::SetFullSuffix(bool value) { + return SetModifier(SFX_FULL, value, &value_); +} + +bool ChannelInfo::HasMultiFailSuffix() const { + return HasModifier(SFX_MULTI_FAIL, value_); +} + +bool ChannelInfo::SetMultiFailSuffix(bool value) { + return SetModifier(SFX_MULTI_FAIL, value, &value_); } } // namespace installer diff --git a/chrome/installer/util/channel_info.h b/chrome/installer/util/channel_info.h index 5ba919a..7954e1c 100644 --- a/chrome/installer/util/channel_info.h +++ b/chrome/installer/util/channel_info.h @@ -16,8 +16,8 @@ class RegKey; namespace installer { -// A helper class for parsing and modifying the Omaha additional parameter -// ("ap") client state value for a product. +// A helper class for parsing and modifying the Google Update additional +// parameter ("ap") client state value for a product. class ChannelInfo { public: @@ -31,6 +31,9 @@ class ChannelInfo { const std::wstring& value() const { return value_; } void set_value(const std::wstring& value) { value_ = value; } + bool Equals(const ChannelInfo& other) const { + return value_ == other.value_; + } // Determines the update channel for the value. Possible |channel_name| // results are the empty string (stable channel), "beta", and "dev". Returns @@ -45,12 +48,19 @@ class ChannelInfo { // modified. bool SetCeee(bool value); - // Returns true if the -full modifier is present in the value. - bool IsFullInstall() const; + // Returns true if the -chrome modifier is present in the value. + bool IsChrome() const; - // Adds or removes the -full modifier, returning true if the value is + // Adds or removes the -chrome modifier, returning true if the value is // modified. - bool SetFullInstall(bool value); + bool SetChrome(bool value); + + // Returns true if the -chromeframe modifier is present in the value. + bool IsChromeFrame() const; + + // Adds or removes the -chromeframe modifier, returning true if the value is + // modified. + bool SetChromeFrame(bool value); // Returns true if the -multi modifier is present in the value. bool IsMultiInstall() const; @@ -59,12 +69,28 @@ class ChannelInfo { // modified. bool SetMultiInstall(bool value); - private: - static bool HasModifier(const wchar_t* modifier, - const std::wstring& ap_value); - static bool SetModifier(const wchar_t* modifier, bool set, - std::wstring* ap_value); + // Returns true if the -readymode modifier is present in the value. + bool IsReadyMode() const; + + // Adds or removes the -readymode modifier, returning true if the value is + // modified. + bool SetReadyMode(bool value); + + // Returns true if the -full suffix is present in the value. + bool HasFullSuffix() const; + // Adds or removes the -full suffix, returning true if the value is + // modified. + bool SetFullSuffix(bool value); + + // Returns true if the -multifail suffix is present in the value. + bool HasMultiFailSuffix() const; + + // Adds or removes the -multifail suffix, returning true if the value is + // modified. + bool SetMultiFailSuffix(bool value); + + private: std::wstring value_; }; // class ChannelInfo diff --git a/chrome/installer/util/channel_info_unittest.cc b/chrome/installer/util/channel_info_unittest.cc index f5ea4bb..febc33a 100644 --- a/chrome/installer/util/channel_info_unittest.cc +++ b/chrome/installer/util/channel_info_unittest.cc @@ -90,31 +90,31 @@ TEST(ChannelInfoTest, FullInstall) { installer::ChannelInfo ci; ci.set_value(L""); - EXPECT_TRUE(ci.SetFullInstall(true)); - EXPECT_TRUE(ci.IsFullInstall()); + EXPECT_TRUE(ci.SetFullSuffix(true)); + EXPECT_TRUE(ci.HasFullSuffix()); EXPECT_EQ(L"-full", ci.value()); - EXPECT_FALSE(ci.SetFullInstall(true)); - EXPECT_TRUE(ci.IsFullInstall()); + EXPECT_FALSE(ci.SetFullSuffix(true)); + EXPECT_TRUE(ci.HasFullSuffix()); EXPECT_EQ(L"-full", ci.value()); - EXPECT_TRUE(ci.SetFullInstall(false)); - EXPECT_FALSE(ci.IsFullInstall()); + EXPECT_TRUE(ci.SetFullSuffix(false)); + EXPECT_FALSE(ci.HasFullSuffix()); EXPECT_EQ(L"", ci.value()); - EXPECT_FALSE(ci.SetFullInstall(false)); - EXPECT_FALSE(ci.IsFullInstall()); + EXPECT_FALSE(ci.SetFullSuffix(false)); + EXPECT_FALSE(ci.HasFullSuffix()); EXPECT_EQ(L"", ci.value()); ci.set_value(L"2.0-beta"); - EXPECT_TRUE(ci.SetFullInstall(true)); - EXPECT_TRUE(ci.IsFullInstall()); + EXPECT_TRUE(ci.SetFullSuffix(true)); + EXPECT_TRUE(ci.HasFullSuffix()); EXPECT_EQ(L"2.0-beta-full", ci.value()); - EXPECT_FALSE(ci.SetFullInstall(true)); - EXPECT_TRUE(ci.IsFullInstall()); + EXPECT_FALSE(ci.SetFullSuffix(true)); + EXPECT_TRUE(ci.HasFullSuffix()); EXPECT_EQ(L"2.0-beta-full", ci.value()); - EXPECT_TRUE(ci.SetFullInstall(false)); - EXPECT_FALSE(ci.IsFullInstall()); + EXPECT_TRUE(ci.SetFullSuffix(false)); + EXPECT_FALSE(ci.HasFullSuffix()); EXPECT_EQ(L"2.0-beta", ci.value()); - EXPECT_FALSE(ci.SetFullInstall(false)); - EXPECT_FALSE(ci.IsFullInstall()); + EXPECT_FALSE(ci.SetFullSuffix(false)); + EXPECT_FALSE(ci.HasFullSuffix()); EXPECT_EQ(L"2.0-beta", ci.value()); } @@ -149,3 +149,12 @@ TEST(ChannelInfoTest, MultiInstall) { EXPECT_FALSE(ci.IsMultiInstall()); EXPECT_EQ(L"2.0-beta", ci.value()); } + +TEST(ChannelInfoTest, Combinations) { + installer::ChannelInfo ci; + + ci.set_value(L"2.0-beta-chromeframe"); + EXPECT_FALSE(ci.IsChrome()); + ci.set_value(L"2.0-beta-chromeframe-chrome"); + EXPECT_TRUE(ci.IsChrome()); +} diff --git a/chrome/installer/util/chrome_frame_distribution.cc b/chrome/installer/util/chrome_frame_distribution.cc index 9d643c4..73aa3f6 100644 --- a/chrome/installer/util/chrome_frame_distribution.cc +++ b/chrome/installer/util/chrome_frame_distribution.cc @@ -12,6 +12,7 @@ #include <string> #include "base/string_util.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/helper.h" @@ -141,11 +142,14 @@ bool ChromeFrameDistribution::CanSetAsDefault() { return false; } -void ChromeFrameDistribution::UpdateDiffInstallStatus(bool system_install, - bool incremental_install, installer::InstallStatus install_status) { - GoogleUpdateSettings::UpdateDiffInstallStatus(system_install, - incremental_install, InstallUtil::GetInstallReturnCode(install_status), - kChromeFrameGuid); +void ChromeFrameDistribution::UpdateInstallStatus(bool system_install, + bool incremental_install, bool multi_install, + installer::InstallStatus install_status) { +#if defined(GOOGLE_CHROME_BUILD) + GoogleUpdateSettings::UpdateInstallStatus(system_install, + incremental_install, multi_install, + InstallUtil::GetInstallReturnCode(install_status), kChromeFrameGuid); +#endif } std::vector<FilePath> ChromeFrameDistribution::GetKeyFiles() { @@ -185,3 +189,23 @@ bool ChromeFrameDistribution::ShouldCreateUninstallEntry() { // add an entry to the add/remove dialog. return !ready_mode_; } + +bool ChromeFrameDistribution::SetChannelFlags( + bool set, + installer::ChannelInfo* channel_info) { +#if defined(GOOGLE_CHROME_BUILD) + DCHECK(channel_info); + bool modified = channel_info->SetChromeFrame(set); + + // Always remove the options if we're called to remove flags. + if (!set || ceee_) + modified |= channel_info->SetCeee(set); + + if (!set || ready_mode_) + modified |= channel_info->SetReadyMode(set); + + return modified; +#else + return false; +#endif +} diff --git a/chrome/installer/util/chrome_frame_distribution.h b/chrome/installer/util/chrome_frame_distribution.h index 94df4bd..f34cc86 100644 --- a/chrome/installer/util/chrome_frame_distribution.h +++ b/chrome/installer/util/chrome_frame_distribution.h @@ -10,6 +10,7 @@ #pragma once #include <string> +#include <vector> #include "chrome/installer/util/browser_distribution.h" #include "chrome/installer/util/util_constants.h" @@ -50,11 +51,9 @@ class ChromeFrameDistribution : public BrowserDistribution { virtual bool CanSetAsDefault(); - // This is the point at which the Google Chrome installer removes the Google - // Update ap value. We implement this simply to have the same behaviour re. - // the ap value. - virtual void UpdateDiffInstallStatus(bool system_install, - bool incremental_install, installer::InstallStatus install_status); + virtual void UpdateInstallStatus(bool system_install, + bool incremental_install, bool multi_install, + installer::InstallStatus install_status); virtual std::vector<FilePath> GetKeyFiles(); @@ -64,6 +63,8 @@ class ChromeFrameDistribution : public BrowserDistribution { virtual bool ShouldCreateUninstallEntry(); + virtual bool SetChannelFlags(bool set, installer::ChannelInfo* channel_info); + protected: friend class BrowserDistribution; diff --git a/chrome/installer/util/google_chrome_distribution.cc b/chrome/installer/util/google_chrome_distribution.cc index 99c47f9..f1010f5 100644 --- a/chrome/installer/util/google_chrome_distribution.cc +++ b/chrome/installer/util/google_chrome_distribution.cc @@ -26,6 +26,7 @@ #include "chrome/common/json_value_serializer.h" #include "chrome/common/pref_names.h" #include "chrome/common/result_codes.h" +#include "chrome/installer/util/channel_info.h" #include "chrome/installer/util/product.h" #include "chrome/installer/util/install_util.h" #include "chrome/installer/util/l10n_string_util.h" @@ -500,11 +501,12 @@ std::wstring GoogleChromeDistribution::GetVersionKey() { // - If we are currently running full installer, we remove this magic // string (if it is present) regardless of whether installer failed or not. // There is no fall-back for full installer :) -void GoogleChromeDistribution::UpdateDiffInstallStatus(bool system_install, - bool incremental_install, installer::InstallStatus install_status) { - GoogleUpdateSettings::UpdateDiffInstallStatus(system_install, - incremental_install, InstallUtil::GetInstallReturnCode(install_status), - product_guid().c_str()); +void GoogleChromeDistribution::UpdateInstallStatus(bool system_install, + bool incremental_install, bool multi_install, + installer::InstallStatus install_status) { + GoogleUpdateSettings::UpdateInstallStatus(system_install, + incremental_install, multi_install, + InstallUtil::GetInstallReturnCode(install_status), product_guid()); } // The functions below are not used by the 64-bit Windows binary - @@ -686,3 +688,10 @@ void GoogleChromeDistribution::InactiveUserToastExperiment(int flavor, base::LaunchApp(cmd, false, false, NULL); } #endif + +bool GoogleChromeDistribution::SetChannelFlags( + bool set, + installer::ChannelInfo* channel_info) { + DCHECK(channel_info); + return channel_info->SetChrome(set); +} diff --git a/chrome/installer/util/google_chrome_distribution.h b/chrome/installer/util/google_chrome_distribution.h index 006ed13..f4feb6e 100644 --- a/chrome/installer/util/google_chrome_distribution.h +++ b/chrome/installer/util/google_chrome_distribution.h @@ -65,8 +65,9 @@ class GoogleChromeDistribution : public BrowserDistribution { virtual std::wstring GetVersionKey(); - virtual void UpdateDiffInstallStatus(bool system_install, - bool incremental_install, installer::InstallStatus install_status); + virtual void UpdateInstallStatus(bool system_install, + bool incremental_install, bool multi_install, + installer::InstallStatus install_status); virtual void LaunchUserExperiment(installer::InstallStatus status, const Version& version, @@ -81,6 +82,8 @@ class GoogleChromeDistribution : public BrowserDistribution { const std::wstring& product_guid() { return product_guid_; } + virtual bool SetChannelFlags(bool set, installer::ChannelInfo* channel_info); + protected: void set_product_guid(const std::wstring& guid) { product_guid_ = guid; } diff --git a/chrome/installer/util/google_chrome_distribution_dummy.cc b/chrome/installer/util/google_chrome_distribution_dummy.cc index 370fec8..4d16c68 100644 --- a/chrome/installer/util/google_chrome_distribution_dummy.cc +++ b/chrome/installer/util/google_chrome_distribution_dummy.cc @@ -100,8 +100,9 @@ std::wstring GoogleChromeDistribution::GetVersionKey() { return std::wstring(); } -void GoogleChromeDistribution::UpdateDiffInstallStatus(bool system_install, - bool incremental_install, installer::InstallStatus install_status) { +void GoogleChromeDistribution::UpdateInstallStatus(bool system_install, + bool incremental_install, bool multi_install, + installer::InstallStatus install_status) { NOTREACHED(); } @@ -134,3 +135,9 @@ bool GoogleChromeDistribution::BuildUninstallMetricsString( return false; } +bool GoogleChromeDistribution::SetChannelFlags( + bool set, + installer::ChannelInfo* channel_info) { + NOTREACHED(); + return false; +} diff --git a/chrome/installer/util/google_update_settings.cc b/chrome/installer/util/google_update_settings.cc index 8621e9f..1e1d5e3 100644 --- a/chrome/installer/util/google_update_settings.cc +++ b/chrome/installer/util/google_update_settings.cc @@ -237,8 +237,8 @@ bool GoogleUpdateSettings::GetChromeChannel(bool system_install, return true; } -void GoogleUpdateSettings::UpdateDiffInstallStatus(bool system_install, - bool incremental_install, int install_return_code, +void GoogleUpdateSettings::UpdateInstallStatus(bool system_install, + bool incremental_install, bool multi_install, int install_return_code, const std::wstring& product_guid) { HKEY reg_root = (system_install) ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER; @@ -247,54 +247,70 @@ void GoogleUpdateSettings::UpdateDiffInstallStatus(bool system_install, std::wstring reg_key(google_update::kRegPathClientState); reg_key.append(L"\\"); reg_key.append(product_guid); - if (!key.Open(reg_root, reg_key.c_str(), KEY_ALL_ACCESS) || + if (!key.Open(reg_root, reg_key.c_str(), KEY_QUERY_VALUE | KEY_SET_VALUE) || !channel_info.Initialize(key)) { VLOG(1) << "Application key not found."; - if (!incremental_install || !install_return_code) { + if (!incremental_install && !multi_install || !install_return_code) { VLOG(1) << "Returning without changing application key."; - key.Close(); return; } else if (!key.Valid()) { reg_key.assign(google_update::kRegPathClientState); - if (!key.Open(reg_root, reg_key.c_str(), KEY_ALL_ACCESS) || - !key.CreateKey(product_guid.c_str(), KEY_ALL_ACCESS)) { + if (!key.Open(reg_root, reg_key.c_str(), KEY_CREATE_SUB_KEY) || + !key.CreateKey(product_guid.c_str(), KEY_SET_VALUE)) { LOG(ERROR) << "Failed to create application key."; - key.Close(); return; } } } - if (UpdateGoogleUpdateApKey(incremental_install, install_return_code, - &channel_info) && + if (UpdateGoogleUpdateApKey(incremental_install, multi_install, + install_return_code, &channel_info) && !channel_info.Write(&key)) { LOG(ERROR) << "Failed to write value " << channel_info.value() << " to the registry field " << google_update::kRegApField; } - key.Close(); } bool GoogleUpdateSettings::UpdateGoogleUpdateApKey( - bool diff_install, int install_return_code, + bool diff_install, bool multi_install, int install_return_code, installer::ChannelInfo* value) { + bool modified = false; + if (!diff_install || !install_return_code) { - if (value->SetFullInstall(false)) { - VLOG(1) << "Removed incremental installer failure key; new value: " + if (value->SetFullSuffix(false)) { + VLOG(1) << "Removed incremental installer failure key; " + "switching to channel: " << value->value(); - return true; + modified = true; } - } else if (diff_install && install_return_code) { - if (value->SetFullInstall(true)) { - VLOG(1) << "Incremental installer failed, setting failure key; " - "new value: " + } else { + if (value->SetFullSuffix(true)) { + VLOG(1) << "Incremental installer failed; switching to channel: " << value->value(); - return true; + modified = true; } else { - VLOG(1) << "Incremental installer failure key already set."; + VLOG(1) << "Incremental installer failure; already on channel: " + << value->value(); } } - return false; + if (!multi_install || !install_return_code) { + if (value->SetMultiFailSuffix(false)) { + VLOG(1) << "Removed multi-install failure key; switching to channel: " + << value->value(); + modified = true; + } + } else { + if (value->SetMultiFailSuffix(true)) { + VLOG(1) << "Multi-install failed; switching to channel: " + << value->value(); + modified = true; + } else { + VLOG(1) << "Multi-install failed; already on channel: " << value->value(); + } + } + + return modified; } int GoogleUpdateSettings::DuplicateGoogleUpdateSystemClientKey() { diff --git a/chrome/installer/util/google_update_settings.h b/chrome/installer/util/google_update_settings.h index 0ac8991..36e020c 100644 --- a/chrome/installer/util/google_update_settings.h +++ b/chrome/installer/util/google_update_settings.h @@ -90,10 +90,22 @@ class GoogleUpdateSettings { // on success, channel contains one of "", "unknown", "dev" or "beta". static bool GetChromeChannel(bool system_install, std::wstring* channel); - static void UpdateDiffInstallStatus(bool system_install, - bool incremental_install, - int install_return_code, - const std::wstring& product_guid); + // This method changes the Google Update "ap" value to move the installation + // on to or off of one of the recovery channels. + // - If incremental installer fails we append a magic string ("-full"), if + // it is not present already, so that Google Update server next time will send + // full installer to update Chrome on the local machine + // - If we are currently running full installer, we remove this magic + // string (if it is present) regardless of whether installer failed or not. + // There is no fall-back for full installer :) + // - If multi-install fails we append -multifail; otherwise, we remove it + // (i.e., success or single-install). + // |state_key| should be obtained via InstallerState::state_key(). + static void UpdateInstallStatus(bool system_install, + bool incremental_install, + bool multi_install, + int install_return_code, + const std::wstring& product_guid); // This method updates the value for Google Update "ap" key for Chrome // based on whether we are doing incremental install (or not) and whether @@ -109,6 +121,7 @@ class GoogleUpdateSettings { // value: current value of Google Update "ap" key. // Returns true if |value| is modified. static bool UpdateGoogleUpdateApKey(bool diff_install, + bool multi_install, int install_return_code, installer::ChannelInfo* value); diff --git a/chrome/installer/util/google_update_settings_unittest.cc b/chrome/installer/util/google_update_settings_unittest.cc index 672e589..d041d12 100644 --- a/chrome/installer/util/google_update_settings_unittest.cc +++ b/chrome/installer/util/google_update_settings_unittest.cc @@ -5,6 +5,9 @@ #include <windows.h> #include <shlwapi.h> // For SHDeleteKey. +#include <functional> +#include <map> + #include "base/ref_counted.h" #include "base/scoped_ptr.h" #include "base/win/registry.h" @@ -20,6 +23,7 @@ #include "testing/gtest/include/gtest/gtest.h" using base::win::RegKey; +using installer::ChannelInfo; namespace { @@ -217,120 +221,114 @@ TEST_F(GoogleUpdateSettingsTest, CurrentChromeChannelVariousApValuesUser) { TestCurrentChromeChannelWithVariousApValues(USER_INSTALL); } +// Run through all combinations of diff vs. full install, single vs. multi +// install, success and failure results, and a fistfull of initial "ap" values +// checking that the expected final "ap" value is generated by +// GoogleUpdateSettings::UpdateGoogleUpdateApKey. TEST_F(GoogleUpdateSettingsTest, UpdateGoogleUpdateApKey) { - installer::InstallStatus s = installer::FIRST_INSTALL_SUCCESS; - installer::InstallStatus f = installer::INSTALL_FAILED; - - // Incremental Installer that worked. - installer::ChannelInfo v; - v.set_value(L""); - EXPECT_FALSE(GoogleUpdateSettings::UpdateGoogleUpdateApKey(true, s, &v)); - EXPECT_EQ(v.value(), L""); - - v.set_value(L"1.1"); - EXPECT_FALSE(GoogleUpdateSettings::UpdateGoogleUpdateApKey(true, s, &v)); - EXPECT_EQ(v.value(), L"1.1"); - - v.set_value(L"1.1-dev"); - EXPECT_FALSE(GoogleUpdateSettings::UpdateGoogleUpdateApKey(true, s, &v)); - EXPECT_EQ(v.value(), L"1.1-dev"); - - v.set_value(L"-full"); - EXPECT_TRUE(GoogleUpdateSettings::UpdateGoogleUpdateApKey(true, s, &v)); - EXPECT_EQ(v.value(), L""); - - v.set_value(L"1.1-full"); - EXPECT_TRUE(GoogleUpdateSettings::UpdateGoogleUpdateApKey(true, s, &v)); - EXPECT_EQ(v.value(), L"1.1"); - - v.set_value(L"1.1-dev-full"); - EXPECT_TRUE(GoogleUpdateSettings::UpdateGoogleUpdateApKey(true, s, &v)); - EXPECT_EQ(v.value(), L"1.1-dev"); - - // Incremental Installer that failed. - v.set_value(L""); - EXPECT_TRUE(GoogleUpdateSettings::UpdateGoogleUpdateApKey(true, f, &v)); - EXPECT_EQ(v.value(), L"-full"); - - v.set_value(L"1.1"); - EXPECT_TRUE(GoogleUpdateSettings::UpdateGoogleUpdateApKey(true, f, &v)); - EXPECT_EQ(v.value(), L"1.1-full"); - - v.set_value(L"1.1-dev"); - EXPECT_TRUE(GoogleUpdateSettings::UpdateGoogleUpdateApKey(true, f, &v)); - EXPECT_EQ(v.value(), L"1.1-dev-full"); - - v.set_value(L"-full"); - EXPECT_FALSE(GoogleUpdateSettings::UpdateGoogleUpdateApKey(true, f, &v)); - EXPECT_EQ(v.value(), L"-full"); - - v.set_value(L"1.1-full"); - EXPECT_FALSE(GoogleUpdateSettings::UpdateGoogleUpdateApKey(true, f, &v)); - EXPECT_EQ(v.value(), L"1.1-full"); - - v.set_value(L"1.1-dev-full"); - EXPECT_FALSE(GoogleUpdateSettings::UpdateGoogleUpdateApKey(true, f, &v)); - EXPECT_EQ(v.value(), L"1.1-dev-full"); - - // Full Installer that worked. - v.set_value(L""); - EXPECT_FALSE(GoogleUpdateSettings::UpdateGoogleUpdateApKey(false, s, &v)); - EXPECT_EQ(v.value(), L""); - - v.set_value(L"1.1"); - EXPECT_FALSE(GoogleUpdateSettings::UpdateGoogleUpdateApKey(false, s, &v)); - EXPECT_EQ(v.value(), L"1.1"); - - v.set_value(L"1.1-dev"); - EXPECT_FALSE(GoogleUpdateSettings::UpdateGoogleUpdateApKey(false, s, &v)); - EXPECT_EQ(v.value(), L"1.1-dev"); - - v.set_value(L"-full"); - EXPECT_TRUE(GoogleUpdateSettings::UpdateGoogleUpdateApKey(false, s, &v)); - EXPECT_EQ(v.value(), L""); - - v.set_value(L"1.1-full"); - EXPECT_TRUE(GoogleUpdateSettings::UpdateGoogleUpdateApKey(false, s, &v)); - EXPECT_EQ(v.value(), L"1.1"); - - v.set_value(L"1.1-dev-full"); - EXPECT_TRUE(GoogleUpdateSettings::UpdateGoogleUpdateApKey(false, s, &v)); - EXPECT_EQ(v.value(), L"1.1-dev"); - - // Full Installer that failed. - v.set_value(L""); - EXPECT_FALSE(GoogleUpdateSettings::UpdateGoogleUpdateApKey(false, f, &v)); - EXPECT_EQ(v.value(), L""); - - v.set_value(L"1.1"); - EXPECT_FALSE(GoogleUpdateSettings::UpdateGoogleUpdateApKey(false, f, &v)); - EXPECT_EQ(v.value(), L"1.1"); - - v.set_value(L"1.1-dev"); - EXPECT_FALSE(GoogleUpdateSettings::UpdateGoogleUpdateApKey(false, f, &v)); - EXPECT_EQ(v.value(), L"1.1-dev"); - - v.set_value(L"-full"); - EXPECT_TRUE(GoogleUpdateSettings::UpdateGoogleUpdateApKey(false, f, &v)); - EXPECT_EQ(v.value(), L""); - - v.set_value(L"1.1-full"); - EXPECT_TRUE(GoogleUpdateSettings::UpdateGoogleUpdateApKey(false, f, &v)); - EXPECT_EQ(v.value(), L"1.1"); - - v.set_value(L"1.1-dev-full"); - EXPECT_TRUE(GoogleUpdateSettings::UpdateGoogleUpdateApKey(false, f, &v)); - EXPECT_EQ(v.value(), L"1.1-dev"); + const bool is_multi[] = { + false, + true + }; + const bool is_diff[] = { + false, + true + }; + const int results[] = { + installer::FIRST_INSTALL_SUCCESS, + installer::INSTALL_FAILED + }; + const wchar_t* const plain[] = { + L"", + L"1.1", + L"1.1-dev" + }; + const wchar_t* const full[] = { + L"-full", + L"1.1-full", + L"1.1-dev-full" + }; + COMPILE_ASSERT(arraysize(full) == arraysize(plain), bad_full_array_size); + const wchar_t* const multifail[] = { + L"-multifail", + L"1.1-multifail", + L"1.1-dev-multifail" + }; + COMPILE_ASSERT(arraysize(multifail) == arraysize(plain), + bad_multifail_array_size); + const wchar_t* const multifail_full[] = { + L"-multifail-full", + L"1.1-multifail-full", + L"1.1-dev-multifail-full" + }; + COMPILE_ASSERT(arraysize(multifail_full) == arraysize(plain), + bad_multifail_full_array_size); + const wchar_t* const* input_arrays[] = { + plain, + full, + multifail, + multifail_full + }; + ChannelInfo v; + for (int multi_idx = 0; multi_idx < arraysize(is_multi); ++multi_idx) { + const bool multi = is_multi[multi_idx]; + for (int diff_idx = 0; diff_idx < arraysize(is_diff); ++diff_idx) { + const bool diff = is_diff[diff_idx]; + for (int result_idx = 0; result_idx < arraysize(results); ++result_idx) { + const int result = results[result_idx]; + const wchar_t* const* outputs; + if (result == installer::FIRST_INSTALL_SUCCESS || !multi && !diff) + outputs = plain; + else if (!multi && diff) + outputs = full; + else if (multi && !diff) + outputs = multifail; + else + outputs = multifail_full; + + for (int inputs_idx = 0; inputs_idx < arraysize(input_arrays); + ++inputs_idx) { + const wchar_t* const* inputs = input_arrays[inputs_idx]; + for (int input_idx = 0; input_idx < arraysize(plain); ++input_idx) { + const wchar_t* input = inputs[input_idx]; + const wchar_t* output = outputs[input_idx]; + + v.set_value(input); + if (output == v.value()) { + EXPECT_FALSE(GoogleUpdateSettings::UpdateGoogleUpdateApKey( + diff, multi, result, &v)) + << "diff: " << diff + << ", multi: " << multi + << ", result: " << result + << ", input ap value: " << input; + } else { + EXPECT_TRUE(GoogleUpdateSettings::UpdateGoogleUpdateApKey( + diff, multi, result, &v)) + << "diff: " << diff + << ", multi: " << multi + << ", result: " << result + << ", input ap value: " << input; + } + EXPECT_EQ(output, v.value()) + << "diff: " << diff + << ", multi: " << multi + << ", result: " << result + << ", input ap value: " << input; + } + } + } + } + } } -TEST_F(GoogleUpdateSettingsTest, UpdateDiffInstallStatusTest) { +TEST_F(GoogleUpdateSettingsTest, UpdateInstallStatusTest) { scoped_ptr<WorkItemList> work_item_list(WorkItem::CreateWorkItemList()); // Test incremental install failure ASSERT_TRUE(CreateApKey(work_item_list.get(), L"")) << "Failed to create ap key."; - GoogleUpdateSettings::UpdateDiffInstallStatus(false, true, - installer::INSTALL_FAILED, - kTestProductGuid); + GoogleUpdateSettings::UpdateInstallStatus(false, true, false, + installer::INSTALL_FAILED, + kTestProductGuid); EXPECT_STREQ(ReadApKeyValue().c_str(), L"-full"); work_item_list->Rollback(); @@ -338,9 +336,9 @@ TEST_F(GoogleUpdateSettingsTest, UpdateDiffInstallStatusTest) { // Test incremental install success ASSERT_TRUE(CreateApKey(work_item_list.get(), L"")) << "Failed to create ap key."; - GoogleUpdateSettings::UpdateDiffInstallStatus(false, true, - installer::FIRST_INSTALL_SUCCESS, - kTestProductGuid); + GoogleUpdateSettings::UpdateInstallStatus(false, true, false, + installer::FIRST_INSTALL_SUCCESS, + kTestProductGuid); EXPECT_STREQ(ReadApKeyValue().c_str(), L""); work_item_list->Rollback(); @@ -348,9 +346,9 @@ TEST_F(GoogleUpdateSettingsTest, UpdateDiffInstallStatusTest) { // Test full install failure ASSERT_TRUE(CreateApKey(work_item_list.get(), L"-full")) << "Failed to create ap key."; - GoogleUpdateSettings::UpdateDiffInstallStatus(false, false, - installer::INSTALL_FAILED, - kTestProductGuid); + GoogleUpdateSettings::UpdateInstallStatus(false, false, false, + installer::INSTALL_FAILED, + kTestProductGuid); EXPECT_STREQ(ReadApKeyValue().c_str(), L""); work_item_list->Rollback(); @@ -358,9 +356,9 @@ TEST_F(GoogleUpdateSettingsTest, UpdateDiffInstallStatusTest) { // Test full install success ASSERT_TRUE(CreateApKey(work_item_list.get(), L"-full")) << "Failed to create ap key."; - GoogleUpdateSettings::UpdateDiffInstallStatus(false, false, - installer::FIRST_INSTALL_SUCCESS, - kTestProductGuid); + GoogleUpdateSettings::UpdateInstallStatus(false, false, false, + installer::FIRST_INSTALL_SUCCESS, + kTestProductGuid); EXPECT_STREQ(ReadApKeyValue().c_str(), L""); work_item_list->Rollback(); @@ -378,14 +376,14 @@ TEST_F(GoogleUpdateSettingsTest, UpdateDiffInstallStatusTest) { ap_key_deleted = true; } // try differential installer - GoogleUpdateSettings::UpdateDiffInstallStatus(false, true, - installer::INSTALL_FAILED, - kTestProductGuid); + GoogleUpdateSettings::UpdateInstallStatus(false, true, false, + installer::INSTALL_FAILED, + kTestProductGuid); EXPECT_STREQ(ReadApKeyValue().c_str(), L"-full"); // try full installer now - GoogleUpdateSettings::UpdateDiffInstallStatus(false, false, - installer::INSTALL_FAILED, - kTestProductGuid); + GoogleUpdateSettings::UpdateInstallStatus(false, false, false, + installer::INSTALL_FAILED, + kTestProductGuid); EXPECT_STREQ(ReadApKeyValue().c_str(), L""); // Now cleanup to leave the system in unchanged state. // - Diff installer creates an ap key if it didnt exist, so delete this ap key diff --git a/chrome/installer/util/install_util.cc b/chrome/installer/util/install_util.cc index 2592429..2223b15 100644 --- a/chrome/installer/util/install_util.cc +++ b/chrome/installer/util/install_util.cc @@ -34,7 +34,7 @@ using installer::MasterPreferences; bool InstallUtil::ExecuteExeAsAdmin(const CommandLine& cmd, DWORD* exit_code) { FilePath::StringType program(cmd.GetProgram().value()); DCHECK(!program.empty()); - DCHECK(program[0] != '\"'); + DCHECK_NE(program[0], L'\"'); CommandLine::StringType params(cmd.command_line_string()); if (params[0] == '"') { @@ -110,6 +110,34 @@ bool InstallUtil::IsOSSupported() { (version == base::win::VERSION_XP && major >= 2); } +void InstallUtil::WriteInstallerResult(bool system_install, + const std::wstring& state_key, + installer::InstallStatus status, + int string_resource_id, + const std::wstring* const launch_cmd) { + const HKEY root = system_install ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER; + int installer_result = (GetInstallReturnCode(status) == 0) ? 0 : 1; + scoped_ptr<WorkItemList> install_list(WorkItem::CreateWorkItemList()); + install_list->AddCreateRegKeyWorkItem(root, state_key); + install_list->AddSetRegValueWorkItem(root, state_key, + installer::kInstallerResult, + installer_result, true); + install_list->AddSetRegValueWorkItem(root, state_key, + installer::kInstallerError, status, + true); + if (string_resource_id != 0) { + std::wstring msg = installer::GetLocalizedString(string_resource_id); + install_list->AddSetRegValueWorkItem(root, state_key, + installer::kInstallerResultUIString, msg, true); + } + if (launch_cmd != NULL && !launch_cmd->empty()) { + install_list->AddSetRegValueWorkItem(root, state_key, + installer::kInstallerSuccessLaunchCmdLine, *launch_cmd, true); + } + if (!install_list->Do()) + LOG(ERROR) << "Failed to record installer error information in registry."; +} + bool InstallUtil::IsPerUserInstall(const wchar_t* const exe_path) { wchar_t program_files_path[MAX_PATH] = {0}; if (SUCCEEDED(SHGetFolderPath(NULL, CSIDL_PROGRAM_FILES, NULL, diff --git a/chrome/installer/util/install_util.h b/chrome/installer/util/install_util.h index 0d20932..f2ba551 100644 --- a/chrome/installer/util/install_util.h +++ b/chrome/installer/util/install_util.h @@ -54,6 +54,16 @@ class InstallUtil { // This function checks if the current OS is supported for Chromium. static bool IsOSSupported(); + // This function sets installer error information in registry so that Google + // Update can read it and display to the user. |state_key| should be + // obtained via the state_key method of an InstallerState instance created + // before the machine state is modified by the installer. + static void WriteInstallerResult(bool system_install, + const std::wstring& state_key, + installer::InstallStatus status, + int string_resource_id, + const std::wstring* const launch_cmd); + // Returns true if this installation path is per user, otherwise returns // false (per machine install, meaning: the exe_path contains path to // Program Files). diff --git a/chrome/installer/util/install_util_unittest.cc b/chrome/installer/util/install_util_unittest.cc new file mode 100644 index 0000000..95e0c3d --- /dev/null +++ b/chrome/installer/util/install_util_unittest.cc @@ -0,0 +1,77 @@ +// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include <string> + +#include "base/command_line.h" +#include "base/win/registry.h" +#include "chrome/installer/util/browser_distribution.h" +#include "chrome/installer/util/installation_state.h" +#include "chrome/installer/util/installer_state.h" +#include "chrome/installer/util/install_util.h" +#include "chrome/installer/util/master_preferences.h" +#include "chrome/installer/util/product_unittest.h" + +using base::win::RegKey; +using installer::InstallationState; +using installer::InstallerState; +using installer::MasterPreferences; + +class InstallUtilTest : public TestWithTempDirAndDeleteTempOverrideKeys { + protected: +}; + +TEST_F(InstallUtilTest, InstallerResult) { + const bool system_level = true; + bool multi_install = false; + HKEY root = system_level ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER; + + RegKey key; + std::wstring launch_cmd = L"hey diddle diddle"; + std::wstring value; + + // check results for a fresh install of single Chrome + { + TempRegKeyOverride override(root, L"root_inst_res"); + const MasterPreferences prefs( + CommandLine::FromString(L"setup.exe --system-level")); + InstallationState machine_state; + machine_state.Initialize(prefs); + InstallerState state; + state.Initialize(prefs, machine_state); + InstallUtil::WriteInstallerResult(system_level, state.state_key(), + installer::FIRST_INSTALL_SUCCESS, 0, &launch_cmd); + BrowserDistribution* distribution = + BrowserDistribution::GetSpecificDistribution( + BrowserDistribution::CHROME_BROWSER, prefs); + EXPECT_TRUE(key.Open(root, distribution->GetStateKey().c_str(), KEY_READ)); + EXPECT_TRUE(key.ReadValue(installer::kInstallerSuccessLaunchCmdLine, + &value)); + EXPECT_EQ(launch_cmd, value); + } + TempRegKeyOverride::DeleteAllTempKeys(); + + // check results for a fresh install of multi Chrome + { + TempRegKeyOverride override(root, L"root_inst_res"); + const MasterPreferences prefs( + CommandLine::FromString( + L"setup.exe --system-level --multi-install --chrome")); + InstallationState machine_state; + machine_state.Initialize(prefs); + InstallerState state; + state.Initialize(prefs, machine_state); + InstallUtil::WriteInstallerResult(system_level, state.state_key(), + installer::FIRST_INSTALL_SUCCESS, 0, &launch_cmd); + BrowserDistribution* distribution = + BrowserDistribution::GetSpecificDistribution( + BrowserDistribution::CHROME_BROWSER, prefs); + 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(); +} diff --git a/chrome/installer/util/installation_state.cc b/chrome/installer/util/installation_state.cc new file mode 100644 index 0000000..5db624e --- /dev/null +++ b/chrome/installer/util/installation_state.cc @@ -0,0 +1,135 @@ +// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/installer/util/installation_state.h" + +#include "base/logging.h" +#include "base/string_util.h" +#include "base/version.h" +#include "base/win/registry.h" +#include "chrome/installer/util/google_update_constants.h" +#include "chrome/installer/util/package_properties.h" + +namespace installer { + +ProductState::ProductState() { +} + +void ProductState::Initialize(bool system_install, + const std::wstring& version_key, + const std::wstring& state_key) { + const HKEY root_key = system_install ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER; + base::win::RegKey key(root_key, version_key.c_str(), KEY_QUERY_VALUE); + std::wstring version_str; + if (key.ReadValue(google_update::kRegVersionField, &version_str)) { + version_.reset(Version::GetVersionFromString(WideToASCII(version_str))); + if (version_.get() != NULL) { + // The product is installed. Check for the channel value (absent if not + // installed/managed by Google Update). + if (!key.Open(root_key, state_key.c_str(), KEY_QUERY_VALUE) || + !channel_.Initialize(key)) { + channel_.set_value(std::wstring()); + } + } + } else { + version_.reset(); + } +} + +const Version& ProductState::version() const { + DCHECK(version_.get() != NULL); + return *version_; +} + +void ProductState::CopyFrom(const ProductState& other) { + channel_.set_value(other.channel_.value()); + if (other.version_.get() == NULL) + version_.reset(); + else + version_.reset(other.version_->Clone()); +} + +InstallationState::InstallationState() { +} + +// static +int InstallationState::IndexFromDistType(BrowserDistribution::Type type) { + COMPILE_ASSERT(BrowserDistribution::CHROME_BROWSER == CHROME_BROWSER_INDEX, + unexpected_chrome_browser_distribution_value_); + COMPILE_ASSERT(BrowserDistribution::CHROME_FRAME == CHROME_FRAME_INDEX, + unexpected_chrome_frame_distribution_value_); + DCHECK(type == BrowserDistribution::CHROME_BROWSER || + type == BrowserDistribution::CHROME_FRAME); + return type; +} + +void InstallationState::Initialize(const MasterPreferences& prefs) { + BrowserDistribution* distribution; + + distribution = BrowserDistribution::GetSpecificDistribution( + BrowserDistribution::CHROME_BROWSER, prefs); + InitializeProduct(false, distribution, &user_products_[CHROME_BROWSER_INDEX]); + InitializeProduct(true, distribution, + &system_products_[CHROME_BROWSER_INDEX]); + + distribution = BrowserDistribution::GetSpecificDistribution( + BrowserDistribution::CHROME_FRAME, prefs); + InitializeProduct(false, distribution, &user_products_[CHROME_FRAME_INDEX]); + InitializeProduct(true, distribution, &system_products_[CHROME_FRAME_INDEX]); + + ActivePackageProperties package_properties; + InitializeMultiPackage(false, package_properties, + &user_products_[MULTI_PACKAGE_INDEX]); + InitializeMultiPackage(true, package_properties, + &system_products_[MULTI_PACKAGE_INDEX]); +} + +// static +void InstallationState::InitializeProduct(bool system_install, + BrowserDistribution* distribution, + ProductState* product) { + product->Initialize(system_install, distribution->GetVersionKey(), + distribution->GetStateKey()); +} + +// static +void InstallationState::InitializeMultiPackage(bool system_install, + PackageProperties& properties, + ProductState* product) { + product->Initialize(system_install, properties.GetVersionKey(), + properties.GetStateKey()); +} + +const ProductState* InstallationState::GetMultiPackageState( + bool system_install) const { + const ProductState& product_state = + (system_install ? system_products_ : user_products_)[MULTI_PACKAGE_INDEX]; + return product_state.version_.get() == NULL ? NULL : &product_state; +} + +// Included for testing. +void InstallationState::SetMultiPackageState(bool system_install, + const ProductState& package_state) { + ProductState& target = + (system_install ? system_products_ : user_products_)[MULTI_PACKAGE_INDEX]; + target.CopyFrom(package_state); +} + +const ProductState* InstallationState::GetProductState( + bool system_install, + BrowserDistribution::Type type) const { + const ProductState& product_state = (system_install ? system_products_ : + user_products_)[IndexFromDistType(type)]; + return product_state.version_.get() == NULL ? NULL : &product_state; +} + +// Included for testing. +void InstallationState::SetProductState(bool system_install, + BrowserDistribution::Type type, const ProductState& product_state) { + ProductState& target = (system_install ? system_products_ : + user_products_)[IndexFromDistType(type)]; + target.CopyFrom(product_state); +} + +} // namespace installer diff --git a/chrome/installer/util/installation_state.h b/chrome/installer/util/installation_state.h new file mode 100644 index 0000000..29a4006 --- /dev/null +++ b/chrome/installer/util/installation_state.h @@ -0,0 +1,97 @@ +// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_INSTALLER_UTIL_INSTALLATION_STATE_H_ +#define CHROME_INSTALLER_UTIL_INSTALLATION_STATE_H_ +#pragma once + +#include <string> + +#include "base/basictypes.h" +#include "base/scoped_ptr.h" +#include "chrome/installer/util/browser_distribution.h" +#include "chrome/installer/util/channel_info.h" + +class Version; + +namespace installer { + +class InstallationState; +class MasterPreferences; +class PackageProperties; + +class ProductState { + public: + ProductState(); + void Initialize(bool system_install, + const std::wstring& version_key, + const std::wstring& state_key); + + const ChannelInfo& channel() const { return channel_; } + ChannelInfo& channel() { return channel_; } + + const Version& version() const; + // Takes ownership of |version|. + void set_version(Version* version) { version_.reset(version); } + + void CopyFrom(const ProductState& other); + + private: + friend class InstallationState; + + ChannelInfo channel_; + scoped_ptr<Version> version_; + DISALLOW_COPY_AND_ASSIGN(ProductState); +}; // class ProductState + +// Encapsulates the state of all products on the system. +class InstallationState { + public: + InstallationState(); + + // Initializes |this| with the machine's current state. + void Initialize(const MasterPreferences& prefs); + + // Returns the state of the multi-installer package or NULL if no + // multi-install products are installed. + const ProductState* GetMultiPackageState(bool system_install) const; + + // Sets the state of the multi-installer package; intended for tests. + void SetMultiPackageState(bool system_install, + const ProductState& package_state); + + // Returns the state of a product or NULL if not installed. + const ProductState* GetProductState(bool system_install, + BrowserDistribution::Type type) const; + + // Sets the state of a product; indended for tests. + void SetProductState(bool system_install, + BrowserDistribution::Type type, + const ProductState& product_state); + + private: + enum { + CHROME_BROWSER_INDEX, + CHROME_FRAME_INDEX, + MULTI_PACKAGE_INDEX, + NUM_PRODUCTS + }; + + static int IndexFromDistType(BrowserDistribution::Type type); + static void InitializeProduct(bool system_install, + BrowserDistribution* distribution, + ProductState* product); + static void InitializeMultiPackage(bool system_install, + PackageProperties& properties, + ProductState* product); + + ProductState user_products_[NUM_PRODUCTS]; + ProductState system_products_[NUM_PRODUCTS]; + + DISALLOW_COPY_AND_ASSIGN(InstallationState); +}; // class InstallationState + +} // namespace installer + +#endif // CHROME_INSTALLER_UTIL_INSTALLATION_STATE_H_ diff --git a/chrome/installer/util/installer_state.cc b/chrome/installer/util/installer_state.cc new file mode 100644 index 0000000..fd396da --- /dev/null +++ b/chrome/installer/util/installer_state.cc @@ -0,0 +1,93 @@ +// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/installer/util/installer_state.h" + +#include "base/logging.h" +#include "chrome/installer/util/installation_state.h" +#include "chrome/installer/util/master_preferences.h" +#include "chrome/installer/util/master_preferences_constants.h" +#include "chrome/installer/util/package_properties.h" + +namespace installer { + +bool InstallerState::IsMultiInstallUpdate(const MasterPreferences& prefs, + const InstallationState& machine_state) { + // First, is the package present? + const ProductState* package = + machine_state.GetMultiPackageState(system_install_); + if (package == NULL) { + // The multi-install package has not been installed, so it certainly isn't + // being updated. + return false; + } + + BrowserDistribution::Type types[2]; + size_t num_types = 0; + if (prefs.install_chrome()) + types[num_types++] = BrowserDistribution::CHROME_BROWSER; + if (prefs.install_chrome_frame()) + types[num_types++] = BrowserDistribution::CHROME_FRAME; + + for (const BrowserDistribution::Type* scan = &types[0], + *end = &types[num_types]; scan != end; ++scan) { + const ProductState* product = + machine_state.GetProductState(system_install_, *scan); + if (product == NULL) { + VLOG(2) << "It seems that distribution type " << *scan + << " is being installed for the first time."; + return false; + } + if (!product->channel().Equals(package->channel())) { + VLOG(2) << "It seems that distribution type " << *scan + << " is being over installed."; + return false; + } + } + + VLOG(2) << "It seems that the package is being updated."; + + return true; +} + +InstallerState::InstallerState() : operation_(UNINITIALIZED) { +} + +void InstallerState::Initialize(const MasterPreferences& prefs, + const InstallationState& machine_state) { + if (!prefs.GetBool(installer::master_preferences::kSystemLevel, + &system_install_)) + system_install_ = false; + + BrowserDistribution* operand = NULL; + + if (!prefs.is_multi_install()) { + // For a single-install, the current browser dist is the operand. + operand = BrowserDistribution::GetDistribution(); + operation_ = SINGLE_INSTALL_OR_UPDATE; + } else if (IsMultiInstallUpdate(prefs, machine_state)) { + // Updates driven by Google Update take place under the multi-installer's + // app guid. + installer::ActivePackageProperties package_properties; + operation_ = MULTI_UPDATE; + state_key_ = package_properties.GetStateKey(); + } else { + // Initial and over installs will always take place under one of the + // product app guids. Chrome Frame's will be used if only Chrome Frame + // is being installed. In all other cases, Chrome's is used. + operand = BrowserDistribution::GetSpecificDistribution( + prefs.install_chrome() ? + BrowserDistribution::CHROME_BROWSER : + BrowserDistribution::CHROME_FRAME, + prefs); + operation_ = MULTI_INSTALL; + } + + if (operand != NULL) { + install_operand_ = operand->GetType(); + state_key_ = operand->GetStateKey(); + } +} + +} // namespace installer diff --git a/chrome/installer/util/installer_state.h b/chrome/installer/util/installer_state.h new file mode 100644 index 0000000..214ae45 --- /dev/null +++ b/chrome/installer/util/installer_state.h @@ -0,0 +1,62 @@ +// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_INSTALLER_UTIL_INSTALLER_STATE_H_ +#define CHROME_INSTALLER_UTIL_INSTALLER_STATE_H_ +#pragma once + +#include <string> + +#include "base/basictypes.h" +#include "chrome/installer/util/browser_distribution.h" + +namespace installer { + +class InstallationState; +class MasterPreferences; + +// Encapsulates the state of the current installation operation. Only valid +// for installs and upgrades (not for uninstalls or non-install commands) +class InstallerState { + public: + enum Operation { + UNINITIALIZED, + SINGLE_INSTALL_OR_UPDATE, + MULTI_INSTALL, + MULTI_UPDATE, + }; + + InstallerState(); + + // Initializes |this| based on the current operation. + void Initialize(const MasterPreferences& prefs, + const InstallationState& machine_state); + + // true if system-level, false if user-level. + bool system_install() const { return system_install_; } + + Operation operation() const { return operation_; } + + BrowserDistribution::Type GetInstallOperand() const { + return install_operand_; + } + + // The ClientState key by which we interact with Google Update. + const std::wstring& state_key() const { return state_key_; } + + private: + bool IsMultiInstallUpdate(const MasterPreferences& prefs, + const InstallationState& machine_state); + + Operation operation_; + BrowserDistribution::Type install_operand_; + std::wstring state_key_; + bool system_install_; + + DISALLOW_COPY_AND_ASSIGN(InstallerState); +}; // class InstallerState + +} // namespace installer + +#endif // CHROME_INSTALLER_UTIL_INSTALLER_STATE_H_ diff --git a/chrome/installer/util/package.cc b/chrome/installer/util/package.cc index 6e88a30..3122cef 100644 --- a/chrome/installer/util/package.cc +++ b/chrome/installer/util/package.cc @@ -9,12 +9,9 @@ #include "base/string_util.h" #include "base/utf_string_conversions.h" #include "base/win/registry.h" -#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/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/package_properties.h" #include "chrome/installer/util/product.h" @@ -22,35 +19,8 @@ #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 multi_install, bool system_level, const FilePath& path, @@ -214,31 +184,5 @@ 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 c54c13d..d523fc2 100644 --- a/chrome/installer/util/package.h +++ b/chrome/installer/util/package.h @@ -71,12 +71,6 @@ 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_; diff --git a/chrome/installer/util/package_properties.cc b/chrome/installer/util/package_properties.cc index 814fc9e..2ab87cb 100644 --- a/chrome/installer/util/package_properties.cc +++ b/chrome/installer/util/package_properties.cc @@ -54,11 +54,15 @@ const std::wstring& PackagePropertiesImpl::GetVersionKey() { return version_key_; } -void PackagePropertiesImpl::UpdateDiffInstallStatus(bool system_level, - bool incremental_install, - InstallStatus status) { - GoogleUpdateSettings::UpdateDiffInstallStatus(system_level, - incremental_install, InstallUtil::GetInstallReturnCode(status), guid_); +void PackagePropertiesImpl::UpdateInstallStatus(bool system_level, + bool incremental_install, + bool multi_install, + InstallStatus status) { + if (ReceivesUpdates()) { + GoogleUpdateSettings::UpdateInstallStatus(system_level, + incremental_install, multi_install, + InstallUtil::GetInstallReturnCode(status), guid_); + } } ChromiumPackageProperties::ChromiumPackageProperties() diff --git a/chrome/installer/util/package_properties.h b/chrome/installer/util/package_properties.h index e3444da..a3f7714 100644 --- a/chrome/installer/util/package_properties.h +++ b/chrome/installer/util/package_properties.h @@ -39,8 +39,8 @@ class PackageProperties { 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; + virtual void UpdateInstallStatus(bool system_level, bool incremental_install, + bool multi_install, installer::InstallStatus status) = 0; private: DISALLOW_COPY_AND_ASSIGN(PackageProperties); @@ -57,8 +57,8 @@ class PackagePropertiesImpl : public PackageProperties { 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); + virtual void UpdateInstallStatus(bool system_level, bool incremental_install, + bool multi_install, installer::InstallStatus status); protected: std::wstring guid_; @@ -96,6 +96,12 @@ class ChromePackageProperties : public PackagePropertiesImpl { DISALLOW_COPY_AND_ASSIGN(ChromePackageProperties); }; // class ChromePackageProperties +#if defined(GOOGLE_CHROME_BUILD) +typedef ChromePackageProperties ActivePackageProperties; +#else +typedef ChromiumPackageProperties ActivePackageProperties; +#endif + } // namespace installer #endif // CHROME_INSTALLER_UTIL_PACKAGE_PROPERTIES_H_ diff --git a/chrome/installer/util/package_properties_unittest.cc b/chrome/installer/util/package_properties_unittest.cc index f1a7cab..6b6618d 100644 --- a/chrome/installer/util/package_properties_unittest.cc +++ b/chrome/installer/util/package_properties_unittest.cc @@ -29,24 +29,7 @@ TEST_F(PackagePropertiesTest, Basic) { EXPECT_FALSE(state_key.empty()); std::wstring version_key(props[i]->GetVersionKey()); EXPECT_FALSE(version_key.empty()); - if (props[i]->ReceivesUpdates()) { - HKEY roots[] = { HKEY_CURRENT_USER, HKEY_LOCAL_MACHINE }; - for (size_t j = 0; j < arraysize(roots); ++j) { - { - TempRegKeyOverride override(roots[j], L"props"); - RegKey key; - EXPECT_TRUE(key.Create(roots[j], state_key.c_str(), KEY_ALL_ACCESS)); - EXPECT_TRUE(key.WriteValue(google_update::kRegApField, L"")); - props[i]->UpdateDiffInstallStatus(roots[j] == HKEY_LOCAL_MACHINE, - true, - installer::INSTALL_FAILED); - std::wstring value; - key.ReadValue(google_update::kRegApField, &value); - EXPECT_FALSE(value.empty()); - } - TempRegKeyOverride::DeleteAllTempKeys(); - } - } else { + if (!props[i]->ReceivesUpdates()) { TempRegKeyOverride override(HKEY_CURRENT_USER, L"props"); RegKey key; EXPECT_TRUE(key.Create(HKEY_CURRENT_USER, state_key.c_str(), diff --git a/chrome/installer/util/package_unittest.cc b/chrome/installer/util/package_unittest.cc index e2a9bb6..851f188 100644 --- a/chrome/installer/util/package_unittest.cc +++ b/chrome/installer/util/package_unittest.cc @@ -187,58 +187,3 @@ TEST_F(PackageTest, Dependency) { SetUninstallArguments(root, cf, multi_uninstall_cmd); 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 43f371a..bddd7d8 100644 --- a/chrome/installer/util/product.cc +++ b/chrome/installer/util/product.cc @@ -161,21 +161,6 @@ bool Product::SetMsiMarker(bool set) const { return success; } -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; - } - - return installed_version_.get(); -} - -bool Product::IsInstalled() const { - return GetInstalledVersion() != NULL; -} - bool Product::ShouldCreateUninstallEntry() const { if (IsMsi()) { // MSI installations will manage their own uninstall shortcuts. @@ -188,11 +173,7 @@ bool Product::ShouldCreateUninstallEntry() const { /////////////////////////////////////////////////////////////////////////////// ProductPackageMapping::ProductPackageMapping(bool multi_install, bool system_level) -#if defined(GOOGLE_CHROME_BUILD) - : package_properties_(new ChromePackageProperties()), -#else - : package_properties_(new ChromiumPackageProperties()), -#endif + : package_properties_(new ActivePackageProperties()), multi_install_(multi_install), system_level_(system_level) { } diff --git a/chrome/installer/util/product.h b/chrome/installer/util/product.h index 36362af..28361df 100644 --- a/chrome/installer/util/product.h +++ b/chrome/installer/util/product.h @@ -14,7 +14,6 @@ #include "chrome/installer/util/package.h" class CommandLine; -class Version; namespace installer { class MasterPreferences; @@ -98,27 +97,17 @@ class Product : public base::RefCounted<Product> { // ClientState key. bool SetMsiMarker(bool set) 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. The returned Version object is owned by |this| Product instance. - const Version* GetInstalledVersion() const; - // Returns true if setup should create an entry in the Add/Remove list // of installed applications. bool ShouldCreateUninstallEntry() const; - // Returns true if the product is already installed. - bool IsInstalled() const; - protected: enum CacheStateFlags { - MSI_STATE = 0x01, - VERSION = 0x02 + MSI_STATE = 0x01 }; BrowserDistribution* distribution_; scoped_refptr<Package> package_; - mutable scoped_ptr<Version> installed_version_; mutable bool msi_; mutable uint8 cache_state_; diff --git a/chrome/installer/util/product_unittest.cc b/chrome/installer/util/product_unittest.cc index 0e928bc..b6f8f27 100644 --- a/chrome/installer/util/product_unittest.cc +++ b/chrome/installer/util/product_unittest.cc @@ -9,6 +9,7 @@ #include "base/utf_string_conversions.h" #include "chrome/installer/util/chrome_frame_distribution.h" #include "chrome/installer/util/google_update_constants.h" +#include "chrome/installer/util/installation_state.h" #include "chrome/installer/util/package.h" #include "chrome/installer/util/package_properties.h" #include "chrome/installer/util/master_preferences.h" @@ -126,8 +127,12 @@ TEST_F(ProductTest, ProductInstallBasic) { EXPECT_TRUE(product->IsMsi()); // There should be no installed version in the registry. - EXPECT_FALSE(product->IsInstalled()); - EXPECT_TRUE(product->GetInstalledVersion() == NULL); + { + installer::InstallationState state; + state.Initialize(prefs); + EXPECT_TRUE(state.GetProductState(system_level, + distribution->GetType()) == NULL); + } // Let's pretend chrome is installed. RegKey version_key(root, distribution->GetVersionKey().c_str(), @@ -140,14 +145,15 @@ TEST_F(ProductTest, ProductInstallBasic) { version_key.WriteValue(google_update::kRegVersionField, UTF8ToWide(current_version->GetString()).c_str()); - 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())); + { + installer::InstallationState state; + state.Initialize(prefs); + const installer::ProductState* prod_state = + state.GetProductState(system_level, distribution->GetType()); + EXPECT_TRUE(prod_state != NULL); + if (prod_state != NULL) { + EXPECT_TRUE(prod_state->version().Equals(*current_version.get())); + } } } } diff --git a/chrome/installer/util/util_constants.h b/chrome/installer/util/util_constants.h index 0028c78..96bfb8a 100644 --- a/chrome/installer/util/util_constants.h +++ b/chrome/installer/util/util_constants.h @@ -13,44 +13,44 @@ namespace installer { // Return status of installer enum InstallStatus { - FIRST_INSTALL_SUCCESS, // 0. Successfully installed Chrome for the first time - INSTALL_REPAIRED, // 1. Same version reinstalled for repair - NEW_VERSION_UPDATED, // 2. Chrome successfully updated to new version + FIRST_INSTALL_SUCCESS, // 0. Successfully installed Chrome for the first time + INSTALL_REPAIRED, // 1. Same version reinstalled for repair + NEW_VERSION_UPDATED, // 2. Chrome successfully updated to new version EXISTING_VERSION_LAUNCHED, // 3. No work done, just launched existing chrome - HIGHER_VERSION_EXISTS, // 4. Higher version of Chrome already exists - USER_LEVEL_INSTALL_EXISTS, // 5. User level install already exists - SYSTEM_LEVEL_INSTALL_EXISTS, // 6. Machine level install already exists - INSTALL_FAILED, // 7. Install/update failed - SETUP_PATCH_FAILED, // 8. Failed to patch setup.exe - OS_NOT_SUPPORTED, // 9. Current OS not supported - OS_ERROR, // 10. OS API call failed - TEMP_DIR_FAILED, // 11. Unable to get Temp directory - UNCOMPRESSION_FAILED, // 12. Failed to uncompress Chrome archive - INVALID_ARCHIVE, // 13. Something wrong with the installer archive - INSUFFICIENT_RIGHTS, // 14. User trying system level install is not Admin - CHROME_NOT_INSTALLED, // 15. Chrome not installed (returned in case of - // uninstall) - CHROME_RUNNING, // 16. Chrome currently running (when trying to - // uninstall) - UNINSTALL_CONFIRMED, // 17. User has confirmed Chrome uninstall + HIGHER_VERSION_EXISTS, // 4. Higher version of Chrome already exists + USER_LEVEL_INSTALL_EXISTS, // 5. User level install already exists + SYSTEM_LEVEL_INSTALL_EXISTS, // 6. Machine level install already exists + INSTALL_FAILED, // 7. Install/update failed + SETUP_PATCH_FAILED, // 8. Failed to patch setup.exe + OS_NOT_SUPPORTED, // 9. Current OS not supported + OS_ERROR, // 10. OS API call failed + TEMP_DIR_FAILED, // 11. Unable to get Temp directory + UNCOMPRESSION_FAILED, // 12. Failed to uncompress Chrome archive + INVALID_ARCHIVE, // 13. Something wrong with the installer archive + INSUFFICIENT_RIGHTS, // 14. User trying system level install is not Admin + CHROME_NOT_INSTALLED, // 15. Chrome not installed (returned in case of + // uninstall) + CHROME_RUNNING, // 16. Chrome currently running (when trying to + // uninstall) + UNINSTALL_CONFIRMED, // 17. User has confirmed Chrome uninstall UNINSTALL_DELETE_PROFILE, // 18. User confirmed uninstall and profile deletion - UNINSTALL_SUCCESSFUL, // 19. Chrome successfully uninstalled - UNINSTALL_FAILED, // 20. Chrome uninstallation failed - UNINSTALL_CANCELLED, // 21. User cancelled Chrome uninstallation - UNKNOWN_STATUS, // 22. Unknown status (this should never happen) - RENAME_SUCCESSFUL, // 23. Rename of new_chrome.exe to chrome.exe worked - RENAME_FAILED, // 24. Rename of new_chrome.exe failed - EULA_REJECTED, // 25. EULA dialog was not accepted by user. - EULA_ACCEPTED, // 26. EULA dialog was accepted by user. - EULA_ACCEPTED_OPT_IN, // 27. EULA accepted wtih the crash optin selected. - INSTALL_DIR_IN_USE, // 28. Installation directory is in use by another - // process - UNINSTALL_REQUIRES_REBOOT, // 29. Uninstallation required a reboot. - IN_USE_UPDATED, // 30. Chrome successfully updated but old version - // running - SAME_VERSION_REPAIR_FAILED, // 31. Chrome repair failed as Chrome was running - REENTRY_SYS_UPDATE, // 32. Setup has been re-launched as the interactive - // user + UNINSTALL_SUCCESSFUL, // 19. Chrome successfully uninstalled + UNINSTALL_FAILED, // 20. Chrome uninstallation failed + UNINSTALL_CANCELLED, // 21. User cancelled Chrome uninstallation + UNKNOWN_STATUS, // 22. Unknown status (this should never happen) + RENAME_SUCCESSFUL, // 23. Rename of new_chrome.exe to chrome.exe worked + RENAME_FAILED, // 24. Rename of new_chrome.exe failed + EULA_REJECTED, // 25. EULA dialog was not accepted by user. + EULA_ACCEPTED, // 26. EULA dialog was accepted by user. + EULA_ACCEPTED_OPT_IN, // 27. EULA accepted wtih the crash optin selected. + INSTALL_DIR_IN_USE, // 28. Installation directory is in use by another + // process + UNINSTALL_REQUIRES_REBOOT, // 29. Uninstallation required a reboot. + IN_USE_UPDATED, // 30. Chrome successfully updated but old version + // running + SAME_VERSION_REPAIR_FAILED, // 31. Chrome repair failed as Chrome was running + REENTRY_SYS_UPDATE, // 32. Setup has been re-launched as the interactive + // user SXS_OPTION_NOT_SUPPORTED, // 33. The chrome-sxs option provided does not work // with other command line options. NON_MULTI_INSTALLATION_EXISTS, // 34. We tried to do a multi-install but @@ -129,7 +129,7 @@ extern const wchar_t kUninstallInstallationDate[]; extern const char kUninstallMetricsName[]; extern const wchar_t kUninstallStringField[]; -// Used by ProductInstall::WriteInstallerResult. +// Used by InstallUtil::WriteInstallerResult. extern const wchar_t kInstallerResult[]; extern const wchar_t kInstallerError[]; extern const wchar_t kInstallerResultUIString[]; |