diff options
author | grt@chromium.org <grt@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-01-25 16:44:37 +0000 |
---|---|---|
committer | grt@chromium.org <grt@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-01-25 16:44:37 +0000 |
commit | f0260d27d34e40f2e619fb7a16dcd7f9d63fc683 (patch) | |
tree | 7e7c9e83bbd2f67b4bbbe11d076c7cc70abd8855 /chrome/installer/util | |
parent | ce7937429f63f3d966346fcd973d720f268cd888 (diff) | |
download | chromium_src-f0260d27d34e40f2e619fb7a16dcd7f9d63fc683.zip chromium_src-f0260d27d34e40f2e619fb7a16dcd7f9d63fc683.tar.gz chromium_src-f0260d27d34e40f2e619fb7a16dcd7f9d63fc683.tar.bz2 |
More installer refactoring in the interest of fixing some bugs and cleaning things up:
- Introduced ProductOperations: an interface implemented for each product that takes care of product-specific functions. Each Product owns an instance and delegates certain operations to it.
- Removed the use of MasterPreferences by BrowserDistribution so that the former isn't needed outside of the installer.
- Replaced PackageProperties with a new BrowserDistribution type (CHROME_BINARIES)
- Plumbed the concept of InstallerState more thoroughly through installer
- Removed ProductPackageMapping and Package
- Moved more registry read ops into ProductState
- Validation of products to be installed is now done in CheckPreInstallConditions
- Ignore --chrome-frame --ready-mode if chrome is also being installed/updated and a SxS GCF is found (chrome is updated).
- Migrates existing single-install Chrome to multi-install where appropriate.
- Fixes update to Chrome's uninstallation arguments when Chrome Frame is uninstalled.
- Removed dead code from install.cc.
- Added code to update products' "ap" values when ready-mode is accepted.
- Skip post-install things such as launching the browser when Chrome was implicitly added to the install/upgrade process by virtue of being part of a multi-install.
BUG=61609
TEST=run the installer, see it work. existing tests in installer_util_unittests have been updated; new tests are included for ProductState, ChannelInfo, etc.
Review URL: http://codereview.chromium.org/6288009
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@72497 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/installer/util')
51 files changed, 2536 insertions, 1751 deletions
diff --git a/chrome/installer/util/browser_distribution.cc b/chrome/installer/util/browser_distribution.cc index 4387b51..be452c5 100644 --- a/chrome/installer/util/browser_distribution.cc +++ b/chrome/installer/util/browser_distribution.cc @@ -17,7 +17,9 @@ #include "base/win/registry.h" #include "chrome/common/env_vars.h" #include "chrome/installer/util/chrome_frame_distribution.h" +#include "chrome/installer/util/chromium_binaries_distribution.h" #include "chrome/installer/util/google_chrome_distribution.h" +#include "chrome/installer/util/google_chrome_binaries_distribution.h" #include "chrome/installer/util/google_chrome_sxs_distribution.h" #include "chrome/installer/util/install_util.h" #include "chrome/installer/util/l10n_string_util.h" @@ -31,6 +33,7 @@ namespace { // The BrowserDistribution objects are never freed. BrowserDistribution* g_browser_distribution = NULL; BrowserDistribution* g_chrome_frame_distribution = NULL; +BrowserDistribution* g_binaries_distribution = NULL; // Returns true if currently running in npchrome_frame.dll bool IsChromeFrameModule() { @@ -59,17 +62,19 @@ BrowserDistribution::Type GetCurrentDistributionType() { } // end namespace -BrowserDistribution::BrowserDistribution( - const installer::MasterPreferences& prefs) - : type_(BrowserDistribution::CHROME_BROWSER) { +BrowserDistribution::BrowserDistribution() + : type_(CHROME_BROWSER) { +} + +BrowserDistribution::BrowserDistribution(Type type) + : type_(type) { } template<class DistributionClass> BrowserDistribution* BrowserDistribution::GetOrCreateBrowserDistribution( - const installer::MasterPreferences& prefs, BrowserDistribution** dist) { if (!*dist) { - DistributionClass* temp = new DistributionClass(prefs); + DistributionClass* temp = new DistributionClass(); if (base::subtle::NoBarrier_CompareAndSwap( reinterpret_cast<base::subtle::AtomicWord*>(dist), NULL, reinterpret_cast<base::subtle::AtomicWord>(temp)) != NULL) @@ -80,33 +85,43 @@ BrowserDistribution* BrowserDistribution::GetOrCreateBrowserDistribution( } BrowserDistribution* BrowserDistribution::GetDistribution() { - const installer::MasterPreferences& prefs = - installer::MasterPreferences::ForCurrentProcess(); - return GetSpecificDistribution(GetCurrentDistributionType(), prefs); + return GetSpecificDistribution(GetCurrentDistributionType()); } // static BrowserDistribution* BrowserDistribution::GetSpecificDistribution( - BrowserDistribution::Type type, - const installer::MasterPreferences& prefs) { + BrowserDistribution::Type type) { BrowserDistribution* dist = NULL; - if (type == CHROME_FRAME) { - dist = GetOrCreateBrowserDistribution<ChromeFrameDistribution>( - prefs, &g_chrome_frame_distribution); - } else { - DCHECK_EQ(CHROME_BROWSER, type); + switch (type) { + case CHROME_BROWSER: +#if defined(GOOGLE_CHROME_BUILD) + if (InstallUtil::IsChromeSxSProcess()) { + dist = GetOrCreateBrowserDistribution<GoogleChromeSxSDistribution>( + &g_browser_distribution); + } else { + dist = GetOrCreateBrowserDistribution<GoogleChromeDistribution>( + &g_browser_distribution); + } +#else + dist = GetOrCreateBrowserDistribution<BrowserDistribution>( + &g_browser_distribution); +#endif + break; + + case CHROME_FRAME: + dist = GetOrCreateBrowserDistribution<ChromeFrameDistribution>( + &g_chrome_frame_distribution); + break; + + default: + DCHECK_EQ(CHROME_BINARIES, type); #if defined(GOOGLE_CHROME_BUILD) - if (InstallUtil::IsChromeSxSProcess()) { - dist = GetOrCreateBrowserDistribution<GoogleChromeSxSDistribution>( - prefs, &g_browser_distribution); - } else { - dist = GetOrCreateBrowserDistribution<GoogleChromeDistribution>( - prefs, &g_browser_distribution); - } + dist = GetOrCreateBrowserDistribution<GoogleChromeBinariesDistribution>( + &g_binaries_distribution); #else - dist = GetOrCreateBrowserDistribution<BrowserDistribution>( - prefs, &g_browser_distribution); + dist = GetOrCreateBrowserDistribution<ChromiumBinariesDistribution>( + &g_binaries_distribution); #endif } @@ -212,31 +227,6 @@ void BrowserDistribution::LaunchUserExperiment( void BrowserDistribution::InactiveUserToastExperiment(int flavor, - const installer::Product& installation) { -} - -std::vector<FilePath> BrowserDistribution::GetKeyFiles() { - std::vector<FilePath> key_files; - key_files.push_back(FilePath(installer::kChromeDll)); - return key_files; -} - -std::vector<FilePath> BrowserDistribution::GetComDllList() { - return std::vector<FilePath>(); -} - -void BrowserDistribution::AppendUninstallCommandLineFlags( - CommandLine* cmd_line) { - DCHECK(cmd_line); - cmd_line->AppendSwitch(installer::switches::kChrome); -} - -bool BrowserDistribution::ShouldCreateUninstallEntry() { - return true; -} - -bool BrowserDistribution::SetChannelFlags( - bool set, - installer::ChannelInfo* channel_info) { - return false; + const installer::Product& installation, + const FilePath& application_path) { } diff --git a/chrome/installer/util/browser_distribution.h b/chrome/installer/util/browser_distribution.h index 1f6a1c9..3fb1ded 100644 --- a/chrome/installer/util/browser_distribution.h +++ b/chrome/installer/util/browser_distribution.h @@ -35,12 +35,12 @@ class BrowserDistribution { enum Type { CHROME_BROWSER, CHROME_FRAME, + CHROME_BINARIES, }; static BrowserDistribution* GetDistribution(); - static BrowserDistribution* GetSpecificDistribution( - Type type, const installer::MasterPreferences& prefs); + static BrowserDistribution* GetSpecificDistribution(Type type); Type GetType() const { return type_; } @@ -104,45 +104,21 @@ class BrowserDistribution { // The user has qualified for the inactive user toast experiment and this // function just performs it. virtual void InactiveUserToastExperiment(int flavor, - const installer::Product& installation); - - // A key-file is a file such as a DLL on Windows that is expected to be - // in use when the product is being used. For example "chrome.dll" for - // Chrome. Before attempting to delete an installation directory during - // an uninstallation, the uninstaller will check if any one of a potential - // set of key files is in use and if they are, abort the delete operation. - // Only if none of the key files are in use, can the folder be deleted. - // Note that this function does not return a full path to the key file(s), - // only (a) file name(s). - virtual std::vector<FilePath> GetKeyFiles(); - - // Returns the list of Com Dlls that this product cares about having - // registered and unregistered. The list may be empty. - virtual std::vector<FilePath> GetComDllList(); - - // Given a command line, appends the set of uninstall flags the uninstaller - // for this distribution will require. - virtual void AppendUninstallCommandLineFlags(CommandLine* cmd_line); - - // Returns true if install should create an uninstallation entry in the - // 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); + const installer::Product& installation, + const FilePath& application_path); protected: - explicit BrowserDistribution(const installer::MasterPreferences& prefs); + explicit BrowserDistribution(Type type); template<class DistributionClass> static BrowserDistribution* GetOrCreateBrowserDistribution( - const installer::MasterPreferences& prefs, BrowserDistribution** dist); - Type type_; + const Type type_; private: + BrowserDistribution(); + DISALLOW_COPY_AND_ASSIGN(BrowserDistribution); }; diff --git a/chrome/installer/util/browser_distribution_unittest.cc b/chrome/installer/util/browser_distribution_unittest.cc index f35ad3f..61c9652 100644 --- a/chrome/installer/util/browser_distribution_unittest.cc +++ b/chrome/installer/util/browser_distribution_unittest.cc @@ -5,7 +5,6 @@ // Unit tests for BrowserDistribution class. #include "chrome/installer/util/browser_distribution.h" -#include "chrome/installer/util/master_preferences.h" #include "chrome/installer/util/shell_util.h" #include "testing/gtest/include/gtest/gtest.h" @@ -25,21 +24,14 @@ class BrowserDistributionTest : public testing::Test { // The distribution strings should not be empty. The unit tests are not linking // with the chrome resources so we cannot test official build. TEST(BrowserDistributionTest, StringsTest) { - struct browser_test_type { - BrowserDistribution::Type type; - bool has_com_dlls; - } browser_tests[] = { - { BrowserDistribution::CHROME_BROWSER, false }, - { BrowserDistribution::CHROME_FRAME, true }, + BrowserDistribution::Type browser_tests[] = { + BrowserDistribution::CHROME_BROWSER, + BrowserDistribution::CHROME_FRAME, }; - const installer::MasterPreferences& prefs = - installer::MasterPreferences::ForCurrentProcess(); - for (int i = 0; i < arraysize(browser_tests); ++i) { BrowserDistribution* dist = - BrowserDistribution::GetSpecificDistribution(browser_tests[i].type, - prefs); + BrowserDistribution::GetSpecificDistribution(browser_tests[i]); ASSERT_TRUE(dist != NULL); std::wstring name = dist->GetApplicationName(); EXPECT_FALSE(name.empty()); @@ -47,12 +39,6 @@ TEST(BrowserDistributionTest, StringsTest) { EXPECT_FALSE(desc.empty()); std::wstring alt_name = dist->GetAlternateApplicationName(); EXPECT_FALSE(alt_name.empty()); - std::vector<FilePath> com_dlls(dist->GetComDllList()); - if (browser_tests[i].has_com_dlls) { - EXPECT_FALSE(com_dlls.empty()); - } else { - EXPECT_TRUE(com_dlls.empty()); - } } } diff --git a/chrome/installer/util/channel_info.cc b/chrome/installer/util/channel_info.cc index 4abcb70..98f54d8 100644 --- a/chrome/installer/util/channel_info.cc +++ b/chrome/installer/util/channel_info.cc @@ -153,6 +153,18 @@ bool ChannelInfo::GetChannelName(std::wstring* channel_name) const { return false; } +bool ChannelInfo::EqualsBaseOf(const ChannelInfo& other) const { + std::wstring::size_type this_base_end; + std::wstring::size_type other_base_end; + + if (!FindModifier(MOD_MULTI_INSTALL, value_, &this_base_end)) + this_base_end = FindInsertionPoint(MOD_MULTI_INSTALL, value_); + if (!FindModifier(MOD_MULTI_INSTALL, other.value_, &other_base_end)) + other_base_end = FindInsertionPoint(MOD_MULTI_INSTALL, other.value_); + return value_.compare(0, this_base_end, + other.value_.c_str(), other_base_end) == 0; +} + bool ChannelInfo::IsCeee() const { return HasModifier(MOD_CEEE, value_); } diff --git a/chrome/installer/util/channel_info.h b/chrome/installer/util/channel_info.h index 7954e1c..a5b895d 100644 --- a/chrome/installer/util/channel_info.h +++ b/chrome/installer/util/channel_info.h @@ -41,6 +41,10 @@ class ChannelInfo { // determined. bool GetChannelName(std::wstring* channel_name) const; + // Returns true if this object and |other| have a common base (that which + // remains when all modifiers and suffixes are omitted). + bool EqualsBaseOf(const ChannelInfo& other) const; + // Returns true if the -CEEE modifier is present in the value. bool IsCeee() const; diff --git a/chrome/installer/util/channel_info_unittest.cc b/chrome/installer/util/channel_info_unittest.cc index febc33a..5c03040 100644 --- a/chrome/installer/util/channel_info_unittest.cc +++ b/chrome/installer/util/channel_info_unittest.cc @@ -2,6 +2,9 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include <utility> + +#include "base/basictypes.h" #include "chrome/installer/util/channel_info.h" #include "testing/gtest/include/gtest/gtest.h" @@ -158,3 +161,36 @@ TEST(ChannelInfoTest, Combinations) { ci.set_value(L"2.0-beta-chromeframe-chrome"); EXPECT_TRUE(ci.IsChrome()); } + +TEST(ChannelInfoTest, EqualsBaseOf) { + installer::ChannelInfo ci1; + installer::ChannelInfo ci2; + + std::pair<std::wstring, std::wstring> trues[] = { + std::make_pair(std::wstring(L""), std::wstring(L"")), + std::make_pair(std::wstring(L"2.0-beta"), std::wstring(L"2.0-beta")), + std::make_pair(std::wstring(L"-full"), std::wstring(L"-full")), + std::make_pair(std::wstring(L""), std::wstring(L"-multi")) + }; + for (int i = 0; i < arraysize(trues); ++i) { + std::pair<std::wstring, std::wstring>& the_pair = trues[i]; + ci1.set_value(the_pair.first); + ci2.set_value(the_pair.second); + EXPECT_TRUE(ci1.EqualsBaseOf(ci2)) << the_pair.first << " " + << the_pair.second; + } + + std::pair<std::wstring, std::wstring> falses[] = { + std::make_pair(std::wstring(L""), std::wstring(L"2.0-beta")), + std::make_pair(std::wstring(L"2.0-gamma"), std::wstring(L"2.0-beta")), + std::make_pair(std::wstring(L"spam-full"), std::wstring(L"-full")), + std::make_pair(std::wstring(L"multi"), std::wstring(L"-multi")) + }; + for (int i = 0; i < arraysize(falses); ++i) { + std::pair<std::wstring, std::wstring>& the_pair = falses[i]; + ci1.set_value(the_pair.first); + ci2.set_value(the_pair.second); + EXPECT_FALSE(ci1.EqualsBaseOf(ci2)) << the_pair.first << " " + << the_pair.second; + } +} diff --git a/chrome/installer/util/chrome_browser_operations.cc b/chrome/installer/util/chrome_browser_operations.cc new file mode 100644 index 0000000..c4acd5c --- /dev/null +++ b/chrome/installer/util/chrome_browser_operations.cc @@ -0,0 +1,82 @@ +// Copyright (c) 2011 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/chrome_browser_operations.h" + +#include "base/command_line.h" +#include "base/file_path.h" +#include "base/logging.h" +#include "chrome/installer/util/browser_distribution.h" +#include "chrome/installer/util/channel_info.h" +#include "chrome/installer/util/helper.h" +#include "chrome/installer/util/master_preferences.h" +#include "chrome/installer/util/master_preferences_constants.h" +#include "chrome/installer/util/util_constants.h" + +namespace installer { + +void ChromeBrowserOperations::ReadOptions( + const MasterPreferences& prefs, + std::set<std::wstring>* options) const { + DCHECK(options); + + bool pref_value; + + if (prefs.GetBool(master_preferences::kMultiInstall, &pref_value) && + pref_value) { + options->insert(kOptionMultiInstall); + } +} + +void ChromeBrowserOperations::ReadOptions( + const CommandLine& uninstall_command, + std::set<std::wstring>* options) const { + DCHECK(options); + + if (uninstall_command.HasSwitch(switches::kMultiInstall)) + options->insert(kOptionMultiInstall); +} + +void ChromeBrowserOperations::AddKeyFiles( + const std::set<std::wstring>& options, + std::vector<FilePath>* key_files) const { + DCHECK(key_files); + key_files->push_back(FilePath(installer::kChromeDll)); +} + +void ChromeBrowserOperations::AddComDllList( + const std::set<std::wstring>& options, + std::vector<FilePath>* com_dll_list) const { +} + +void ChromeBrowserOperations::AppendProductFlags( + const std::set<std::wstring>& options, + CommandLine* uninstall_command) const { + DCHECK(uninstall_command); + + if (options.find(kOptionMultiInstall) != options.end()) { + if (!uninstall_command->HasSwitch(switches::kMultiInstall)) + uninstall_command->AppendSwitch(switches::kMultiInstall); + uninstall_command->AppendSwitch(switches::kChrome); + } +} + +bool ChromeBrowserOperations::SetChannelFlags( + const std::set<std::wstring>& options, + bool set, + ChannelInfo* channel_info) const { +#if defined(GOOGLE_CHROME_BUILD) + DCHECK(channel_info); + return channel_info->SetChrome(set); +#else + return false; +#endif +} + +bool ChromeBrowserOperations::ShouldCreateUninstallEntry( + const std::set<std::wstring>& options) const { + return true; +} + +} // namespace installer diff --git a/chrome/installer/util/chrome_browser_operations.h b/chrome/installer/util/chrome_browser_operations.h new file mode 100644 index 0000000..5628b7d --- /dev/null +++ b/chrome/installer/util/chrome_browser_operations.h @@ -0,0 +1,54 @@ +// Copyright (c) 2011 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_CHROME_BROWSER_OPERATIONS_H_ +#define CHROME_INSTALLER_UTIL_CHROME_BROWSER_OPERATIONS_H_ +#pragma once + +#include <set> +#include <string> +#include <vector> + +#include "base/basictypes.h" +#include "base/compiler_specific.h" +#include "chrome/installer/util/product_operations.h" + +namespace installer { + +// Operations specific to Chrome; see ProductOperations for general info. +class ChromeBrowserOperations : public ProductOperations { + public: + ChromeBrowserOperations() {} + + virtual void ReadOptions(const MasterPreferences& prefs, + std::set<std::wstring>* options) const OVERRIDE; + + virtual void ReadOptions(const CommandLine& uninstall_command, + std::set<std::wstring>* options) const OVERRIDE; + + virtual void AddKeyFiles(const std::set<std::wstring>& options, + std::vector<FilePath>* key_files) const OVERRIDE; + + virtual void AddComDllList( + const std::set<std::wstring>& options, + std::vector<FilePath>* com_dll_list) const OVERRIDE; + + virtual void AppendProductFlags( + const std::set<std::wstring>& options, + CommandLine* uninstall_command) const OVERRIDE; + + virtual bool SetChannelFlags(const std::set<std::wstring>& options, + bool set, + ChannelInfo* channel_info) const OVERRIDE; + + virtual bool ShouldCreateUninstallEntry( + const std::set<std::wstring>& options) const OVERRIDE; + + private: + DISALLOW_COPY_AND_ASSIGN(ChromeBrowserOperations); +}; + +} // namespace installer + +#endif // CHROME_INSTALLER_UTIL_CHROME_BROWSER_OPERATIONS_H_ diff --git a/chrome/installer/util/chrome_browser_sxs_operations.cc b/chrome/installer/util/chrome_browser_sxs_operations.cc new file mode 100644 index 0000000..6c7fd81 --- /dev/null +++ b/chrome/installer/util/chrome_browser_sxs_operations.cc @@ -0,0 +1,22 @@ +// Copyright (c) 2011 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/chrome_browser_sxs_operations.h" + +#include "base/command_line.h" +#include "base/logging.h" +#include "chrome/installer/util/util_constants.h" + +namespace installer { + +void ChromeBrowserSxSOperations::AppendProductFlags( + const std::set<std::wstring>& options, + CommandLine* uninstall_command) const { + DCHECK(uninstall_command); + + uninstall_command->AppendSwitch(switches::kChromeSxS); + ChromeBrowserOperations::AppendProductFlags(options, uninstall_command); +} + +} // namespace installer diff --git a/chrome/installer/util/chrome_browser_sxs_operations.h b/chrome/installer/util/chrome_browser_sxs_operations.h new file mode 100644 index 0000000..de6101e --- /dev/null +++ b/chrome/installer/util/chrome_browser_sxs_operations.h @@ -0,0 +1,33 @@ +// Copyright (c) 2011 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_CHROME_BROWSER_SXS_OPERATIONS_H_ +#define CHROME_INSTALLER_UTIL_CHROME_BROWSER_SXS_OPERATIONS_H_ +#pragma once + +#include <set> +#include <string> + +#include "base/basictypes.h" +#include "base/compiler_specific.h" +#include "chrome/installer/util/chrome_browser_operations.h" + +namespace installer { + +// Operations specific to Chrome SxS; see ProductOperations for general info. +class ChromeBrowserSxSOperations : public ChromeBrowserOperations { + public: + ChromeBrowserSxSOperations() {} + + virtual void AppendProductFlags( + const std::set<std::wstring>& options, + CommandLine* uninstall_command) const OVERRIDE; + + private: + DISALLOW_COPY_AND_ASSIGN(ChromeBrowserSxSOperations); +}; + +} // namespace installer + +#endif // CHROME_INSTALLER_UTIL_CHROME_BROWSER_SXS_OPERATIONS_H_ diff --git a/chrome/installer/util/chrome_frame_distribution.cc b/chrome/installer/util/chrome_frame_distribution.cc index 2507f1d..86a1abc 100644 --- a/chrome/installer/util/chrome_frame_distribution.cc +++ b/chrome/installer/util/chrome_frame_distribution.cc @@ -18,8 +18,6 @@ #include "chrome/installer/util/helper.h" #include "chrome/installer/util/install_util.h" #include "chrome/installer/util/l10n_string_util.h" -#include "chrome/installer/util/master_preferences.h" -#include "chrome/installer/util/master_preferences_constants.h" #include "installer_util_strings.h" // NOLINT @@ -27,38 +25,8 @@ namespace { const wchar_t kChromeFrameGuid[] = L"{8BA986DA-5100-405E-AA35-86F34A02ACBF}"; } -ChromeFrameDistribution::ChromeFrameDistribution( - const installer::MasterPreferences& prefs) - : BrowserDistribution(prefs), ceee_(prefs.install_ceee()), - ready_mode_(false) { - type_ = BrowserDistribution::CHROME_FRAME; - prefs.GetBool(installer::master_preferences::kChromeFrameReadyMode, - &ready_mode_); - - bool system_install = false; - prefs.GetBool(installer::master_preferences::kSystemLevel, &system_install); - - // See if Chrome Frame is already installed. If so, we must make sure that - // the ceee and ready mode flags match. - CommandLine uninstall(CommandLine::NO_PROGRAM); - if (installer::GetUninstallSwitches(system_install, this, &uninstall)) { - if (!ceee_ && uninstall.HasSwitch(installer::switches::kCeee)) { - LOG(INFO) << "CEEE is not specified on the command line but CEEE is " - "already installed. Implicitly enabling CEEE."; - ceee_ = true; - } - - // If the user has already opted in to CF, we shouldn't set the ready-mode - // flag. If we don't do this, we might have two entries in the Add/Remove - // Programs list that can uninstall GCF. - if (ready_mode_) { - if (!uninstall.HasSwitch(installer::switches::kChromeFrameReadyMode)) { - LOG(INFO) << "Ready mode was specified on the command line but GCF " - "is already fully installed. Ignoring command line."; - ready_mode_ = false; - } - } - } +ChromeFrameDistribution::ChromeFrameDistribution() + : BrowserDistribution(CHROME_FRAME) { } std::wstring ChromeFrameDistribution::GetAppGuid() { @@ -146,61 +114,3 @@ void ChromeFrameDistribution::UpdateInstallStatus(bool system_install, InstallUtil::GetInstallReturnCode(install_status), kChromeFrameGuid); #endif } - -std::vector<FilePath> ChromeFrameDistribution::GetKeyFiles() { - std::vector<FilePath> key_files; - key_files.push_back(FilePath(installer::kChromeFrameDll)); - if (ceee_) { - key_files.push_back(FilePath(installer::kCeeeIeDll)); - key_files.push_back(FilePath(installer::kCeeeBrokerExe)); - } - return key_files; -} - -std::vector<FilePath> ChromeFrameDistribution::GetComDllList() { - std::vector<FilePath> dll_list; - dll_list.push_back(FilePath(installer::kChromeFrameDll)); - if (ceee_) { - dll_list.push_back(FilePath(installer::kCeeeInstallHelperDll)); - dll_list.push_back(FilePath(installer::kCeeeIeDll)); - } - return dll_list; -} - -void ChromeFrameDistribution::AppendUninstallCommandLineFlags( - CommandLine* cmd_line) { - DCHECK(cmd_line); - cmd_line->AppendSwitch(installer::switches::kChromeFrame); - - if (ceee_) - cmd_line->AppendSwitch(installer::switches::kCeee); - - if (ready_mode_) - cmd_line->AppendSwitch(installer::switches::kChromeFrameReadyMode); -} - -bool ChromeFrameDistribution::ShouldCreateUninstallEntry() { - // If Chrome Frame is being installed in ready mode, then we will not - // 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 f34cc86..043dc68 100644 --- a/chrome/installer/util/chrome_frame_distribution.h +++ b/chrome/installer/util/chrome_frame_distribution.h @@ -55,29 +55,11 @@ class ChromeFrameDistribution : public BrowserDistribution { bool incremental_install, bool multi_install, installer::InstallStatus install_status); - virtual std::vector<FilePath> GetKeyFiles(); - - virtual std::vector<FilePath> GetComDllList(); - - virtual void AppendUninstallCommandLineFlags(CommandLine* cmd_line); - - virtual bool ShouldCreateUninstallEntry(); - - virtual bool SetChannelFlags(bool set, installer::ChannelInfo* channel_info); - protected: friend class BrowserDistribution; // Disallow construction from non-friends. - explicit ChromeFrameDistribution( - const installer::MasterPreferences& prefs); - - // Determines whether this Chrome Frame distribution is being used to work - // with CEEE bits as well. - bool ceee_; - - // True when Chrome Frame is installed in ready mode (users have to opt in). - bool ready_mode_; + ChromeFrameDistribution(); }; #endif // CHROME_INSTALLER_UTIL_CHROME_FRAME_DISTRIBUTION_H_ diff --git a/chrome/installer/util/chrome_frame_operations.cc b/chrome/installer/util/chrome_frame_operations.cc new file mode 100644 index 0000000..4ab5b2a --- /dev/null +++ b/chrome/installer/util/chrome_frame_operations.cc @@ -0,0 +1,148 @@ +// Copyright (c) 2011 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/chrome_frame_operations.h" + +#include "base/command_line.h" +#include "base/file_path.h" +#include "base/logging.h" +#include "chrome/installer/util/browser_distribution.h" +#include "chrome/installer/util/channel_info.h" +#include "chrome/installer/util/helper.h" +#include "chrome/installer/util/master_preferences.h" +#include "chrome/installer/util/master_preferences_constants.h" +#include "chrome/installer/util/util_constants.h" + +namespace installer { + +// Remove ready-mode if not multi-install. +void ChromeFrameOperations::NormalizeOptions( + std::set<std::wstring>* options) const { + std::set<std::wstring>::iterator ready_mode(options->find(kOptionReadyMode)); + if (ready_mode != options->end() && + options->find(kOptionMultiInstall) == options->end()) { + LOG(WARNING) << "--ready-mode option does not apply when --multi-install " + "is not also specified; ignoring."; + options->erase(ready_mode); + } +} + +void ChromeFrameOperations::ReadOptions( + const MasterPreferences& prefs, + std::set<std::wstring>* options) const { + DCHECK(options); + + static const struct PrefToOption { + const char* pref_name; + const wchar_t* option_name; + } map[] = { + { master_preferences::kCeee, kOptionCeee }, + { master_preferences::kChromeFrameReadyMode, kOptionReadyMode }, + { master_preferences::kMultiInstall, kOptionMultiInstall } + }; + + bool pref_value; + + for (const PrefToOption* scan = &map[0], *end = &map[arraysize(map)]; + scan != end; ++scan) { + if (prefs.GetBool(scan->pref_name, &pref_value) && pref_value) + options->insert(scan->option_name); + } + + NormalizeOptions(options); +} + +void ChromeFrameOperations::ReadOptions( + const CommandLine& uninstall_command, + std::set<std::wstring>* options) const { + DCHECK(options); + + static const struct FlagToOption { + const char* flag_name; + const wchar_t* option_name; + } map[] = { + { switches::kCeee, kOptionCeee }, + { switches::kChromeFrameReadyMode, kOptionReadyMode }, + { switches::kMultiInstall, kOptionMultiInstall } + }; + + for (const FlagToOption* scan = &map[0], *end = &map[arraysize(map)]; + scan != end; ++scan) { + if (uninstall_command.HasSwitch(scan->flag_name)) + options->insert(scan->option_name); + } + + NormalizeOptions(options); +} + +void ChromeFrameOperations::AddKeyFiles( + const std::set<std::wstring>& options, + std::vector<FilePath>* key_files) const { + DCHECK(key_files); + key_files->push_back(FilePath(installer::kChromeFrameDll)); + if (options.find(kOptionCeee) != options.end()) { + key_files->push_back(FilePath(installer::kCeeeIeDll)); + key_files->push_back(FilePath(installer::kCeeeBrokerExe)); + } +} + +void ChromeFrameOperations::AddComDllList( + const std::set<std::wstring>& options, + std::vector<FilePath>* com_dll_list) const { + DCHECK(com_dll_list); + std::vector<FilePath> dll_list; + com_dll_list->push_back(FilePath(installer::kChromeFrameDll)); + if (options.find(kOptionCeee) != options.end()) { + com_dll_list->push_back(FilePath(installer::kCeeeInstallHelperDll)); + com_dll_list->push_back(FilePath(installer::kCeeeIeDll)); + } +} + +void ChromeFrameOperations::AppendProductFlags( + const std::set<std::wstring>& options, + CommandLine* uninstall_command) const { + DCHECK(uninstall_command); + uninstall_command->AppendSwitch(switches::kChromeFrame); + + if (options.find(kOptionCeee) != options.end()) + uninstall_command->AppendSwitch(switches::kCeee); + + if (options.find(kOptionMultiInstall) != options.end()) { + if (!uninstall_command->HasSwitch(switches::kMultiInstall)) + uninstall_command->AppendSwitch(switches::kMultiInstall); + + // ready-mode is only supported in multi-installs of Chrome Frame. + if (options.find(kOptionReadyMode) != options.end()) + uninstall_command->AppendSwitch(switches::kChromeFrameReadyMode); + } +} + +bool ChromeFrameOperations::SetChannelFlags( + const std::set<std::wstring>& options, + bool set, + ChannelInfo* channel_info) const { +#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 or if the + // corresponding option isn't set. + modified |= channel_info->SetCeee( + set && options.find(kOptionCeee) != options.end()); + + modified |= channel_info->SetReadyMode( + set && options.find(kOptionReadyMode) != options.end()); + + return modified; +#else + return false; +#endif +} + +bool ChromeFrameOperations::ShouldCreateUninstallEntry( + const std::set<std::wstring>& options) const { + return options.find(kOptionReadyMode) == options.end(); +} + +} // namespace installer diff --git a/chrome/installer/util/chrome_frame_operations.h b/chrome/installer/util/chrome_frame_operations.h new file mode 100644 index 0000000..267eef6 --- /dev/null +++ b/chrome/installer/util/chrome_frame_operations.h @@ -0,0 +1,58 @@ +// Copyright (c) 2011 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_CHROME_FRAME_OPERATIONS_H_ +#define CHROME_INSTALLER_UTIL_CHROME_FRAME_OPERATIONS_H_ +#pragma once + +#include <set> +#include <string> +#include <vector> + +#include "base/basictypes.h" +#include "base/file_path.h" +#include "base/compiler_specific.h" +#include "chrome/installer/util/product_operations.h" + +namespace installer { + +// Operations specific to Chrome Frame; see ProductOperations for general info. +class ChromeFrameOperations : public ProductOperations { + public: + ChromeFrameOperations() {} + + virtual void ReadOptions(const MasterPreferences& prefs, + std::set<std::wstring>* options) const OVERRIDE; + + virtual void ReadOptions(const CommandLine& uninstall_command, + std::set<std::wstring>* options) const OVERRIDE; + + virtual void AddKeyFiles(const std::set<std::wstring>& options, + std::vector<FilePath>* key_files) const OVERRIDE; + + virtual void AddComDllList( + const std::set<std::wstring>& options, + std::vector<FilePath>* com_dll_list) const OVERRIDE; + + virtual void AppendProductFlags( + const std::set<std::wstring>& options, + CommandLine* uninstall_command) const OVERRIDE; + + virtual bool SetChannelFlags(const std::set<std::wstring>& options, + bool set, + ChannelInfo* channel_info) const OVERRIDE; + + virtual bool ShouldCreateUninstallEntry( + const std::set<std::wstring>& options) const OVERRIDE; + + protected: + void NormalizeOptions(std::set<std::wstring>* options) const; + + private: + DISALLOW_COPY_AND_ASSIGN(ChromeFrameOperations); +}; + +} // namespace installer + +#endif // CHROME_INSTALLER_UTIL_CHROME_FRAME_OPERATIONS_H_ diff --git a/chrome/installer/util/chromium_binaries_distribution.cc b/chrome/installer/util/chromium_binaries_distribution.cc new file mode 100644 index 0000000..8e39ffb --- /dev/null +++ b/chrome/installer/util/chromium_binaries_distribution.cc @@ -0,0 +1,105 @@ +// Copyright (c) 2011 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. +// +// This file declares a class that contains various method related to branding. + +#include "chrome/installer/util/google_chrome_binaries_distribution.h" + +#include "base/logging.h" + +namespace { + +const wchar_t kChromiumBinariesName[] = L"Chromium Binaries"; + +} // namespace + +ChromiumBinariesDistribution::ChromiumBinariesDistribution() + : BrowserDistribution(CHROME_BINARIES), + browser_distribution_( + BrowserDistribution::GetSpecificDistribution(CHROME_BROWSER)) { +} + +std::wstring ChromiumBinariesDistribution::GetAppGuid() { + return std::wstring(); +} + +std::wstring ChromiumBinariesDistribution::GetApplicationName() { + NOTREACHED() << "GetApplicationName unsupported"; + return std::wstring(); +} + +std::wstring ChromiumBinariesDistribution::GetAppShortCutName() { + return kChromiumBinariesName; +} + +std::wstring ChromiumBinariesDistribution::GetAlternateApplicationName() { + NOTREACHED() << "GetApplicationName unsupported"; + return std::wstring(); +} + +std::wstring ChromiumBinariesDistribution::GetBrowserAppId() { + NOTREACHED() << "GetApplicationName unsupported"; + return std::wstring(); +} + +std::wstring ChromiumBinariesDistribution::GetInstallSubDir() { + return browser_distribution_->GetInstallSubDir(); +} + +std::wstring ChromiumBinariesDistribution::GetPublisherName() { + NOTREACHED() << "GetApplicationName unsupported"; + return std::wstring(); +} + +std::wstring ChromiumBinariesDistribution::GetAppDescription() { + NOTREACHED() << "GetApplicationName unsupported"; + return std::wstring(); +} + +std::wstring ChromiumBinariesDistribution::GetLongAppDescription() { + NOTREACHED() << "GetApplicationName unsupported"; + return std::wstring(); +} + +std::string ChromiumBinariesDistribution::GetSafeBrowsingName() { + NOTREACHED() << "GetApplicationName unsupported"; + return std::string(); +} + +std::wstring ChromiumBinariesDistribution::GetStateKey() { + return std::wstring(L"Software\\").append(kChromiumBinariesName); +} + +std::wstring ChromiumBinariesDistribution::GetStateMediumKey() { + return std::wstring(L"Software\\").append(kChromiumBinariesName); +} + +std::wstring ChromiumBinariesDistribution::GetUninstallLinkName() { + NOTREACHED() << "GetApplicationName unsupported"; + return std::wstring(); +} + +std::wstring ChromiumBinariesDistribution::GetUninstallRegPath() { + NOTREACHED() << "GetApplicationName unsupported"; + return std::wstring(); +} + +std::wstring ChromiumBinariesDistribution::GetVersionKey() { + return std::wstring(L"Software\\").append(kChromiumBinariesName); +} + +bool ChromiumBinariesDistribution::CanSetAsDefault() { + NOTREACHED() << "GetApplicationName unsupported"; + return false; +} + +int ChromiumBinariesDistribution::GetIconIndex() { + NOTREACHED() << "GetApplicationName unsupported"; + return 0; +} + +bool ChromiumBinariesDistribution::GetChromeChannel(std::wstring* channel) { + NOTREACHED() << "GetApplicationName unsupported"; + return false; +} diff --git a/chrome/installer/util/chromium_binaries_distribution.h b/chrome/installer/util/chromium_binaries_distribution.h new file mode 100644 index 0000000..6ee0c4f --- /dev/null +++ b/chrome/installer/util/chromium_binaries_distribution.h @@ -0,0 +1,64 @@ +// Copyright (c) 2011 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. +// +// This file declares a class that contains various method related to branding. + +#ifndef CHROME_INSTALLER_UTIL_CHROMIUM_BINARIES_DISTRIBUTION_H_ +#define CHROME_INSTALLER_UTIL_CHROMIUM_BINARIES_DISTRIBUTION_H_ +#pragma once + +#include <string> + +#include "chrome/installer/util/browser_distribution.h" + +class ChromiumBinariesDistribution : public BrowserDistribution { + public: + virtual std::wstring GetAppGuid(); + + virtual std::wstring GetApplicationName(); + + virtual std::wstring GetAppShortCutName(); + + virtual std::wstring GetAlternateApplicationName(); + + virtual std::wstring GetBrowserAppId(); + + virtual std::wstring GetInstallSubDir(); + + virtual std::wstring GetPublisherName(); + + virtual std::wstring GetAppDescription(); + + virtual std::wstring GetLongAppDescription(); + + virtual std::string GetSafeBrowsingName(); + + virtual std::wstring GetStateKey(); + + virtual std::wstring GetStateMediumKey(); + + virtual std::wstring GetUninstallLinkName(); + + virtual std::wstring GetUninstallRegPath(); + + virtual std::wstring GetVersionKey(); + + virtual bool CanSetAsDefault(); + + virtual int GetIconIndex(); + + virtual bool GetChromeChannel(std::wstring* channel); + + protected: + friend class BrowserDistribution; + + ChromiumBinariesDistribution(); + + BrowserDistribution* browser_distribution_; + + private: + DISALLOW_COPY_AND_ASSIGN(ChromiumBinariesDistribution); +}; + +#endif // CHROME_INSTALLER_UTIL_CHROMIUM_BINARIES_DISTRIBUTION_H_ diff --git a/chrome/installer/util/google_chrome_binaries_distribution.cc b/chrome/installer/util/google_chrome_binaries_distribution.cc new file mode 100644 index 0000000..00229bf --- /dev/null +++ b/chrome/installer/util/google_chrome_binaries_distribution.cc @@ -0,0 +1,56 @@ +// Copyright (c) 2011 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. +// +// This file declares a class that contains various method related to branding. + +#include "chrome/installer/util/google_chrome_binaries_distribution.h" + +#include "chrome/installer/util/google_update_constants.h" +#include "chrome/installer/util/google_update_settings.h" +#include "chrome/installer/util/install_util.h" + +namespace { + +const wchar_t kChromeBinariesGuid[] = L"{4DC8B4CA-1BDA-483e-B5FA-D3C12E15B62D}"; +const wchar_t kChromeBinariesName[] = L"Google Chrome binaries"; + +} // namespace + +GoogleChromeBinariesDistribution::GoogleChromeBinariesDistribution() + : ChromiumBinariesDistribution() { +} + +std::wstring GoogleChromeBinariesDistribution::GetAppGuid() { + return kChromeBinariesGuid; +} + +std::wstring GoogleChromeBinariesDistribution::GetAppShortCutName() { + return kChromeBinariesName; +} + +std::wstring GoogleChromeBinariesDistribution::GetStateKey() { + return std::wstring(google_update::kRegPathClientState) + .append(1, L'\\') + .append(kChromeBinariesGuid); +} + +std::wstring GoogleChromeBinariesDistribution::GetStateMediumKey() { + return std::wstring(google_update::kRegPathClientStateMedium) + .append(1, L'\\') + .append(kChromeBinariesGuid); +} + +std::wstring GoogleChromeBinariesDistribution::GetVersionKey() { + return std::wstring(google_update::kRegPathClients) + .append(1, L'\\') + .append(kChromeBinariesGuid); +} + +void GoogleChromeBinariesDistribution::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), kChromeBinariesGuid); +} diff --git a/chrome/installer/util/google_chrome_binaries_distribution.h b/chrome/installer/util/google_chrome_binaries_distribution.h new file mode 100644 index 0000000..3ddbf34 --- /dev/null +++ b/chrome/installer/util/google_chrome_binaries_distribution.h @@ -0,0 +1,38 @@ +// Copyright (c) 2011 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. +// +// This file declares a class that contains various method related to branding. + +#ifndef CHROME_INSTALLER_UTIL_GOOGLE_CHROME_BINARIES_DISTRIBUTION_H_ +#define CHROME_INSTALLER_UTIL_GOOGLE_CHROME_BINARIES_DISTRIBUTION_H_ +#pragma once + +#include "chrome/installer/util/chromium_binaries_distribution.h" + +class GoogleChromeBinariesDistribution : public ChromiumBinariesDistribution { + public: + virtual std::wstring GetAppGuid(); + + virtual std::wstring GetAppShortCutName(); + + virtual std::wstring GetStateKey(); + + virtual std::wstring GetStateMediumKey(); + + virtual std::wstring GetVersionKey(); + + virtual void UpdateInstallStatus(bool system_install, + bool incremental_install, bool multi_install, + installer::InstallStatus install_status); + + protected: + friend class BrowserDistribution; + + GoogleChromeBinariesDistribution(); + + private: + DISALLOW_COPY_AND_ASSIGN(GoogleChromeBinariesDistribution); +}; + +#endif // CHROME_INSTALLER_UTIL_GOOGLE_CHROME_BINARIES_DISTRIBUTION_H_ diff --git a/chrome/installer/util/google_chrome_distribution.cc b/chrome/installer/util/google_chrome_distribution.cc index e0ab343..300ee1d 100644 --- a/chrome/installer/util/google_chrome_distribution.cc +++ b/chrome/installer/util/google_chrome_distribution.cc @@ -253,9 +253,9 @@ bool RelaunchSetupAsConsoleUser(const std::string& flag) { } // namespace -GoogleChromeDistribution::GoogleChromeDistribution( - const installer::MasterPreferences& prefs) - : BrowserDistribution(prefs), product_guid_(kChromeGuid) { +GoogleChromeDistribution::GoogleChromeDistribution() + : BrowserDistribution(CHROME_BROWSER), + product_guid_(kChromeGuid) { } // The functions below are not used by the 64-bit Windows binary - @@ -633,7 +633,8 @@ void GoogleChromeDistribution::LaunchUserExperiment( // User qualifies for the experiment. Launch chrome with --try-chrome=flavor. void GoogleChromeDistribution::InactiveUserToastExperiment(int flavor, - const installer::Product& installation) { + const installer::Product& installation, + const FilePath& application_path) { bool has_welcome_url = (flavor == 0); // Possibly add a url to launch depending on the experiment flavor. CommandLine options(CommandLine::NO_PROGRAM); @@ -651,7 +652,7 @@ void GoogleChromeDistribution::InactiveUserToastExperiment(int flavor, } // Launch chrome now. It will show the toast UI. int32 exit_code = 0; - if (!installation.LaunchChromeAndWait(options, &exit_code)) + if (!installation.LaunchChromeAndWait(application_path, options, &exit_code)) return; // The chrome process has exited, figure out what happened. @@ -688,10 +689,3 @@ 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 038d27b..9610518 100644 --- a/chrome/installer/util/google_chrome_distribution.h +++ b/chrome/installer/util/google_chrome_distribution.h @@ -79,18 +79,16 @@ class GoogleChromeDistribution : public BrowserDistribution { // toast experiment. It will use chrome to show the UI and it will record the // outcome in the registry. virtual void InactiveUserToastExperiment(int flavor, - const installer::Product& installation); + const installer::Product& installation, + const FilePath& application_path); 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; } // Disallow construction from others. - explicit GoogleChromeDistribution( - const installer::MasterPreferences& prefs); + GoogleChromeDistribution(); private: friend class BrowserDistribution; diff --git a/chrome/installer/util/google_chrome_distribution_dummy.cc b/chrome/installer/util/google_chrome_distribution_dummy.cc index 1b515d9..9b022be 100644 --- a/chrome/installer/util/google_chrome_distribution_dummy.cc +++ b/chrome/installer/util/google_chrome_distribution_dummy.cc @@ -15,9 +15,8 @@ #include "base/file_path.h" #include "base/logging.h" -GoogleChromeDistribution::GoogleChromeDistribution( - const installer::MasterPreferences& prefs) - : BrowserDistribution(prefs) { +GoogleChromeDistribution::GoogleChromeDistribution() + : BrowserDistribution(CHROME_BROWSER) { } void GoogleChromeDistribution::DoPostUninstallOperations( @@ -114,7 +113,8 @@ void GoogleChromeDistribution::LaunchUserExperiment( } void GoogleChromeDistribution::InactiveUserToastExperiment(int flavor, - const installer::Product& installation) { + const installer::Product& installation, + const FilePath& application_path) { NOTREACHED(); } @@ -135,10 +135,3 @@ bool GoogleChromeDistribution::BuildUninstallMetricsString( NOTREACHED(); return false; } - -bool GoogleChromeDistribution::SetChannelFlags( - bool set, - installer::ChannelInfo* channel_info) { - NOTREACHED(); - return false; -} diff --git a/chrome/installer/util/google_chrome_distribution_unittest.cc b/chrome/installer/util/google_chrome_distribution_unittest.cc index 1222ff3..ed566ea 100644 --- a/chrome/installer/util/google_chrome_distribution_unittest.cc +++ b/chrome/installer/util/google_chrome_distribution_unittest.cc @@ -11,7 +11,6 @@ #include "chrome/installer/util/browser_distribution.h" #include "chrome/installer/util/google_update_constants.h" #include "chrome/installer/util/google_chrome_distribution.h" -#include "chrome/installer/util/master_preferences.h" #include "testing/gtest/include/gtest/gtest.h" #if defined(GOOGLE_CHROME_BUILD) @@ -52,12 +51,9 @@ TEST(GoogleChromeDistTest, TestExtractUninstallMetrics) { ASSERT_TRUE(root.get()); std::wstring uninstall_metrics_string; - const installer::MasterPreferences& prefs = - installer::MasterPreferences::ForCurrentProcess(); - GoogleChromeDistribution* dist = static_cast<GoogleChromeDistribution*>( BrowserDistribution::GetSpecificDistribution( - BrowserDistribution::CHROME_BROWSER, prefs)); + BrowserDistribution::CHROME_BROWSER)); EXPECT_TRUE( dist->ExtractUninstallMetrics(*static_cast<DictionaryValue*>(root.get()), diff --git a/chrome/installer/util/google_chrome_sxs_distribution.cc b/chrome/installer/util/google_chrome_sxs_distribution.cc index 9461a52..9ea35f1 100644 --- a/chrome/installer/util/google_chrome_sxs_distribution.cc +++ b/chrome/installer/util/google_chrome_sxs_distribution.cc @@ -9,7 +9,7 @@ #include "base/command_line.h" #include "base/logging.h" -#include "installer_util_strings.h" +#include "installer_util_strings.h" // NOLINT namespace { @@ -20,9 +20,8 @@ const int kSxSIconIndex = 4; } // namespace -GoogleChromeSxSDistribution::GoogleChromeSxSDistribution( - const installer::MasterPreferences& prefs) - : GoogleChromeDistribution(prefs) { +GoogleChromeSxSDistribution::GoogleChromeSxSDistribution() + : GoogleChromeDistribution() { GoogleChromeDistribution::set_product_guid(kChromeSxSGuid); } @@ -62,9 +61,3 @@ bool GoogleChromeSxSDistribution::GetChromeChannel(std::wstring* channel) { std::wstring GoogleChromeSxSDistribution::ChannelName() { return kChannelName; } - -void GoogleChromeSxSDistribution::AppendUninstallCommandLineFlags( - CommandLine* cmd_line) { - DCHECK(cmd_line); - cmd_line->AppendSwitch(installer::switches::kChromeSxS); -} diff --git a/chrome/installer/util/google_chrome_sxs_distribution.h b/chrome/installer/util/google_chrome_sxs_distribution.h index 7088c56..10df80a 100644 --- a/chrome/installer/util/google_chrome_sxs_distribution.h +++ b/chrome/installer/util/google_chrome_sxs_distribution.h @@ -32,13 +32,11 @@ class GoogleChromeSxSDistribution : public GoogleChromeDistribution { virtual bool GetChromeChannel(std::wstring* channel); // returns the channel name for GoogleChromeSxSDistribution static std::wstring ChannelName(); - virtual void AppendUninstallCommandLineFlags(CommandLine* cmd_line); private: friend class BrowserDistribution; // Disallow construction from non-friends. - explicit GoogleChromeSxSDistribution( - const installer::MasterPreferences& prefs); + GoogleChromeSxSDistribution(); }; #endif // CHROME_INSTALLER_UTIL_GOOGLE_CHROME_SXS_DISTRIBUTION_H_ diff --git a/chrome/installer/util/google_update_settings.cc b/chrome/installer/util/google_update_settings.cc index 44ee0f0..76d13d2 100644 --- a/chrome/installer/util/google_update_settings.cc +++ b/chrome/installer/util/google_update_settings.cc @@ -17,11 +17,11 @@ #include "chrome/installer/util/channel_info.h" #include "chrome/installer/util/google_update_constants.h" #include "chrome/installer/util/install_util.h" -#include "chrome/installer/util/package.h" -#include "chrome/installer/util/package_properties.h" +#include "chrome/installer/util/installer_state.h" #include "chrome/installer/util/product.h" using base::win::RegKey; +using installer::InstallerState; namespace { @@ -126,33 +126,43 @@ bool GoogleUpdateSettings::SetMetricsId(const std::wstring& metrics_id) { } bool GoogleUpdateSettings::SetEULAConsent( - const installer::Package& package, + const InstallerState& installer_state, bool consented) { // If this is a multi install, Google Update will have put eulaaccepted=0 into // the ClientState key of the multi-installer. Conduct a brief search for // this value and store the consent in the corresponding location. - HKEY root = package.system_level() ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER; - - std::wstring reg_path = package.properties()->GetStateMediumKey(); - EulaSearchResult status = HasEULASetting( - root, package.properties()->GetStateKey(), !consented); + HKEY root = installer_state.root_key(); + EulaSearchResult status = NO_SETTING; + std::wstring reg_path; + std::wstring fallback_reg_path; + + if (installer_state.package_type() == InstallerState::MULTI_PACKAGE) { + BrowserDistribution* binaries_dist = + installer_state.multi_package_binaries_distribution(); + fallback_reg_path = reg_path = binaries_dist->GetStateMediumKey(); + status = HasEULASetting(root, binaries_dist->GetStateKey(), !consented); + } if (status != FOUND_SAME_SETTING) { EulaSearchResult new_status = NO_SETTING; - installer::Products::const_iterator scan = package.products().begin(); - installer::Products::const_iterator end = package.products().end(); + installer::Products::const_iterator scan = + installer_state.products().begin(); + installer::Products::const_iterator end = + installer_state.products().end(); for (; status != FOUND_SAME_SETTING && scan != end; ++scan) { - const installer::Product& product = *(scan->get()); - new_status = HasEULASetting(root, product.distribution()->GetStateKey(), + if (fallback_reg_path.empty()) + fallback_reg_path = (*scan)->distribution()->GetStateMediumKey(); + new_status = HasEULASetting(root, (*scan)->distribution()->GetStateKey(), !consented); if (new_status > status) { status = new_status; - reg_path = product.distribution()->GetStateMediumKey(); + reg_path = (*scan)->distribution()->GetStateMediumKey(); } } if (status == NO_SETTING) { LOG(WARNING) - << "eulaaccepted value not found; setting consent on package"; - reg_path = package.properties()->GetStateMediumKey(); + << "eulaaccepted value not found; setting consent in key " + << fallback_reg_path; + reg_path = fallback_reg_path; } } RegKey key(HKEY_LOCAL_MACHINE, reg_path.c_str(), KEY_SET_VALUE); diff --git a/chrome/installer/util/google_update_settings.h b/chrome/installer/util/google_update_settings.h index 36e020c..12b5fa5 100644 --- a/chrome/installer/util/google_update_settings.h +++ b/chrome/installer/util/google_update_settings.h @@ -12,7 +12,7 @@ namespace installer { class ChannelInfo; -class Package; +class InstallerState; } // This class provides accessors to the Google Update 'ClientState' information @@ -38,7 +38,7 @@ class GoogleUpdateSettings { // Sets the machine-wide EULA consented flag required on OEM installs. // Returns false if the setting could not be recorded. - static bool SetEULAConsent(const installer::Package& package, + static bool SetEULAConsent(const installer::InstallerState& installer_state, bool consented); // Returns the last time chrome was run in days. It uses a recorded value diff --git a/chrome/installer/util/google_update_settings_unittest.cc b/chrome/installer/util/google_update_settings_unittest.cc index 96a6dae..2234192 100644 --- a/chrome/installer/util/google_update_settings_unittest.cc +++ b/chrome/installer/util/google_update_settings_unittest.cc @@ -15,9 +15,9 @@ #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/installation_state.h" +#include "chrome/installer/util/installer_state.h" #include "chrome/installer/util/master_preferences.h" -#include "chrome/installer/util/package.h" -#include "chrome/installer/util/package_properties.h" #include "chrome/installer/util/product.h" #include "chrome/installer/util/work_item_list.h" #include "testing/gtest/include/gtest/gtest.h" @@ -404,28 +404,32 @@ TEST_F(GoogleUpdateSettingsTest, UpdateInstallStatusTest) { } TEST_F(GoogleUpdateSettingsTest, SetEULAConsent) { - const bool multi_install = false; + const bool multi_install = true; const bool system_level = true; - HKEY root = system_level ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER; - - const installer::MasterPreferences& prefs = - installer::MasterPreferences::ForCurrentProcess(); - installer::ChromePackageProperties properties; - BrowserDistribution* distribution = - BrowserDistribution::GetSpecificDistribution( - BrowserDistribution::CHROME_BROWSER, prefs); - scoped_refptr<installer::Package> package( - new installer::Package(multi_install, system_level, FilePath(), - &properties)); - scoped_refptr<installer::Product> product( - new installer::Product(distribution, package.get())); + CommandLine cmd_line = CommandLine::FromString( + std::wstring(L"setup.exe") + + (multi_install ? L" --multi-install --chrome" : L"") + + (system_level ? L" --system-level" : L"")); + installer::MasterPreferences prefs(cmd_line); + installer::InstallationState machine_state; + machine_state.Initialize(); + installer::InstallerState installer_state; + installer_state.Initialize(cmd_line, prefs, machine_state); + HKEY root = installer_state.root_key(); + RegKey key; DWORD value; + BrowserDistribution* binaries = + installer_state.multi_package_binaries_distribution(); + EXPECT_EQ(BrowserDistribution::CHROME_BINARIES, binaries->GetType()); + BrowserDistribution* chrome = + installer_state.products()[0]->distribution(); + EXPECT_EQ(BrowserDistribution::CHROME_BROWSER, chrome->GetType()); // By default, eulaconsent ends up on the package. - EXPECT_TRUE(GoogleUpdateSettings::SetEULAConsent(*package.get(), true)); + EXPECT_TRUE(GoogleUpdateSettings::SetEULAConsent(installer_state, true)); EXPECT_EQ(ERROR_SUCCESS, - key.Open(HKEY_LOCAL_MACHINE, properties.GetStateMediumKey().c_str(), + key.Open(HKEY_LOCAL_MACHINE, binaries->GetStateMediumKey().c_str(), KEY_QUERY_VALUE | KEY_SET_VALUE)); EXPECT_EQ(ERROR_SUCCESS, key.ReadValueDW(google_update::kRegEULAAceptedField, &value)); @@ -435,14 +439,14 @@ TEST_F(GoogleUpdateSettingsTest, SetEULAConsent) { // But it will end up on the product if needed EXPECT_EQ(ERROR_SUCCESS, - key.Create(HKEY_LOCAL_MACHINE, distribution->GetStateKey().c_str(), + key.Create(HKEY_LOCAL_MACHINE, chrome->GetStateKey().c_str(), KEY_SET_VALUE)); EXPECT_EQ(ERROR_SUCCESS, key.WriteValue(google_update::kRegEULAAceptedField, static_cast<DWORD>(0))); - EXPECT_TRUE(GoogleUpdateSettings::SetEULAConsent(*package.get(), true)); + EXPECT_TRUE(GoogleUpdateSettings::SetEULAConsent(installer_state, true)); EXPECT_EQ(ERROR_SUCCESS, - key.Open(HKEY_LOCAL_MACHINE, distribution->GetStateMediumKey().c_str(), + key.Open(HKEY_LOCAL_MACHINE, chrome->GetStateMediumKey().c_str(), KEY_QUERY_VALUE | KEY_SET_VALUE)); EXPECT_EQ(ERROR_SUCCESS, key.ReadValueDW(google_update::kRegEULAAceptedField, &value)); diff --git a/chrome/installer/util/helper.cc b/chrome/installer/util/helper.cc index 6cddf25..82f8a36 100644 --- a/chrome/installer/util/helper.cc +++ b/chrome/installer/util/helper.cc @@ -4,17 +4,13 @@ #include "chrome/installer/util/helper.h" -#include "base/command_line.h" -#include "base/file_path.h" #include "base/logging.h" +#include "base/file_path.h" #include "base/path_service.h" -#include "base/win/registry.h" #include "chrome/installer/util/browser_distribution.h" +#include "chrome/installer/util/installation_state.h" #include "chrome/installer/util/install_util.h" -#include "chrome/installer/util/master_preferences.h" -#include "chrome/installer/util/package_properties.h" - -using base::win::RegKey; +#include "chrome/installer/util/util_constants.h" namespace { @@ -40,101 +36,32 @@ FilePath GetChromeInstallBasePath(bool system, namespace installer { -bool IsInstalledAsMulti(bool system_install, BrowserDistribution* dist) { - bool installed_as_multi = false; - CommandLine cmd(CommandLine::NO_PROGRAM); - if (GetUninstallSwitches(system_install, dist, &cmd)) - installed_as_multi = cmd.HasSwitch(installer::switches::kMultiInstall); - return installed_as_multi; -} - -bool GetUninstallSwitches(bool system_install, BrowserDistribution* dist, - CommandLine* cmd_line_switches) { - scoped_ptr<Version> installed(InstallUtil::GetChromeVersion(dist, - system_install)); - if (installed.get()) { - HKEY root = system_install ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER; - RegKey key(root, dist->GetStateKey().c_str(), KEY_READ); - if (key.Valid()) { - std::wstring args; - key.ReadValue(installer::kUninstallArgumentsField, &args); - if (!args.empty()) { - args.insert(0, L"foo.exe "); - *cmd_line_switches = CommandLine::FromString(args); - } else { - LOG(ERROR) << "No uninstallation arguments for " - << dist->GetApplicationName(); - installed.reset(); - } - } else { - LOG(ERROR) << "Product looks to be installed but we can't access the " - "state key: " << dist->GetApplicationName(); - installed.reset(); - } - } - - return installed.get() != NULL; -} - FilePath GetChromeInstallPath(bool system_install, BrowserDistribution* dist) { - return GetChromeInstallBasePath(system_install, dist, - installer::kInstallBinaryDir); + return GetChromeInstallBasePath(system_install, dist, kInstallBinaryDir); } FilePath GetChromeUserDataPath(BrowserDistribution* dist) { return GetChromeInstallBasePath(false, dist, kInstallUserDataDir); } -FilePath GetChromeFrameInstallPath(bool multi_install, bool system_install, - BrowserDistribution* dist) { - DCHECK_EQ(BrowserDistribution::CHROME_FRAME, dist->GetType()); - - scoped_ptr<Version> installed_version( - InstallUtil::GetChromeVersion(dist, system_install)); - - if (!multi_install) { - // Check if Chrome Frame is installed as multi. If it is, return an empty - // path and log an error. - if (installed_version.get() && IsInstalledAsMulti(system_install, dist)) { - LOG(ERROR) << "Cannot install Chrome Frame in single mode as a multi mode" - " installation already exists."; - return FilePath(); - } - VLOG(1) << "Chrome Frame will be installed as 'single'"; - return GetChromeInstallPath(system_install, dist); - } - - // TODO(tommi): If Chrome Frame is installed as single and the installed - // channel is older than the one we're installing, we should migrate - // CF to Chrome's install folder and change its channel. +BrowserDistribution* GetBinariesDistribution(bool system_install) { + BrowserDistribution* dist = BrowserDistribution::GetDistribution(); + ProductState state; - // Multi install. Check if Chrome Frame is already installed. - // If CF is installed as single (i.e. not multi), we will return an empty - // path (for now). Otherwise, if CF is not installed or if it is installed - // as multi, we will return Chrome's install folder. - if (installed_version.get() && !IsInstalledAsMulti(system_install, dist)) { - LOG(ERROR) << "Cannot install Chrome Frame in multi mode as a single mode" - " installation already exists."; - return FilePath(); + // If we're part of a multi-install, we need to poll using the multi-installer + // package's app guid rather than the browser's or Chrome Frame's app guid. + // If we can't read the app's state from the registry, assume it isn't + // multi-installed. + if (state.Initialize(system_install, dist) && state.is_multi_install()) { + return BrowserDistribution::GetSpecificDistribution( + BrowserDistribution::CHROME_BINARIES); + } else { + return dist; } - - // Return Chrome's installation folder. - VLOG(1) << "Chrome Frame will be installed as 'multi'"; - const MasterPreferences& prefs = MasterPreferences::ForCurrentProcess(); - BrowserDistribution* chrome = - BrowserDistribution::GetSpecificDistribution( - BrowserDistribution::CHROME_BROWSER, prefs); - return GetChromeInstallPath(system_install, chrome); } std::wstring GetAppGuidForUpdates(bool system_install) { - BrowserDistribution* dist = BrowserDistribution::GetDistribution(); - - // If we're part of a multi-install, we need to poll using the multi-installer - // package's app guid rather than the browser's or Chrome Frame's app guid. - return IsInstalledAsMulti(system_install, dist) ? - ActivePackageProperties().GetAppGuid() : - dist->GetAppGuid(); + return GetBinariesDistribution(system_install)->GetAppGuid(); } } // namespace installer. diff --git a/chrome/installer/util/helper.h b/chrome/installer/util/helper.h index bcee4c6..fa996b6 100644 --- a/chrome/installer/util/helper.h +++ b/chrome/installer/util/helper.h @@ -16,17 +16,6 @@ class FilePath; namespace installer { -// Checks if a distribution is currently installed as part of a multi-install. -bool IsInstalledAsMulti(bool system_install, BrowserDistribution* dist); - -// Retrieves the command line switches for uninstalling the distribution. -// Note that the returned CommandLine object does not include a "program". -// Only the switches should be used. -// Returns true if the product is installed and the uninstall switches -// were successfully retrieved, otherwise false. -bool GetUninstallSwitches(bool system_install, BrowserDistribution* dist, - CommandLine* cmd_line_switches); - // This function returns the install path for Chrome depending on whether its // system wide install or user specific install. // system_install: if true, the function returns system wide location @@ -40,18 +29,10 @@ FilePath GetChromeInstallPath(bool system_install, BrowserDistribution* dist); // that it can be overriden with a command line parameter. FilePath GetChromeUserDataPath(BrowserDistribution* dist); -// This is a workaround while we unify Chrome and Chrome Frame installation -// folders. Right now, Chrome Frame can be installed into two different -// folders: 1) A special "Chrome Frame" folder next to Chrome's folder -// 2) The same folder as Chrome is installed into. -// Right now this function will only return Chrome's installation folder -// if Chrome Frame is not already installed or if Chrome Frame is installed -// in multi_install mode. -// If multi_install is false or if CF is installed in single mode, then the -// returned path will be the "Chrome Frame" subfolder of either the user or -// system default installation folders. -FilePath GetChromeFrameInstallPath(bool multi_install, bool system_install, - BrowserDistribution* dist); +// Returns the distribution corresponding to the current process's binaries. +// In the case of a multi-install product, this will be the CHROME_BINARIES +// distribution. +BrowserDistribution* GetBinariesDistribution(bool system_install); // Returns the app guid under which the current process receives updates from // Google Update. diff --git a/chrome/installer/util/helper_unittest.cc b/chrome/installer/util/helper_unittest.cc deleted file mode 100644 index 48b2476..0000000 --- a/chrome/installer/util/helper_unittest.cc +++ /dev/null @@ -1,204 +0,0 @@ -// Copyright (c) 2006-2008 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 <windows.h> - -#include <fstream> - -#include "base/base_paths.h" -#include "base/file_util.h" -#include "base/path_service.h" -#include "base/process_util.h" -#include "base/string_util.h" -#include "base/version.h" -#include "chrome/installer/util/helper.h" -#include "chrome/installer/util/package.h" -#include "chrome/installer/util/package_properties.h" -#include "chrome/installer/util/work_item.h" -#include "testing/gtest/include/gtest/gtest.h" - -using installer::ChromePackageProperties; -using installer::Package; - -namespace { - class SetupHelperTest : public testing::Test { - protected: - virtual void SetUp() { - // Name a subdirectory of the user temp directory. - ASSERT_TRUE(PathService::Get(base::DIR_TEMP, &test_dir_)); - test_dir_ = test_dir_.AppendASCII("SetupHelperTest"); - - // Create a fresh, empty copy of this test directory. - file_util::Delete(test_dir_, true); - file_util::CreateDirectoryW(test_dir_); - ASSERT_TRUE(file_util::PathExists(test_dir_)); - } - - virtual void TearDown() { - logging::CloseLogFile(); - // Clean up test directory - ASSERT_TRUE(file_util::Delete(test_dir_, true)); - ASSERT_FALSE(file_util::PathExists(test_dir_)); - } - - // the path to temporary directory used to contain the test operations - FilePath test_dir_; - }; - - // Simple function to dump some text into a new file. - void CreateTextFile(const std::wstring& filename, - const std::wstring& contents) { - std::ofstream file; - file.open(filename.c_str()); - ASSERT_TRUE(file.is_open()); - file << contents; - file.close(); - } - - wchar_t text_content_1[] = L"delete me"; - wchar_t text_content_2[] = L"delete me as well"; -}; - -// Delete version directories. Everything lower than the given version -// should be deleted. -TEST_F(SetupHelperTest, Delete) { - // Create a Chrome dir - FilePath chrome_dir(test_dir_); - chrome_dir = chrome_dir.AppendASCII("chrome"); - file_util::CreateDirectory(chrome_dir); - ASSERT_TRUE(file_util::PathExists(chrome_dir)); - - FilePath chrome_dir_1(chrome_dir); - chrome_dir_1 = chrome_dir_1.AppendASCII("1.0.1.0"); - file_util::CreateDirectory(chrome_dir_1); - ASSERT_TRUE(file_util::PathExists(chrome_dir_1)); - - FilePath chrome_dir_2(chrome_dir); - chrome_dir_2 = chrome_dir_2.AppendASCII("1.0.2.0"); - file_util::CreateDirectory(chrome_dir_2); - ASSERT_TRUE(file_util::PathExists(chrome_dir_2)); - - FilePath chrome_dir_3(chrome_dir); - chrome_dir_3 = chrome_dir_3.AppendASCII("1.0.3.0"); - file_util::CreateDirectory(chrome_dir_3); - ASSERT_TRUE(file_util::PathExists(chrome_dir_3)); - - FilePath chrome_dir_4(chrome_dir); - chrome_dir_4 = chrome_dir_4.AppendASCII("1.0.4.0"); - file_util::CreateDirectory(chrome_dir_4); - ASSERT_TRUE(file_util::PathExists(chrome_dir_4)); - - FilePath chrome_dll_1(chrome_dir_1); - chrome_dll_1 = chrome_dll_1.AppendASCII("chrome.dll"); - CreateTextFile(chrome_dll_1.value(), text_content_1); - ASSERT_TRUE(file_util::PathExists(chrome_dll_1)); - - FilePath chrome_dll_2(chrome_dir_2); - chrome_dll_2 = chrome_dll_2.AppendASCII("chrome.dll"); - CreateTextFile(chrome_dll_2.value(), text_content_1); - ASSERT_TRUE(file_util::PathExists(chrome_dll_2)); - - FilePath chrome_dll_3(chrome_dir_3); - chrome_dll_3 = chrome_dll_3.AppendASCII("chrome.dll"); - CreateTextFile(chrome_dll_3.value(), text_content_1); - ASSERT_TRUE(file_util::PathExists(chrome_dll_3)); - - FilePath chrome_dll_4(chrome_dir_4); - chrome_dll_4 = chrome_dll_4.AppendASCII("chrome.dll"); - CreateTextFile(chrome_dll_4.value(), text_content_1); - ASSERT_TRUE(file_util::PathExists(chrome_dll_4)); - - scoped_ptr<Version> latest_version(Version::GetVersionFromString("1.0.4.0")); - ChromePackageProperties properties; - scoped_refptr<Package> package(new Package(false, true, chrome_dir, - &properties)); - package->RemoveOldVersionDirectories(*latest_version.get()); - - // old versions should be gone - EXPECT_FALSE(file_util::PathExists(chrome_dir_1)); - EXPECT_FALSE(file_util::PathExists(chrome_dir_2)); - EXPECT_FALSE(file_util::PathExists(chrome_dir_3)); - // the latest version should stay - EXPECT_TRUE(file_util::PathExists(chrome_dll_4)); -} - -// Delete older version directories, keeping the one in used intact. -TEST_F(SetupHelperTest, DeleteInUsed) { - // Create a Chrome dir - FilePath chrome_dir(test_dir_); - chrome_dir = chrome_dir.AppendASCII("chrome"); - file_util::CreateDirectory(chrome_dir); - ASSERT_TRUE(file_util::PathExists(chrome_dir)); - - FilePath chrome_dir_1(chrome_dir); - chrome_dir_1 = chrome_dir_1.AppendASCII("1.0.1.0"); - file_util::CreateDirectory(chrome_dir_1); - ASSERT_TRUE(file_util::PathExists(chrome_dir_1)); - - FilePath chrome_dir_2(chrome_dir); - chrome_dir_2 = chrome_dir_2.AppendASCII("1.0.2.0"); - file_util::CreateDirectory(chrome_dir_2); - ASSERT_TRUE(file_util::PathExists(chrome_dir_2)); - - FilePath chrome_dir_3(chrome_dir); - chrome_dir_3 = chrome_dir_3.AppendASCII("1.0.3.0"); - file_util::CreateDirectory(chrome_dir_3); - ASSERT_TRUE(file_util::PathExists(chrome_dir_3)); - - FilePath chrome_dir_4(chrome_dir); - chrome_dir_4 = chrome_dir_4.AppendASCII("1.0.4.0"); - file_util::CreateDirectory(chrome_dir_4); - ASSERT_TRUE(file_util::PathExists(chrome_dir_4)); - - FilePath chrome_dll_1(chrome_dir_1); - chrome_dll_1 = chrome_dll_1.AppendASCII("chrome.dll"); - CreateTextFile(chrome_dll_1.value(), text_content_1); - ASSERT_TRUE(file_util::PathExists(chrome_dll_1)); - - FilePath chrome_dll_2(chrome_dir_2); - chrome_dll_2 = chrome_dll_2.AppendASCII("chrome.dll"); - CreateTextFile(chrome_dll_2.value(), text_content_1); - ASSERT_TRUE(file_util::PathExists(chrome_dll_2)); - - // Open the file to make it in use. - std::ofstream file; - file.open(chrome_dll_2.value().c_str()); - - FilePath chrome_othera_2(chrome_dir_2); - chrome_othera_2 = chrome_othera_2.AppendASCII("othera.dll"); - CreateTextFile(chrome_othera_2.value(), text_content_2); - ASSERT_TRUE(file_util::PathExists(chrome_othera_2)); - - FilePath chrome_otherb_2(chrome_dir_2); - chrome_otherb_2 = chrome_otherb_2.AppendASCII("otherb.dll"); - CreateTextFile(chrome_otherb_2.value(), text_content_2); - ASSERT_TRUE(file_util::PathExists(chrome_otherb_2)); - - FilePath chrome_dll_3(chrome_dir_3); - chrome_dll_3 = chrome_dll_3.AppendASCII("chrome.dll"); - CreateTextFile(chrome_dll_3.value(), text_content_1); - ASSERT_TRUE(file_util::PathExists(chrome_dll_3)); - - FilePath chrome_dll_4(chrome_dir_4); - chrome_dll_4 = chrome_dll_4.AppendASCII("chrome.dll"); - CreateTextFile(chrome_dll_4.value(), text_content_1); - ASSERT_TRUE(file_util::PathExists(chrome_dll_4)); - - scoped_ptr<Version> latest_version(Version::GetVersionFromString("1.0.4.0")); - ChromePackageProperties properties; - scoped_refptr<Package> install_path(new Package(false, true, chrome_dir, - &properties)); - install_path->RemoveOldVersionDirectories(*latest_version.get()); - - // old versions not in used should be gone - EXPECT_FALSE(file_util::PathExists(chrome_dir_1)); - EXPECT_FALSE(file_util::PathExists(chrome_dir_3)); - // every thing under in used version should stay - EXPECT_TRUE(file_util::PathExists(chrome_dir_2)); - EXPECT_TRUE(file_util::PathExists(chrome_dll_2)); - EXPECT_TRUE(file_util::PathExists(chrome_othera_2)); - EXPECT_TRUE(file_util::PathExists(chrome_otherb_2)); - // the latest version should stay - EXPECT_TRUE(file_util::PathExists(chrome_dll_4)); -} diff --git a/chrome/installer/util/install_util.cc b/chrome/installer/util/install_util.cc index 0e598dd..48af659 100644 --- a/chrome/installer/util/install_util.cc +++ b/chrome/installer/util/install_util.cc @@ -12,24 +12,24 @@ #include <algorithm> +#include "base/command_line.h" #include "base/file_util.h" #include "base/logging.h" #include "base/path_service.h" #include "base/scoped_ptr.h" #include "base/string_util.h" #include "base/values.h" +#include "base/version.h" #include "base/win/registry.h" #include "base/win/windows_version.h" #include "chrome/common/json_value_serializer.h" #include "chrome/installer/util/browser_distribution.h" #include "chrome/installer/util/google_update_constants.h" #include "chrome/installer/util/l10n_string_util.h" -#include "chrome/installer/util/master_preferences_constants.h" #include "chrome/installer/util/util_constants.h" #include "chrome/installer/util/work_item_list.h" using base::win::RegKey; -using installer::MasterPreferences; bool InstallUtil::ExecuteExeAsAdmin(const CommandLine& cmd, DWORD* exit_code) { FilePath::StringType program(cmd.GetProgram().value()); @@ -240,3 +240,25 @@ int InstallUtil::GetInstallReturnCode(installer::InstallStatus status) { return status; } } + +// static +void InstallUtil::MakeUninstallCommand(const std::wstring& exe_path, + const std::wstring& arguments, + CommandLine* command_line) { + const bool no_program = exe_path.empty(); + + // Return a bunch of nothingness. + if (no_program && arguments.empty()) { + *command_line = CommandLine(CommandLine::NO_PROGRAM); + } else { + // Form a full command line string. + std::wstring command; + command.append(1, L'"') + .append(no_program ? L"" : exe_path) + .append(L"\" ") + .append(arguments); + + // If we have a program name, return this complete command line. + *command_line = CommandLine::FromString(command); + } +} diff --git a/chrome/installer/util/install_util.h b/chrome/installer/util/install_util.h index f2ba551..1912c09 100644 --- a/chrome/installer/util/install_util.h +++ b/chrome/installer/util/install_util.h @@ -15,13 +15,12 @@ #include <string> #include "base/basictypes.h" -#include "base/command_line.h" -#include "base/version.h" -#include "chrome/installer/util/master_preferences.h" #include "chrome/installer/util/util_constants.h" -class WorkItemList; class BrowserDistribution; +class CommandLine; +class Version; +class WorkItemList; namespace base { namespace win { @@ -107,6 +106,11 @@ class InstallUtil { // Returns zero on install success, or an InstallStatus value otherwise. static int GetInstallReturnCode(installer::InstallStatus install_status); + // Composes |exe_path| and |arguments| into |command_line|. + static void MakeUninstallCommand(const std::wstring& exe_path, + const std::wstring& arguments, + CommandLine* command_line); + private: DISALLOW_COPY_AND_ASSIGN(InstallUtil); }; diff --git a/chrome/installer/util/install_util_unittest.cc b/chrome/installer/util/install_util_unittest.cc index b0e05ba..a5cb86f 100644 --- a/chrome/installer/util/install_util_unittest.cc +++ b/chrome/installer/util/install_util_unittest.cc @@ -3,6 +3,7 @@ // found in the LICENSE file. #include <string> +#include <utility> #include "base/command_line.h" #include "base/win/registry.h" @@ -34,17 +35,17 @@ TEST_F(InstallUtilTest, InstallerResult) { // 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")); + CommandLine cmd_line = CommandLine::FromString(L"setup.exe --system-level"); + const MasterPreferences prefs(cmd_line); InstallationState machine_state; - machine_state.Initialize(prefs); + machine_state.Initialize(); InstallerState state; - state.Initialize(prefs, machine_state); + state.Initialize(cmd_line, 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); + BrowserDistribution::CHROME_BROWSER); EXPECT_EQ(ERROR_SUCCESS, key.Open(root, distribution->GetStateKey().c_str(), KEY_READ)); EXPECT_EQ(ERROR_SUCCESS, @@ -56,18 +57,18 @@ TEST_F(InstallUtilTest, InstallerResult) { // 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")); + CommandLine cmd_line = CommandLine::FromString( + L"setup.exe --system-level --multi-install --chrome"); + const MasterPreferences prefs(cmd_line); InstallationState machine_state; - machine_state.Initialize(prefs); + machine_state.Initialize(); InstallerState state; - state.Initialize(prefs, machine_state); + state.Initialize(cmd_line, 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); + BrowserDistribution::CHROME_BROWSER); EXPECT_EQ(ERROR_SUCCESS, key.Open(root, distribution->GetStateKey().c_str(), KEY_READ)); EXPECT_EQ(ERROR_SUCCESS, @@ -77,3 +78,27 @@ TEST_F(InstallUtilTest, InstallerResult) { } TempRegKeyOverride::DeleteAllTempKeys(); } + +TEST_F(InstallUtilTest, MakeUninstallCommand) { + CommandLine command_line(CommandLine::NO_PROGRAM); + + std::pair<std::wstring, std::wstring> params[] = { + std::make_pair(std::wstring(L""), std::wstring(L"")), + std::make_pair(std::wstring(L""), std::wstring(L"--do-something --silly")), + std::make_pair(std::wstring(L"spam.exe"), std::wstring(L"")), + std::make_pair(std::wstring(L"spam.exe"), + std::wstring(L"--do-something --silly")), + }; + for (int i = 0; i < arraysize(params); ++i) { + std::pair<std::wstring, std::wstring>& param = params[i]; + InstallUtil::MakeUninstallCommand(param.first, param.second, &command_line); + EXPECT_EQ(param.first, command_line.GetProgram().value()); + if (param.second.empty()) { + EXPECT_EQ(0U, command_line.GetSwitchCount()); + } else { + EXPECT_EQ(2U, command_line.GetSwitchCount()); + EXPECT_TRUE(command_line.HasSwitch("do-something")); + EXPECT_TRUE(command_line.HasSwitch("silly")); + } + } +} diff --git a/chrome/installer/util/installation_state.cc b/chrome/installer/util/installation_state.cc index c0ab82d..f766195 100644 --- a/chrome/installer/util/installation_state.cc +++ b/chrome/installer/util/installation_state.cc @@ -9,33 +9,82 @@ #include "base/version.h" #include "base/win/registry.h" #include "chrome/installer/util/google_update_constants.h" -#include "chrome/installer/util/package_properties.h" +#include "chrome/installer/util/install_util.h" namespace installer { -ProductState::ProductState() { +ProductState::ProductState() + : uninstall_command_(CommandLine::NO_PROGRAM), + msi_(false), + multi_install_(false) { } -void ProductState::Initialize(bool system_install, - const std::wstring& version_key, - const std::wstring& state_key) { +bool ProductState::Initialize(bool system_install, + BrowserDistribution::Type type) { + return Initialize(system_install, + BrowserDistribution::GetSpecificDistribution(type)); +} + +bool ProductState::Initialize(bool system_install, + BrowserDistribution* distribution) { + const std::wstring version_key(distribution->GetVersionKey()); + const std::wstring state_key(distribution->GetStateKey()); 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) - == ERROR_SUCCESS) { + if (key.ReadValue(google_update::kRegVersionField, + &version_str) == ERROR_SUCCESS) { 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) != - ERROR_SUCCESS) || !channel_.Initialize(key)) { - channel_.set_value(std::wstring()); + // The product is installed. + if (key.ReadValue(google_update::kRegOldVersionField, + &version_str) == ERROR_SUCCESS) { + old_version_.reset( + Version::GetVersionFromString(WideToASCII(version_str))); + } else { + old_version_.reset(); + } + if (key.ReadValue(google_update::kRegRenameCmdField, + &rename_cmd_) != ERROR_SUCCESS) + rename_cmd_.clear(); + // Read from the ClientState key. + channel_.set_value(std::wstring()); + uninstall_command_ = CommandLine(CommandLine::NO_PROGRAM); + msi_ = false; + multi_install_ = false; + if (key.Open(root_key, state_key.c_str(), + KEY_QUERY_VALUE) == ERROR_SUCCESS) { + std::wstring setup_path; + std::wstring uninstall_arguments; + // "ap" will be absent if not managed by Google Update. + channel_.Initialize(key); + // "UninstallString" will be absent for the multi-installer package. + key.ReadValue(kUninstallStringField, &setup_path); + // "UninstallArguments" will be absent for the multi-installer package. + key.ReadValue(kUninstallArgumentsField, &uninstall_arguments); + InstallUtil::MakeUninstallCommand(setup_path, uninstall_arguments, + &uninstall_command_); + // "msi" may be absent, 0 or 1 + DWORD dw_value = 0; + msi_ = (key.ReadValueDW(google_update::kRegMSIField, + &dw_value) == ERROR_SUCCESS) && (dw_value != 0); + // Multi-install is implied or is derived from the command-line. + if (distribution->GetType() == BrowserDistribution::CHROME_BINARIES) { + multi_install_ = true; + } else { + multi_install_ = uninstall_command_.HasSwitch( + switches::kMultiInstall); + } } } } else { version_.reset(); } + return version_.get() != NULL; +} + +FilePath ProductState::GetSetupPath() const { + return uninstall_command_.GetProgram(); } const Version& ProductState::version() const { @@ -43,12 +92,17 @@ const Version& ProductState::version() const { return *version_; } -void ProductState::CopyFrom(const ProductState& other) { +ProductState& ProductState::CopyFrom(const ProductState& other) { channel_.set_value(other.channel_.value()); - if (other.version_.get() == NULL) - version_.reset(); - else - version_.reset(other.version_->Clone()); + version_.reset(other.version_.get() == NULL ? NULL : other.version_->Clone()); + old_version_.reset( + other.old_version_.get() == NULL ? NULL : other.old_version_->Clone()); + rename_cmd_ = other.rename_cmd_; + uninstall_command_ = other.uninstall_command_; + msi_ = other.msi_; + multi_install_ = other.multi_install_; + + return *this; } InstallationState::InstallationState() { @@ -60,53 +114,31 @@ int InstallationState::IndexFromDistType(BrowserDistribution::Type type) { unexpected_chrome_browser_distribution_value_); COMPILE_ASSERT(BrowserDistribution::CHROME_FRAME == CHROME_FRAME_INDEX, unexpected_chrome_frame_distribution_value_); + COMPILE_ASSERT(BrowserDistribution::CHROME_BINARIES == CHROME_BINARIES_INDEX, + unexpected_chrome_frame_distribution_value_); DCHECK(type == BrowserDistribution::CHROME_BROWSER || - type == BrowserDistribution::CHROME_FRAME); + type == BrowserDistribution::CHROME_FRAME || + type == BrowserDistribution::CHROME_BINARIES); return type; } -void InstallationState::Initialize(const MasterPreferences& prefs) { +void InstallationState::Initialize() { 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]); + BrowserDistribution::CHROME_BROWSER); + user_products_[CHROME_BROWSER_INDEX].Initialize(false, distribution); + system_products_[CHROME_BROWSER_INDEX].Initialize(true, distribution); 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]); -} + BrowserDistribution::CHROME_FRAME); + user_products_[CHROME_FRAME_INDEX].Initialize(false, distribution); + system_products_[CHROME_FRAME_INDEX].Initialize(true, distribution); -// 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; + distribution = BrowserDistribution::GetSpecificDistribution( + BrowserDistribution::CHROME_BINARIES); + user_products_[CHROME_BINARIES_INDEX].Initialize(false, distribution); + system_products_[CHROME_BINARIES_INDEX].Initialize(true, distribution); } const ProductState* InstallationState::GetProductState( diff --git a/chrome/installer/util/installation_state.h b/chrome/installer/util/installation_state.h index 3657c62..817e0af 100644 --- a/chrome/installer/util/installation_state.h +++ b/chrome/installer/util/installation_state.h @@ -1,4 +1,4 @@ -// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Copyright (c) 2011 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. @@ -9,6 +9,8 @@ #include <string> #include "base/basictypes.h" +#include "base/command_line.h" +#include "base/file_path.h" #include "base/scoped_ptr.h" #include "chrome/installer/util/browser_distribution.h" #include "chrome/installer/util/channel_info.h" @@ -19,44 +21,75 @@ namespace installer { class InstallationState; class MasterPreferences; -class PackageProperties; +// A representation of a product's state on the machine based on the contents +// of the Windows registry. +// TODO(grt): Pull this out into its own file. class ProductState { public: ProductState(); - void Initialize(bool system_install, - const std::wstring& version_key, - const std::wstring& state_key); + // Returns true if the product is installed (i.e., the product's Clients key + // exists and has a "pv" value); false otherwise. + bool Initialize(bool system_install, + BrowserDistribution::Type type); + bool Initialize(bool system_install, + BrowserDistribution* distribution); + + // Returns the product's channel info (i.e., the Google Update "ap" value). const ChannelInfo& channel() const { return channel_; } - ChannelInfo& channel() { return channel_; } + // Returns the path to the product's "setup.exe"; may be empty. + FilePath GetSetupPath() const; + + // Returns the product's version. This method may only be called on an + // instance that has been initialized for an installed product. const Version& version() const; - // Takes ownership of |version|. - void set_version(Version* version) { version_.reset(version); } - void CopyFrom(const ProductState& other); + // Returns the current version of the product if a new version is awaiting + // update; may be NULL. Ownership of a returned value is not passed to the + // caller. + const Version* old_version() const { return old_version_.get(); } - private: - friend class InstallationState; + // Returns the command to be used to update to the new version that is + // awaiting update; may be empty. + const std::wstring& rename_cmd() const { return rename_cmd_; } + + // True if the "msi" value in the ClientState key is present and non-zero. + bool is_msi() const { return msi_; } + + // The command to uninstall the product; may be empty. + const CommandLine& uninstall_command() const { return uninstall_command_; } + + // True if |uninstall_command| contains --multi-install. + bool is_multi_install() const { return multi_install_; } + + // Returns this object a la operator=(). + ProductState& CopyFrom(const ProductState& other); + protected: ChannelInfo channel_; scoped_ptr<Version> version_; + scoped_ptr<Version> old_version_; + std::wstring rename_cmd_; + CommandLine uninstall_command_; + bool msi_; + bool multi_install_; + + private: + friend class InstallationState; + DISALLOW_COPY_AND_ASSIGN(ProductState); }; // class ProductState // Encapsulates the state of all products on the system. +// TODO(grt): Rename this to MachineState and put it in its own file. 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. - // Caller does NOT assume ownership of returned pointer. - const ProductState* GetMultiPackageState(bool system_install) const; + // Initializes this object with the machine's current state. + void Initialize(); // Returns the state of a product or NULL if not installed. // Caller does NOT assume ownership of returned pointer. @@ -67,17 +100,11 @@ class InstallationState { enum { CHROME_BROWSER_INDEX, CHROME_FRAME_INDEX, - MULTI_PACKAGE_INDEX, + CHROME_BINARIES_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]; diff --git a/chrome/installer/util/installer_state.cc b/chrome/installer/util/installer_state.cc index 69d2841..9137b29 100644 --- a/chrome/installer/util/installer_state.cc +++ b/chrome/installer/util/installer_state.cc @@ -4,11 +4,23 @@ #include "chrome/installer/util/installer_state.h" +#include <algorithm> +#include <functional> +#include <utility> + +#include "base/command_line.h" +#include "base/file_util.h" #include "base/logging.h" +#include "base/scoped_ptr.h" +#include "base/string_util.h" +#include "base/utf_string_conversions.h" +#include "chrome/installer/util/delete_tree_work_item.h" +#include "chrome/installer/util/helper.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" +#include "chrome/installer/util/product.h" +#include "chrome/installer/util/work_item.h" namespace installer { @@ -16,7 +28,8 @@ bool InstallerState::IsMultiInstallUpdate(const MasterPreferences& prefs, const InstallationState& machine_state) { // First, is the package present? const ProductState* package = - machine_state.GetMultiPackageState(system_install_); + machine_state.GetProductState(level_ == SYSTEM_LEVEL, + BrowserDistribution::CHROME_BINARIES); if (package == NULL) { // The multi-install package has not been installed, so it certainly isn't // being updated. @@ -33,7 +46,7 @@ bool InstallerState::IsMultiInstallUpdate(const MasterPreferences& prefs, for (const BrowserDistribution::Type* scan = &types[0], *end = &types[num_types]; scan != end; ++scan) { const ProductState* product = - machine_state.GetProductState(system_install_, *scan); + machine_state.GetProductState(level_ == SYSTEM_LEVEL, *scan); if (product == NULL) { VLOG(2) << "It seems that distribution type " << *scan << " is being installed for the first time."; @@ -51,42 +64,382 @@ bool InstallerState::IsMultiInstallUpdate(const MasterPreferences& prefs, return true; } -InstallerState::InstallerState() : operation_(UNINITIALIZED) { +InstallerState::InstallerState() + : operation_(UNINITIALIZED), + multi_package_distribution_(NULL), + level_(UNKNOWN_LEVEL), + package_type_(UNKNOWN_PACKAGE_TYPE), + root_key_(NULL), + msi_(false), + verbose_logging_(false) { +} + +InstallerState::InstallerState(Level level) + : operation_(UNINITIALIZED), + multi_package_distribution_(NULL), + level_(UNKNOWN_LEVEL), + package_type_(UNKNOWN_PACKAGE_TYPE), + root_key_(NULL), + msi_(false), + verbose_logging_(false) { + // Use set_level() so that root_key_ is updated properly. + set_level(level); } -void InstallerState::Initialize(const MasterPreferences& prefs, +void InstallerState::Initialize(const CommandLine& command_line, + const MasterPreferences& prefs, const InstallationState& machine_state) { - if (!prefs.GetBool(installer::master_preferences::kSystemLevel, - &system_install_)) - system_install_ = false; + bool pref_bool; + if (!prefs.GetBool(master_preferences::kSystemLevel, &pref_bool)) + pref_bool = false; + set_level(pref_bool ? SYSTEM_LEVEL : USER_LEVEL); + + if (!prefs.GetBool(master_preferences::kVerboseLogging, &verbose_logging_)) + verbose_logging_ = false; + + if (!prefs.GetBool(master_preferences::kMultiInstall, &pref_bool)) + pref_bool = false; + set_package_type(pref_bool ? MULTI_PACKAGE : SINGLE_PACKAGE); + + if (!prefs.GetBool(master_preferences::kMsi, &msi_)) + msi_ = false; + + const bool is_uninstall = command_line.HasSwitch(switches::kUninstall); + + if (prefs.install_chrome()) { + Product* p = + AddProductFromPreferences(BrowserDistribution::CHROME_BROWSER, prefs, + machine_state); + VLOG(1) << (is_uninstall ? "Uninstall" : "Install") + << " distribution: " << p->distribution()->GetApplicationName(); + } + if (prefs.install_chrome_frame()) { + Product* p = + AddProductFromPreferences(BrowserDistribution::CHROME_FRAME, prefs, + machine_state); + VLOG(1) << (is_uninstall ? "Uninstall" : "Install") + << " distribution: " << p->distribution()->GetApplicationName(); + } BrowserDistribution* operand = NULL; - if (!prefs.is_multi_install()) { + if (is_uninstall) { + operation_ = UNINSTALL; + } else 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; + operand = multi_package_distribution_; 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. + operation_ = MULTI_INSTALL; + } + + if (operand == NULL) { operand = BrowserDistribution::GetSpecificDistribution( prefs.install_chrome() ? BrowserDistribution::CHROME_BROWSER : - BrowserDistribution::CHROME_FRAME, - prefs); - operation_ = MULTI_INSTALL; + BrowserDistribution::CHROME_FRAME); } - if (operand != NULL) { - state_key_ = operand->GetStateKey(); + state_key_ = operand->GetStateKey(); +} + +void InstallerState::set_level(Level level) { + level_ = level; + switch (level) { + case USER_LEVEL: + root_key_ = HKEY_CURRENT_USER; + break; + case SYSTEM_LEVEL: + root_key_ = HKEY_LOCAL_MACHINE; + break; + default: + DCHECK(level == UNKNOWN_LEVEL); + level_ = UNKNOWN_LEVEL; + root_key_ = NULL; + break; + } +} + +void InstallerState::set_package_type(PackageType type) { + package_type_ = type; + switch (type) { + case SINGLE_PACKAGE: + multi_package_distribution_ = NULL; + break; + case MULTI_PACKAGE: + multi_package_distribution_ = + BrowserDistribution::GetSpecificDistribution( + BrowserDistribution::CHROME_BINARIES); + break; + default: + DCHECK(type == UNKNOWN_PACKAGE_TYPE); + package_type_ = UNKNOWN_PACKAGE_TYPE; + multi_package_distribution_ = NULL; + break; + } +} + +// Returns the Chrome binaries directory for multi-install or |dist|'s directory +// otherwise. +FilePath InstallerState::GetDefaultProductInstallPath( + BrowserDistribution* dist) const { + DCHECK(dist); + DCHECK(package_type_ != UNKNOWN_PACKAGE_TYPE); + + if (package_type_ == SINGLE_PACKAGE) { + return GetChromeInstallPath(system_install(), dist); + } else { + return GetChromeInstallPath(system_install(), + BrowserDistribution::GetSpecificDistribution( + BrowserDistribution::CHROME_BINARIES)); + } +} + +// Evaluates a product's eligibility for participation in this operation. +// We never expect these checks to fail, hence they all terminate the process in +// debug builds. See the log messages for details. +bool InstallerState::CanAddProduct(const Product& product, + const FilePath* product_dir) const { + switch (package_type_) { + case SINGLE_PACKAGE: + if (!products_.empty()) { + LOG(DFATAL) << "Cannot process more than one single-install product."; + return false; + } + break; + case MULTI_PACKAGE: + if (!product.HasOption(kOptionMultiInstall)) { + LOG(DFATAL) << "Cannot process a single-install product with a " + "multi-install state."; + return false; + } + if (FindProduct(product.distribution()->GetType()) != NULL) { + LOG(DFATAL) << "Cannot process more than one product of the same type."; + return false; + } + if (!target_path_.empty()) { + FilePath default_dir; + if (product_dir == NULL) + default_dir = GetDefaultProductInstallPath(product.distribution()); + if (!FilePath::CompareEqualIgnoreCase( + (product_dir == NULL ? default_dir : *product_dir).value(), + target_path_.value())) { + LOG(DFATAL) << "Cannot process products in different directories."; + return false; + } + } + break; + default: + DCHECK_EQ(UNKNOWN_PACKAGE_TYPE, package_type_); + break; + } + return true; +} + +// Adds |product|, installed in |product_dir| to this object's collection. If +// |product_dir| is NULL, the product's default install location is used. +// Returns NULL if |product| is incompatible with this object. Otherwise, +// returns a pointer to the product (ownership is held by this object). +Product* InstallerState::AddProductInDirectory(const FilePath* product_dir, + scoped_ptr<Product>* product) { + DCHECK(product != NULL); + DCHECK(product->get() != NULL); + const Product& the_product = *product->get(); + + if (!CanAddProduct(the_product, product_dir)) + return NULL; + + if (package_type_ == UNKNOWN_PACKAGE_TYPE) { + set_package_type(the_product.HasOption(kOptionMultiInstall) ? + MULTI_PACKAGE : SINGLE_PACKAGE); + } + + if (target_path_.empty()) { + if (product_dir == NULL) + target_path_ = GetDefaultProductInstallPath(the_product.distribution()); + else + target_path_ = *product_dir; + } + + if (state_key_.empty()) + state_key_ = the_product.distribution()->GetStateKey(); + + products_.push_back(product->release()); + return products_[products_->size() - 1]; +} + +Product* InstallerState::AddProduct(scoped_ptr<Product>* product) { + return AddProductInDirectory(NULL, product); +} + +// Adds a product of type |distribution_type| constructed on the basis of +// |prefs|, setting this object's msi flag if the product is represented in +// |machine_state| and is msi-installed. Returns the product that was added, +// or NULL if |state| is incompatible with this object. Ownership is not passed +// to the caller. +Product* InstallerState::AddProductFromPreferences( + BrowserDistribution::Type distribution_type, + const MasterPreferences& prefs, + const InstallationState& machine_state) { + scoped_ptr<Product> product_ptr( + new Product(BrowserDistribution::GetSpecificDistribution( + distribution_type))); + product_ptr->InitializeFromPreferences(prefs); + + Product* product = AddProductInDirectory(NULL, &product_ptr); + + if (product != NULL && !msi_) { + const ProductState* product_state = machine_state.GetProductState( + system_install(), distribution_type); + if (product_state != NULL) + msi_ = product_state->is_msi(); + } + + return product; +} + +Product* InstallerState::AddProductFromState( + BrowserDistribution::Type type, + const ProductState& state) { + scoped_ptr<Product> product_ptr( + new Product(BrowserDistribution::GetSpecificDistribution(type))); + product_ptr->InitializeFromUninstallCommand(state.uninstall_command()); + + // Strip off <version>/Installer/setup.exe; see GetInstallerDirectory(). + FilePath product_dir = state.GetSetupPath().DirName().DirName().DirName(); + + Product* product = AddProductInDirectory(&product_dir, &product_ptr); + + if (product != NULL) + msi_ |= state.is_msi(); + + return product; +} + +bool InstallerState::system_install() const { + DCHECK(level_ == USER_LEVEL || level_ == SYSTEM_LEVEL); + return level_ == SYSTEM_LEVEL; +} + +bool InstallerState::is_multi_install() const { + DCHECK(package_type_ == SINGLE_PACKAGE || package_type_ == MULTI_PACKAGE); + return package_type_ != SINGLE_PACKAGE; +} + +bool InstallerState::RemoveProduct(const Product* product) { + ScopedVector<Product>::iterator it = + std::find(products_.begin(), products_.end(), product); + if (it != products_.end()) { + products_->erase(it); + return true; + } + return false; +} + +const Product* InstallerState::FindProduct( + BrowserDistribution::Type distribution_type) const { + for (Products::const_iterator scan = products_.begin(), end = products_.end(); + scan != end; ++scan) { + if ((*scan)->is_type(distribution_type)) + return *scan; + } + return NULL; +} + +Version* InstallerState::GetCurrentVersion( + const InstallationState& machine_state) const { + DCHECK(!products_.empty()); + scoped_ptr<Version> current_version; + const BrowserDistribution::Type prod_type = (package_type_ == MULTI_PACKAGE) ? + BrowserDistribution::CHROME_BINARIES : + products_[0]->distribution()->GetType(); + const ProductState* product_state = + machine_state.GetProductState(level_ == SYSTEM_LEVEL, prod_type); + + if (product_state != NULL) { + const Version* version = NULL; + + // Be aware that there might be a pending "new_chrome.exe" already in the + // installation path. If so, we use old_version, which holds the version of + // "chrome.exe" itself. + if (file_util::PathExists(target_path().Append(kChromeNewExe))) + version = product_state->old_version(); + + if (version == NULL) + version = &product_state->version(); + + current_version.reset(version->Clone()); + } + + return current_version.release(); +} + +FilePath InstallerState::GetInstallerDirectory(const Version& version) const { + return target_path().Append(ASCIIToWide(version.GetString())) + .Append(kInstallerDir); +} + +void InstallerState::RemoveOldVersionDirectories( + const Version& latest_version) const { + file_util::FileEnumerator version_enum(target_path(), false, + file_util::FileEnumerator::DIRECTORIES); + scoped_ptr<Version> version; + std::vector<FilePath> key_files; + + // We try to delete all directories whose versions are lower than + // latest_version. + FilePath next_version = version_enum.Next(); + while (!next_version.empty()) { + file_util::FileEnumerator::FindInfo find_data = {0}; + version_enum.GetFindInfo(&find_data); + VLOG(1) << "directory found: " << find_data.cFileName; + version.reset(Version::GetVersionFromString( + WideToASCII(find_data.cFileName))); + if (version.get() && latest_version.CompareTo(*version) > 0) { + key_files.clear(); + std::for_each(products_.begin(), products_.end(), + std::bind2nd(std::mem_fun(&Product::AddKeyFiles), + &key_files)); + const std::vector<FilePath>::iterator end = key_files.end(); + for (std::vector<FilePath>::iterator scan = key_files.begin(); + scan != end; ++scan) { + *scan = next_version.Append(*scan); + } + + VLOG(1) << "Deleting directory: " << next_version.value(); + + scoped_ptr<WorkItem> item( + WorkItem::CreateDeleteTreeWorkItem(next_version, key_files)); + if (!item->Do()) + item->Rollback(); + } + + next_version = version_enum.Next(); + } +} + +void InstallerState::AddComDllList(std::vector<FilePath>* com_dll_list) const { + std::for_each(products_.begin(), products_.end(), + std::bind2nd(std::mem_fun(&Product::AddComDllList), + com_dll_list)); +} + +bool InstallerState::SetChannelFlags(bool set, + ChannelInfo* channel_info) const { + bool modified = false; + for (Products::const_iterator scan = products_.begin(), end = products_.end(); + scan != end; ++scan) { + modified |= (*scan)->SetChannelFlags(set, channel_info); } + return modified; } } // namespace installer diff --git a/chrome/installer/util/installer_state.h b/chrome/installer/util/installer_state.h index 0bc2a5f..0b4ea0b 100644 --- a/chrome/installer/util/installer_state.h +++ b/chrome/installer/util/installer_state.h @@ -7,47 +7,183 @@ #pragma once #include <string> +#include <vector> #include "base/basictypes.h" +#include "base/file_path.h" +#include "base/logging.h" +#include "base/scoped_ptr.h" +#include "base/scoped_vector.h" #include "chrome/installer/util/browser_distribution.h" +#include "chrome/installer/util/product.h" + +#if defined(OS_WIN) +#include <windows.h> // NOLINT +#endif + +class CommandLine; +class Version; namespace installer { +class ChannelInfo; class InstallationState; class MasterPreferences; +class ProductState; + +typedef std::vector<Product*> Products; + // Encapsulates the state of the current installation operation. Only valid -// for installs and upgrades (not for uninstalls or non-install commands) +// for installs and upgrades (not for uninstalls or non-install commands). +// TODO(grt): Rename to InstallerEngine/Conductor or somesuch? class InstallerState { public: + enum Level { + UNKNOWN_LEVEL, + USER_LEVEL, + SYSTEM_LEVEL + }; + + enum PackageType { + UNKNOWN_PACKAGE_TYPE, + SINGLE_PACKAGE, + MULTI_PACKAGE + }; + enum Operation { UNINITIALIZED, SINGLE_INSTALL_OR_UPDATE, MULTI_INSTALL, MULTI_UPDATE, + UNINSTALL }; + // Constructs an uninitialized instance; see Initialize(). InstallerState(); - // Initializes |this| based on the current operation. - void Initialize(const MasterPreferences& prefs, + // Constructs an initialized but empty instance. + explicit InstallerState(Level level); + + // Initializes this object based on the current operation. + void Initialize(const CommandLine& command_line, + const MasterPreferences& prefs, const InstallationState& machine_state); - // true if system-level, false if user-level. - bool system_install() const { return system_install_; } + // Adds a product constructed on the basis of |state|, setting this object's + // msi flag if |state| is msi-installed. Returns the product that was added, + // or NULL if |state| is incompatible with this object. Ownership is not + // passed to the caller. + Product* AddProductFromState(BrowserDistribution::Type type, + const ProductState& state); + + // Returns the product that was added, or NULL if |product| is incompatible + // with this object. Ownership of |product| is taken by this object, while + // ownership of the return value is not passed to the caller. + Product* AddProduct(scoped_ptr<Product>* product); + + // Removes |product| from the set of products to be operated on. The object + // pointed to by |product| is freed. Returns false if |product| is not + // present in the set. + bool RemoveProduct(const Product* product); + + // The level (user or system) of this operation. + Level level() const { return level_; } + // The package type (single or multi) of this operation. + PackageType package_type() const { return package_type_; } + + // An identifier of this operation. Operation operation() const { return operation_; } + // A convenience method returning level() == SYSTEM_LEVEL. + // TODO(grt): Eradicate the bool in favor of the enum. + bool system_install() const; + + // A convenience method returning package_type() == MULTI_PACKAGE. + // TODO(grt): Eradicate the bool in favor of the enum. + bool is_multi_install() const; + + // The full path to the place where the operand resides. + const FilePath& target_path() const { return target_path_; } + + // True if the "msi" preference is set or if a product with the "msi" state + // flag is set is to be operated on. + bool is_msi() const { return msi_; } + + // True if the --verbose-logging command-line flag is set or if the + // verbose_logging master preferences option is true. + bool verbose_logging() const { return verbose_logging_; } + +#if defined(OS_WIN) + HKEY root_key() const { return root_key_; } +#endif + // The ClientState key by which we interact with Google Update. const std::wstring& state_key() const { return state_key_; } + // Returns the BrowserDistribution instance corresponding to the binaries for + // this run if we're operating on a multi-package product. + BrowserDistribution* multi_package_binaries_distribution() const { + DCHECK(package_type_ == MULTI_PACKAGE); + DCHECK(multi_package_distribution_ != NULL); + return multi_package_distribution_; + } + + const Products& products() const { return products_.get(); } + + // Returns the product of the desired type, or NULL if none found. + const Product* FindProduct(BrowserDistribution::Type distribution_type) const; + + // Returns the currently installed version in |target_path|, or NULL if no + // products are installed. Ownership is passed to the caller. + Version* GetCurrentVersion(const InstallationState& machine_state) const; + + // Returns the path to the installer under Chrome version folder + // (for example <target_path>\Google\Chrome\Application\<Version>\Installer) + FilePath GetInstallerDirectory(const Version& version) const; + + // Try to delete all directories whose versions are lower than + // |latest_version|. + void RemoveOldVersionDirectories(const Version& latest_version) const; + + // Adds to |com_dll_list| the list of COM DLLs that are to be registered + // and/or unregistered. The list may be empty. + void AddComDllList(std::vector<FilePath>* com_dll_list) const; + + bool SetChannelFlags(bool set, ChannelInfo* channel_info) const; + protected: + FilePath GetDefaultProductInstallPath(BrowserDistribution* dist) const; + bool CanAddProduct(const Product& product, const FilePath* product_dir) const; + Product* AddProductInDirectory(const FilePath* product_dir, + scoped_ptr<Product>* product); + Product* AddProductFromPreferences( + BrowserDistribution::Type distribution_type, + const MasterPreferences& prefs, + const InstallationState& machine_state); bool IsMultiInstallUpdate(const MasterPreferences& prefs, const InstallationState& machine_state); + // Sets this object's level and updates the root_key_ accordingly. + void set_level(Level level); + + // Sets this object's package type and updates the multi_package_distribution_ + // accordingly. + void set_package_type(PackageType type); + Operation operation_; + FilePath target_path_; std::wstring state_key_; - bool system_install_; + ScopedVector<Product> products_; + BrowserDistribution* multi_package_distribution_; + Level level_; + PackageType package_type_; +#if defined(OS_WIN) + HKEY root_key_; +#endif + bool msi_; + bool verbose_logging_; private: DISALLOW_COPY_AND_ASSIGN(InstallerState); diff --git a/chrome/installer/util/installer_state_unittest.cc b/chrome/installer/util/installer_state_unittest.cc new file mode 100644 index 0000000..25efc07 --- /dev/null +++ b/chrome/installer/util/installer_state_unittest.cc @@ -0,0 +1,327 @@ +// Copyright (c) 2011 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 <windows.h> + +#include <fstream> + +#include "base/base_paths.h" +#include "base/command_line.h" +#include "base/file_util.h" +#include "base/path_service.h" +#include "base/process_util.h" +#include "base/string_util.h" +#include "base/utf_string_conversions.h" +#include "base/version.h" +#include "base/win/registry.h" +#include "base/win/scoped_handle.h" +#include "chrome/installer/util/google_update_constants.h" +#include "chrome/installer/util/helper.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/product_unittest.h" +#include "chrome/installer/util/work_item.h" +#include "testing/gtest/include/gtest/gtest.h" + +class InstallerStateTest : public TestWithTempDirAndDeleteTempOverrideKeys { + protected: +}; + +// An installer state on which we can tweak the target path. +class MockInstallerState : public installer::InstallerState { + public: + MockInstallerState() : InstallerState() { } + void set_target_path(const FilePath& target_path) { + target_path_ = target_path; + } +}; + +// Simple function to dump some text into a new file. +void CreateTextFile(const std::wstring& filename, + const std::wstring& contents) { + std::ofstream file; + file.open(filename.c_str()); + ASSERT_TRUE(file.is_open()); + file << contents; + file.close(); +} + +void BuildSingleChromeState(const FilePath& target_dir, + MockInstallerState* installer_state) { + CommandLine cmd_line = CommandLine::FromString(L"setup.exe"); + installer::MasterPreferences prefs(cmd_line); + installer::InstallationState machine_state; + machine_state.Initialize(); + installer_state->Initialize(cmd_line, prefs, machine_state); + installer_state->set_target_path(target_dir); + EXPECT_TRUE(installer_state->FindProduct(BrowserDistribution::CHROME_BROWSER) + != NULL); + EXPECT_TRUE(installer_state->FindProduct(BrowserDistribution::CHROME_FRAME) + == NULL); +} + +wchar_t text_content_1[] = L"delete me"; +wchar_t text_content_2[] = L"delete me as well"; + +// Delete version directories. Everything lower than the given version +// should be deleted. +TEST_F(InstallerStateTest, Delete) { + // TODO(grt): move common stuff into the test fixture. + // Create a Chrome dir + FilePath chrome_dir(test_dir_.path()); + chrome_dir = chrome_dir.AppendASCII("chrome"); + file_util::CreateDirectory(chrome_dir); + ASSERT_TRUE(file_util::PathExists(chrome_dir)); + + FilePath chrome_dir_1(chrome_dir); + chrome_dir_1 = chrome_dir_1.AppendASCII("1.0.1.0"); + file_util::CreateDirectory(chrome_dir_1); + ASSERT_TRUE(file_util::PathExists(chrome_dir_1)); + + FilePath chrome_dir_2(chrome_dir); + chrome_dir_2 = chrome_dir_2.AppendASCII("1.0.2.0"); + file_util::CreateDirectory(chrome_dir_2); + ASSERT_TRUE(file_util::PathExists(chrome_dir_2)); + + FilePath chrome_dir_3(chrome_dir); + chrome_dir_3 = chrome_dir_3.AppendASCII("1.0.3.0"); + file_util::CreateDirectory(chrome_dir_3); + ASSERT_TRUE(file_util::PathExists(chrome_dir_3)); + + FilePath chrome_dir_4(chrome_dir); + chrome_dir_4 = chrome_dir_4.AppendASCII("1.0.4.0"); + file_util::CreateDirectory(chrome_dir_4); + ASSERT_TRUE(file_util::PathExists(chrome_dir_4)); + + FilePath chrome_dll_1(chrome_dir_1); + chrome_dll_1 = chrome_dll_1.AppendASCII("chrome.dll"); + CreateTextFile(chrome_dll_1.value(), text_content_1); + ASSERT_TRUE(file_util::PathExists(chrome_dll_1)); + + FilePath chrome_dll_2(chrome_dir_2); + chrome_dll_2 = chrome_dll_2.AppendASCII("chrome.dll"); + CreateTextFile(chrome_dll_2.value(), text_content_1); + ASSERT_TRUE(file_util::PathExists(chrome_dll_2)); + + FilePath chrome_dll_3(chrome_dir_3); + chrome_dll_3 = chrome_dll_3.AppendASCII("chrome.dll"); + CreateTextFile(chrome_dll_3.value(), text_content_1); + ASSERT_TRUE(file_util::PathExists(chrome_dll_3)); + + FilePath chrome_dll_4(chrome_dir_4); + chrome_dll_4 = chrome_dll_4.AppendASCII("chrome.dll"); + CreateTextFile(chrome_dll_4.value(), text_content_1); + ASSERT_TRUE(file_util::PathExists(chrome_dll_4)); + + MockInstallerState installer_state; + BuildSingleChromeState(chrome_dir, &installer_state); + scoped_ptr<Version> latest_version(Version::GetVersionFromString("1.0.4.0")); + installer_state.RemoveOldVersionDirectories(*latest_version.get()); + + // old versions should be gone + EXPECT_FALSE(file_util::PathExists(chrome_dir_1)); + EXPECT_FALSE(file_util::PathExists(chrome_dir_2)); + EXPECT_FALSE(file_util::PathExists(chrome_dir_3)); + // the latest version should stay + EXPECT_TRUE(file_util::PathExists(chrome_dll_4)); +} + +// Delete older version directories, keeping the one in used intact. +TEST_F(InstallerStateTest, DeleteInUsed) { + // Create a Chrome dir + FilePath chrome_dir(test_dir_.path()); + chrome_dir = chrome_dir.AppendASCII("chrome"); + file_util::CreateDirectory(chrome_dir); + ASSERT_TRUE(file_util::PathExists(chrome_dir)); + + FilePath chrome_dir_1(chrome_dir); + chrome_dir_1 = chrome_dir_1.AppendASCII("1.0.1.0"); + file_util::CreateDirectory(chrome_dir_1); + ASSERT_TRUE(file_util::PathExists(chrome_dir_1)); + + FilePath chrome_dir_2(chrome_dir); + chrome_dir_2 = chrome_dir_2.AppendASCII("1.0.2.0"); + file_util::CreateDirectory(chrome_dir_2); + ASSERT_TRUE(file_util::PathExists(chrome_dir_2)); + + FilePath chrome_dir_3(chrome_dir); + chrome_dir_3 = chrome_dir_3.AppendASCII("1.0.3.0"); + file_util::CreateDirectory(chrome_dir_3); + ASSERT_TRUE(file_util::PathExists(chrome_dir_3)); + + FilePath chrome_dir_4(chrome_dir); + chrome_dir_4 = chrome_dir_4.AppendASCII("1.0.4.0"); + file_util::CreateDirectory(chrome_dir_4); + ASSERT_TRUE(file_util::PathExists(chrome_dir_4)); + + FilePath chrome_dll_1(chrome_dir_1); + chrome_dll_1 = chrome_dll_1.AppendASCII("chrome.dll"); + CreateTextFile(chrome_dll_1.value(), text_content_1); + ASSERT_TRUE(file_util::PathExists(chrome_dll_1)); + + FilePath chrome_dll_2(chrome_dir_2); + chrome_dll_2 = chrome_dll_2.AppendASCII("chrome.dll"); + CreateTextFile(chrome_dll_2.value(), text_content_1); + ASSERT_TRUE(file_util::PathExists(chrome_dll_2)); + + // Open the file to make it in use. + std::ofstream file; + file.open(chrome_dll_2.value().c_str()); + + FilePath chrome_othera_2(chrome_dir_2); + chrome_othera_2 = chrome_othera_2.AppendASCII("othera.dll"); + CreateTextFile(chrome_othera_2.value(), text_content_2); + ASSERT_TRUE(file_util::PathExists(chrome_othera_2)); + + FilePath chrome_otherb_2(chrome_dir_2); + chrome_otherb_2 = chrome_otherb_2.AppendASCII("otherb.dll"); + CreateTextFile(chrome_otherb_2.value(), text_content_2); + ASSERT_TRUE(file_util::PathExists(chrome_otherb_2)); + + FilePath chrome_dll_3(chrome_dir_3); + chrome_dll_3 = chrome_dll_3.AppendASCII("chrome.dll"); + CreateTextFile(chrome_dll_3.value(), text_content_1); + ASSERT_TRUE(file_util::PathExists(chrome_dll_3)); + + FilePath chrome_dll_4(chrome_dir_4); + chrome_dll_4 = chrome_dll_4.AppendASCII("chrome.dll"); + CreateTextFile(chrome_dll_4.value(), text_content_1); + ASSERT_TRUE(file_util::PathExists(chrome_dll_4)); + + MockInstallerState installer_state; + BuildSingleChromeState(chrome_dir, &installer_state); + scoped_ptr<Version> latest_version(Version::GetVersionFromString("1.0.4.0")); + installer_state.RemoveOldVersionDirectories(*latest_version.get()); + + // old versions not in used should be gone + EXPECT_FALSE(file_util::PathExists(chrome_dir_1)); + EXPECT_FALSE(file_util::PathExists(chrome_dir_3)); + // every thing under in used version should stay + EXPECT_TRUE(file_util::PathExists(chrome_dir_2)); + EXPECT_TRUE(file_util::PathExists(chrome_dll_2)); + EXPECT_TRUE(file_util::PathExists(chrome_othera_2)); + EXPECT_TRUE(file_util::PathExists(chrome_otherb_2)); + // the latest version should stay + EXPECT_TRUE(file_util::PathExists(chrome_dll_4)); +} + +// Tests a few basic things of the Package class. Makes sure that the path +// operations are correct +TEST_F(InstallerStateTest, Basic) { + const bool multi_install = false; + const bool system_level = true; + CommandLine cmd_line = CommandLine::FromString( + std::wstring(L"setup.exe") + + (multi_install ? L" --multi-install --chrome" : L"") + + (system_level ? L" --system-level" : L"")); + installer::MasterPreferences prefs(cmd_line); + installer::InstallationState machine_state; + machine_state.Initialize(); + MockInstallerState installer_state; + installer_state.Initialize(cmd_line, prefs, machine_state); + installer_state.set_target_path(test_dir_.path()); + EXPECT_EQ(test_dir_.path().value(), installer_state.target_path().value()); + EXPECT_EQ(1U, installer_state.products().size()); + + const char kOldVersion[] = "1.2.3.4"; + const char kNewVersion[] = "2.3.4.5"; + + scoped_ptr<Version> new_version(Version::GetVersionFromString(kNewVersion)); + scoped_ptr<Version> old_version(Version::GetVersionFromString(kOldVersion)); + ASSERT_TRUE(new_version.get() != NULL); + ASSERT_TRUE(old_version.get() != NULL); + + FilePath installer_dir( + installer_state.GetInstallerDirectory(*new_version.get())); + EXPECT_FALSE(installer_dir.empty()); + + FilePath new_version_dir(installer_state.target_path().Append( + UTF8ToWide(new_version->GetString()))); + FilePath old_version_dir(installer_state.target_path().Append( + UTF8ToWide(old_version->GetString()))); + + EXPECT_FALSE(file_util::PathExists(new_version_dir)); + EXPECT_FALSE(file_util::PathExists(old_version_dir)); + + EXPECT_FALSE(file_util::PathExists(installer_dir)); + file_util::CreateDirectory(installer_dir); + EXPECT_TRUE(file_util::PathExists(new_version_dir)); + + file_util::CreateDirectory(old_version_dir); + EXPECT_TRUE(file_util::PathExists(old_version_dir)); + + // Create a fake chrome.dll key file in the old version directory. This + // should prevent the old version directory from getting deleted. + FilePath old_chrome_dll(old_version_dir.Append(installer::kChromeDll)); + EXPECT_FALSE(file_util::PathExists(old_chrome_dll)); + + // Hold on to the file exclusively to prevent the directory from + // being deleted. + base::win::ScopedHandle file( + ::CreateFile(old_chrome_dll.value().c_str(), GENERIC_READ, + 0, NULL, OPEN_ALWAYS, 0, NULL)); + EXPECT_TRUE(file.IsValid()); + EXPECT_TRUE(file_util::PathExists(old_chrome_dll)); + + installer_state.RemoveOldVersionDirectories(*new_version.get()); + // The old directory should still exist. + EXPECT_TRUE(file_util::PathExists(old_version_dir)); + EXPECT_TRUE(file_util::PathExists(new_version_dir)); + + // Now close the file handle to make it possible to delete our key file. + file.Close(); + + installer_state.RemoveOldVersionDirectories(*new_version.get()); + // The new directory should still exist. + EXPECT_TRUE(file_util::PathExists(new_version_dir)); + + // Now, the old directory and key file should be gone. + EXPECT_FALSE(file_util::PathExists(old_chrome_dll)); + EXPECT_FALSE(file_util::PathExists(old_version_dir)); +} + +TEST_F(InstallerStateTest, WithProduct) { + const bool multi_install = false; + const bool system_level = true; + CommandLine cmd_line = CommandLine::FromString( + std::wstring(L"setup.exe") + + (multi_install ? L" --multi-install --chrome" : L"") + + (system_level ? L" --system-level" : L"")); + installer::MasterPreferences prefs(cmd_line); + installer::InstallationState machine_state; + machine_state.Initialize(); + MockInstallerState installer_state; + installer_state.Initialize(cmd_line, prefs, machine_state); + installer_state.set_target_path(test_dir_.path()); + EXPECT_EQ(1U, installer_state.products().size()); + EXPECT_EQ(system_level, installer_state.system_install()); + + const char kCurrentVersion[] = "1.2.3.4"; + scoped_ptr<Version> current_version( + Version::GetVersionFromString(kCurrentVersion)); + + HKEY root = system_level ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER; + EXPECT_EQ(root, installer_state.root_key()); + { + TempRegKeyOverride override(root, L"root_pit"); + BrowserDistribution* dist = BrowserDistribution::GetSpecificDistribution( + BrowserDistribution::CHROME_BROWSER); + base::win::RegKey chrome_key(root, dist->GetVersionKey().c_str(), + KEY_ALL_ACCESS); + EXPECT_TRUE(chrome_key.Valid()); + if (chrome_key.Valid()) { + chrome_key.WriteValue(google_update::kRegVersionField, + UTF8ToWide(current_version->GetString()).c_str()); + machine_state.Initialize(); + // TODO(tommi): Also test for when there exists a new_chrome.exe. + scoped_ptr<Version> found_version(installer_state.GetCurrentVersion( + machine_state)); + EXPECT_TRUE(found_version.get() != NULL); + if (found_version.get()) { + EXPECT_TRUE(current_version->Equals(*found_version)); + } + } + } +} diff --git a/chrome/installer/util/package.cc b/chrome/installer/util/package.cc deleted file mode 100644 index 3122cef..0000000 --- a/chrome/installer/util/package.cc +++ /dev/null @@ -1,188 +0,0 @@ -// Copyright (c) 2010 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "chrome/installer/util/package.h" - -#include "base/file_util.h" -#include "base/logging.h" -#include "base/string_util.h" -#include "base/utf_string_conversions.h" -#include "base/win/registry.h" -#include "chrome/installer/util/delete_tree_work_item.h" -#include "chrome/installer/util/google_update_constants.h" -#include "chrome/installer/util/helper.h" -#include "chrome/installer/util/master_preferences.h" -#include "chrome/installer/util/package_properties.h" -#include "chrome/installer/util/product.h" -#include "chrome/installer/util/util_constants.h" -#include "chrome/installer/util/work_item_list.h" - -using base::win::RegKey; -using installer::MasterPreferences; - -namespace installer { - -Package::Package(bool multi_install, bool system_level, const FilePath& path, - PackageProperties* properties) - : multi_install_(multi_install), - system_level_(system_level), - path_(path), - properties_(properties) { - DCHECK(properties_); -} - -Package::~Package() { -} - -const FilePath& Package::path() const { - return path_; -} - -const Products& Package::products() const { - return products_; -} - -PackageProperties* Package::properties() const { - return properties_; -} - -bool Package::IsEqual(const FilePath& path) const { - return FilePath::CompareEqualIgnoreCase(path_.value(), path.value()); -} - -void Package::AssociateProduct(const Product* product) { -#ifndef NDEBUG - for (size_t i = 0; i < products_.size(); ++i) { - DCHECK_NE(product->distribution()->GetType(), - products_[i]->distribution()->GetType()); - } -#endif - products_.push_back(product); -} - -bool Package::multi_install() const { - return multi_install_; -} - -bool Package::system_level() const { - return system_level_; -} - -FilePath Package::GetInstallerDirectory( - const Version& version) const { - return path_.Append(UTF8ToWide(version.GetString())) - .Append(installer::kInstallerDir); -} - -Version* Package::GetCurrentVersion() const { - scoped_ptr<Version> current_version; - // Be aware that there might be a pending "new_chrome.exe" already in the - // installation path. - FilePath new_chrome_exe(path_.Append(installer::kChromeNewExe)); - bool new_chrome_exists = file_util::PathExists(new_chrome_exe); - - HKEY root = system_level_ ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER; - - for (size_t i = 0; i < products_.size(); ++i) { - const Product* product = products_[i]; - RegKey chrome_key(root, product->distribution()->GetVersionKey().c_str(), - KEY_READ); - std::wstring version; - if (new_chrome_exists) - chrome_key.ReadValue(google_update::kRegOldVersionField, &version); - - if (version.empty()) - chrome_key.ReadValue(google_update::kRegVersionField, &version); - - if (!version.empty()) { - scoped_ptr<Version> this_version(Version::GetVersionFromString( - WideToASCII(version))); - if (this_version.get()) { - if (!current_version.get() || - (current_version->CompareTo(*this_version) > 0)) { - current_version.reset(this_version.release()); - } else if (current_version.get()) { - DCHECK_EQ(current_version->GetString(), this_version->GetString()) - << "found distributions of different versions in the same " - "installation folder!"; - } - } - } - } - - return current_version.release(); -} - -void Package::RemoveOldVersionDirectories( - const Version& latest_version) const { - file_util::FileEnumerator version_enum(path_, false, - file_util::FileEnumerator::DIRECTORIES); - scoped_ptr<Version> version; - - // We try to delete all directories whose versions are lower than - // latest_version. - FilePath next_version = version_enum.Next(); - while (!next_version.empty()) { - file_util::FileEnumerator::FindInfo find_data = {0}; - version_enum.GetFindInfo(&find_data); - VLOG(1) << "directory found: " << find_data.cFileName; - version.reset(Version::GetVersionFromString( - WideToASCII(find_data.cFileName))); - if (version.get() && (latest_version.CompareTo(*version) > 0)) { - std::vector<FilePath> key_files; - for (Products::const_iterator it = products_.begin(); - it != products_.end(); ++it) { - BrowserDistribution* dist = it->get()->distribution(); - std::vector<FilePath> dist_key_files(dist->GetKeyFiles()); - std::vector<FilePath>::const_iterator key_file_iter( - dist_key_files.begin()); - for (; key_file_iter != dist_key_files.end(); ++key_file_iter) { - key_files.push_back(next_version.Append(*key_file_iter)); - } - } - - VLOG(1) << "Deleting directory: " << next_version.value(); - - scoped_ptr<DeleteTreeWorkItem> item( - WorkItem::CreateDeleteTreeWorkItem(next_version, key_files)); - if (!item->Do()) - item->Rollback(); - } - - next_version = version_enum.Next(); - } -} - -size_t Package::GetMultiInstallDependencyCount() const { - BrowserDistribution::Type product_types[] = { - BrowserDistribution::CHROME_BROWSER, - BrowserDistribution::CHROME_FRAME, - }; - - const MasterPreferences& prefs = MasterPreferences::ForCurrentProcess(); - HKEY root_key = system_level_ ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER; - - size_t ret = 0; - - for (int i = 0; i < arraysize(product_types); ++i) { - BrowserDistribution* dist = - BrowserDistribution::GetSpecificDistribution(product_types[i], prefs); - // First see if the product is installed by checking its version key. - // If the key doesn't exist, the product isn't installed. - RegKey version_key(root_key, dist->GetVersionKey().c_str(), KEY_READ); - if (!version_key.Valid()) { - VLOG(1) << "Product not installed: " << dist->GetApplicationName(); - } else { - if (installer::IsInstalledAsMulti(system_level_, dist)) { - VLOG(1) << "Product dependency: " << dist->GetApplicationName(); - ++ret; - } - } - } - - return ret; -} - -} // namespace installer - diff --git a/chrome/installer/util/package.h b/chrome/installer/util/package.h deleted file mode 100644 index d523fc2..0000000 --- a/chrome/installer/util/package.h +++ /dev/null @@ -1,90 +0,0 @@ -// Copyright (c) 2010 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef CHROME_INSTALLER_UTIL_PACKAGE_H_ -#define CHROME_INSTALLER_UTIL_PACKAGE_H_ -#pragma once - -#include <vector> - -#include "base/file_path.h" -#include "base/ref_counted.h" - -class CommandLine; -class Version; - -namespace installer { - -enum InstallStatus; -class Product; -class PackageProperties; - -typedef std::vector<scoped_refptr<const Product> > Products; - -// Represents a physical installation. An instance of this class is associated -// with one or more Product instances. Product objects can share a Package but -// not vice versa. -class Package : public base::RefCounted<Package> { - public: - Package(bool multi_install, bool system_level, const FilePath& path, - PackageProperties* properties); - - // Returns the path of the installation folder. - const FilePath& path() const; - - const Products& products() const; - - PackageProperties* properties() const; - - bool multi_install() const; - - bool system_level() const; - - bool IsEqual(const FilePath& path) const; - - void AssociateProduct(const Product* product); - - // Get path to the installer under Chrome version folder - // (for example <path>\Google\Chrome\Application\<Version>\Installer) - FilePath GetInstallerDirectory(const Version& version) const; - - // Figure out the oldest currently installed version for this package - // Returns NULL if none is found. Caller is responsible for freeing - // the returned Version object if valid. - // The function DCHECKs if it finds that not all products in this - // folder have the same current version. - Version* GetCurrentVersion() const; - - // Tries to remove all previous version directories (after a new Chrome - // update). If an instance of Chrome with older version is still running - // on the system, its corresponding version directory will be left intact. - // (The version directory is subject for removal again during next update.) - // - // latest_version: the latest version of Chrome installed. - void RemoveOldVersionDirectories(const Version& latest_version) const; - - // Returns how many installed products depend on the binaries currently - // in the installation path. - // Note: The function counts only products that are installed as part of - // a multi install installation and only products that have the same - // system_level() value. - size_t GetMultiInstallDependencyCount() const; - - protected: - bool multi_install_; - bool system_level_; - FilePath path_; - Products products_; - PackageProperties* properties_; // Weak reference. - - private: - friend class base::RefCounted<Package>; - ~Package(); - - DISALLOW_COPY_AND_ASSIGN(Package); -}; - -} // namespace installer - -#endif // CHROME_INSTALLER_UTIL_PACKAGE_H_ diff --git a/chrome/installer/util/package_properties.cc b/chrome/installer/util/package_properties.cc deleted file mode 100644 index e33c2f9..0000000 --- a/chrome/installer/util/package_properties.cc +++ /dev/null @@ -1,94 +0,0 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "chrome/installer/util/package_properties.h" - -#include "base/basictypes.h" -#include "base/string_util.h" -#include "chrome/installer/util/browser_distribution.h" -#include "chrome/installer/util/google_update_constants.h" -#include "chrome/installer/util/google_update_settings.h" -#include "chrome/installer/util/install_util.h" -#include "chrome/installer/util/util_constants.h" - -namespace { - -const wchar_t kChromePackageGuid[] = - L"{4DC8B4CA-1BDA-483e-B5FA-D3C12E15B62D}"; - -std::wstring GetKeyForGuid(const wchar_t* base_key, const wchar_t* guid) { - std::wstring key(base_key); - key.append(L"\\"); - key.append(guid); - return key; -} - -} // end namespace - -namespace installer { - -const char PackageProperties::kPackageProductName[] = "Chrome binaries"; - -PackagePropertiesImpl::PackagePropertiesImpl( - const wchar_t* guid, - const std::wstring& state_key, - const std::wstring& state_medium_key, - const std::wstring& version_key) - : guid_(guid), state_key_(state_key), state_medium_key_(state_medium_key), - version_key_(version_key) { -} - -PackagePropertiesImpl::~PackagePropertiesImpl() { -} - -const std::wstring& PackagePropertiesImpl::GetAppGuid() { - return guid_; -} - -const std::wstring& PackagePropertiesImpl::GetStateKey() { - return state_key_; -} - -const std::wstring& PackagePropertiesImpl::GetStateMediumKey() { - return state_medium_key_; -} - -const std::wstring& PackagePropertiesImpl::GetVersionKey() { - return version_key_; -} - -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() - : PackagePropertiesImpl(L"", L"Software\\Chromium", L"Software\\Chromium", - L"Software\\Chromium") { -} - -ChromiumPackageProperties::~ChromiumPackageProperties() { -} - -ChromePackageProperties::ChromePackageProperties() - : PackagePropertiesImpl( - kChromePackageGuid, - GetKeyForGuid(google_update::kRegPathClientState, - kChromePackageGuid), - GetKeyForGuid(google_update::kRegPathClientStateMedium, - kChromePackageGuid), - GetKeyForGuid(google_update::kRegPathClients, - kChromePackageGuid)) { -} - -ChromePackageProperties::~ChromePackageProperties() { -} - -} // namespace installer diff --git a/chrome/installer/util/package_properties.h b/chrome/installer/util/package_properties.h deleted file mode 100644 index 5fd5e5f5..0000000 --- a/chrome/installer/util/package_properties.h +++ /dev/null @@ -1,109 +0,0 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef CHROME_INSTALLER_UTIL_PACKAGE_PROPERTIES_H_ -#define CHROME_INSTALLER_UTIL_PACKAGE_PROPERTIES_H_ -#pragma once - -#include <windows.h> - -#include <string> - -#include "base/basictypes.h" - -namespace installer { -enum InstallStatus; -}; - -namespace installer { - -// Pure virtual interface that exposes properties of a package installation. -// A package represents a set of binaries on disk that can be shared by two or -// more products. Also see the Package class for further details. -// PackageProperties is comparable to the BrowserDistribution class but the -// difference is that the BrowserDistribution class represents a product -// installation whereas PackageProperties represents a package -// (horizontal vs vertical). -class PackageProperties { - public: - PackageProperties() {} - virtual ~PackageProperties() {} - - static const char kPackageProductName[]; - - // Returns true iff this package will be updated by Google Update. - virtual bool ReceivesUpdates() const = 0; - - // Equivalent to BrowserDistribution::GetAppGuid() - virtual const std::wstring& GetAppGuid() = 0; - virtual const std::wstring& GetStateKey() = 0; - virtual const std::wstring& GetStateMediumKey() = 0; - virtual const std::wstring& GetVersionKey() = 0; - virtual void UpdateInstallStatus(bool system_level, bool incremental_install, - bool multi_install, installer::InstallStatus status) = 0; - - private: - DISALLOW_COPY_AND_ASSIGN(PackageProperties); -}; // class PackageProperties - -class PackagePropertiesImpl : public PackageProperties { - public: - explicit PackagePropertiesImpl(const wchar_t* guid, - const std::wstring& state_key, - const std::wstring& state_medium_key, - const std::wstring& version_key); - virtual ~PackagePropertiesImpl(); - - virtual const std::wstring& GetAppGuid(); - virtual const std::wstring& GetStateKey(); - virtual const std::wstring& GetStateMediumKey(); - virtual const std::wstring& GetVersionKey(); - virtual void UpdateInstallStatus(bool system_level, bool incremental_install, - bool multi_install, installer::InstallStatus status); - - protected: - std::wstring guid_; - std::wstring state_key_; - std::wstring state_medium_key_; - std::wstring version_key_; - - private: - DISALLOW_COPY_AND_ASSIGN(PackagePropertiesImpl); -}; // class PackagePropertiesImpl - -class ChromiumPackageProperties : public PackagePropertiesImpl { - public: - ChromiumPackageProperties(); - virtual ~ChromiumPackageProperties(); - - virtual bool ReceivesUpdates() const { - return false; - } - - private: - DISALLOW_COPY_AND_ASSIGN(ChromiumPackageProperties); -}; // class ChromiumPackageProperties - -class ChromePackageProperties : public PackagePropertiesImpl { - public: - ChromePackageProperties(); - virtual ~ChromePackageProperties(); - - virtual bool ReceivesUpdates() const { - return true; - } - - private: - 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 deleted file mode 100644 index 000cc72..0000000 --- a/chrome/installer/util/package_properties_unittest.cc +++ /dev/null @@ -1,40 +0,0 @@ -// Copyright (c) 2010 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/logging.h" -#include "base/win/registry.h" -#include "chrome/installer/util/google_update_constants.h" -#include "chrome/installer/util/package_properties.h" -#include "chrome/installer/util/product_unittest.h" -#include "chrome/installer/util/util_constants.h" -#include "testing/gtest/include/gtest/gtest.h" - -using base::win::RegKey; -using installer::PackageProperties; -using installer::ChromePackageProperties; -using installer::ChromiumPackageProperties; - -class PackagePropertiesTest : public testing::Test { - protected: -}; - -TEST_F(PackagePropertiesTest, Basic) { - TempRegKeyOverride::DeleteAllTempKeys(); - ChromePackageProperties chrome_props; - ChromiumPackageProperties chromium_props; - PackageProperties* props[] = { &chrome_props, &chromium_props }; - for (size_t i = 0; i < arraysize(props); ++i) { - std::wstring state_key(props[i]->GetStateKey()); - EXPECT_FALSE(state_key.empty()); - std::wstring version_key(props[i]->GetVersionKey()); - EXPECT_FALSE(version_key.empty()); - if (!props[i]->ReceivesUpdates()) { - TempRegKeyOverride override(HKEY_CURRENT_USER, L"props"); - RegKey key; - EXPECT_EQ(ERROR_SUCCESS, - key.Create(HKEY_CURRENT_USER, state_key.c_str(), KEY_ALL_ACCESS)); - } - TempRegKeyOverride::DeleteAllTempKeys(); - } -} diff --git a/chrome/installer/util/package_unittest.cc b/chrome/installer/util/package_unittest.cc deleted file mode 100644 index ea696a7..0000000 --- a/chrome/installer/util/package_unittest.cc +++ /dev/null @@ -1,190 +0,0 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/command_line.h" -#include "base/logging.h" -#include "base/utf_string_conversions.h" -#include "base/win/scoped_handle.h" -#include "chrome/installer/util/browser_distribution.h" -#include "chrome/installer/util/google_update_constants.h" -#include "chrome/installer/util/master_preferences.h" -#include "chrome/installer/util/package.h" -#include "chrome/installer/util/package_properties.h" -#include "chrome/installer/util/product.h" -#include "chrome/installer/util/product_unittest.h" -#include "chrome/installer/util/util_constants.h" - -using base::win::RegKey; -using installer::ChromePackageProperties; -using installer::ChromiumPackageProperties; -using installer::Package; -using installer::Product; -using installer::MasterPreferences; - -class PackageTest : public TestWithTempDirAndDeleteTempOverrideKeys { - protected: -}; - -// Tests a few basic things of the Package class. Makes sure that the path -// operations are correct -TEST_F(PackageTest, Basic) { - const bool multi_install = false; - const bool system_level = true; - ChromiumPackageProperties properties; - scoped_refptr<Package> package(new Package(multi_install, system_level, - test_dir_.path(), &properties)); - EXPECT_EQ(test_dir_.path().value(), package->path().value()); - EXPECT_TRUE(package->IsEqual(test_dir_.path())); - EXPECT_EQ(0U, package->products().size()); - - const char kOldVersion[] = "1.2.3.4"; - const char kNewVersion[] = "2.3.4.5"; - - scoped_ptr<Version> new_version(Version::GetVersionFromString(kNewVersion)); - scoped_ptr<Version> old_version(Version::GetVersionFromString(kOldVersion)); - ASSERT_TRUE(new_version.get() != NULL); - ASSERT_TRUE(old_version.get() != NULL); - - FilePath installer_dir(package->GetInstallerDirectory(*new_version.get())); - EXPECT_FALSE(installer_dir.empty()); - - FilePath new_version_dir(package->path().Append( - UTF8ToWide(new_version->GetString()))); - FilePath old_version_dir(package->path().Append( - UTF8ToWide(old_version->GetString()))); - - EXPECT_FALSE(file_util::PathExists(new_version_dir)); - EXPECT_FALSE(file_util::PathExists(old_version_dir)); - - EXPECT_FALSE(file_util::PathExists(installer_dir)); - file_util::CreateDirectory(installer_dir); - EXPECT_TRUE(file_util::PathExists(new_version_dir)); - - file_util::CreateDirectory(old_version_dir); - EXPECT_TRUE(file_util::PathExists(old_version_dir)); - - // Create a fake chrome.dll key file in the old version directory. This - // should prevent the old version directory from getting deleted. - FilePath old_chrome_dll(old_version_dir.Append(installer::kChromeDll)); - EXPECT_FALSE(file_util::PathExists(old_chrome_dll)); - - // Hold on to the file exclusively to prevent the directory from - // being deleted. - base::win::ScopedHandle file( - ::CreateFile(old_chrome_dll.value().c_str(), GENERIC_READ, - 0, NULL, OPEN_ALWAYS, 0, NULL)); - EXPECT_TRUE(file.IsValid()); - EXPECT_TRUE(file_util::PathExists(old_chrome_dll)); - - package->RemoveOldVersionDirectories(*new_version.get()); - // The old directory should still exist. - EXPECT_TRUE(file_util::PathExists(old_version_dir)); - EXPECT_TRUE(file_util::PathExists(new_version_dir)); - - // Now close the file handle to make it possible to delete our key file. - file.Close(); - - package->RemoveOldVersionDirectories(*new_version.get()); - // The new directory should still exist. - EXPECT_TRUE(file_util::PathExists(new_version_dir)); - - // Now, the old directory and key file should be gone. - EXPECT_FALSE(file_util::PathExists(old_chrome_dll)); - EXPECT_FALSE(file_util::PathExists(old_version_dir)); -} - -TEST_F(PackageTest, WithProduct) { - const MasterPreferences& prefs = MasterPreferences::ForCurrentProcess(); - - // TODO(tommi): We should mock this and use our mocked distribution. - const bool multi_install = false; - const bool system_level = true; - BrowserDistribution* distribution = - BrowserDistribution::GetSpecificDistribution( - BrowserDistribution::CHROME_BROWSER, prefs); - ChromePackageProperties properties; - scoped_refptr<Package> package(new Package(multi_install, system_level, - test_dir_.path(), &properties)); - scoped_refptr<Product> product(new Product(distribution, package.get())); - EXPECT_EQ(1U, package->products().size()); - EXPECT_EQ(system_level, package->system_level()); - - const char kCurrentVersion[] = "1.2.3.4"; - scoped_ptr<Version> current_version( - Version::GetVersionFromString(kCurrentVersion)); - - HKEY root = system_level ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER; - { - TempRegKeyOverride override(root, L"root_pit"); - RegKey chrome_key(root, distribution->GetVersionKey().c_str(), - KEY_ALL_ACCESS); - EXPECT_TRUE(chrome_key.Valid()); - if (chrome_key.Valid()) { - chrome_key.WriteValue(google_update::kRegVersionField, - UTF8ToWide(current_version->GetString()).c_str()); - // TODO(tommi): Also test for when there exists a new_chrome.exe. - scoped_ptr<Version> found_version(package->GetCurrentVersion()); - EXPECT_TRUE(found_version.get() != NULL); - if (found_version.get()) { - EXPECT_TRUE(current_version->Equals(*found_version)); - } - } - } -} - -namespace { -bool SetUninstallArguments(HKEY root, BrowserDistribution* dist, - const CommandLine& args) { - RegKey key(root, dist->GetStateKey().c_str(), KEY_ALL_ACCESS); - return (key.WriteValue(installer::kUninstallArgumentsField, - args.command_line_string().c_str()) == ERROR_SUCCESS); -} - -bool SetInstalledVersion(HKEY root, BrowserDistribution* dist, - const std::wstring& version) { - RegKey key(root, dist->GetVersionKey().c_str(), KEY_ALL_ACCESS); - return (key.WriteValue(google_update::kRegVersionField, version.c_str()) == - ERROR_SUCCESS); -} -} // end namespace - -TEST_F(PackageTest, Dependency) { - const bool multi_install = false; - const bool system_level = true; - HKEY root = system_level ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER; - TempRegKeyOverride override(root, L"root_dep"); - - ChromePackageProperties properties; - scoped_refptr<Package> package(new Package(multi_install, system_level, - test_dir_.path(), &properties)); - EXPECT_EQ(0U, package->GetMultiInstallDependencyCount()); - - const MasterPreferences& prefs = MasterPreferences::ForCurrentProcess(); - - BrowserDistribution* chrome = BrowserDistribution::GetSpecificDistribution( - BrowserDistribution::CHROME_BROWSER, prefs); - BrowserDistribution* cf = BrowserDistribution::GetSpecificDistribution( - BrowserDistribution::CHROME_FRAME, prefs); - - CommandLine multi_uninstall_cmd(CommandLine::NO_PROGRAM); - multi_uninstall_cmd.AppendSwitch(installer::switches::kUninstall); - multi_uninstall_cmd.AppendSwitch(installer::switches::kMultiInstall); - - CommandLine single_uninstall_cmd(CommandLine::NO_PROGRAM); - single_uninstall_cmd.AppendSwitch(installer::switches::kUninstall); - - // "install" Chrome. - SetUninstallArguments(root, chrome, multi_uninstall_cmd); - SetInstalledVersion(root, chrome, L"1.2.3.4"); - EXPECT_EQ(1U, package->GetMultiInstallDependencyCount()); - - // "install" Chrome Frame without multi-install. - SetUninstallArguments(root, cf, single_uninstall_cmd); - SetInstalledVersion(root, cf, L"1.2.3.4"); - EXPECT_EQ(1U, package->GetMultiInstallDependencyCount()); - - // "install" Chrome Frame with multi-install. - SetUninstallArguments(root, cf, multi_uninstall_cmd); - EXPECT_EQ(2U, package->GetMultiInstallDependencyCount()); -} diff --git a/chrome/installer/util/product.cc b/chrome/installer/util/product.cc index de56027..a1e99f6 100644 --- a/chrome/installer/util/product.cc +++ b/chrome/installer/util/product.cc @@ -10,74 +10,70 @@ #include "base/logging.h" #include "base/process_util.h" #include "base/win/registry.h" +#include "chrome/installer/util/chrome_browser_operations.h" +#include "chrome/installer/util/chrome_browser_sxs_operations.h" +#include "chrome/installer/util/chrome_frame_operations.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/master_preferences.h" #include "chrome/installer/util/master_preferences_constants.h" -#include "chrome/installer/util/package_properties.h" +#include "chrome/installer/util/product_operations.h" using base::win::RegKey; using installer::MasterPreferences; -namespace { -class ProductIsOfType { - public: - explicit ProductIsOfType(BrowserDistribution::Type type) - : type_(type) { } - bool operator()( - const scoped_refptr<const installer::Product>& pi) const { - return pi->distribution()->GetType() == type_; - } - private: - BrowserDistribution::Type type_; -}; // class ProductIsOfType -} // end namespace - namespace installer { -const Product* FindProduct(const Products& products, - BrowserDistribution::Type type) { - Products::const_iterator i = - std::find_if(products.begin(), products.end(), ProductIsOfType(type)); - return i == products.end() ? NULL : *i; +Product::Product(BrowserDistribution* distribution) + : distribution_(distribution) { + switch (distribution->GetType()) { + case BrowserDistribution::CHROME_BROWSER: + operations_.reset(InstallUtil::IsChromeSxSProcess() ? + new ChromeBrowserSxSOperations() : + new ChromeBrowserOperations()); + break; + case BrowserDistribution::CHROME_FRAME: + operations_.reset(new ChromeFrameOperations()); + break; + default: + NOTREACHED() << "Unsupported BrowserDistribution::Type: " + << distribution->GetType(); + } } -//////////////////////////////////////////////////////////////////////////////// +Product::~Product() { +} -Product::Product(BrowserDistribution* distribution, Package* package) - : distribution_(distribution), - package_(package), - msi_(false), - cache_state_(0) { - package_->AssociateProduct(this); +void Product::InitializeFromPreferences(const MasterPreferences& prefs) { + operations_->ReadOptions(prefs, &options_); } -const Package& Product::package() const { - return *package_.get(); +void Product::InitializeFromUninstallCommand( + const CommandLine& uninstall_command) { + operations_->ReadOptions(uninstall_command, &options_); } FilePath Product::GetUserDataPath() const { return GetChromeUserDataPath(distribution_); } -bool Product::LaunchChrome() const { - const FilePath& install_package = package_->path(); - bool success = !install_package.empty(); +bool Product::LaunchChrome(const FilePath& application_path) const { + bool success = !application_path.empty(); if (success) { - CommandLine cmd(install_package.Append(installer::kChromeExe)); + CommandLine cmd(application_path.Append(installer::kChromeExe)); success = base::LaunchApp(cmd, false, false, NULL); } return success; } -bool Product::LaunchChromeAndWait(const CommandLine& options, +bool Product::LaunchChromeAndWait(const FilePath& application_path, + const CommandLine& options, int32* exit_code) const { - const FilePath& install_package = package_->path(); - if (install_package.empty()) + if (application_path.empty()) return false; - CommandLine cmd(install_package.Append(installer::kChromeExe)); + CommandLine cmd(application_path.Append(installer::kChromeExe)); cmd.AppendArguments(options, false); bool success = false; @@ -113,36 +109,8 @@ bool Product::LaunchChromeAndWait(const CommandLine& options, return success; } -bool Product::IsMsi() const { - if ((cache_state_ & MSI_STATE) == 0) { - msi_ = false; // Covers failure cases below. - - const MasterPreferences& prefs = MasterPreferences::ForCurrentProcess(); - - bool is_msi = false; - prefs.GetBool(installer::master_preferences::kMsi, &is_msi); - - if (!is_msi) { - // We didn't find it in the preferences, try looking in the registry. - HKEY reg_root = system_level() ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER; - RegKey key; - if (key.Open(reg_root, distribution_->GetStateKey().c_str(), - KEY_READ) == ERROR_SUCCESS) { - DWORD msi_value = 0; - key.ReadValueDW(google_update::kRegMSIField, &msi_value); - msi_ = msi_value != 0; - } - } else { - msi_ = true; - } - cache_state_ |= MSI_STATE; - } - - return msi_; -} - -bool Product::SetMsiMarker(bool set) const { - HKEY reg_root = system_level() ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER; +bool Product::SetMsiMarker(bool system_install, bool set) const { + HKEY reg_root = system_install ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER; RegKey client_state_key; LONG result = client_state_key.Open(reg_root, distribution_->GetStateKey().c_str(), KEY_READ | KEY_WRITE); @@ -158,92 +126,23 @@ bool Product::SetMsiMarker(bool set) const { } bool Product::ShouldCreateUninstallEntry() const { - if (IsMsi()) { - // MSI installations will manage their own uninstall shortcuts. - return false; - } - - return distribution_->ShouldCreateUninstallEntry(); -} - -/////////////////////////////////////////////////////////////////////////////// -ProductPackageMapping::ProductPackageMapping(bool multi_install, - bool system_level) - : package_properties_(new ActivePackageProperties()), - multi_install_(multi_install), - system_level_(system_level) { + return operations_->ShouldCreateUninstallEntry(options_); } -const Packages& ProductPackageMapping::packages() const { - return packages_; +void Product::AddKeyFiles(std::vector<FilePath>* key_files) const { + operations_->AddKeyFiles(options_, key_files); } -const Products& ProductPackageMapping::products() const { - return products_; +void Product::AddComDllList(std::vector<FilePath>* com_dll_list) const { + operations_->AddComDllList(options_, com_dll_list); } -bool ProductPackageMapping::AddDistribution(BrowserDistribution* distribution) { - DCHECK(distribution); - // Each product type can be added exactly once. - DCHECK(FindProduct(products_, distribution->GetType()) == NULL); - - FilePath install_package; - if (distribution->GetType() == BrowserDistribution::CHROME_BROWSER) { - install_package = GetChromeInstallPath(system_level_, distribution); - } else { - DCHECK_EQ(BrowserDistribution::CHROME_FRAME, distribution->GetType()); - install_package = GetChromeFrameInstallPath(multi_install_, system_level_, - distribution); - } - - if (install_package.empty()) { - LOG(ERROR) << "Got an empty installation path for " - << distribution->GetApplicationName() - << ". It's likely that there's a conflicting " - "installation present"; - return false; - } - - scoped_refptr<Package> target_package; - for (size_t i = 0; i < packages_.size(); ++i) { - if (packages_[i]->IsEqual(install_package)) { - // Use an existing Package. - target_package = packages_[i]; - break; - } - } - - if (!target_package.get()) { - DCHECK(packages_.empty()) << "Multiple packages per run unsupported."; - // create new one and add. - target_package = new Package(multi_install_, system_level_, install_package, - package_properties_.get()); - packages_.push_back(target_package); - } - - scoped_refptr<Product> product(new Product(distribution, target_package)); -#ifndef NDEBUG - for (size_t i = 0; i < products_.size(); ++i) { - DCHECK_EQ(product->IsMsi(), products_[i]->IsMsi()); - } -#endif - products_.push_back(product); - - return true; +void Product::AppendProductFlags(CommandLine* command_line) const { + operations_->AppendProductFlags(options_, command_line); } -bool ProductPackageMapping::AddDistribution( - BrowserDistribution::Type type, - const MasterPreferences& prefs) { - BrowserDistribution* distribution = - BrowserDistribution::GetSpecificDistribution(type, prefs); - if (!distribution) { - NOTREACHED(); - return false; - } - - return AddDistribution(distribution); +bool Product::SetChannelFlags(bool set, ChannelInfo* channel_info) const { + return operations_->SetChannelFlags(options_, set, channel_info); } } // namespace installer - diff --git a/chrome/installer/util/product.h b/chrome/installer/util/product.h index 28361df..86d3fca 100644 --- a/chrome/installer/util/product.h +++ b/chrome/installer/util/product.h @@ -6,30 +6,20 @@ #define CHROME_INSTALLER_UTIL_PRODUCT_H_ #pragma once +#include <set> +#include <string> #include <vector> -#include "base/ref_counted.h" #include "base/scoped_ptr.h" #include "chrome/installer/util/browser_distribution.h" -#include "chrome/installer/util/package.h" class CommandLine; namespace installer { -class MasterPreferences; -} - -namespace installer { +class MasterPreferences; class Product; -class Package; -class PackageProperties; - -typedef std::vector<scoped_refptr<Package> > Packages; -typedef std::vector<scoped_refptr<const Product> > Products; - -const Product* FindProduct(const Products& products, - BrowserDistribution::Type type); +class ProductOperations; // Represents an installation of a specific product which has a one-to-one // relation to a BrowserDistribution. A product has registry settings, related @@ -40,23 +30,22 @@ const Product* FindProduct(const Products& products, // the future, as we move away from global functions and towards a data driven // installation, each distribution could derive from this class and provide // distribution specific functionality. -class Product : public base::RefCounted<Product> { +class Product { public: - Product(BrowserDistribution* distribution, Package* installation_package); + explicit Product(BrowserDistribution* distribution); + + ~Product(); + + void InitializeFromPreferences(const MasterPreferences& prefs); + + void InitializeFromUninstallCommand(const CommandLine& uninstall_command); BrowserDistribution* distribution() const { return distribution_; } - // Returns the install package object for the installation of this product. - // If the product is installed at system level,the function returns a system - // wide location (ProgramFiles\Google). Otherwise it returns a package in a - // user specific location (Users\<user>\Local Settings...) - const Package& package() const; - - // Convenience getter for package().system_level(). - bool system_level() const { - return package().system_level(); + bool is_type(BrowserDistribution::Type type) const { + return distribution_->GetType() == type; } bool is_chrome() const { @@ -67,6 +56,18 @@ class Product : public base::RefCounted<Product> { return distribution_->GetType() == BrowserDistribution::CHROME_FRAME; } + bool HasOption(const std::wstring& option) const { + return options_.find(option) != options_.end(); + } + + // Returns true if the set of options is mutated by this operation. + bool SetOption(const std::wstring& option, bool set) { + if (set) + return options_.insert(option).second; + else + return options_.erase(option) != 0; + } + // Returns the path to the directory that holds the user data. This is always // inside "Users\<user>\Local Settings". Note that this is the default user // data directory and does not take into account that it can be overriden with @@ -74,7 +75,7 @@ class Product : public base::RefCounted<Product> { FilePath GetUserDataPath() const; // Launches Chrome without waiting for it to exit. - bool LaunchChrome() const; + bool LaunchChrome(const FilePath& application_path) const; // Launches Chrome with given command line, waits for Chrome indefinitely // (until it terminates), and gets the process exit code if available. @@ -82,77 +83,44 @@ class Product : public base::RefCounted<Product> { // The status of Chrome at the return of the function is given by exit_code. // NOTE: The 'options' CommandLine object should only contain parameters. // The program part will be ignored. - bool LaunchChromeAndWait(const CommandLine& options, int32* exit_code) const; - - // Returns true if this setup process is running as an install managed by an - // MSI wrapper. There are three things that are checked: - // 1) the presence of --msi on the command line - // 2) the presence of "msi": true in the master preferences file - // 3) the presence of a DWORD value in the ClientState key called msi with - // value 1 - bool IsMsi() const; + bool LaunchChromeAndWait(const FilePath& application_path, + const CommandLine& options, + int32* exit_code) const; // Sets the boolean MSI marker for this installation if set is true or clears // it otherwise. The MSI marker is stored in the registry under the // ClientState key. - bool SetMsiMarker(bool set) const; + bool SetMsiMarker(bool system_install, bool set) const; // Returns true if setup should create an entry in the Add/Remove list // of installed applications. bool ShouldCreateUninstallEntry() const; + // See ProductOperations::AddKeyFiles. + void AddKeyFiles(std::vector<FilePath>* key_files) const; + + // See ProductOperations::AddComDllList. + void AddComDllList(std::vector<FilePath>* com_dll_list) const; + + // See ProductOperations::AppendProductFlags. + void AppendProductFlags(CommandLine* command_line) const; + + // See Productoperations::SetChannelFlags. + bool SetChannelFlags(bool set, ChannelInfo* channel_info) const; + protected: enum CacheStateFlags { MSI_STATE = 0x01 }; BrowserDistribution* distribution_; - scoped_refptr<Package> package_; - mutable bool msi_; - mutable uint8 cache_state_; + scoped_ptr<ProductOperations> operations_; + std::set<std::wstring> options_; private: - friend class base::RefCounted<Product>; - ~Product() { - } DISALLOW_COPY_AND_ASSIGN(Product); }; -// A collection of Product objects and related physical installation -// packages. Each Product is associated with a single installation -// package object, and each package object is associated with one or more -// Product objects. -class ProductPackageMapping { - public: - explicit ProductPackageMapping(bool multi_install, bool system_level); - - bool multi_install() const { - return multi_install_; - } - - bool system_level() const { - return system_level_; - } - - const Packages& packages() const; - - const Products& products() const; - - bool AddDistribution(BrowserDistribution::Type type, - const installer::MasterPreferences& prefs); - bool AddDistribution(BrowserDistribution* distribution); - - protected: - bool multi_install_; - bool system_level_; - Packages packages_; - Products products_; - scoped_ptr<PackageProperties> package_properties_; - - private: - DISALLOW_COPY_AND_ASSIGN(ProductPackageMapping); -}; - } // namespace installer #endif // CHROME_INSTALLER_UTIL_PRODUCT_H_ diff --git a/chrome/installer/util/product_operations.h b/chrome/installer/util/product_operations.h new file mode 100644 index 0000000..0874d3d --- /dev/null +++ b/chrome/installer/util/product_operations.h @@ -0,0 +1,74 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_INSTALLER_UTIL_PRODUCT_OPERATIONS_H_ +#define CHROME_INSTALLER_UTIL_PRODUCT_OPERATIONS_H_ +#pragma once + +#include <set> +#include <string> +#include <vector> + +#include "base/file_path.h" + +class CommandLine; + +namespace installer { + +class ChannelInfo; +class MasterPreferences; + +// An interface to product-specific operations that depend on product +// configuration. Implementations are expected to be stateless. Configuration +// can be read from a MasterPreferences instance or from a product's uninstall +// command. +class ProductOperations { + public: + virtual ~ProductOperations() {} + + // Reads product-specific options from |prefs|, adding them to |options|. + virtual void ReadOptions(const MasterPreferences& prefs, + std::set<std::wstring>* options) const = 0; + + // Reads product-specific options from |command|, adding them to |options|. + virtual void ReadOptions(const CommandLine& command, + std::set<std::wstring>* options) const = 0; + + // A key-file is a file such as a DLL on Windows that is expected to be in use + // when the product is being used. For example "chrome.dll" for Chrome. + // Before attempting to delete an installation directory during an + // uninstallation, the uninstaller will check if any one of a potential set of + // key files is in use and if they are, abort the delete operation. Only if + // none of the key files are in use, can the folder be deleted. Note that + // this function does not return a full path to the key file(s), only (a) file + // name(s). + virtual void AddKeyFiles(const std::set<std::wstring>& options, + std::vector<FilePath>* key_files) const = 0; + + // Adds to |com_dll_list| the list of COM DLLs that are to be registered + // and/or unregistered. The list may be empty. + virtual void AddComDllList(const std::set<std::wstring>& options, + std::vector<FilePath>* com_dll_list) const = 0; + + // Given a command line, appends the set of uninstall flags the uninstaller + // for this product will require. + virtual void AppendProductFlags(const std::set<std::wstring>& options, + CommandLine* uninstall_command) const = 0; + + // Adds or removes product-specific flags in |channel_info|. Returns true if + // |channel_info| is modified. + virtual bool SetChannelFlags(const std::set<std::wstring>& options, + bool set, + ChannelInfo* channel_info) const = 0; + + // Returns true if setup should create an entry in the Add/Remove list + // of installed applications for this product. This does not test for use of + // MSI; see InstallerState::is_msi. + virtual bool ShouldCreateUninstallEntry( + const std::set<std::wstring>& options) const = 0; +}; + +} // namespace installer + +#endif // CHROME_INSTALLER_UTIL_PRODUCT_OPERATIONS_H_ diff --git a/chrome/installer/util/product_state_unittest.cc b/chrome/installer/util/product_state_unittest.cc new file mode 100644 index 0000000..c6031359 --- /dev/null +++ b/chrome/installer/util/product_state_unittest.cc @@ -0,0 +1,416 @@ +// Copyright (c) 2011 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 <windows.h> + +#include "base/utf_string_conversions.h" +#include "base/version.h" +#include "base/win/registry.h" +#include "chrome/installer/util/browser_distribution.h" +#include "chrome/installer/util/google_update_constants.h" +#include "chrome/installer/util/installation_state.h" +#include "chrome/installer/util/product_unittest.h" +#include "chrome/installer/util/util_constants.h" +#include "testing/gtest/include/gtest/gtest.h" + +using base::win::RegKey; +using installer::ProductState; + +class ProductStateTest : public testing::Test { + protected: + static void SetUpTestCase(); + static void TearDownTestCase(); + + virtual void SetUp(); + virtual void TearDown(); + + void ApplyUninstallCommand(const wchar_t* exe_path, const wchar_t* args); + void MinimallyInstallProduct(const wchar_t* version); + + static BrowserDistribution* dist_; + static std::wstring temp_key_path_; + bool system_install_; + HKEY overridden_; + RegKey clients_; + RegKey client_state_; +}; + +BrowserDistribution* ProductStateTest::dist_; +std::wstring ProductStateTest::temp_key_path_; + +// static +void ProductStateTest::SetUpTestCase() { + testing::Test::SetUpTestCase(); + + // We'll use Chrome as our test subject. + dist_ = BrowserDistribution::GetSpecificDistribution( + BrowserDistribution::CHROME_BROWSER); + + // And we'll play in HKCU here: + temp_key_path_.assign(TempRegKeyOverride::kTempTestKeyPath) + .append(1, L'\\') + .append(L"ProductStateTest"); +} + +// static +void ProductStateTest::TearDownTestCase() { + temp_key_path_.clear(); + dist_ = NULL; + + testing::Test::TearDownTestCase(); +} + +void ProductStateTest::SetUp() { + testing::Test::SetUp(); + + // Create/open the keys for the product we'll test. + system_install_ = true; + overridden_ = (system_install_ ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER); + + // Override for test purposes. We don't use TempRegKeyOverride + // directly because it doesn't suit itself to our use here. + RegKey temp_key; + EXPECT_EQ(ERROR_SUCCESS, + temp_key.Create(HKEY_CURRENT_USER, temp_key_path_.c_str(), + KEY_ALL_ACCESS)); + EXPECT_EQ(ERROR_SUCCESS, + ::RegOverridePredefKey(overridden_, temp_key.Handle())); + + EXPECT_EQ(ERROR_SUCCESS, + clients_.Create(overridden_, dist_->GetVersionKey().c_str(), + KEY_ALL_ACCESS)); + EXPECT_EQ(ERROR_SUCCESS, + client_state_.Create(overridden_, dist_->GetStateKey().c_str(), + KEY_ALL_ACCESS)); +} + +void ProductStateTest::TearDown() { + // Done with the keys. + client_state_.Close(); + clients_.Close(); + EXPECT_EQ(ERROR_SUCCESS, ::RegOverridePredefKey(overridden_, NULL)); + overridden_ = NULL; + system_install_ = false; + + // Shotgun approach to clearing out data we may have written. + TempRegKeyOverride::DeleteAllTempKeys(); + + testing::Test::TearDown(); +} + +void ProductStateTest::MinimallyInstallProduct(const wchar_t* version) { + EXPECT_EQ(ERROR_SUCCESS, + clients_.WriteValue(google_update::kRegVersionField, version)); +} + +void ProductStateTest::ApplyUninstallCommand(const wchar_t* exe_path, + const wchar_t* args) { + if (exe_path == NULL) { + LONG result = client_state_.DeleteValue(installer::kUninstallStringField); + EXPECT_TRUE(result == ERROR_SUCCESS || result == ERROR_FILE_NOT_FOUND); + } else { + EXPECT_EQ(ERROR_SUCCESS, + client_state_.WriteValue(installer::kUninstallStringField, + exe_path)); + } + + if (args == NULL) { + LONG result = + client_state_.DeleteValue(installer::kUninstallArgumentsField); + EXPECT_TRUE(result == ERROR_SUCCESS || result == ERROR_FILE_NOT_FOUND); + } else { + EXPECT_EQ(ERROR_SUCCESS, + client_state_.WriteValue(installer::kUninstallArgumentsField, + args)); + } +} + +TEST_F(ProductStateTest, InitializeInstalled) { + // Not installed. + { + ProductState state; + LONG result = clients_.DeleteValue(google_update::kRegVersionField); + EXPECT_TRUE(result == ERROR_SUCCESS || result == ERROR_FILE_NOT_FOUND); + EXPECT_FALSE(state.Initialize(system_install_, dist_)); + } + + // Empty version. + { + ProductState state; + LONG result = clients_.WriteValue(google_update::kRegVersionField, L""); + EXPECT_TRUE(result == ERROR_SUCCESS || result == ERROR_FILE_NOT_FOUND); + EXPECT_FALSE(state.Initialize(system_install_, dist_)); + } + + // Bogus version. + { + ProductState state; + LONG result = clients_.WriteValue(google_update::kRegVersionField, + L"goofy"); + EXPECT_TRUE(result == ERROR_SUCCESS || result == ERROR_FILE_NOT_FOUND); + EXPECT_FALSE(state.Initialize(system_install_, dist_)); + } + + // Valid "pv" value. + { + ProductState state; + LONG result = clients_.WriteValue(google_update::kRegVersionField, + L"10.0.47.0"); + EXPECT_TRUE(result == ERROR_SUCCESS || result == ERROR_FILE_NOT_FOUND); + EXPECT_TRUE(state.Initialize(system_install_, dist_)); + EXPECT_EQ("10.0.47.0", state.version().GetString()); + } +} + +// Test extraction of the "opv" value from the Clients key. +TEST_F(ProductStateTest, InitializeOldVersion) { + MinimallyInstallProduct(L"10.0.1.1"); + + // No "opv" value. + { + ProductState state; + LONG result = clients_.DeleteValue(google_update::kRegOldVersionField); + EXPECT_TRUE(result == ERROR_SUCCESS || result == ERROR_FILE_NOT_FOUND); + EXPECT_TRUE(state.Initialize(system_install_, dist_)); + EXPECT_TRUE(state.old_version() == NULL); + } + + // Empty "opv" value. + { + ProductState state; + LONG result = clients_.WriteValue(google_update::kRegOldVersionField, L""); + EXPECT_TRUE(result == ERROR_SUCCESS || result == ERROR_FILE_NOT_FOUND); + EXPECT_TRUE(state.Initialize(system_install_, dist_)); + EXPECT_TRUE(state.old_version() == NULL); + } + + // Bogus "opv" value. + { + ProductState state; + LONG result = clients_.WriteValue(google_update::kRegOldVersionField, + L"coming home"); + EXPECT_TRUE(result == ERROR_SUCCESS || result == ERROR_FILE_NOT_FOUND); + EXPECT_TRUE(state.Initialize(system_install_, dist_)); + EXPECT_TRUE(state.old_version() == NULL); + } + + // Valid "opv" value. + { + ProductState state; + LONG result = clients_.WriteValue(google_update::kRegOldVersionField, + L"10.0.47.0"); + EXPECT_TRUE(result == ERROR_SUCCESS || result == ERROR_FILE_NOT_FOUND); + EXPECT_TRUE(state.Initialize(system_install_, dist_)); + EXPECT_TRUE(state.old_version() != NULL); + EXPECT_EQ("10.0.47.0", state.old_version()->GetString()); + } +} + +// Test extraction of the "cmd" value from the Clients key. +TEST_F(ProductStateTest, InitializeRenameCmd) { + MinimallyInstallProduct(L"10.0.1.1"); + + // No "cmd" value. + { + ProductState state; + LONG result = clients_.DeleteValue(google_update::kRegRenameCmdField); + EXPECT_TRUE(result == ERROR_SUCCESS || result == ERROR_FILE_NOT_FOUND); + EXPECT_TRUE(state.Initialize(system_install_, dist_)); + EXPECT_TRUE(state.rename_cmd().empty()); + } + + // Empty "cmd" value. + { + ProductState state; + LONG result = clients_.WriteValue(google_update::kRegRenameCmdField, L""); + EXPECT_TRUE(result == ERROR_SUCCESS || result == ERROR_FILE_NOT_FOUND); + EXPECT_TRUE(state.Initialize(system_install_, dist_)); + EXPECT_TRUE(state.rename_cmd().empty()); + } + + // Valid "cmd" value. + { + ProductState state; + LONG result = clients_.WriteValue(google_update::kRegRenameCmdField, + L"spam.exe --spamalot"); + EXPECT_TRUE(result == ERROR_SUCCESS || result == ERROR_FILE_NOT_FOUND); + EXPECT_TRUE(state.Initialize(system_install_, dist_)); + EXPECT_EQ(L"spam.exe --spamalot", state.rename_cmd()); + } +} + +// Test extraction of the "ap" value from the ClientState key. +TEST_F(ProductStateTest, InitializeChannelInfo) { + MinimallyInstallProduct(L"10.0.1.1"); + + // No "ap" value. + { + ProductState state; + LONG result = client_state_.DeleteValue(google_update::kRegApField); + EXPECT_TRUE(result == ERROR_SUCCESS || result == ERROR_FILE_NOT_FOUND); + EXPECT_TRUE(state.Initialize(system_install_, dist_)); + EXPECT_TRUE(state.channel().value().empty()); + } + + // Empty "ap" value. + { + ProductState state; + LONG result = client_state_.WriteValue(google_update::kRegApField, L""); + EXPECT_TRUE(result == ERROR_SUCCESS || result == ERROR_FILE_NOT_FOUND); + EXPECT_TRUE(state.Initialize(system_install_, dist_)); + EXPECT_TRUE(state.channel().value().empty()); + } + + // Valid "ap" value. + { + ProductState state; + LONG result = client_state_.WriteValue(google_update::kRegApField, L"spam"); + EXPECT_TRUE(result == ERROR_SUCCESS || result == ERROR_FILE_NOT_FOUND); + EXPECT_TRUE(state.Initialize(system_install_, dist_)); + EXPECT_EQ(L"spam", state.channel().value()); + } +} + +// Test extraction of the uninstall command and arguments from the ClientState +// key. +TEST_F(ProductStateTest, InitializeUninstallCommand) { + MinimallyInstallProduct(L"10.0.1.1"); + + // No uninstall command. + { + ProductState state; + ApplyUninstallCommand(NULL, NULL); + EXPECT_TRUE(state.Initialize(system_install_, dist_)); + EXPECT_TRUE(state.GetSetupPath().empty()); + EXPECT_TRUE(state.uninstall_command().command_line_string().empty()); + EXPECT_EQ(0U, state.uninstall_command().GetSwitchCount()); + } + + // Empty values. + { + ProductState state; + ApplyUninstallCommand(L"", L""); + EXPECT_TRUE(state.Initialize(system_install_, dist_)); + EXPECT_TRUE(state.GetSetupPath().empty()); + EXPECT_TRUE(state.uninstall_command().command_line_string().empty()); + EXPECT_EQ(0U, state.uninstall_command().GetSwitchCount()); + } + + // Uninstall command without exe. + { + ProductState state; + ApplyUninstallCommand(NULL, L"--uninstall"); + EXPECT_TRUE(state.Initialize(system_install_, dist_)); + EXPECT_TRUE(state.GetSetupPath().empty()); + EXPECT_EQ(L"\"\" --uninstall", + state.uninstall_command().command_line_string()); + EXPECT_EQ(1U, state.uninstall_command().GetSwitchCount()); + } + + // Uninstall command without args. + { + ProductState state; + ApplyUninstallCommand(L"setup.exe", NULL); + EXPECT_TRUE(state.Initialize(system_install_, dist_)); + EXPECT_EQ(L"setup.exe", state.GetSetupPath().value()); + EXPECT_EQ(L"\"setup.exe\"", + state.uninstall_command().command_line_string()); + EXPECT_EQ(0U, state.uninstall_command().GetSwitchCount()); + } + + // Uninstall command with both exe and args. + { + ProductState state; + ApplyUninstallCommand(L"setup.exe", L"--uninstall"); + EXPECT_TRUE(state.Initialize(system_install_, dist_)); + EXPECT_EQ(L"setup.exe", state.GetSetupPath().value()); + EXPECT_EQ(L"\"setup.exe\" --uninstall", + state.uninstall_command().command_line_string()); + EXPECT_EQ(1U, state.uninstall_command().GetSwitchCount()); + } +} + +// Test extraction of the msi marker from the ClientState key. +TEST_F(ProductStateTest, InitializeMsi) { + MinimallyInstallProduct(L"10.0.1.1"); + + // No msi marker. + { + ProductState state; + LONG result = client_state_.DeleteValue(google_update::kRegMSIField); + EXPECT_TRUE(result == ERROR_SUCCESS || result == ERROR_FILE_NOT_FOUND); + EXPECT_TRUE(state.Initialize(system_install_, dist_)); + EXPECT_FALSE(state.is_msi()); + } + + // Msi marker set to zero. + { + ProductState state; + EXPECT_EQ(ERROR_SUCCESS, + client_state_.WriteValue(google_update::kRegMSIField, + static_cast<DWORD>(0))); + EXPECT_TRUE(state.Initialize(system_install_, dist_)); + EXPECT_FALSE(state.is_msi()); + } + + // Msi marker set to one. + { + ProductState state; + EXPECT_EQ(ERROR_SUCCESS, + client_state_.WriteValue(google_update::kRegMSIField, + static_cast<DWORD>(1))); + EXPECT_TRUE(state.Initialize(system_install_, dist_)); + EXPECT_TRUE(state.is_msi()); + } + + // Msi marker set to a bogus DWORD. + { + ProductState state; + EXPECT_EQ(ERROR_SUCCESS, + client_state_.WriteValue(google_update::kRegMSIField, + static_cast<DWORD>(47))); + EXPECT_TRUE(state.Initialize(system_install_, dist_)); + EXPECT_TRUE(state.is_msi()); + } + + // Msi marker set to a bogus string. + { + ProductState state; + EXPECT_EQ(ERROR_SUCCESS, + client_state_.WriteValue(google_update::kRegMSIField, + L"bogus!")); + EXPECT_TRUE(state.Initialize(system_install_, dist_)); + EXPECT_FALSE(state.is_msi()); + } +} + +// Test detection of multi-install. +TEST_F(ProductStateTest, InitializeMultiInstall) { + MinimallyInstallProduct(L"10.0.1.1"); + + // No uninstall command means single install. + { + ProductState state; + ApplyUninstallCommand(NULL, NULL); + EXPECT_TRUE(state.Initialize(system_install_, dist_)); + EXPECT_FALSE(state.is_multi_install()); + } + + // Uninstall command without --multi-install is single install. + { + ProductState state; + ApplyUninstallCommand(L"setup.exe", L"--uninstall"); + EXPECT_TRUE(state.Initialize(system_install_, dist_)); + EXPECT_FALSE(state.is_multi_install()); + } + + // Uninstall command with --multi-install is multi install. + { + ProductState state; + ApplyUninstallCommand(L"setup.exe", + L"--uninstall --chrome --multi-install"); + EXPECT_TRUE(state.Initialize(system_install_, dist_)); + EXPECT_TRUE(state.is_multi_install()); + } +} diff --git a/chrome/installer/util/product_unittest.cc b/chrome/installer/util/product_unittest.cc index c072dc5..913a6ff 100644 --- a/chrome/installer/util/product_unittest.cc +++ b/chrome/installer/util/product_unittest.cc @@ -9,17 +9,12 @@ #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/installer_state.h" #include "chrome/installer/util/master_preferences.h" #include "chrome/installer/util/product.h" using base::win::RegKey; -using installer::ChromePackageProperties; -using installer::ChromiumPackageProperties; -using installer::Package; using installer::Product; -using installer::ProductPackageMapping; using installer::MasterPreferences; void TestWithTempDir::SetUp() { @@ -82,15 +77,19 @@ TEST_F(ProductTest, ProductInstallBasic) { // TODO(tommi): We should mock this and use our mocked distribution. const bool multi_install = false; const bool system_level = true; - const installer::MasterPreferences& prefs = - installer::MasterPreferences::ForCurrentProcess(); - BrowserDistribution* distribution = - BrowserDistribution::GetSpecificDistribution( - BrowserDistribution::CHROME_BROWSER, prefs); - ChromePackageProperties properties; - scoped_refptr<Package> package(new Package(multi_install, system_level, - test_dir_.path(), &properties)); - scoped_refptr<Product> product(new Product(distribution, package.get())); + CommandLine cmd_line = CommandLine::FromString( + std::wstring(L"setup.exe") + + (multi_install ? L" --multi-install --chrome" : L"") + + (system_level ? L" --system-level" : L"")); + installer::MasterPreferences prefs(cmd_line); + installer::InstallationState machine_state; + machine_state.Initialize(); + installer::InstallerState installer_state; + installer_state.Initialize(cmd_line, prefs, machine_state); + + const Product* product = installer_state.products()[0]; + BrowserDistribution* distribution = product->distribution(); + EXPECT_EQ(BrowserDistribution::CHROME_BROWSER, distribution->GetType()); FilePath user_data(product->GetUserDataPath()); EXPECT_FALSE(user_data.empty()); @@ -104,35 +103,15 @@ TEST_F(ProductTest, ProductInstallBasic) { EXPECT_EQ(std::wstring::npos, user_data.value().find(program_files.value())); - // We started out with a non-msi product. - EXPECT_FALSE(product->IsMsi()); + // There should be no installed version in the registry. + machine_state.Initialize(); + EXPECT_TRUE(machine_state.GetProductState( + system_level, distribution->GetType()) == NULL); - HKEY root = system_level ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER; + HKEY root = installer_state.root_key(); { TempRegKeyOverride override(root, L"root_pit"); - // Create a make-believe client state key. - RegKey key; - std::wstring state_key_path(distribution->GetStateKey()); - ASSERT_EQ(ERROR_SUCCESS, - key.Create(root, state_key_path.c_str(), KEY_ALL_ACCESS)); - - // Set the MSI marker, delete the objects, create new ones and verify - // that we now see the MSI marker. - EXPECT_TRUE(product->SetMsiMarker(true)); - package = new Package(multi_install, system_level, test_dir_.path(), - &properties); - product = new Product(distribution, package.get()); - EXPECT_TRUE(product->IsMsi()); - - // There should be no installed version in the registry. - { - 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(), KEY_ALL_ACCESS); @@ -144,16 +123,30 @@ TEST_F(ProductTest, ProductInstallBasic) { version_key.WriteValue(google_update::kRegVersionField, UTF8ToWide(current_version->GetString()).c_str()); - { - 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())); - } + // We started out with a non-msi product. + machine_state.Initialize(); + const installer::ProductState* chrome_state = + machine_state.GetProductState(system_level, distribution->GetType()); + EXPECT_TRUE(chrome_state != NULL); + if (chrome_state != NULL) { + EXPECT_TRUE(chrome_state->version().Equals(*current_version.get())); + EXPECT_FALSE(chrome_state->is_msi()); } + + // Create a make-believe client state key. + RegKey key; + std::wstring state_key_path(distribution->GetStateKey()); + ASSERT_EQ(ERROR_SUCCESS, + key.Create(root, state_key_path.c_str(), KEY_ALL_ACCESS)); + + // Set the MSI marker, refresh, and verify that we now see the MSI marker. + EXPECT_TRUE(product->SetMsiMarker(system_level, true)); + machine_state.Initialize(); + chrome_state = + machine_state.GetProductState(system_level, distribution->GetType()); + EXPECT_TRUE(chrome_state != NULL); + if (chrome_state != NULL) + EXPECT_TRUE(chrome_state->is_msi()); } } @@ -162,41 +155,3 @@ TEST_F(ProductTest, LaunchChrome) { // Product::LaunchChromeAndWait. LOG(ERROR) << "Test not implemented."; } - -// Overrides ChromeFrameDistribution for the sole purpose of returning -// the Chrome (not Chrome Frame) installation path. -class FakeChromeFrameDistribution : public ChromeFrameDistribution { - public: - explicit FakeChromeFrameDistribution( - const installer::MasterPreferences& prefs) - : ChromeFrameDistribution(prefs) {} - virtual std::wstring GetInstallSubDir() { - const MasterPreferences& prefs = - installer::MasterPreferences::ForCurrentProcess(); - return BrowserDistribution::GetSpecificDistribution( - BrowserDistribution::CHROME_BROWSER, prefs)->GetInstallSubDir(); - } -}; - -TEST_F(ProductTest, ProductInstallsBasic) { - const bool multi_install = true; - const bool system_level = true; - ProductPackageMapping installs(multi_install, system_level); - EXPECT_EQ(multi_install, installs.multi_install()); - EXPECT_EQ(system_level, installs.system_level()); - EXPECT_EQ(0U, installs.packages().size()); - EXPECT_EQ(0U, installs.products().size()); - - // TODO(robertshield): Include test that use mock master preferences. - const MasterPreferences& prefs = - installer::MasterPreferences::ForCurrentProcess(); - - installs.AddDistribution(BrowserDistribution::CHROME_BROWSER, prefs); - FakeChromeFrameDistribution fake_chrome_frame(prefs); - installs.AddDistribution(&fake_chrome_frame); - EXPECT_EQ(2U, installs.products().size()); - // Since our fake Chrome Frame distribution class is reporting the same - // installation directory as Chrome, we should have only one package object. - EXPECT_EQ(1U, installs.packages().size()); - EXPECT_EQ(multi_install, installs.packages()[0]->multi_install()); -} diff --git a/chrome/installer/util/util_constants.cc b/chrome/installer/util/util_constants.cc index f59d6a4..39e47e9 100644 --- a/chrome/installer/util/util_constants.cc +++ b/chrome/installer/util/util_constants.cc @@ -177,4 +177,8 @@ const wchar_t kInstallerResultUIString[] = L"InstallerResultUIString"; const wchar_t kInstallerSuccessLaunchCmdLine[] = L"InstallerSuccessLaunchCmdLine"; +const wchar_t kOptionCeee[] = L"ceee"; +const wchar_t kOptionMultiInstall[] = L"multi-install"; +const wchar_t kOptionReadyMode[] = L"ready-mode"; + } // namespace installer diff --git a/chrome/installer/util/util_constants.h b/chrome/installer/util/util_constants.h index 5b2f230..9ca8900 100644 --- a/chrome/installer/util/util_constants.h +++ b/chrome/installer/util/util_constants.h @@ -66,6 +66,9 @@ enum InstallStatus { // Chrome Frame. READY_MODE_END_TEMP_OPT_OUT_FAILED, // 38. Failed to end temporary opt-out // of Chrome Frame. + CONFLICTING_CHANNEL_EXISTS, // 39. A multi-install product on a different + // update channel exists. + READY_MODE_REQUIRES_CHROME, // 40. Chrome Frame in ready-mode requires Chrome }; namespace switches { @@ -141,6 +144,11 @@ extern const wchar_t kInstallerError[]; extern const wchar_t kInstallerResultUIString[]; extern const wchar_t kInstallerSuccessLaunchCmdLine[]; +// Product options. +extern const wchar_t kOptionCeee[]; +extern const wchar_t kOptionMultiInstall[]; +extern const wchar_t kOptionReadyMode[]; + } // namespace installer #endif // CHROME_INSTALLER_UTIL_UTIL_CONSTANTS_H_ |