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