| // 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 |