blob: 87fb66eb8d75405158e40aa93dafb3faf8f44791 [file] [log] [blame]
// Copyright (c) 2012 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.
// Implementation of the installation validator.
#include "chrome/installer/util/installation_validator.h"
#include <algorithm>
#include <set>
#include <string>
#include "base/logging.h"
#include "base/strings/utf_string_conversions.h"
#include "base/version.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/installation_state.h"
namespace installer {
BrowserDistribution::Type
InstallationValidator::ChromeRules::distribution_type() const {
return BrowserDistribution::CHROME_BROWSER;
}
void InstallationValidator::ChromeRules::AddUninstallSwitchExpectations(
const ProductContext& ctx,
SwitchExpectations* expectations) const {
const bool is_multi_install =
ctx.state.uninstall_command().HasSwitch(switches::kMultiInstall);
// --chrome should be present for uninstall iff --multi-install. This wasn't
// the case in Chrome 10 (between r68996 and r72497), though, so consider it
// optional.
}
void InstallationValidator::ChromeRules::AddRenameSwitchExpectations(
const ProductContext& ctx,
SwitchExpectations* expectations) const {
const bool is_multi_install =
ctx.state.uninstall_command().HasSwitch(switches::kMultiInstall);
// --chrome should not be present for rename. It was for a time, so we'll be
// lenient so that mini_installer tests pass.
// --chrome-frame should never be present.
expectations->push_back(
std::make_pair(std::string(switches::kChromeFrame), false));
}
bool InstallationValidator::ChromeRules::UsageStatsAllowed(
const ProductContext& ctx) const {
// Products must not have usagestats consent values when multi-install
// (only the multi-install binaries may).
return !ctx.state.is_multi_install();
}
BrowserDistribution::Type
InstallationValidator::ChromeFrameRules::distribution_type() const {
return BrowserDistribution::CHROME_FRAME;
}
void InstallationValidator::ChromeFrameRules::AddUninstallSwitchExpectations(
const ProductContext& ctx,
SwitchExpectations* expectations) const {
// --chrome-frame must be present.
expectations->push_back(std::make_pair(std::string(switches::kChromeFrame),
true));
// --chrome must not be present.
expectations->push_back(std::make_pair(std::string(switches::kChrome),
false));
}
void InstallationValidator::ChromeFrameRules::AddRenameSwitchExpectations(
const ProductContext& ctx,
SwitchExpectations* expectations) const {
// --chrome-frame must be present for SxS rename.
expectations->push_back(std::make_pair(std::string(switches::kChromeFrame),
!ctx.state.is_multi_install()));
// --chrome must not be present.
expectations->push_back(std::make_pair(std::string(switches::kChrome),
false));
}
bool InstallationValidator::ChromeFrameRules::UsageStatsAllowed(
const ProductContext& ctx) const {
// Products must not have usagestats consent values when multi-install
// (only the multi-install binaries may).
return !ctx.state.is_multi_install();
}
BrowserDistribution::Type
InstallationValidator::ChromeAppHostRules::distribution_type() const {
return BrowserDistribution::CHROME_APP_HOST;
}
void InstallationValidator::ChromeAppHostRules::AddUninstallSwitchExpectations(
const ProductContext& ctx,
SwitchExpectations* expectations) const {
// --app-launcher must be present.
expectations->push_back(
std::make_pair(std::string(switches::kChromeAppLauncher), true));
// --chrome must not be present.
expectations->push_back(std::make_pair(std::string(switches::kChrome),
false));
// --chrome-frame must not be present.
expectations->push_back(std::make_pair(std::string(switches::kChromeFrame),
false));
}
void InstallationValidator::ChromeAppHostRules::AddRenameSwitchExpectations(
const ProductContext& ctx,
SwitchExpectations* expectations) const {
// TODO(erikwright): I guess there will be none?
}
bool InstallationValidator::ChromeAppHostRules::UsageStatsAllowed(
const ProductContext& ctx) const {
// App Host doesn't manage usage stats. The Chrome Binaries will.
return false;
}
BrowserDistribution::Type
InstallationValidator::ChromeBinariesRules::distribution_type() const {
return BrowserDistribution::CHROME_BINARIES;
}
void InstallationValidator::ChromeBinariesRules::AddUninstallSwitchExpectations(
const ProductContext& ctx,
SwitchExpectations* expectations) const {
NOTREACHED();
}
void InstallationValidator::ChromeBinariesRules::AddRenameSwitchExpectations(
const ProductContext& ctx,
SwitchExpectations* expectations) const {
NOTREACHED();
}
bool InstallationValidator::ChromeBinariesRules::UsageStatsAllowed(
const ProductContext& ctx) const {
// UsageStats consent values are always allowed on the binaries.
return true;
}
// static
const InstallationValidator::InstallationType
InstallationValidator::kInstallationTypes[] = {
NO_PRODUCTS,
CHROME_SINGLE,
CHROME_MULTI,
CHROME_FRAME_SINGLE,
CHROME_FRAME_SINGLE_CHROME_SINGLE,
CHROME_FRAME_SINGLE_CHROME_MULTI,
CHROME_FRAME_MULTI,
CHROME_FRAME_MULTI_CHROME_MULTI,
CHROME_APP_HOST,
CHROME_APP_HOST_CHROME_FRAME_SINGLE,
CHROME_APP_HOST_CHROME_FRAME_SINGLE_CHROME_MULTI,
CHROME_APP_HOST_CHROME_FRAME_MULTI,
CHROME_APP_HOST_CHROME_FRAME_MULTI_CHROME_MULTI,
CHROME_APP_HOST_CHROME_MULTI,
};
void InstallationValidator::ValidateAppCommandFlags(
const ProductContext& ctx,
const AppCommand& app_cmd,
const std::set<string16>& flags_exp,
const string16& name,
bool* is_valid) {
const struct {
const string16 exp_key;
bool val;
const char* msg;
} check_list[] = {
{google_update::kRegSendsPingsField,
app_cmd.sends_pings(),
"be configured to send pings"},
{google_update::kRegWebAccessibleField,
app_cmd.is_web_accessible(),
"be web accessible"},
{google_update::kRegAutoRunOnOSUpgradeField,
app_cmd.is_auto_run_on_os_upgrade(),
"be marked to run on OS upgrade"},
{google_update::kRegRunAsUserField,
app_cmd.is_run_as_user(),
"be marked to run as user"},
};
for (int i = 0; i < arraysize(check_list); ++i) {
bool expected = flags_exp.find(check_list[i].exp_key) != flags_exp.end();
if (check_list[i].val != expected) {
*is_valid = false;
LOG(ERROR) << ctx.dist->GetDisplayName() << ": "
<< name << " command should " << (expected ? "" : "not ")
<< check_list[i].msg << ".";
}
}
}
// Validates both "install-application" and "install-extension" depending on
// what is passed in.
void InstallationValidator::ValidateInstallCommand(
const ProductContext& ctx,
const AppCommand& app_cmd,
const wchar_t* expected_command,
const wchar_t* expected_app_name,
const char* expected_switch,
bool* is_valid) {
DCHECK(is_valid);
CommandLine cmd_line(CommandLine::FromString(app_cmd.command_line()));
string16 name(expected_command);
base::FilePath expected_path(
installer::GetChromeInstallPath(ctx.system_install, ctx.dist)
.Append(expected_app_name));
if (!base::FilePath::CompareEqualIgnoreCase(expected_path.value(),
cmd_line.GetProgram().value())) {
*is_valid = false;
LOG(ERROR) << name << "'s path is not "
<< expected_path.value() << ": "
<< cmd_line.GetProgram().value();
}
SwitchExpectations expected;
expected.push_back(std::make_pair(std::string(expected_switch), true));
ValidateCommandExpectations(ctx, cmd_line, expected, name, is_valid);
std::set<string16> flags_exp;
flags_exp.insert(google_update::kRegSendsPingsField);
flags_exp.insert(google_update::kRegWebAccessibleField);
flags_exp.insert(google_update::kRegRunAsUserField);
ValidateAppCommandFlags(ctx, app_cmd, flags_exp, name, is_valid);
}
// Validates the "install-application" Google Update product command.
void InstallationValidator::ValidateInstallAppCommand(
const ProductContext& ctx,
const AppCommand& app_cmd,
bool* is_valid) {
ValidateInstallCommand(ctx, app_cmd, kCmdInstallApp,
installer::kChromeAppHostExe,
::switches::kInstallFromWebstore, is_valid);
}
// Validates the "install-extension" Google Update product command.
void InstallationValidator::ValidateInstallExtensionCommand(
const ProductContext& ctx,
const AppCommand& app_cmd,
bool* is_valid) {
ValidateInstallCommand(ctx, app_cmd, kCmdInstallExtension,
installer::kChromeExe,
::switches::kLimitedInstallFromWebstore, is_valid);
}
// Validates the "on-os-upgrade" Google Update internal command.
void InstallationValidator::ValidateOnOsUpgradeCommand(
const ProductContext& ctx,
const AppCommand& app_cmd,
bool* is_valid) {
DCHECK(is_valid);
CommandLine cmd_line(CommandLine::FromString(app_cmd.command_line()));
string16 name(kCmdOnOsUpgrade);
ValidateSetupPath(ctx, cmd_line.GetProgram(), name, is_valid);
SwitchExpectations expected;
expected.push_back(std::make_pair(std::string(switches::kOnOsUpgrade), true));
expected.push_back(std::make_pair(std::string(switches::kSystemLevel),
ctx.system_install));
expected.push_back(std::make_pair(std::string(switches::kMultiInstall),
ctx.state.is_multi_install()));
// Expecting kChrome if and only if kMultiInstall.
expected.push_back(std::make_pair(std::string(switches::kChrome),
ctx.state.is_multi_install()));
ValidateCommandExpectations(ctx, cmd_line, expected, name, is_valid);
std::set<string16> flags_exp;
flags_exp.insert(google_update::kRegAutoRunOnOSUpgradeField);
ValidateAppCommandFlags(ctx, app_cmd, flags_exp, name, is_valid);
}
// Validates the "query-eula-acceptance" Google Update product command.
void InstallationValidator::ValidateQueryEULAAcceptanceCommand(
const ProductContext& ctx,
const AppCommand& app_cmd,
bool* is_valid) {
DCHECK(is_valid);
CommandLine cmd_line(CommandLine::FromString(app_cmd.command_line()));
string16 name(kCmdQueryEULAAcceptance);
ValidateSetupPath(ctx, cmd_line.GetProgram(), name, is_valid);
SwitchExpectations expected;
expected.push_back(std::make_pair(std::string(switches::kQueryEULAAcceptance),
true));
expected.push_back(std::make_pair(std::string(switches::kSystemLevel),
ctx.system_install));
ValidateCommandExpectations(ctx, cmd_line, expected, name, is_valid);
std::set<string16> flags_exp;
flags_exp.insert(google_update::kRegWebAccessibleField);
flags_exp.insert(google_update::kRegRunAsUserField);
ValidateAppCommandFlags(ctx, app_cmd, flags_exp, name, is_valid);
}
// Validates the "quick-enable-cf" Google Update product command.
void InstallationValidator::ValidateQuickEnableCfCommand(
const ProductContext& ctx,
const AppCommand& app_cmd,
bool* is_valid) {
DCHECK(is_valid);
CommandLine cmd_line(CommandLine::FromString(app_cmd.command_line()));
string16 name(kCmdQuickEnableCf);
ValidateSetupPath(ctx, cmd_line.GetProgram(), name, is_valid);
SwitchExpectations expected;
expected.push_back(
std::make_pair(std::string(switches::kChromeFrameQuickEnable), true));
expected.push_back(std::make_pair(std::string(switches::kSystemLevel),
ctx.system_install));
expected.push_back(std::make_pair(std::string(switches::kMultiInstall),
ctx.state.is_multi_install()));
ValidateCommandExpectations(ctx, cmd_line, expected, name, is_valid);
std::set<string16> flags_exp;
flags_exp.insert(google_update::kRegSendsPingsField);
flags_exp.insert(google_update::kRegWebAccessibleField);
ValidateAppCommandFlags(ctx, app_cmd, flags_exp, name, is_valid);
}
// Validates the "quick-enable-application-host" Google Update product command.
void InstallationValidator::ValidateQuickEnableApplicationHostCommand(
const ProductContext& ctx,
const AppCommand& app_cmd,
bool* is_valid) {
DCHECK(is_valid);
CommandLine cmd_line(CommandLine::FromString(app_cmd.command_line()));
string16 name(kCmdQuickEnableApplicationHost);
ValidateSetupPath(ctx, cmd_line.GetProgram(), name, is_valid);
SwitchExpectations expected;
expected.push_back(std::make_pair(
std::string(switches::kChromeAppLauncher), true));
expected.push_back(std::make_pair(
std::string(switches::kSystemLevel), false));
expected.push_back(std::make_pair(
std::string(switches::kMultiInstall), true));
expected.push_back(std::make_pair(
std::string(switches::kEnsureGoogleUpdatePresent), true));
ValidateCommandExpectations(ctx, cmd_line, expected, name, is_valid);
std::set<string16> flags_exp;
flags_exp.insert(google_update::kRegSendsPingsField);
flags_exp.insert(google_update::kRegWebAccessibleField);
flags_exp.insert(google_update::kRegRunAsUserField);
ValidateAppCommandFlags(ctx, app_cmd, flags_exp, name, is_valid);
}
// Validates a product's set of Google Update product commands against a
// collection of expectations.
void InstallationValidator::ValidateAppCommandExpectations(
const ProductContext& ctx,
const CommandExpectations& expectations,
bool* is_valid) {
DCHECK(is_valid);
CommandExpectations the_expectations(expectations);
AppCommands::CommandMapRange cmd_iterators(
ctx.state.commands().GetIterators());
CommandExpectations::iterator expectation;
for (; cmd_iterators.first != cmd_iterators.second; ++cmd_iterators.first) {
const string16& cmd_id = cmd_iterators.first->first;
// Do we have an expectation for this command?
expectation = the_expectations.find(cmd_id);
if (expectation != the_expectations.end()) {
(expectation->second)(ctx, cmd_iterators.first->second, is_valid);
// Remove this command from the set of expectations since we found it.
the_expectations.erase(expectation);
} else {
*is_valid = false;
LOG(ERROR) << ctx.dist->GetDisplayName()
<< " has an unexpected Google Update product command named \""
<< cmd_id << "\".";
}
}
// Report on any expected commands that weren't present.
CommandExpectations::const_iterator scan(the_expectations.begin());
CommandExpectations::const_iterator end(the_expectations.end());
for (; scan != end; ++scan) {
*is_valid = false;
LOG(ERROR) << ctx.dist->GetDisplayName()
<< " is missing the Google Update product command named \""
<< scan->first << "\".";
}
}
// Validates the multi-install binaries' Google Update commands.
void InstallationValidator::ValidateBinariesCommands(
const ProductContext& ctx,
bool* is_valid) {
DCHECK(is_valid);
// The quick-enable-cf command must be present if Chrome Binaries are
// installed and Chrome Frame is not installed.
const ChannelInfo& channel = ctx.state.channel();
const ProductState* binaries_state = ctx.machine_state.GetProductState(
ctx.system_install, BrowserDistribution::CHROME_BINARIES);
const ProductState* cf_state = ctx.machine_state.GetProductState(
ctx.system_install, BrowserDistribution::CHROME_FRAME);
CommandExpectations expectations;
if (binaries_state != NULL) {
if (cf_state == NULL)
expectations[kCmdQuickEnableCf] = &ValidateQuickEnableCfCommand;
expectations[kCmdQuickEnableApplicationHost] =
&ValidateQuickEnableApplicationHostCommand;
expectations[kCmdQueryEULAAcceptance] = &ValidateQueryEULAAcceptanceCommand;
}
ValidateAppCommandExpectations(ctx, expectations, is_valid);
}
// Validates the multi-install binaries at level |system_level|.
void InstallationValidator::ValidateBinaries(
const InstallationState& machine_state,
bool system_install,
const ProductState& binaries_state,
bool* is_valid) {
const ChannelInfo& channel = binaries_state.channel();
// ap must have -multi
if (!channel.IsMultiInstall()) {
*is_valid = false;
LOG(ERROR) << "Chrome Binaries are missing \"-multi\" in channel name: \""
<< channel.value() << "\"";
}
// ap must have -chrome iff Chrome is installed
const ProductState* chrome_state = machine_state.GetProductState(
system_install, BrowserDistribution::CHROME_BROWSER);
if (chrome_state != NULL) {
if (!channel.IsChrome()) {
*is_valid = false;
LOG(ERROR) << "Chrome Binaries are missing \"chrome\" in channel name:"
<< " \"" << channel.value() << "\"";
}
} else if (channel.IsChrome()) {
*is_valid = false;
LOG(ERROR) << "Chrome Binaries have \"-chrome\" in channel name, yet Chrome"
" is not installed: \"" << channel.value() << "\"";
}
// ap must have -chromeframe iff Chrome Frame is installed multi
const ProductState* cf_state = machine_state.GetProductState(
system_install, BrowserDistribution::CHROME_FRAME);
if (cf_state != NULL && cf_state->is_multi_install()) {
if (!channel.IsChromeFrame()) {
*is_valid = false;
LOG(ERROR) << "Chrome Binaries are missing \"-chromeframe\" in channel"
" name: \"" << channel.value() << "\"";
}
} else if (channel.IsChromeFrame()) {
*is_valid = false;
LOG(ERROR) << "Chrome Binaries have \"-chromeframe\" in channel name, yet "
"Chrome Frame is not installed multi: \"" << channel.value()
<< "\"";
}
// ap must have -applauncher iff Chrome App Launcher is installed multi
const ProductState* app_host_state = machine_state.GetProductState(
system_install, BrowserDistribution::CHROME_APP_HOST);
if (app_host_state != NULL) {
if (!app_host_state->is_multi_install()) {
*is_valid = false;
LOG(ERROR) << "Chrome App Launcher is installed in non-multi mode.";
}
if (!channel.IsAppLauncher()) {
*is_valid = false;
LOG(ERROR) << "Chrome Binaries are missing \"-applauncher\" in channel"
" name: \"" << channel.value() << "\"";
}
} else if (channel.IsAppLauncher()) {
*is_valid = false;
LOG(ERROR) << "Chrome Binaries have \"-applauncher\" in channel name, yet "
"Chrome App Launcher is not installed: \"" << channel.value()
<< "\"";
}
// Chrome, Chrome Frame, or App Host must be present
if (chrome_state == NULL && cf_state == NULL && app_host_state == NULL) {
*is_valid = false;
LOG(ERROR) << "Chrome Binaries are present with no other products.";
}
// Chrome must be multi-install if present.
if (chrome_state != NULL && !chrome_state->is_multi_install()) {
*is_valid = false;
LOG(ERROR)
<< "Chrome Binaries are present yet Chrome is not multi-install.";
}
// Chrome Frame must be multi-install if Chrome & App Host are not present.
if (cf_state != NULL && app_host_state == NULL && chrome_state == NULL &&
!cf_state->is_multi_install()) {
*is_valid = false;
LOG(ERROR) << "Chrome Binaries are present without Chrome nor App Launcher "
<< "yet Chrome Frame is not multi-install.";
}
ChromeBinariesRules binaries_rules;
ProductContext ctx(machine_state, system_install, binaries_state,
binaries_rules);
ValidateBinariesCommands(ctx, is_valid);
ValidateUsageStats(ctx, is_valid);
}
// Validates the path to |setup_exe| for the product described by |ctx|.
void InstallationValidator::ValidateSetupPath(const ProductContext& ctx,
const base::FilePath& setup_exe,
const string16& purpose,
bool* is_valid) {
DCHECK(is_valid);
BrowserDistribution* bins_dist = ctx.dist;
if (ctx.state.is_multi_install()) {
bins_dist = BrowserDistribution::GetSpecificDistribution(
BrowserDistribution::CHROME_BINARIES);
}
base::FilePath expected_path = installer::GetChromeInstallPath(
ctx.system_install, bins_dist);
expected_path = expected_path
.AppendASCII(ctx.state.version().GetString())
.Append(installer::kInstallerDir)
.Append(installer::kSetupExe);
if (!base::FilePath::CompareEqualIgnoreCase(expected_path.value(),
setup_exe.value())) {
*is_valid = false;
LOG(ERROR) << ctx.dist->GetDisplayName() << " path to " << purpose
<< " is not " << expected_path.value() << ": "
<< setup_exe.value();
}
}
// Validates that |command| meets the expectations described in |expected|.
void InstallationValidator::ValidateCommandExpectations(
const ProductContext& ctx,
const CommandLine& command,
const SwitchExpectations& expected,
const string16& source,
bool* is_valid) {
for (SwitchExpectations::size_type i = 0, size = expected.size(); i < size;
++i) {
const SwitchExpectations::value_type& expectation = expected[i];
if (command.HasSwitch(expectation.first) != expectation.second) {
*is_valid = false;
LOG(ERROR) << ctx.dist->GetDisplayName() << " " << source
<< (expectation.second ? " is missing" : " has") << " \""
<< expectation.first << "\""
<< (expectation.second ? "" : " but shouldn't") << ": "
<< command.GetCommandLineString();
}
}
}
// Validates that |command|, originating from |source|, is formed properly for
// the product described by |ctx|
void InstallationValidator::ValidateUninstallCommand(const ProductContext& ctx,
const CommandLine& command,
const string16& source,
bool* is_valid) {
DCHECK(is_valid);
ValidateSetupPath(ctx, command.GetProgram(), ASCIIToUTF16("uninstaller"),
is_valid);
const bool is_multi_install = ctx.state.is_multi_install();
SwitchExpectations expected;
expected.push_back(std::make_pair(std::string(switches::kUninstall), true));
expected.push_back(std::make_pair(std::string(switches::kSystemLevel),
ctx.system_install));
expected.push_back(std::make_pair(std::string(switches::kMultiInstall),
is_multi_install));
ctx.rules.AddUninstallSwitchExpectations(ctx, &expected);
ValidateCommandExpectations(ctx, command, expected, source, is_valid);
}
// Validates the rename command for the product described by |ctx|.
void InstallationValidator::ValidateRenameCommand(const ProductContext& ctx,
bool* is_valid) {
DCHECK(is_valid);
DCHECK(!ctx.state.rename_cmd().empty());
CommandLine command = CommandLine::FromString(ctx.state.rename_cmd());
string16 name(ASCIIToUTF16("in-use renamer"));
ValidateSetupPath(ctx, command.GetProgram(), name, is_valid);
SwitchExpectations expected;
expected.push_back(std::make_pair(std::string(switches::kRenameChromeExe),
true));
expected.push_back(std::make_pair(std::string(switches::kSystemLevel),
ctx.system_install));
expected.push_back(std::make_pair(std::string(switches::kMultiInstall),
ctx.state.is_multi_install()));
ctx.rules.AddRenameSwitchExpectations(ctx, &expected);
ValidateCommandExpectations(ctx, command, expected, name, is_valid);
}
// Validates the "opv" and "cmd" values for the product described in |ctx|.
void InstallationValidator::ValidateOldVersionValues(
const ProductContext& ctx,
bool* is_valid) {
DCHECK(is_valid);
// opv and cmd must both be present or both absent
if (ctx.state.old_version() == NULL) {
if (!ctx.state.rename_cmd().empty()) {
*is_valid = false;
LOG(ERROR) << ctx.dist->GetDisplayName()
<< " has a rename command but no opv: "
<< ctx.state.rename_cmd();
}
} else {
if (ctx.state.rename_cmd().empty()) {
*is_valid = false;
LOG(ERROR) << ctx.dist->GetDisplayName()
<< " has an opv but no rename command: "
<< ctx.state.old_version()->GetString();
} else {
ValidateRenameCommand(ctx, is_valid);
}
}
}
// Validates the multi-install state of the product described in |ctx|.
void InstallationValidator::ValidateMultiInstallProduct(
const ProductContext& ctx,
bool* is_valid) {
DCHECK(is_valid);
const ProductState* binaries =
ctx.machine_state.GetProductState(ctx.system_install,
BrowserDistribution::CHROME_BINARIES);
if (!binaries) {
if (ctx.dist->GetType() == BrowserDistribution::CHROME_APP_HOST) {
if (!ctx.machine_state.GetProductState(
true, // system-level
BrowserDistribution::CHROME_BINARIES) &&
!ctx.machine_state.GetProductState(
true, // system-level
BrowserDistribution::CHROME_BROWSER)) {
*is_valid = false;
LOG(ERROR) << ctx.dist->GetDisplayName()
<< " (" << ctx.state.version().GetString() << ") is "
<< "installed without Chrome Binaries or a system-level "
<< "Chrome.";
}
} else {
*is_valid = false;
LOG(ERROR) << ctx.dist->GetDisplayName()
<< " (" << ctx.state.version().GetString() << ") is installed "
<< "without Chrome Binaries.";
}
} else {
// Version must match that of binaries.
if (ctx.state.version().CompareTo(binaries->version()) != 0) {
*is_valid = false;
LOG(ERROR) << "Version of " << ctx.dist->GetDisplayName()
<< " (" << ctx.state.version().GetString() << ") does not "
"match that of Chrome Binaries ("
<< binaries->version().GetString() << ").";
}
// Channel value must match that of binaries.
if (!ctx.state.channel().Equals(binaries->channel())) {
*is_valid = false;
LOG(ERROR) << "Channel name of " << ctx.dist->GetDisplayName()
<< " (" << ctx.state.channel().value()
<< ") does not match that of Chrome Binaries ("
<< binaries->channel().value() << ").";
}
}
}
// Validates the Google Update commands for the product described in |ctx|.
void InstallationValidator::ValidateAppCommands(
const ProductContext& ctx,
bool* is_valid) {
DCHECK(is_valid);
CommandExpectations expectations;
if (ctx.dist->GetType() == BrowserDistribution::CHROME_APP_HOST) {
expectations[kCmdInstallApp] = &ValidateInstallAppCommand;
}
if (ctx.dist->GetType() == BrowserDistribution::CHROME_BROWSER) {
expectations[kCmdInstallExtension] = &ValidateInstallExtensionCommand;
expectations[kCmdOnOsUpgrade] = &ValidateOnOsUpgradeCommand;
}
ValidateAppCommandExpectations(ctx, expectations, is_valid);
}
// Validates usagestats for the product or binaries in |ctx|.
void InstallationValidator::ValidateUsageStats(const ProductContext& ctx,
bool* is_valid) {
DWORD usagestats = 0;
if (ctx.state.GetUsageStats(&usagestats)) {
if (!ctx.rules.UsageStatsAllowed(ctx)) {
*is_valid = false;
LOG(ERROR) << ctx.dist->GetDisplayName()
<< " has a usagestats value (" << usagestats
<< "), yet should not.";
} else if (usagestats != 0 && usagestats != 1) {
*is_valid = false;
LOG(ERROR) << ctx.dist->GetDisplayName()
<< " has an unsupported usagestats value (" << usagestats
<< ").";
}
}
}
// Validates the product described in |product_state| according to |rules|.
void InstallationValidator::ValidateProduct(
const InstallationState& machine_state,
bool system_install,
const ProductState& product_state,
const ProductRules& rules,
bool* is_valid) {
DCHECK(is_valid);
ProductContext ctx(machine_state, system_install, product_state, rules);
ValidateUninstallCommand(ctx, ctx.state.uninstall_command(),
ASCIIToUTF16("Google Update uninstall command"),
is_valid);
ValidateOldVersionValues(ctx, is_valid);
if (ctx.state.is_multi_install())
ValidateMultiInstallProduct(ctx, is_valid);
ValidateAppCommands(ctx, is_valid);
ValidateUsageStats(ctx, is_valid);
}
// static
bool InstallationValidator::ValidateInstallationTypeForState(
const InstallationState& machine_state,
bool system_level,
InstallationType* type) {
DCHECK(type);
bool rock_on = true;
*type = NO_PRODUCTS;
// Does the system have any multi-installed products?
const ProductState* multi_state =
machine_state.GetProductState(system_level,
BrowserDistribution::CHROME_BINARIES);
if (multi_state != NULL)
ValidateBinaries(machine_state, system_level, *multi_state, &rock_on);
// Is Chrome installed?
const ProductState* product_state =
machine_state.GetProductState(system_level,
BrowserDistribution::CHROME_BROWSER);
if (product_state != NULL) {
ChromeRules chrome_rules;
ValidateProduct(machine_state, system_level, *product_state,
chrome_rules, &rock_on);
*type = static_cast<InstallationType>(
*type | (product_state->is_multi_install() ?
ProductBits::CHROME_MULTI :
ProductBits::CHROME_SINGLE));
}
// Is Chrome Frame installed?
product_state =
machine_state.GetProductState(system_level,
BrowserDistribution::CHROME_FRAME);
if (product_state != NULL) {
ChromeFrameRules chrome_frame_rules;
ValidateProduct(machine_state, system_level, *product_state,
chrome_frame_rules, &rock_on);
int cf_bit = !product_state->is_multi_install() ?
ProductBits::CHROME_FRAME_SINGLE :
ProductBits::CHROME_FRAME_MULTI;
*type = static_cast<InstallationType>(*type | cf_bit);
}
// Is Chrome App Host installed?
product_state =
machine_state.GetProductState(system_level,
BrowserDistribution::CHROME_APP_HOST);
if (product_state != NULL) {
ChromeAppHostRules chrome_app_host_rules;
ValidateProduct(machine_state, system_level, *product_state,
chrome_app_host_rules, &rock_on);
*type = static_cast<InstallationType>(*type | ProductBits::CHROME_APP_HOST);
if (!product_state->is_multi_install()) {
LOG(ERROR) << "Chrome App Launcher must always be multi-install.";
rock_on = false;
}
}
DCHECK_NE(std::find(&kInstallationTypes[0],
&kInstallationTypes[arraysize(kInstallationTypes)],
*type),
&kInstallationTypes[arraysize(kInstallationTypes)])
<< "Invalid combination of products found on system (" << *type << ")";
return rock_on;
}
// static
bool InstallationValidator::ValidateInstallationType(bool system_level,
InstallationType* type) {
DCHECK(type);
InstallationState machine_state;
machine_state.Initialize();
return ValidateInstallationTypeForState(machine_state, system_level, type);
}
} // namespace installer