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