diff options
author | tommi@chromium.org <tommi@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-12-16 21:34:44 +0000 |
---|---|---|
committer | tommi@chromium.org <tommi@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-12-16 21:34:44 +0000 |
commit | 0c5f45a87e93ac32d037ea015f67bceafbd2e340 (patch) | |
tree | d877a78ba8ece1df301e6db8ebeca0905a47b7d9 /chrome/installer | |
parent | 87639f3ca70b43063316af530971bfdabbc86bec (diff) | |
download | chromium_src-0c5f45a87e93ac32d037ea015f67bceafbd2e340.zip chromium_src-0c5f45a87e93ac32d037ea015f67bceafbd2e340.tar.gz chromium_src-0c5f45a87e93ac32d037ea015f67bceafbd2e340.tar.bz2 |
Only delete the shared binaries when there are no installed products that depend on them.
BUG=61609
TEST=When more than one product is installed with the chrome binaries, the first product should not delete the binaries but the second one should.
Review URL: http://codereview.chromium.org/5875004
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@69468 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/installer')
-rw-r--r-- | chrome/installer/setup/uninstall.cc | 47 | ||||
-rw-r--r-- | chrome/installer/util/package.cc | 44 | ||||
-rw-r--r-- | chrome/installer/util/package.h | 7 | ||||
-rw-r--r-- | chrome/installer/util/package_unittest.cc | 48 |
4 files changed, 131 insertions, 15 deletions
diff --git a/chrome/installer/setup/uninstall.cc b/chrome/installer/setup/uninstall.cc index f9be2fa..c9bca0d 100644 --- a/chrome/installer/setup/uninstall.cc +++ b/chrome/installer/setup/uninstall.cc @@ -20,6 +20,7 @@ #include "chrome/installer/setup/install.h" #include "chrome/installer/setup/setup_constants.h" #include "chrome/installer/util/browser_distribution.h" +#include "chrome/installer/util/channel_info.h" #include "chrome/installer/util/delete_after_reboot_helper.h" #include "chrome/installer/util/helper.h" #include "chrome/installer/util/install_util.h" @@ -31,6 +32,7 @@ #include "registered_dlls.h" // NOLINT using base::win::RegKey; +using installer::ChannelInfo; using installer::InstallStatus; namespace installer { @@ -210,12 +212,6 @@ bool DeleteEmptyParentDir(const FilePath& path) { return ret; } -enum DeleteResult { - DELETE_SUCCEEDED, - DELETE_FAILED, - DELETE_REQUIRES_REBOOT -}; - FilePath GetLocalStateFolder(const Product& product) { // Obtain the location of the user profile data. Chrome Frame needs to // build this path manually since it doesn't use the Chrome default dir. @@ -244,6 +240,12 @@ FilePath BackupLocalStateFile(const FilePath& local_state_folder) { return backup; } +enum DeleteResult { + DELETE_SUCCEEDED, + DELETE_FAILED, + DELETE_REQUIRES_REBOOT, +}; + // Copies the local state to the temp folder and then deletes it. // The path to the copy is returned via the local_state_copy parameter. DeleteResult DeleteLocalState(const Product& product) { @@ -500,6 +502,17 @@ InstallStatus UninstallChrome(const FilePath& setup_path, VLOG(1) << "UninstallChrome: " << browser_dist->GetApplicationName(); + // Stash away information about the channel which the product is currently + // installed on. We'll need this later to determine if we should delete + // the binaries or not. + ChannelInfo channel_info; + { + HKEY root_key = product.system_level() ? HKEY_LOCAL_MACHINE : + HKEY_CURRENT_USER; + RegKey key(root_key, browser_dist->GetStateKey().c_str(), KEY_READ); + channel_info.Initialize(key); + } + if (force_uninstall) { // Since --force-uninstall command line option is used, we are going to // do silent uninstall. Try to close all running Chrome instances. @@ -627,10 +640,24 @@ InstallStatus UninstallChrome(const FilePath& setup_path, FilePath backup_state_file(BackupLocalStateFile( GetLocalStateFolder(product))); - // TODO(tommi): We should only do this when the last distribution is being - // uninstalled. - DeleteResult delete_result = DeleteFilesAndFolders(product.package(), - *installed_version); + // When deleting files, we must make sure that we're either a "single" + // (aka non-multi) installation or, in the case of multi, that no other + // "multi" products share the binaries we are about to delete. + + bool can_delete_files; + if (channel_info.IsMultiInstall()) { + can_delete_files = + (product.package().GetMultiInstallDependencyCount() == 0); + LOG(INFO) << (can_delete_files ? "Shared binaries will be deleted." : + "Shared binaries still in use."); + } else { + can_delete_files = true; + } + + DeleteResult delete_result = DELETE_SUCCEEDED; + if (can_delete_files) + delete_result = DeleteFilesAndFolders(product.package(), + *installed_version); if (delete_profile) DeleteLocalState(product); diff --git a/chrome/installer/util/package.cc b/chrome/installer/util/package.cc index 68e1a33..c2fff7b 100644 --- a/chrome/installer/util/package.cc +++ b/chrome/installer/util/package.cc @@ -8,12 +8,16 @@ #include "base/logging.h" #include "base/utf_string_conversions.h" #include "base/win/registry.h" +#include "chrome/installer/util/channel_info.h" #include "chrome/installer/util/delete_tree_work_item.h" #include "chrome/installer/util/google_update_constants.h" +#include "chrome/installer/util/master_preferences.h" #include "chrome/installer/util/package_properties.h" #include "chrome/installer/util/product.h" using base::win::RegKey; +using installer::ChannelInfo; +using installer::MasterPreferences; namespace installer { @@ -139,5 +143,45 @@ void Package::RemoveOldVersionDirectories( } } +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 { + RegKey key(root_key, dist->GetStateKey().c_str(), KEY_READ); + ChannelInfo channel_info; + if (channel_info.Initialize(key)) { + if (channel_info.IsMultiInstall()) { + VLOG(1) << "Product dependency: " << dist->GetApplicationName(); + ret++; + } else { + VLOG(1) << "Product is installed, but not multi: " + << dist->GetApplicationName(); + } + } else { + LOG(INFO) << "Product missing 'ap' value: " + << dist->GetApplicationName(); + } + } + } + + return ret; +} + } // namespace installer diff --git a/chrome/installer/util/package.h b/chrome/installer/util/package.h index d89baa6..c673825 100644 --- a/chrome/installer/util/package.h +++ b/chrome/installer/util/package.h @@ -61,6 +61,13 @@ class Package : public base::RefCounted<Package> { // 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 system_level_; FilePath path_; diff --git a/chrome/installer/util/package_unittest.cc b/chrome/installer/util/package_unittest.cc index b553a46..f1eda9c 100644 --- a/chrome/installer/util/package_unittest.cc +++ b/chrome/installer/util/package_unittest.cc @@ -6,6 +6,7 @@ #include "base/scoped_handle.h" #include "base/utf_string_conversions.h" #include "chrome/installer/util/browser_distribution.h" +#include "chrome/installer/util/channel_info.h" #include "chrome/installer/util/google_update_constants.h" #include "chrome/installer/util/master_preferences.h" #include "chrome/installer/util/package.h" @@ -16,10 +17,12 @@ using base::win::RegKey; using base::win::ScopedHandle; +using installer::ChannelInfo; using installer::ChromePackageProperties; using installer::ChromiumPackageProperties; using installer::Package; using installer::Product; +using installer::MasterPreferences; class PackageTest : public TestWithTempDirAndDeleteTempOverrideKeys { protected: @@ -92,10 +95,7 @@ TEST_F(PackageTest, Basic) { } TEST_F(PackageTest, WithProduct) { - TempRegKeyOverride::DeleteAllTempKeys(); - - const installer::MasterPreferences& prefs = - installer::MasterPreferences::ForCurrentProcess(); + const MasterPreferences& prefs = MasterPreferences::ForCurrentProcess(); // TODO(tommi): We should mock this and use our mocked distribution. const bool system_level = true; @@ -130,6 +130,44 @@ TEST_F(PackageTest, WithProduct) { } } } +} + +TEST_F(PackageTest, Dependency) { + const bool system_level = true; + HKEY root = system_level ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER; + TempRegKeyOverride override(root, L"root_dep"); - TempRegKeyOverride::DeleteAllTempKeys(); + ChromePackageProperties properties; + scoped_refptr<Package> package(new Package(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); + + // "install" Chrome. + RegKey chrome_version_key(root, chrome->GetVersionKey().c_str(), + KEY_ALL_ACCESS); + RegKey chrome_key(root, chrome->GetStateKey().c_str(), KEY_ALL_ACCESS); + ChannelInfo channel; + channel.set_value(L""); + channel.SetMultiInstall(true); + channel.Write(&chrome_key); + EXPECT_EQ(1U, package->GetMultiInstallDependencyCount()); + + // "install" Chrome Frame without multi-install. + RegKey cf_version_key(root, cf->GetVersionKey().c_str(), KEY_ALL_ACCESS); + RegKey cf_key(root, cf->GetStateKey().c_str(), KEY_ALL_ACCESS); + channel.SetMultiInstall(false); + channel.Write(&cf_key); + EXPECT_EQ(1U, package->GetMultiInstallDependencyCount()); + + // "install" Chrome Frame with multi-install. + channel.SetMultiInstall(true); + channel.Write(&cf_key); + EXPECT_EQ(2U, package->GetMultiInstallDependencyCount()); } |