installation_validator.cc revision 2a99a7e74a7f215066514fe81d2bfa6639d9eddd
1// Copyright (c) 2012 The Chromium Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5// Implementation of the installation validator. 6 7#include "chrome/installer/util/installation_validator.h" 8 9#include <algorithm> 10#include <set> 11#include <string> 12 13#include "base/logging.h" 14#include "base/utf_string_conversions.h" 15#include "base/version.h" 16#include "chrome/common/chrome_switches.h" 17#include "chrome/installer/util/browser_distribution.h" 18#include "chrome/installer/util/google_update_constants.h" 19#include "chrome/installer/util/helper.h" 20#include "chrome/installer/util/installation_state.h" 21 22namespace installer { 23 24BrowserDistribution::Type 25 InstallationValidator::ChromeRules::distribution_type() const { 26 return BrowserDistribution::CHROME_BROWSER; 27} 28 29void InstallationValidator::ChromeRules::AddUninstallSwitchExpectations( 30 const ProductContext& ctx, 31 SwitchExpectations* expectations) const { 32 const bool is_multi_install = 33 ctx.state.uninstall_command().HasSwitch(switches::kMultiInstall); 34 35 // --chrome should be present for uninstall iff --multi-install. This wasn't 36 // the case in Chrome 10 (between r68996 and r72497), though, so consider it 37 // optional. 38 39 // --chrome-frame --ready-mode should be present for uninstall iff CF in ready 40 // mode. 41 const ProductState* cf_state = 42 ctx.machine_state.GetProductState(ctx.system_install, 43 BrowserDistribution::CHROME_FRAME); 44 const bool ready_mode = 45 cf_state != NULL && 46 cf_state->uninstall_command().HasSwitch(switches::kChromeFrameReadyMode); 47 expectations->push_back(std::make_pair(std::string(switches::kChromeFrame), 48 ready_mode)); 49 expectations->push_back( 50 std::make_pair(std::string(switches::kChromeFrameReadyMode), ready_mode)); 51} 52 53void InstallationValidator::ChromeRules::AddRenameSwitchExpectations( 54 const ProductContext& ctx, 55 SwitchExpectations* expectations) const { 56 const bool is_multi_install = 57 ctx.state.uninstall_command().HasSwitch(switches::kMultiInstall); 58 59 // --chrome should not be present for rename. It was for a time, so we'll be 60 // lenient so that mini_installer tests pass. 61 62 // --chrome-frame --ready-mode should never be present. 63 expectations->push_back( 64 std::make_pair(std::string(switches::kChromeFrame), false)); 65 expectations->push_back( 66 std::make_pair(std::string(switches::kChromeFrameReadyMode), false)); 67} 68 69bool InstallationValidator::ChromeRules::UsageStatsAllowed( 70 const ProductContext& ctx) const { 71 // Products must not have usagestats consent values when multi-install 72 // (only the multi-install binaries may). 73 return !ctx.state.is_multi_install(); 74} 75 76BrowserDistribution::Type 77 InstallationValidator::ChromeFrameRules::distribution_type() const { 78 return BrowserDistribution::CHROME_FRAME; 79} 80 81void InstallationValidator::ChromeFrameRules::AddUninstallSwitchExpectations( 82 const ProductContext& ctx, 83 SwitchExpectations* expectations) const { 84 // --chrome-frame must be present. 85 expectations->push_back(std::make_pair(std::string(switches::kChromeFrame), 86 true)); 87 // --chrome must not be present. 88 expectations->push_back(std::make_pair(std::string(switches::kChrome), 89 false)); 90} 91 92void InstallationValidator::ChromeFrameRules::AddRenameSwitchExpectations( 93 const ProductContext& ctx, 94 SwitchExpectations* expectations) const { 95 // --chrome-frame must be present for SxS rename. 96 expectations->push_back(std::make_pair(std::string(switches::kChromeFrame), 97 !ctx.state.is_multi_install())); 98 // --chrome must not be present. 99 expectations->push_back(std::make_pair(std::string(switches::kChrome), 100 false)); 101} 102 103bool InstallationValidator::ChromeFrameRules::UsageStatsAllowed( 104 const ProductContext& ctx) const { 105 // Products must not have usagestats consent values when multi-install 106 // (only the multi-install binaries may). 107 return !ctx.state.is_multi_install(); 108} 109 110BrowserDistribution::Type 111 InstallationValidator::ChromeAppHostRules::distribution_type() const { 112 return BrowserDistribution::CHROME_APP_HOST; 113} 114 115void InstallationValidator::ChromeAppHostRules::AddUninstallSwitchExpectations( 116 const ProductContext& ctx, 117 SwitchExpectations* expectations) const { 118 DCHECK(!ctx.system_install); 119 120 // --app-launcher must be present. 121 expectations->push_back( 122 std::make_pair(std::string(switches::kChromeAppLauncher), true)); 123 124 // --chrome must not be present. 125 expectations->push_back(std::make_pair(std::string(switches::kChrome), 126 false)); 127 // --chrome-frame must not be present. 128 expectations->push_back(std::make_pair(std::string(switches::kChromeFrame), 129 false)); 130} 131 132void InstallationValidator::ChromeAppHostRules::AddRenameSwitchExpectations( 133 const ProductContext& ctx, 134 SwitchExpectations* expectations) const { 135 // TODO(erikwright): I guess there will be none? 136} 137 138bool InstallationValidator::ChromeAppHostRules::UsageStatsAllowed( 139 const ProductContext& ctx) const { 140 // App Host doesn't manage usage stats. The Chrome Binaries will. 141 return false; 142} 143 144BrowserDistribution::Type 145 InstallationValidator::ChromeBinariesRules::distribution_type() const { 146 return BrowserDistribution::CHROME_BINARIES; 147} 148 149void InstallationValidator::ChromeBinariesRules::AddUninstallSwitchExpectations( 150 const ProductContext& ctx, 151 SwitchExpectations* expectations) const { 152 NOTREACHED(); 153} 154 155void InstallationValidator::ChromeBinariesRules::AddRenameSwitchExpectations( 156 const ProductContext& ctx, 157 SwitchExpectations* expectations) const { 158 NOTREACHED(); 159} 160 161bool InstallationValidator::ChromeBinariesRules::UsageStatsAllowed( 162 const ProductContext& ctx) const { 163 // UsageStats consent values are always allowed on the binaries. 164 return true; 165} 166 167// static 168const InstallationValidator::InstallationType 169 InstallationValidator::kInstallationTypes[] = { 170 NO_PRODUCTS, 171 CHROME_SINGLE, 172 CHROME_MULTI, 173 CHROME_FRAME_SINGLE, 174 CHROME_FRAME_SINGLE_CHROME_SINGLE, 175 CHROME_FRAME_SINGLE_CHROME_MULTI, 176 CHROME_FRAME_MULTI, 177 CHROME_FRAME_MULTI_CHROME_MULTI, 178 CHROME_FRAME_READY_MODE_CHROME_MULTI, 179 CHROME_APP_HOST, 180 CHROME_APP_HOST_CHROME_FRAME_SINGLE, 181 CHROME_APP_HOST_CHROME_FRAME_SINGLE_CHROME_MULTI, 182 CHROME_APP_HOST_CHROME_FRAME_MULTI, 183 CHROME_APP_HOST_CHROME_FRAME_MULTI_CHROME_MULTI, 184 CHROME_APP_HOST_CHROME_MULTI, 185 CHROME_APP_HOST_CHROME_MULTI_CHROME_FRAME_READY_MODE, 186}; 187 188void InstallationValidator::ValidateAppCommandFlags( 189 const ProductContext& ctx, 190 const AppCommand& app_cmd, 191 const std::set<string16>& flags_exp, 192 const string16& name, 193 bool* is_valid) { 194 const struct { 195 const string16 exp_key; 196 bool val; 197 const char* msg; 198 } check_list[] = { 199 {google_update::kRegSendsPingsField, 200 app_cmd.sends_pings(), 201 "be configured to send pings"}, 202 {google_update::kRegWebAccessibleField, 203 app_cmd.is_web_accessible(), 204 "be web accessible"}, 205 {google_update::kRegAutoRunOnOSUpgradeField, 206 app_cmd.is_auto_run_on_os_upgrade(), 207 "be marked to run on OS upgrade"}, 208 {google_update::kRegRunAsUserField, 209 app_cmd.is_run_as_user(), 210 "be marked to run as user"}, 211 }; 212 for (int i = 0; i < arraysize(check_list); ++i) { 213 bool expected = flags_exp.find(check_list[i].exp_key) != flags_exp.end(); 214 if (check_list[i].val != expected) { 215 *is_valid = false; 216 LOG(ERROR) << ctx.dist->GetAppShortCutName() << ": " 217 << name << " command should " << (expected ? "" : "not ") 218 << check_list[i].msg << "."; 219 } 220 } 221} 222 223// Validates both "install-application" and "install-extension" depending on 224// what is passed in. 225void InstallationValidator::ValidateInstallCommand( 226 const ProductContext& ctx, 227 const AppCommand& app_cmd, 228 const wchar_t* expected_command, 229 const wchar_t* expected_app_name, 230 const char* expected_switch, 231 bool* is_valid) { 232 DCHECK(is_valid); 233 234 CommandLine cmd_line(CommandLine::FromString(app_cmd.command_line())); 235 string16 name(expected_command); 236 237 base::FilePath expected_path( 238 installer::GetChromeInstallPath(ctx.system_install, ctx.dist) 239 .Append(expected_app_name)); 240 241 if (!base::FilePath::CompareEqualIgnoreCase(expected_path.value(), 242 cmd_line.GetProgram().value())) { 243 *is_valid = false; 244 LOG(ERROR) << name << "'s path is not " 245 << expected_path.value() << ": " 246 << cmd_line.GetProgram().value(); 247 } 248 249 SwitchExpectations expected; 250 expected.push_back(std::make_pair(std::string(expected_switch), true)); 251 252 ValidateCommandExpectations(ctx, cmd_line, expected, name, is_valid); 253 254 std::set<string16> flags_exp; 255 flags_exp.insert(google_update::kRegSendsPingsField); 256 flags_exp.insert(google_update::kRegWebAccessibleField); 257 flags_exp.insert(google_update::kRegRunAsUserField); 258 ValidateAppCommandFlags(ctx, app_cmd, flags_exp, name, is_valid); 259} 260 261// Validates the "install-application" Google Update product command. 262void InstallationValidator::ValidateInstallAppCommand( 263 const ProductContext& ctx, 264 const AppCommand& app_cmd, 265 bool* is_valid) { 266 ValidateInstallCommand(ctx, app_cmd, kCmdInstallApp, 267 installer::kChromeAppHostExe, 268 ::switches::kInstallFromWebstore, is_valid); 269} 270 271// Validates the "install-extension" Google Update product command. 272void InstallationValidator::ValidateInstallExtensionCommand( 273 const ProductContext& ctx, 274 const AppCommand& app_cmd, 275 bool* is_valid) { 276 ValidateInstallCommand(ctx, app_cmd, kCmdInstallExtension, 277 installer::kChromeExe, 278 ::switches::kLimitedInstallFromWebstore, is_valid); 279} 280 281// Validates the "on-os-upgrade" Google Update internal command. 282void InstallationValidator::ValidateOnOsUpgradeCommand( 283 const ProductContext& ctx, 284 const AppCommand& app_cmd, 285 bool* is_valid) { 286 DCHECK(is_valid); 287 288 CommandLine cmd_line(CommandLine::FromString(app_cmd.command_line())); 289 string16 name(kCmdOnOsUpgrade); 290 291 ValidateSetupPath(ctx, cmd_line.GetProgram(), name, is_valid); 292 293 SwitchExpectations expected; 294 expected.push_back(std::make_pair(std::string(switches::kOnOsUpgrade), true)); 295 expected.push_back(std::make_pair(std::string(switches::kSystemLevel), 296 ctx.system_install)); 297 expected.push_back(std::make_pair(std::string(switches::kMultiInstall), 298 ctx.state.is_multi_install())); 299 // Expecting kChrome if and only if kMultiInstall. 300 expected.push_back(std::make_pair(std::string(switches::kChrome), 301 ctx.state.is_multi_install())); 302 303 ValidateCommandExpectations(ctx, cmd_line, expected, name, is_valid); 304 305 std::set<string16> flags_exp; 306 flags_exp.insert(google_update::kRegAutoRunOnOSUpgradeField); 307 ValidateAppCommandFlags(ctx, app_cmd, flags_exp, name, is_valid); 308} 309 310// Validates the "query-eula-acceptance" Google Update product command. 311void InstallationValidator::ValidateQueryEULAAcceptanceCommand( 312 const ProductContext& ctx, 313 const AppCommand& app_cmd, 314 bool* is_valid) { 315 DCHECK(is_valid); 316 317 CommandLine cmd_line(CommandLine::FromString(app_cmd.command_line())); 318 string16 name(kCmdQueryEULAAcceptance); 319 320 ValidateSetupPath(ctx, cmd_line.GetProgram(), name, is_valid); 321 322 SwitchExpectations expected; 323 expected.push_back(std::make_pair(std::string(switches::kQueryEULAAcceptance), 324 true)); 325 expected.push_back(std::make_pair(std::string(switches::kSystemLevel), 326 ctx.system_install)); 327 328 ValidateCommandExpectations(ctx, cmd_line, expected, name, is_valid); 329 330 std::set<string16> flags_exp; 331 flags_exp.insert(google_update::kRegWebAccessibleField); 332 flags_exp.insert(google_update::kRegRunAsUserField); 333 ValidateAppCommandFlags(ctx, app_cmd, flags_exp, name, is_valid); 334} 335 336// Validates the "quick-enable-cf" Google Update product command. 337void InstallationValidator::ValidateQuickEnableCfCommand( 338 const ProductContext& ctx, 339 const AppCommand& app_cmd, 340 bool* is_valid) { 341 DCHECK(is_valid); 342 343 CommandLine cmd_line(CommandLine::FromString(app_cmd.command_line())); 344 string16 name(kCmdQuickEnableCf); 345 346 ValidateSetupPath(ctx, cmd_line.GetProgram(), name, is_valid); 347 348 SwitchExpectations expected; 349 350 expected.push_back( 351 std::make_pair(std::string(switches::kChromeFrameQuickEnable), true)); 352 expected.push_back(std::make_pair(std::string(switches::kSystemLevel), 353 ctx.system_install)); 354 expected.push_back(std::make_pair(std::string(switches::kMultiInstall), 355 ctx.state.is_multi_install())); 356 357 ValidateCommandExpectations(ctx, cmd_line, expected, name, is_valid); 358 359 std::set<string16> flags_exp; 360 flags_exp.insert(google_update::kRegSendsPingsField); 361 flags_exp.insert(google_update::kRegWebAccessibleField); 362 ValidateAppCommandFlags(ctx, app_cmd, flags_exp, name, is_valid); 363} 364 365// Validates the "quick-enable-application-host" Google Update product command. 366void InstallationValidator::ValidateQuickEnableApplicationHostCommand( 367 const ProductContext& ctx, 368 const AppCommand& app_cmd, 369 bool* is_valid) { 370 DCHECK(is_valid); 371 372 CommandLine cmd_line(CommandLine::FromString(app_cmd.command_line())); 373 string16 name(kCmdQuickEnableApplicationHost); 374 375 ValidateSetupPath(ctx, cmd_line.GetProgram(), name, is_valid); 376 377 SwitchExpectations expected; 378 379 expected.push_back(std::make_pair( 380 std::string(switches::kChromeAppLauncher), true)); 381 expected.push_back(std::make_pair( 382 std::string(switches::kSystemLevel), false)); 383 expected.push_back(std::make_pair( 384 std::string(switches::kMultiInstall), true)); 385 expected.push_back(std::make_pair( 386 std::string(switches::kEnsureGoogleUpdatePresent), true)); 387 388 ValidateCommandExpectations(ctx, cmd_line, expected, name, is_valid); 389 390 std::set<string16> flags_exp; 391 flags_exp.insert(google_update::kRegSendsPingsField); 392 flags_exp.insert(google_update::kRegWebAccessibleField); 393 flags_exp.insert(google_update::kRegRunAsUserField); 394 ValidateAppCommandFlags(ctx, app_cmd, flags_exp, name, is_valid); 395} 396 397// Validates a product's set of Google Update product commands against a 398// collection of expectations. 399void InstallationValidator::ValidateAppCommandExpectations( 400 const ProductContext& ctx, 401 const CommandExpectations& expectations, 402 bool* is_valid) { 403 DCHECK(is_valid); 404 405 CommandExpectations the_expectations(expectations); 406 407 AppCommands::CommandMapRange cmd_iterators( 408 ctx.state.commands().GetIterators()); 409 CommandExpectations::iterator expectation; 410 for (; cmd_iterators.first != cmd_iterators.second; ++cmd_iterators.first) { 411 const string16& cmd_id = cmd_iterators.first->first; 412 // Do we have an expectation for this command? 413 expectation = the_expectations.find(cmd_id); 414 if (expectation != the_expectations.end()) { 415 (expectation->second)(ctx, cmd_iterators.first->second, is_valid); 416 // Remove this command from the set of expectations since we found it. 417 the_expectations.erase(expectation); 418 } else { 419 *is_valid = false; 420 LOG(ERROR) << ctx.dist->GetAppShortCutName() 421 << " has an unexpected Google Update product command named \"" 422 << cmd_id << "\"."; 423 } 424 } 425 426 // Report on any expected commands that weren't present. 427 CommandExpectations::const_iterator scan(the_expectations.begin()); 428 CommandExpectations::const_iterator end(the_expectations.end()); 429 for (; scan != end; ++scan) { 430 *is_valid = false; 431 LOG(ERROR) << ctx.dist->GetAppShortCutName() 432 << " is missing the Google Update product command named \"" 433 << scan->first << "\"."; 434 } 435} 436 437// Validates the multi-install binaries' Google Update commands. 438void InstallationValidator::ValidateBinariesCommands( 439 const ProductContext& ctx, 440 bool* is_valid) { 441 DCHECK(is_valid); 442 443 // The quick-enable-cf command must be present if Chrome Binaries are 444 // installed and Chrome Frame is not installed (or installed in ready mode). 445 const ChannelInfo& channel = ctx.state.channel(); 446 const ProductState* binaries_state = ctx.machine_state.GetProductState( 447 ctx.system_install, BrowserDistribution::CHROME_BINARIES); 448 const ProductState* cf_state = ctx.machine_state.GetProductState( 449 ctx.system_install, BrowserDistribution::CHROME_FRAME); 450 451 CommandExpectations expectations; 452 453 if (binaries_state != NULL) { 454 if (cf_state == NULL || channel.IsReadyMode()) 455 expectations[kCmdQuickEnableCf] = &ValidateQuickEnableCfCommand; 456 457 expectations[kCmdQuickEnableApplicationHost] = 458 &ValidateQuickEnableApplicationHostCommand; 459 460 expectations[kCmdQueryEULAAcceptance] = &ValidateQueryEULAAcceptanceCommand; 461 } 462 463 ValidateAppCommandExpectations(ctx, expectations, is_valid); 464} 465 466// Validates the multi-install binaries at level |system_level|. 467void InstallationValidator::ValidateBinaries( 468 const InstallationState& machine_state, 469 bool system_install, 470 const ProductState& binaries_state, 471 bool* is_valid) { 472 const ChannelInfo& channel = binaries_state.channel(); 473 474 // ap must have -multi 475 if (!channel.IsMultiInstall()) { 476 *is_valid = false; 477 LOG(ERROR) << "Chrome Binaries are missing \"-multi\" in channel name: \"" 478 << channel.value() << "\""; 479 } 480 481 // ap must have -chrome iff Chrome is installed 482 const ProductState* chrome_state = machine_state.GetProductState( 483 system_install, BrowserDistribution::CHROME_BROWSER); 484 if (chrome_state != NULL) { 485 if (!channel.IsChrome()) { 486 *is_valid = false; 487 LOG(ERROR) << "Chrome Binaries are missing \"chrome\" in channel name:" 488 << " \"" << channel.value() << "\""; 489 } 490 } else if (channel.IsChrome()) { 491 *is_valid = false; 492 LOG(ERROR) << "Chrome Binaries have \"-chrome\" in channel name, yet Chrome" 493 " is not installed: \"" << channel.value() << "\""; 494 } 495 496 // ap must have -chromeframe iff Chrome Frame is installed multi 497 const ProductState* cf_state = machine_state.GetProductState( 498 system_install, BrowserDistribution::CHROME_FRAME); 499 if (cf_state != NULL && cf_state->is_multi_install()) { 500 if (!channel.IsChromeFrame()) { 501 *is_valid = false; 502 LOG(ERROR) << "Chrome Binaries are missing \"-chromeframe\" in channel" 503 " name: \"" << channel.value() << "\""; 504 } 505 } else if (channel.IsChromeFrame()) { 506 *is_valid = false; 507 LOG(ERROR) << "Chrome Binaries have \"-chromeframe\" in channel name, yet " 508 "Chrome Frame is not installed multi: \"" << channel.value() 509 << "\""; 510 } 511 512 // ap must have -readymode iff Chrome Frame is installed in ready-mode 513 if (cf_state != NULL && 514 cf_state->uninstall_command().HasSwitch( 515 installer::switches::kChromeFrameReadyMode)) { 516 if (!channel.IsReadyMode()) { 517 *is_valid = false; 518 LOG(ERROR) << "Chrome Binaries are missing \"-readymode\" in channel" 519 " name: \"" << channel.value() << "\""; 520 } 521 } else if (channel.IsReadyMode()) { 522 *is_valid = false; 523 LOG(ERROR) << "Chrome Binaries have \"-readymode\" in channel name, yet " 524 "Chrome Frame is not in ready mode: \"" << channel.value() 525 << "\""; 526 } 527 528 // ap must have -applauncher iff Chrome App Launcher is installed multi 529 const ProductState* app_host_state = machine_state.GetProductState( 530 system_install, BrowserDistribution::CHROME_APP_HOST); 531 if (app_host_state != NULL) { 532 if (!app_host_state->is_multi_install()) { 533 *is_valid = false; 534 LOG(ERROR) << "Chrome App Launcher is installed in non-multi mode."; 535 } 536 if (!channel.IsAppLauncher()) { 537 *is_valid = false; 538 LOG(ERROR) << "Chrome Binaries are missing \"-applauncher\" in channel" 539 " name: \"" << channel.value() << "\""; 540 } 541 } else if (channel.IsAppLauncher()) { 542 *is_valid = false; 543 LOG(ERROR) << "Chrome Binaries have \"-applauncher\" in channel name, yet " 544 "Chrome App Launcher is not installed: \"" << channel.value() 545 << "\""; 546 } 547 548 // Chrome, Chrome Frame, or App Host must be present 549 if (chrome_state == NULL && cf_state == NULL && app_host_state == NULL) { 550 *is_valid = false; 551 LOG(ERROR) << "Chrome Binaries are present with no other products."; 552 } 553 554 // Chrome must be multi-install if present. 555 if (chrome_state != NULL && !chrome_state->is_multi_install()) { 556 *is_valid = false; 557 LOG(ERROR) 558 << "Chrome Binaries are present yet Chrome is not multi-install."; 559 } 560 561 // Chrome Frame must be multi-install if Chrome & App Host are not present. 562 if (cf_state != NULL && app_host_state == NULL && chrome_state == NULL && 563 !cf_state->is_multi_install()) { 564 *is_valid = false; 565 LOG(ERROR) << "Chrome Binaries are present without Chrome nor App Launcher " 566 << "yet Chrome Frame is not multi-install."; 567 } 568 569 ChromeBinariesRules binaries_rules; 570 ProductContext ctx(machine_state, system_install, binaries_state, 571 binaries_rules); 572 573 ValidateBinariesCommands(ctx, is_valid); 574 575 ValidateUsageStats(ctx, is_valid); 576} 577 578// Validates the path to |setup_exe| for the product described by |ctx|. 579void InstallationValidator::ValidateSetupPath(const ProductContext& ctx, 580 const base::FilePath& setup_exe, 581 const string16& purpose, 582 bool* is_valid) { 583 DCHECK(is_valid); 584 585 BrowserDistribution* bins_dist = ctx.dist; 586 if (ctx.state.is_multi_install()) { 587 bins_dist = BrowserDistribution::GetSpecificDistribution( 588 BrowserDistribution::CHROME_BINARIES); 589 } 590 591 base::FilePath expected_path = installer::GetChromeInstallPath( 592 ctx.system_install, bins_dist); 593 expected_path = expected_path 594 .AppendASCII(ctx.state.version().GetString()) 595 .Append(installer::kInstallerDir) 596 .Append(installer::kSetupExe); 597 if (!base::FilePath::CompareEqualIgnoreCase(expected_path.value(), 598 setup_exe.value())) { 599 *is_valid = false; 600 LOG(ERROR) << ctx.dist->GetAppShortCutName() << " path to " << purpose 601 << " is not " << expected_path.value() << ": " 602 << setup_exe.value(); 603 } 604} 605 606// Validates that |command| meets the expectations described in |expected|. 607void InstallationValidator::ValidateCommandExpectations( 608 const ProductContext& ctx, 609 const CommandLine& command, 610 const SwitchExpectations& expected, 611 const string16& source, 612 bool* is_valid) { 613 for (SwitchExpectations::size_type i = 0, size = expected.size(); i < size; 614 ++i) { 615 const SwitchExpectations::value_type& expectation = expected[i]; 616 if (command.HasSwitch(expectation.first) != expectation.second) { 617 *is_valid = false; 618 LOG(ERROR) << ctx.dist->GetAppShortCutName() << " " << source 619 << (expectation.second ? " is missing" : " has") << " \"" 620 << expectation.first << "\"" 621 << (expectation.second ? "" : " but shouldn't") << ": " 622 << command.GetCommandLineString(); 623 } 624 } 625} 626 627// Validates that |command|, originating from |source|, is formed properly for 628// the product described by |ctx| 629void InstallationValidator::ValidateUninstallCommand(const ProductContext& ctx, 630 const CommandLine& command, 631 const string16& source, 632 bool* is_valid) { 633 DCHECK(is_valid); 634 635 ValidateSetupPath(ctx, command.GetProgram(), ASCIIToUTF16("uninstaller"), 636 is_valid); 637 638 const bool is_multi_install = ctx.state.is_multi_install(); 639 SwitchExpectations expected; 640 641 expected.push_back(std::make_pair(std::string(switches::kUninstall), true)); 642 expected.push_back(std::make_pair(std::string(switches::kSystemLevel), 643 ctx.system_install)); 644 expected.push_back(std::make_pair(std::string(switches::kMultiInstall), 645 is_multi_install)); 646 ctx.rules.AddUninstallSwitchExpectations(ctx, &expected); 647 648 ValidateCommandExpectations(ctx, command, expected, source, is_valid); 649} 650 651// Validates the rename command for the product described by |ctx|. 652void InstallationValidator::ValidateRenameCommand(const ProductContext& ctx, 653 bool* is_valid) { 654 DCHECK(is_valid); 655 DCHECK(!ctx.state.rename_cmd().empty()); 656 657 CommandLine command = CommandLine::FromString(ctx.state.rename_cmd()); 658 string16 name(ASCIIToUTF16("in-use renamer")); 659 660 ValidateSetupPath(ctx, command.GetProgram(), name, is_valid); 661 662 SwitchExpectations expected; 663 664 expected.push_back(std::make_pair(std::string(switches::kRenameChromeExe), 665 true)); 666 expected.push_back(std::make_pair(std::string(switches::kSystemLevel), 667 ctx.system_install)); 668 expected.push_back(std::make_pair(std::string(switches::kMultiInstall), 669 ctx.state.is_multi_install())); 670 ctx.rules.AddRenameSwitchExpectations(ctx, &expected); 671 672 ValidateCommandExpectations(ctx, command, expected, name, is_valid); 673} 674 675// Validates the "opv" and "cmd" values for the product described in |ctx|. 676void InstallationValidator::ValidateOldVersionValues( 677 const ProductContext& ctx, 678 bool* is_valid) { 679 DCHECK(is_valid); 680 681 // opv and cmd must both be present or both absent 682 if (ctx.state.old_version() == NULL) { 683 if (!ctx.state.rename_cmd().empty()) { 684 *is_valid = false; 685 LOG(ERROR) << ctx.dist->GetAppShortCutName() 686 << " has a rename command but no opv: " 687 << ctx.state.rename_cmd(); 688 } 689 } else { 690 if (ctx.state.rename_cmd().empty()) { 691 *is_valid = false; 692 LOG(ERROR) << ctx.dist->GetAppShortCutName() 693 << " has an opv but no rename command: " 694 << ctx.state.old_version()->GetString(); 695 } else { 696 ValidateRenameCommand(ctx, is_valid); 697 } 698 } 699} 700 701// Validates the multi-install state of the product described in |ctx|. 702void InstallationValidator::ValidateMultiInstallProduct( 703 const ProductContext& ctx, 704 bool* is_valid) { 705 DCHECK(is_valid); 706 707 const ProductState* binaries = 708 ctx.machine_state.GetProductState(ctx.system_install, 709 BrowserDistribution::CHROME_BINARIES); 710 if (!binaries) { 711 if (ctx.dist->GetType() == BrowserDistribution::CHROME_APP_HOST) { 712 if (!ctx.machine_state.GetProductState( 713 true, // system-level 714 BrowserDistribution::CHROME_BINARIES) && 715 !ctx.machine_state.GetProductState( 716 true, // system-level 717 BrowserDistribution::CHROME_BROWSER)) { 718 *is_valid = false; 719 LOG(ERROR) << ctx.dist->GetAppShortCutName() 720 << " (" << ctx.state.version().GetString() << ") is " 721 << "installed without Chrome Binaries or a system-level " 722 << "Chrome."; 723 } 724 } else { 725 *is_valid = false; 726 LOG(ERROR) << ctx.dist->GetAppShortCutName() 727 << " (" << ctx.state.version().GetString() << ") is installed " 728 << "without Chrome Binaries."; 729 } 730 } else { 731 // Version must match that of binaries. 732 if (ctx.state.version().CompareTo(binaries->version()) != 0) { 733 *is_valid = false; 734 LOG(ERROR) << "Version of " << ctx.dist->GetAppShortCutName() 735 << " (" << ctx.state.version().GetString() << ") does not " 736 "match that of Chrome Binaries (" 737 << binaries->version().GetString() << ")."; 738 } 739 740 // Channel value must match that of binaries. 741 if (!ctx.state.channel().Equals(binaries->channel())) { 742 *is_valid = false; 743 LOG(ERROR) << "Channel name of " << ctx.dist->GetAppShortCutName() 744 << " (" << ctx.state.channel().value() 745 << ") does not match that of Chrome Binaries (" 746 << binaries->channel().value() << ")."; 747 } 748 } 749} 750 751// Validates the Google Update commands for the product described in |ctx|. 752void InstallationValidator::ValidateAppCommands( 753 const ProductContext& ctx, 754 bool* is_valid) { 755 DCHECK(is_valid); 756 757 CommandExpectations expectations; 758 759 if (ctx.dist->GetType() == BrowserDistribution::CHROME_APP_HOST) { 760 expectations[kCmdInstallApp] = &ValidateInstallAppCommand; 761 } 762 if (ctx.dist->GetType() == BrowserDistribution::CHROME_BROWSER) { 763 expectations[kCmdInstallExtension] = &ValidateInstallExtensionCommand; 764 expectations[kCmdOnOsUpgrade] = &ValidateOnOsUpgradeCommand; 765 } 766 767 ValidateAppCommandExpectations(ctx, expectations, is_valid); 768} 769 770// Validates usagestats for the product or binaries in |ctx|. 771void InstallationValidator::ValidateUsageStats(const ProductContext& ctx, 772 bool* is_valid) { 773 DWORD usagestats = 0; 774 if (ctx.state.GetUsageStats(&usagestats)) { 775 if (!ctx.rules.UsageStatsAllowed(ctx)) { 776 *is_valid = false; 777 LOG(ERROR) << ctx.dist->GetAppShortCutName() 778 << " has a usagestats value (" << usagestats 779 << "), yet should not."; 780 } else if (usagestats != 0 && usagestats != 1) { 781 *is_valid = false; 782 LOG(ERROR) << ctx.dist->GetAppShortCutName() 783 << " has an unsupported usagestats value (" << usagestats 784 << ")."; 785 } 786 } 787} 788 789// Validates the product described in |product_state| according to |rules|. 790void InstallationValidator::ValidateProduct( 791 const InstallationState& machine_state, 792 bool system_install, 793 const ProductState& product_state, 794 const ProductRules& rules, 795 bool* is_valid) { 796 DCHECK(is_valid); 797 798 ProductContext ctx(machine_state, system_install, product_state, rules); 799 800 ValidateUninstallCommand(ctx, ctx.state.uninstall_command(), 801 ASCIIToUTF16("Google Update uninstall command"), 802 is_valid); 803 804 ValidateOldVersionValues(ctx, is_valid); 805 806 if (ctx.state.is_multi_install()) 807 ValidateMultiInstallProduct(ctx, is_valid); 808 809 ValidateAppCommands(ctx, is_valid); 810 811 ValidateUsageStats(ctx, is_valid); 812} 813 814// static 815bool InstallationValidator::ValidateInstallationTypeForState( 816 const InstallationState& machine_state, 817 bool system_level, 818 InstallationType* type) { 819 DCHECK(type); 820 bool rock_on = true; 821 *type = NO_PRODUCTS; 822 823 // Does the system have any multi-installed products? 824 const ProductState* multi_state = 825 machine_state.GetProductState(system_level, 826 BrowserDistribution::CHROME_BINARIES); 827 if (multi_state != NULL) 828 ValidateBinaries(machine_state, system_level, *multi_state, &rock_on); 829 830 // Is Chrome installed? 831 const ProductState* product_state = 832 machine_state.GetProductState(system_level, 833 BrowserDistribution::CHROME_BROWSER); 834 if (product_state != NULL) { 835 ChromeRules chrome_rules; 836 ValidateProduct(machine_state, system_level, *product_state, 837 chrome_rules, &rock_on); 838 *type = static_cast<InstallationType>( 839 *type | (product_state->is_multi_install() ? 840 ProductBits::CHROME_MULTI : 841 ProductBits::CHROME_SINGLE)); 842 } 843 844 // Is Chrome Frame installed? 845 product_state = 846 machine_state.GetProductState(system_level, 847 BrowserDistribution::CHROME_FRAME); 848 if (product_state != NULL) { 849 ChromeFrameRules chrome_frame_rules; 850 ValidateProduct(machine_state, system_level, *product_state, 851 chrome_frame_rules, &rock_on); 852 int cf_bit = !product_state->is_multi_install() ? 853 ProductBits::CHROME_FRAME_SINGLE : 854 (product_state->uninstall_command().HasSwitch( 855 switches::kChromeFrameReadyMode) ? 856 ProductBits::CHROME_FRAME_READY_MODE : 857 ProductBits::CHROME_FRAME_MULTI); 858 *type = static_cast<InstallationType>(*type | cf_bit); 859 } 860 861 // Is Chrome App Host installed? 862 product_state = 863 machine_state.GetProductState(system_level, 864 BrowserDistribution::CHROME_APP_HOST); 865 if (product_state != NULL) { 866 ChromeAppHostRules chrome_app_host_rules; 867 ValidateProduct(machine_state, system_level, *product_state, 868 chrome_app_host_rules, &rock_on); 869 *type = static_cast<InstallationType>(*type | ProductBits::CHROME_APP_HOST); 870 if (system_level) { 871 LOG(ERROR) << 872 "Chrome App Launcher must not be installed at system level."; 873 rock_on = false; 874 } 875 if (!product_state->is_multi_install()) { 876 LOG(ERROR) << "Chrome App Launcher must always be multi-install."; 877 rock_on = false; 878 } 879 } 880 881 DCHECK_NE(std::find(&kInstallationTypes[0], 882 &kInstallationTypes[arraysize(kInstallationTypes)], 883 *type), 884 &kInstallationTypes[arraysize(kInstallationTypes)]) 885 << "Invalid combination of products found on system (" << *type << ")"; 886 887 return rock_on; 888} 889 890// static 891bool InstallationValidator::ValidateInstallationType(bool system_level, 892 InstallationType* type) { 893 DCHECK(type); 894 InstallationState machine_state; 895 896 machine_state.Initialize(); 897 898 return ValidateInstallationTypeForState(machine_state, system_level, type); 899} 900 901} // namespace installer 902