Commit 8f1179ec authored by grt's avatar grt Committed by Commit bot

Support migrating multi-install Chrome to single-install.

When run without "--multi-install", an update will properly convert
multi-install Chrome back to single-install.

BUG=452585
R=robertshield@chromium.org

Review URL: https://codereview.chromium.org/869153004

Cr-Commit-Position: refs/heads/master@{#313916}
parent 0e7f9e80
......@@ -974,6 +974,58 @@ void AddUsageStatsWorkItems(const InstallationState& original_state,
}
}
// Migrates the usagestats value from the binaries to Chrome when migrating
// multi-install Chrome to single-install.
void AddMigrateUsageStatesWorkItems(const InstallationState& original_state,
const InstallerState& installer_state,
WorkItemList* install_list) {
// Ensure that a non-multi install or update is being processed (i.e.,
// no "--multi-install" on the command line).
if (installer_state.is_multi_install())
return;
// Ensure that Chrome is the product being installed or updated (there are no
// other products, so it is especially unexpected for this to fail).
const Product* chrome_product =
installer_state.FindProduct(BrowserDistribution::CHROME_BROWSER);
if (!chrome_product) {
LOG(DFATAL) << "Not operating on Chrome while migrating to single-install.";
return;
}
const ProductState* chrome_state = original_state.GetProductState(
installer_state.system_install(),
BrowserDistribution::CHROME_BROWSER);
// Bail out if there is not an existing multi-install Chrome that is being
// updated.
if (!chrome_state || !chrome_state->is_multi_install()) {
VLOG(1) << "No multi-install Chrome found to migrate to single-install.";
return;
}
const ProductState* binaries_state = original_state.GetProductState(
installer_state.system_install(),
BrowserDistribution::CHROME_BINARIES);
// There is nothing to be done if the binaries do not have stats.
DWORD usagestats = 0;
if (!binaries_state || !binaries_state->GetUsageStats(&usagestats)) {
VLOG(1) << "No usagestats value found to migrate to single-install.";
return;
}
VLOG(1) << "Migrating usagestats value from multi-install to single-install.";
// Write the value that was read to Chrome's ClientState key.
install_list->AddSetRegValueWorkItem(
installer_state.root_key(),
chrome_product->distribution()->GetStateKey(),
KEY_WOW64_32KEY,
google_update::kRegUsageStatsField,
usagestats,
true);
}
bool AppendPostInstallTasks(const InstallerState& installer_state,
const base::FilePath& setup_path,
const Version* current_version,
......@@ -1189,6 +1241,16 @@ void AddInstallWorkItems(const InstallationState& original_state,
install_list);
}
// Ensure that the Clients key for the binaries is gone for single installs.
if (!installer_state.is_multi_install()) {
BrowserDistribution* binaries_dist =
BrowserDistribution::GetSpecificDistribution(
BrowserDistribution::CHROME_BINARIES);
install_list->AddDeleteRegKeyWorkItem(root,
binaries_dist->GetVersionKey(),
KEY_WOW64_32KEY);
}
#if defined(GOOGLE_CHROME_BUILD)
if (!InstallUtil::IsChromeSxSProcess())
AddRemoveLegacyAppCommandsWorkItems(installer_state, install_list);
......@@ -1207,6 +1269,9 @@ void AddInstallWorkItems(const InstallationState& original_state,
// Copy over brand, usagestats, and other values.
AddGoogleUpdateWorkItems(original_state, installer_state, install_list);
// Migrate usagestats back to Chrome.
AddMigrateUsageStatesWorkItems(original_state, installer_state, install_list);
// Append the tasks that run after the installation.
AppendPostInstallTasks(installer_state,
setup_path,
......
......@@ -414,25 +414,7 @@ bool CheckMultiInstallConditions(const InstallationState& original_state,
chrome = installer_state->AddProduct(&multi_chrome);
VLOG(1) << "Upgrading existing Chrome browser in multi-install mode.";
}
} else {
// This is a non-multi installation.
// Check for an existing installation of the product.
const ProductState* product_state = original_state.GetProductState(
system_level, products[0]->distribution()->GetType());
if (product_state != NULL) {
// Block downgrades from multi-install to single-install.
if (product_state->is_multi_install()) {
LOG(ERROR) << "Multi-install "
<< products[0]->distribution()->GetDisplayName()
<< " exists; aborting single install.";
*status = installer::MULTI_INSTALLATION_EXISTS;
installer_state->WriteInstallerResult(*status,
IDS_INSTALL_MULTI_INSTALLATION_EXISTS_BASE, NULL);
return false;
}
}
}
} // else migrate multi-install Chrome to single-install.
return true;
}
......@@ -1247,11 +1229,9 @@ void UninstallMultiChromeFrameIfPresent(const base::CommandLine& cmd_line,
const MasterPreferences& prefs,
InstallationState* original_state,
InstallerState* installer_state) {
// Early exit if not installing or updating multi-install product(s).
if (installer_state->operation() != InstallerState::MULTI_INSTALL &&
installer_state->operation() != InstallerState::MULTI_UPDATE) {
// Early exit if not installing or updating.
if (installer_state->operation() == InstallerState::UNINSTALL)
return;
}
// Early exit if Chrome Frame is not present as multi-install.
const ProductState* chrome_frame_state =
......
......@@ -11,13 +11,17 @@
#include <string>
#include "base/logging.h"
#include "base/strings/string16.h"
#include "base/strings/utf_string_conversions.h"
#include "base/version.h"
#include "base/win/registry.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/installer/util/browser_distribution.h"
#include "chrome/installer/util/google_update_constants.h"
#include "chrome/installer/util/helper.h"
#include "chrome/installer/util/install_util.h"
#include "chrome/installer/util/installation_state.h"
#include "chrome/installer/util/updating_app_registration_data.h"
namespace installer {
......@@ -552,6 +556,30 @@ bool InstallationValidator::ValidateInstallationTypeForState(
ProductBits::CHROME_SINGLE));
}
#if defined(GOOGLE_CHROME_BUILD)
if (!InstallUtil::IsChromeSxSProcess()) {
// Usage of the app launcher is tracked alongside Chrome.
const HKEY root_key = system_level ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER;
base::string16 launcher_key(
UpdatingAppRegistrationData(kAppLauncherGuid).GetVersionKey());
base::win::RegKey key(root_key, launcher_key.c_str(),
KEY_QUERY_VALUE | KEY_WOW64_32KEY);
bool have_launcher =
key.Valid() && key.HasValue(google_update::kRegVersionField);
BrowserDistribution* chrome_dist =
BrowserDistribution::GetSpecificDistribution(
BrowserDistribution::CHROME_BROWSER);
if (!have_launcher) {
LOG_IF(ERROR, product_state) << "App launcher is not installed with "
<< chrome_dist->GetDisplayName();
} else {
LOG_IF(ERROR, !product_state) << "App launcher is installed without "
<< chrome_dist->GetDisplayName();
}
}
#endif // GOOGLE_CHROME_BUILD
// Is Chrome Frame installed?
product_state =
machine_state.GetProductState(system_level,
......
......@@ -576,29 +576,15 @@ void InstallerState::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;
}
void InstallerState::UpdateStage(installer::InstallerStage stage) const {
InstallUtil::UpdateInstallerStage(system_install(), state_key_, stage);
}
void InstallerState::UpdateChannels() const {
if (operation_ != MULTI_INSTALL && operation_ != MULTI_UPDATE) {
VLOG(1) << "InstallerState::UpdateChannels noop: " << operation_;
return;
}
// Update the "ap" value for the product being installed/updated. We get the
// current value from the registry since the InstallationState instance used
// by the bulk of the installer does not track changes made by UpdateStage.
DCHECK_NE(UNINSTALL, operation_);
// Update the "ap" value for the product being installed/updated. Use the
// current value in the registry since the InstallationState instance used by
// the bulk of the installer does not track changes made by UpdateStage.
// Create the app's ClientState key if it doesn't exist.
ChannelInfo channel_info;
base::win::RegKey state_key;
......@@ -610,10 +596,18 @@ void InstallerState::UpdateChannels() const {
channel_info.Initialize(state_key);
// This is a multi-install product.
bool modified = channel_info.SetMultiInstall(true);
// Add the appropriate modifiers for all products and their options.
modified |= SetChannelFlags(true, &channel_info);
bool modified = channel_info.SetMultiInstall(is_multi_install());
if (is_multi_install()) {
// Add the appropriate modifiers for all products and their options.
for (auto* product : products_)
modified |= product->SetChannelFlags(true, &channel_info);
} else {
// Remove all multi-install products from the channel name.
modified |= channel_info.SetChrome(false);
modified |= channel_info.SetChromeFrame(false);
modified |= channel_info.SetAppLauncher(false);
}
VLOG(1) << "ap: " << channel_info.value();
......@@ -621,40 +615,42 @@ void InstallerState::UpdateChannels() const {
if (modified)
channel_info.Write(&state_key);
// Remove the -stage: modifier since we don't want to propagate that to the
// other app_guids.
channel_info.SetStage(NULL);
// Synchronize the other products and the package with this one.
ChannelInfo other_info;
for (int i = 0; i < BrowserDistribution::NUM_TYPES; ++i) {
BrowserDistribution::Type type =
static_cast<BrowserDistribution::Type>(i);
// Skip the app_guid we started with.
if (type == state_type_)
continue;
BrowserDistribution* dist = NULL;
// Always operate on the binaries.
if (i == BrowserDistribution::CHROME_BINARIES) {
dist = multi_package_distribution_;
} else {
const Product* product = FindProduct(type);
// Skip this one if it's for a product we're not operating on.
if (product == NULL)
if (is_multi_install()) {
// Remove the -stage: modifier since we don't want to propagate that to
// the other app_guids.
channel_info.SetStage(NULL);
// Synchronize the other products and the package with this one.
ChannelInfo other_info;
for (int i = 0; i < BrowserDistribution::NUM_TYPES; ++i) {
BrowserDistribution::Type type =
static_cast<BrowserDistribution::Type>(i);
// Skip the app_guid we started with.
if (type == state_type_)
continue;
dist = product->distribution();
}
result =
state_key.Create(root_key_,
dist->GetStateKey().c_str(),
KEY_QUERY_VALUE | KEY_SET_VALUE | KEY_WOW64_32KEY);
if (result == ERROR_SUCCESS) {
other_info.Initialize(state_key);
if (!other_info.Equals(channel_info))
channel_info.Write(&state_key);
} else {
LOG(ERROR) << "Failed opening key " << dist->GetStateKey()
<< " to update app channels; result: " << result;
BrowserDistribution* dist = NULL;
// Always operate on the binaries.
if (i == BrowserDistribution::CHROME_BINARIES) {
dist = multi_package_distribution_;
} else {
const Product* product = FindProduct(type);
// Skip this one if it's for a product we're not operating on.
if (product == NULL)
continue;
dist = product->distribution();
}
result =
state_key.Create(root_key_,
dist->GetStateKey().c_str(),
KEY_QUERY_VALUE | KEY_SET_VALUE | KEY_WOW64_32KEY);
if (result == ERROR_SUCCESS) {
other_info.Initialize(state_key);
if (!other_info.Equals(channel_info))
channel_info.Write(&state_key);
} else {
LOG(ERROR) << "Failed opening key " << dist->GetStateKey()
<< " to update app channels; result: " << result;
}
}
}
} else {
......
......@@ -186,8 +186,6 @@ class InstallerState {
// and/or unregistered. The list may be empty.
void AddComDllList(std::vector<base::FilePath>* com_dll_list) const;
bool SetChannelFlags(bool set, ChannelInfo* channel_info) const;
// See InstallUtil::UpdateInstallerStage.
void UpdateStage(installer::InstallerStage stage) const;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment