Home | History | Annotate | Download | only in util
      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 #include <map>
      6 
      7 #include "base/command_line.h"
      8 #include "base/files/file_path.h"
      9 #include "base/logging.h"
     10 #include "base/memory/ref_counted.h"
     11 #include "base/version.h"
     12 #include "chrome/common/chrome_constants.h"
     13 #include "chrome/common/chrome_switches.h"
     14 #include "chrome/installer/util/channel_info.h"
     15 #include "chrome/installer/util/helper.h"
     16 #include "chrome/installer/util/installation_state.h"
     17 #include "chrome/installer/util/installation_validator.h"
     18 #include "testing/gmock/include/gmock/gmock.h"
     19 #include "testing/gtest/include/gtest/gtest.h"
     20 
     21 using installer::ChannelInfo;
     22 using installer::InstallationValidator;
     23 using installer::InstallationState;
     24 using installer::AppCommand;
     25 using installer::ProductState;
     26 using testing::_;
     27 using testing::StrictMock;
     28 using testing::Values;
     29 
     30 namespace {
     31 
     32 enum Channel {
     33   STABLE_CHANNEL,
     34   BETA_CHANNEL,
     35   DEV_CHANNEL
     36 };
     37 
     38 enum PackageType {
     39   SINGLE_INSTALL,
     40   MULTI_INSTALL
     41 };
     42 
     43 enum Level {
     44   USER_LEVEL,
     45   SYSTEM_LEVEL
     46 };
     47 
     48 enum Vehicle {
     49   GOOGLE_UPDATE,
     50   MSI
     51 };
     52 
     53 enum ChannelModifier {
     54   CM_MULTI        = 0x01,
     55   CM_CHROME       = 0x02,
     56   CM_CHROME_FRAME = 0x04,
     57   CM_FULL         = 0x08
     58 };
     59 
     60 const wchar_t* const kChromeChannels[] = {
     61   L"",
     62   L"1.1-beta",
     63   L"2.0-dev"
     64 };
     65 
     66 const wchar_t* const kChromeFrameChannels[] = {
     67   L"",
     68   L"beta",
     69   L"dev"
     70 };
     71 
     72 class FakeProductState : public ProductState {
     73  public:
     74   void SetChannel(const wchar_t* base, int channel_modifiers);
     75   void SetVersion(const char* version);
     76   void SetUninstallCommand(BrowserDistribution::Type dist_type,
     77                            Level install_level,
     78                            const char* version,
     79                            int channel_modifiers,
     80                            Vehicle vehicle);
     81   void AddInstallExtensionCommand(BrowserDistribution::Type dist_type,
     82                                   Level install_level,
     83                                   const char* version,
     84                                   int channel_modifiers);
     85   void AddOsUpgradeCommand(BrowserDistribution::Type dist_type,
     86                            Level install_level,
     87                            const char* version,
     88                            int channel_modifiers);
     89   void AddQueryEULAAcceptanceCommand(BrowserDistribution::Type dist_type,
     90                                      Level install_level,
     91                                      const char* version,
     92                                      int channel_modifiers);
     93   void AddQuickEnableApplicationHostCommand(BrowserDistribution::Type dist_type,
     94                                             Level install_level,
     95                                             const char* version,
     96                                             int channel_modifiers);
     97   void set_multi_install(bool is_multi_install) {
     98     multi_install_ = is_multi_install;
     99   }
    100   installer::AppCommands& commands() { return commands_; }
    101 
    102  protected:
    103   struct ChannelMethodForModifier {
    104     ChannelModifier modifier;
    105     bool (ChannelInfo::*method)(bool value);
    106   };
    107 
    108   static base::FilePath GetSetupPath(
    109       BrowserDistribution::Type dist_type,
    110       Level install_level,
    111       int channel_modifiers);
    112 
    113   static base::FilePath GetSetupExePath(
    114       BrowserDistribution::Type dist_type,
    115       Level install_level,
    116       const char* version,
    117       int channel_modifiers);
    118 
    119   static const ChannelMethodForModifier kChannelMethods[];
    120 };
    121 
    122 class FakeInstallationState : public InstallationState {
    123  public:
    124   void SetProductState(BrowserDistribution::Type type,
    125                        Level install_level,
    126                        const ProductState& product) {
    127     GetProducts(install_level)[IndexFromDistType(type)].CopyFrom(product);
    128   }
    129 
    130  protected:
    131   ProductState* GetProducts(Level install_level) {
    132     return install_level == USER_LEVEL ? user_products_ : system_products_;
    133   }
    134 };
    135 
    136 // static
    137 const FakeProductState::ChannelMethodForModifier
    138     FakeProductState::kChannelMethods[] = {
    139   { CM_MULTI,        &ChannelInfo::SetMultiInstall },
    140   { CM_CHROME,       &ChannelInfo::SetChrome },
    141   { CM_CHROME_FRAME, &ChannelInfo::SetChromeFrame },
    142   { CM_FULL,         &ChannelInfo::SetFullSuffix }
    143 };
    144 
    145 // static
    146 base::FilePath FakeProductState::GetSetupPath(
    147     BrowserDistribution::Type dist_type,
    148     Level install_level,
    149     int channel_modifiers) {
    150   const bool is_multi_install = (channel_modifiers & CM_MULTI) != 0;
    151   return installer::GetChromeInstallPath(
    152       install_level == SYSTEM_LEVEL,
    153       BrowserDistribution::GetSpecificDistribution(is_multi_install ?
    154               BrowserDistribution::CHROME_BINARIES : dist_type));
    155 }
    156 
    157 // static
    158 base::FilePath FakeProductState::GetSetupExePath(
    159     BrowserDistribution::Type dist_type,
    160     Level install_level,
    161     const char* version,
    162     int channel_modifiers) {
    163   base::FilePath setup_path = GetSetupPath(dist_type, install_level,
    164                                            channel_modifiers);
    165   return setup_path
    166       .AppendASCII(version)
    167       .Append(installer::kInstallerDir)
    168       .Append(installer::kSetupExe);
    169 }
    170 
    171 // Sets the channel_ member of this instance according to a base channel value
    172 // and a set of modifiers.
    173 void FakeProductState::SetChannel(const wchar_t* base, int channel_modifiers) {
    174   channel_.set_value(base);
    175   for (size_t i = 0; i < arraysize(kChannelMethods); ++i) {
    176     if ((channel_modifiers & kChannelMethods[i].modifier) != 0)
    177       (channel_.*kChannelMethods[i].method)(true);
    178   }
    179 }
    180 
    181 void FakeProductState::SetVersion(const char* version) {
    182   version_.reset(version == NULL ? NULL : new Version(version));
    183 }
    184 
    185 // Sets the uninstall command for this object.
    186 void FakeProductState::SetUninstallCommand(BrowserDistribution::Type dist_type,
    187                                            Level install_level,
    188                                            const char* version,
    189                                            int channel_modifiers,
    190                                            Vehicle vehicle) {
    191   DCHECK(version);
    192 
    193   const bool is_multi_install = (channel_modifiers & CM_MULTI) != 0;
    194   uninstall_command_ = CommandLine(GetSetupExePath(dist_type, install_level,
    195                                                    version, channel_modifiers));
    196   uninstall_command_.AppendSwitch(installer::switches::kUninstall);
    197   if (install_level == SYSTEM_LEVEL)
    198     uninstall_command_.AppendSwitch(installer::switches::kSystemLevel);
    199   if (is_multi_install) {
    200     uninstall_command_.AppendSwitch(installer::switches::kMultiInstall);
    201     if (dist_type == BrowserDistribution::CHROME_BROWSER)
    202       uninstall_command_.AppendSwitch(installer::switches::kChrome);
    203     else if (dist_type == BrowserDistribution::CHROME_FRAME)
    204       uninstall_command_.AppendSwitch(installer::switches::kChromeFrame);
    205   } else if (dist_type == BrowserDistribution::CHROME_FRAME) {
    206     uninstall_command_.AppendSwitch(installer::switches::kChromeFrame);
    207   }
    208   if (vehicle == MSI)
    209     uninstall_command_.AppendSwitch(installer::switches::kMsi);
    210 }
    211 
    212 // Adds the "install-extension" Google Update product command.
    213 void FakeProductState::AddInstallExtensionCommand(
    214     BrowserDistribution::Type dist_type,
    215     Level install_level,
    216     const char* version,
    217     int channel_modifiers) {
    218   // Right now only Chrome browser uses this.
    219   DCHECK_EQ(dist_type, BrowserDistribution::CHROME_BROWSER);
    220 
    221   CommandLine cmd_line(GetSetupPath(dist_type, install_level,
    222                                     channel_modifiers).
    223                            Append(installer::kChromeExe));
    224   cmd_line.AppendSwitchASCII(::switches::kLimitedInstallFromWebstore, "%1");
    225   AppCommand app_cmd(cmd_line.GetCommandLineString());
    226   app_cmd.set_sends_pings(true);
    227   app_cmd.set_is_web_accessible(true);
    228   app_cmd.set_is_run_as_user(true);
    229   commands_.Set(installer::kCmdInstallExtension, app_cmd);
    230 }
    231 
    232 // Adds the "on-os-upgrade" Google Update product command.
    233 void FakeProductState::AddOsUpgradeCommand(BrowserDistribution::Type dist_type,
    234                                            Level install_level,
    235                                            const char* version,
    236                                            int channel_modifiers) {
    237   // Right now only Chrome browser uses this.
    238   DCHECK_EQ(dist_type, BrowserDistribution::CHROME_BROWSER);
    239 
    240   CommandLine cmd_line(GetSetupExePath(dist_type, install_level, version,
    241                                        channel_modifiers));
    242   cmd_line.AppendSwitch(installer::switches::kOnOsUpgrade);
    243   // Imitating ChromeBrowserOperations::AppendProductFlags().
    244   if ((channel_modifiers & CM_MULTI) != 0) {
    245     cmd_line.AppendSwitch(installer::switches::kMultiInstall);
    246     cmd_line.AppendSwitch(installer::switches::kChrome);
    247   }
    248   if (install_level == SYSTEM_LEVEL)
    249     cmd_line.AppendSwitch(installer::switches::kSystemLevel);
    250   cmd_line.AppendSwitch(installer::switches::kVerboseLogging);
    251   AppCommand app_cmd(cmd_line.GetCommandLineString());
    252   app_cmd.set_is_auto_run_on_os_upgrade(true);
    253   commands_.Set(installer::kCmdOnOsUpgrade, app_cmd);
    254 }
    255 
    256 // Adds the "query-eula-acceptance" Google Update product command.
    257 void FakeProductState::AddQueryEULAAcceptanceCommand(
    258     BrowserDistribution::Type dist_type,
    259     Level install_level,
    260     const char* version,
    261     int channel_modifiers) {
    262   DCHECK_EQ(dist_type, BrowserDistribution::CHROME_BINARIES);
    263 
    264   CommandLine cmd_line(GetSetupExePath(dist_type, install_level, version,
    265                                        channel_modifiers));
    266   cmd_line.AppendSwitch(installer::switches::kQueryEULAAcceptance);
    267   if (install_level == SYSTEM_LEVEL)
    268     cmd_line.AppendSwitch(installer::switches::kSystemLevel);
    269   cmd_line.AppendSwitch(installer::switches::kVerboseLogging);
    270   AppCommand app_cmd(cmd_line.GetCommandLineString());
    271   app_cmd.set_is_web_accessible(true);
    272   app_cmd.set_is_run_as_user(true);
    273   commands_.Set(installer::kCmdQueryEULAAcceptance, app_cmd);
    274 }
    275 
    276 // Adds the "quick-enable-application-host" Google Update product command.
    277 void FakeProductState::AddQuickEnableApplicationHostCommand(
    278     BrowserDistribution::Type dist_type,
    279     Level install_level,
    280     const char* version,
    281     int channel_modifiers) {
    282   DCHECK_EQ(dist_type, BrowserDistribution::CHROME_BINARIES);
    283   DCHECK_NE(channel_modifiers & CM_MULTI, 0);
    284 
    285   CommandLine cmd_line(GetSetupExePath(dist_type, install_level, version,
    286                                        channel_modifiers));
    287   cmd_line.AppendSwitch(installer::switches::kMultiInstall);
    288   cmd_line.AppendSwitch(installer::switches::kChromeAppLauncher);
    289   cmd_line.AppendSwitch(installer::switches::kEnsureGoogleUpdatePresent);
    290   AppCommand app_cmd(cmd_line.GetCommandLineString());
    291   app_cmd.set_sends_pings(true);
    292   app_cmd.set_is_web_accessible(true);
    293   app_cmd.set_is_run_as_user(true);
    294   commands_.Set(installer::kCmdQuickEnableApplicationHost, app_cmd);
    295 }
    296 
    297 }  // namespace
    298 
    299 // Fixture for testing the InstallationValidator.  Errors logged by the
    300 // validator are sent to an optional mock recipient (see
    301 // set_validation_error_recipient) upon which expectations can be placed.
    302 class InstallationValidatorTest
    303     : public testing::TestWithParam<InstallationValidator::InstallationType> {
    304  public:
    305 
    306   // These shouldn't need to be public, but there seems to be some interaction
    307   // with parameterized tests that requires it.
    308   static void SetUpTestCase();
    309   static void TearDownTestCase();
    310 
    311   // Returns the multi channel modifiers for a given installation type.
    312   static int GetChannelModifiers(InstallationValidator::InstallationType type);
    313 
    314  protected:
    315   typedef std::map<InstallationValidator::InstallationType, int>
    316       InstallationTypeToModifiers;
    317 
    318   class ValidationErrorRecipient {
    319    public:
    320     virtual ~ValidationErrorRecipient() { }
    321     virtual void ReceiveValidationError(const char* file,
    322                                         int line,
    323                                         const char* message) = 0;
    324   };
    325   class MockValidationErrorRecipient : public ValidationErrorRecipient {
    326    public:
    327     MOCK_METHOD3(ReceiveValidationError, void(const char* file,
    328                                               int line,
    329                                               const char* message));
    330   };
    331 
    332  protected:
    333   static bool HandleLogMessage(int severity,
    334                                const char* file,
    335                                int line,
    336                                size_t message_start,
    337                                const std::string& str);
    338   static void set_validation_error_recipient(
    339       ValidationErrorRecipient* recipient);
    340   static void MakeProductState(
    341       BrowserDistribution::Type prod_type,
    342       InstallationValidator::InstallationType inst_type,
    343       Level install_level,
    344       Channel channel,
    345       Vehicle vehicle,
    346       FakeProductState* state);
    347   static void MakeMachineState(
    348       InstallationValidator::InstallationType inst_type,
    349       Level install_level,
    350       Channel channel,
    351       Vehicle vehicle,
    352       FakeInstallationState* state);
    353   virtual void TearDown();
    354 
    355   static logging::LogMessageHandlerFunction old_log_message_handler_;
    356   static ValidationErrorRecipient* validation_error_recipient_;
    357   static InstallationTypeToModifiers* type_to_modifiers_;
    358 };
    359 
    360 // static
    361 logging::LogMessageHandlerFunction
    362     InstallationValidatorTest::old_log_message_handler_ = NULL;
    363 
    364 // static
    365 InstallationValidatorTest::ValidationErrorRecipient*
    366     InstallationValidatorTest::validation_error_recipient_ = NULL;
    367 
    368 // static
    369 InstallationValidatorTest::InstallationTypeToModifiers*
    370     InstallationValidatorTest::type_to_modifiers_ = NULL;
    371 
    372 // static
    373 int InstallationValidatorTest::GetChannelModifiers(
    374     InstallationValidator::InstallationType type) {
    375   DCHECK(type_to_modifiers_);
    376   DCHECK(type_to_modifiers_->find(type) != type_to_modifiers_->end());
    377 
    378   return (*type_to_modifiers_)[type];
    379 }
    380 
    381 // static
    382 void InstallationValidatorTest::SetUpTestCase() {
    383   DCHECK(type_to_modifiers_ == NULL);
    384   old_log_message_handler_ = logging::GetLogMessageHandler();
    385   logging::SetLogMessageHandler(&HandleLogMessage);
    386 
    387   type_to_modifiers_ = new InstallationTypeToModifiers();
    388   InstallationTypeToModifiers& ttm = *type_to_modifiers_;
    389   ttm[InstallationValidator::NO_PRODUCTS] = 0;
    390   ttm[InstallationValidator::CHROME_SINGLE] = 0;
    391   ttm[InstallationValidator::CHROME_MULTI] = CM_MULTI | CM_CHROME;
    392   ttm[InstallationValidator::CHROME_FRAME_SINGLE] = 0;
    393   ttm[InstallationValidator::CHROME_FRAME_SINGLE_CHROME_SINGLE] = 0;
    394   ttm[InstallationValidator::CHROME_FRAME_SINGLE_CHROME_MULTI] =
    395       CM_MULTI | CM_CHROME;
    396   ttm[InstallationValidator::CHROME_FRAME_MULTI] = CM_MULTI | CM_CHROME_FRAME;
    397   ttm[InstallationValidator::CHROME_FRAME_MULTI_CHROME_MULTI] =
    398       CM_MULTI | CM_CHROME_FRAME | CM_CHROME;
    399 }
    400 
    401 // static
    402 void InstallationValidatorTest::TearDownTestCase() {
    403   logging::SetLogMessageHandler(old_log_message_handler_);
    404   old_log_message_handler_ = NULL;
    405 
    406   delete type_to_modifiers_;
    407   type_to_modifiers_ = NULL;
    408 }
    409 
    410 // static
    411 bool InstallationValidatorTest::HandleLogMessage(int severity,
    412                                                  const char* file,
    413                                                  int line,
    414                                                  size_t message_start,
    415                                                  const std::string& str) {
    416   // All validation failures result in LOG(ERROR)
    417   if (severity == logging::LOG_ERROR && !str.empty()) {
    418     // Remove the trailing newline, if present.
    419     size_t message_length = str.size() - message_start;
    420     if (*str.rbegin() == '\n')
    421       --message_length;
    422     if (validation_error_recipient_ != NULL) {
    423       validation_error_recipient_->ReceiveValidationError(
    424           file, line, str.substr(message_start, message_length).c_str());
    425     } else {
    426       // Fail the test if an error wasn't handled.
    427       ADD_FAILURE_AT(file, line)
    428           << base::StringPiece(str.c_str() + message_start, message_length);
    429     }
    430     return true;
    431   }
    432 
    433   if (old_log_message_handler_ != NULL)
    434     return (old_log_message_handler_)(severity, file, line, message_start, str);
    435 
    436   return false;
    437 }
    438 
    439 // static
    440 void InstallationValidatorTest::set_validation_error_recipient(
    441     ValidationErrorRecipient* recipient) {
    442   validation_error_recipient_ = recipient;
    443 }
    444 
    445 // static
    446 // Populates |state| with the state of a valid installation of product
    447 // |prod_type|.  |inst_type| dictates properties of the installation
    448 // (multi-install, etc).
    449 void InstallationValidatorTest::MakeProductState(
    450     BrowserDistribution::Type prod_type,
    451     InstallationValidator::InstallationType inst_type,
    452     Level install_level,
    453     Channel channel,
    454     Vehicle vehicle,
    455     FakeProductState* state) {
    456   DCHECK(state);
    457 
    458   const bool is_multi_install =
    459       prod_type == BrowserDistribution::CHROME_BINARIES ||
    460       (prod_type == BrowserDistribution::CHROME_BROWSER &&
    461        (inst_type & InstallationValidator::ProductBits::CHROME_MULTI) != 0) ||
    462       (prod_type == BrowserDistribution::CHROME_FRAME &&
    463        (inst_type &
    464            InstallationValidator::ProductBits::CHROME_FRAME_MULTI) != 0);
    465 
    466   const wchar_t* const* channels = &kChromeChannels[0];
    467   if (prod_type == BrowserDistribution::CHROME_FRAME && !is_multi_install)
    468     channels = &kChromeFrameChannels[0];  // SxS GCF has its own channel names.
    469   const int channel_modifiers =
    470       is_multi_install ? GetChannelModifiers(inst_type) : 0;
    471 
    472   state->Clear();
    473   state->SetChannel(channels[channel], channel_modifiers);
    474   state->SetVersion(chrome::kChromeVersion);
    475   state->SetUninstallCommand(prod_type, install_level, chrome::kChromeVersion,
    476                              channel_modifiers, vehicle);
    477   state->set_multi_install(is_multi_install);
    478   if (prod_type == BrowserDistribution::CHROME_BINARIES) {
    479     state->AddQueryEULAAcceptanceCommand(prod_type,
    480                                          install_level,
    481                                          chrome::kChromeVersion,
    482                                          channel_modifiers);
    483   }
    484   if (prod_type == BrowserDistribution::CHROME_BINARIES) {
    485     state->AddQuickEnableApplicationHostCommand(prod_type,
    486                                                 install_level,
    487                                                 chrome::kChromeVersion,
    488                                                 channel_modifiers);
    489   }
    490   if (prod_type == BrowserDistribution::CHROME_BROWSER) {
    491     state->AddOsUpgradeCommand(prod_type,
    492                                install_level,
    493                                chrome::kChromeVersion,
    494                                channel_modifiers);
    495     state->AddInstallExtensionCommand(prod_type,
    496                                       install_level,
    497                                       chrome::kChromeVersion,
    498                                       channel_modifiers);
    499   }
    500 }
    501 
    502 // static
    503 // Populates |state| with the state of a valid installation of |inst_type|.
    504 void InstallationValidatorTest::MakeMachineState(
    505     InstallationValidator::InstallationType inst_type,
    506     Level install_level,
    507     Channel channel,
    508     Vehicle vehicle,
    509     FakeInstallationState* state) {
    510   DCHECK(state);
    511 
    512   static const int kChromeMask =
    513       (InstallationValidator::ProductBits::CHROME_SINGLE |
    514        InstallationValidator::ProductBits::CHROME_MULTI);
    515   static const int kChromeFrameMask =
    516       (InstallationValidator::ProductBits::CHROME_FRAME_SINGLE |
    517        InstallationValidator::ProductBits::CHROME_FRAME_MULTI);
    518   static const int kBinariesMask =
    519       (InstallationValidator::ProductBits::CHROME_MULTI |
    520        InstallationValidator::ProductBits::CHROME_FRAME_MULTI);
    521 
    522   FakeProductState prod_state;
    523 
    524   if ((inst_type & kChromeMask) != 0) {
    525     MakeProductState(BrowserDistribution::CHROME_BROWSER, inst_type,
    526                      install_level, channel, vehicle, &prod_state);
    527     state->SetProductState(BrowserDistribution::CHROME_BROWSER, install_level,
    528                            prod_state);
    529   }
    530 
    531   if ((inst_type & kChromeFrameMask) != 0) {
    532     MakeProductState(BrowserDistribution::CHROME_FRAME, inst_type,
    533                      install_level, channel, vehicle, &prod_state);
    534     state->SetProductState(BrowserDistribution::CHROME_FRAME, install_level,
    535                            prod_state);
    536   }
    537 
    538   if ((inst_type & kBinariesMask) != 0) {
    539     MakeProductState(BrowserDistribution::CHROME_BINARIES, inst_type,
    540                      install_level, channel, vehicle, &prod_state);
    541     state->SetProductState(BrowserDistribution::CHROME_BINARIES, install_level,
    542                            prod_state);
    543   }
    544 }
    545 
    546 void InstallationValidatorTest::TearDown() {
    547   validation_error_recipient_ = NULL;
    548 }
    549 
    550 // Builds a proper machine state for a given InstallationType, then validates
    551 // it.
    552 TEST_P(InstallationValidatorTest, TestValidInstallation) {
    553   const InstallationValidator::InstallationType inst_type = GetParam();
    554   FakeInstallationState machine_state;
    555   InstallationValidator::InstallationType type;
    556   StrictMock<MockValidationErrorRecipient> recipient;
    557   set_validation_error_recipient(&recipient);
    558 
    559   MakeMachineState(inst_type, SYSTEM_LEVEL, STABLE_CHANNEL, GOOGLE_UPDATE,
    560                    &machine_state);
    561   EXPECT_TRUE(InstallationValidator::ValidateInstallationTypeForState(
    562                   machine_state, true, &type));
    563   EXPECT_EQ(inst_type, type);
    564 }
    565 
    566 // Run the test for all installation types.
    567 INSTANTIATE_TEST_CASE_P(
    568     AllValidInstallations,
    569     InstallationValidatorTest,
    570     Values(InstallationValidator::NO_PRODUCTS,
    571            InstallationValidator::CHROME_SINGLE,
    572            InstallationValidator::CHROME_MULTI,
    573            InstallationValidator::CHROME_FRAME_SINGLE,
    574            InstallationValidator::CHROME_FRAME_SINGLE_CHROME_SINGLE,
    575            InstallationValidator::CHROME_FRAME_SINGLE_CHROME_MULTI,
    576            InstallationValidator::CHROME_FRAME_MULTI,
    577            InstallationValidator::CHROME_FRAME_MULTI_CHROME_MULTI));
    578