summaryrefslogtreecommitdiffstats
path: root/chrome/installer
diff options
context:
space:
mode:
authortommi@chromium.org <tommi@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-12-16 21:34:44 +0000
committertommi@chromium.org <tommi@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-12-16 21:34:44 +0000
commit0c5f45a87e93ac32d037ea015f67bceafbd2e340 (patch)
treed877a78ba8ece1df301e6db8ebeca0905a47b7d9 /chrome/installer
parent87639f3ca70b43063316af530971bfdabbc86bec (diff)
downloadchromium_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.cc47
-rw-r--r--chrome/installer/util/package.cc44
-rw-r--r--chrome/installer/util/package.h7
-rw-r--r--chrome/installer/util/package_unittest.cc48
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());
}