Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(71)

Side by Side Diff: chrome/installer/util/installation_validator.cc

Issue 6490024: New installation validator machinery to check the machine state.... (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src/
Patch Set: '' Created 9 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
Property Changes:
Added: svn:eol-style
+ LF
OLDNEW
(Empty)
1 // Copyright (c) 2011 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
11 #include "base/logging.h"
12 #include "base/version.h"
13 #include "chrome/installer/util/browser_distribution.h"
14 #include "chrome/installer/util/helper.h"
15 #include "chrome/installer/util/installation_state.h"
16
17 namespace installer {
18
19 BrowserDistribution::Type
20 InstallationValidator::ChromeRules::distribution_type() const {
21 return BrowserDistribution::CHROME_BROWSER;
22 }
23
24 void InstallationValidator::ChromeRules::AddUninstallSwitchExpectations(
25 const InstallationState& machine_state,
26 bool system_install,
27 const ProductState& product_state,
28 SwitchExpectations* expectations) const {
29 const bool is_multi_install =
30 product_state.uninstall_command().HasSwitch(switches::kMultiInstall);
31
32 // --chrome should be present iff --multi-install.
33 expectations->push_back(std::make_pair(std::string(switches::kChrome),
34 is_multi_install));
35 // --chrome-frame --ready-mode should be present iff CF in ready mode.
36 const ProductState* cf_state =
37 machine_state.GetProductState(system_install,
38 BrowserDistribution::CHROME_FRAME);
39 const bool ready_mode =
40 cf_state != NULL &&
41 cf_state->uninstall_command().HasSwitch(switches::kChromeFrameReadyMode);
42 expectations->push_back(std::make_pair(std::string(switches::kChromeFrame),
43 ready_mode));
44 expectations->push_back(
45 std::make_pair(std::string(switches::kChromeFrameReadyMode), ready_mode));
46 }
47
48 BrowserDistribution::Type
49 InstallationValidator::ChromeFrameRules::distribution_type() const {
50 return BrowserDistribution::CHROME_FRAME;
51 }
52
53 void InstallationValidator::ChromeFrameRules::AddUninstallSwitchExpectations(
54 const InstallationState& machine_state,
55 bool system_install,
56 const ProductState& product_state,
57 SwitchExpectations* expectations) const {
58 const bool is_multi_install =
59 product_state.uninstall_command().HasSwitch(switches::kMultiInstall);
robertshield 2011/02/14 14:09:11 is_multi_install appears unused?
grt (UTC plus 2) 2011/02/14 15:48:03 Nice catch. Thanks.
60
61 // --chrome-frame must be present.
62 expectations->push_back(std::make_pair(std::string(switches::kChromeFrame),
63 true));
64 // --chrome must not be present.
65 expectations->push_back(std::make_pair(std::string(switches::kChrome),
66 false));
67 }
68
69 // static
70 const InstallationValidator::InstallationType
71 InstallationValidator::kInstallationTypes[] = {
72 NO_PRODUCTS,
73 CHROME_SINGLE,
74 CHROME_MULTI,
75 CHROME_FRAME_SINGLE,
76 CHROME_FRAME_SINGLE_CHROME_SINGLE,
77 CHROME_FRAME_SINGLE_CHROME_MULTI,
78 CHROME_FRAME_MULTI,
79 CHROME_FRAME_MULTI_CHROME_MULTI,
80 CHROME_FRAME_READY_MODE_CHROME_MULTI
81 };
82
83 // Validates the multi-install binaries at level |system_level|.
84 void InstallationValidator::ValidateBinaries(
85 const InstallationState& machine_state,
86 bool system_install,
87 const ProductState& binaries_state,
88 bool* is_valid) {
89 const ChannelInfo& channel = binaries_state.channel();
90
91 // ap must have -multi
92 if (!channel.IsMultiInstall()) {
93 *is_valid = false;
94 LOG(ERROR) << "Chrome Binaries are missing \"-multi\" in channel name: \""
95 << channel.value() << "\"";
96 }
97
98 // ap must have -chrome iff Chrome is installed
99 const ProductState* chrome_state = machine_state.GetProductState(
100 system_install, BrowserDistribution::CHROME_BROWSER);
101 if (chrome_state != NULL) {
102 if (!channel.IsChrome()) {
103 *is_valid = false;
104 LOG(ERROR) << "Chrome Binaries are missing \"chrome\" in channel name:"
105 << " \"" << channel.value() << "\"";
106 }
107 } else if (channel.IsChrome()) {
108 *is_valid = false;
109 LOG(ERROR) << "Chrome Binaries have \"-chrome\" in channel name, yet Chrome"
110 " is not installed: \"" << channel.value() << "\"";
111 }
112
113 // ap must have -chromeframe iff Chrome Frame is installed multi
114 const ProductState* cf_state = machine_state.GetProductState(
115 system_install, BrowserDistribution::CHROME_FRAME);
116 if (cf_state != NULL && cf_state->is_multi_install()) {
117 if (!channel.IsChromeFrame()) {
118 *is_valid = false;
119 LOG(ERROR) << "Chrome Binaries are missing \"-chromeframe\" in channel"
120 " name: \"" << channel.value() << "\"";
121 }
122 } else if (channel.IsChromeFrame()) {
123 *is_valid = false;
124 LOG(ERROR) << "Chrome Binaries have \"-chromeframe\" in channel name, yet "
125 "Chrome Frame is not installed multi: \"" << channel.value()
126 << "\"";
127 }
128
129 // ap must have -readymode iff Chrome Frame is installed in ready-mode
130 if (cf_state != NULL &&
131 cf_state->uninstall_command().HasSwitch(
132 installer::switches::kChromeFrameReadyMode)) {
133 if (!channel.IsReadyMode()) {
134 *is_valid = false;
135 LOG(ERROR) << "Chrome Binaries are missing \"-readymode\" in channel"
136 " name: \"" << channel.value() << "\"";
137 }
138 } else if (channel.IsReadyMode()) {
139 *is_valid = false;
140 LOG(ERROR) << "Chrome Binaries have \"-readymode\" in channel name, yet "
141 "Chrome Frame is not in ready mode: \"" << channel.value()
142 << "\"";
143 }
144
145 // Chrome or Chrome Frame must be present
146 if (chrome_state == NULL && cf_state == NULL) {
147 *is_valid = false;
148 LOG(ERROR) << "Chrome Binaries are present with no other products.";
149 }
150
151 // Chrome must be multi-install if present.
152 if (chrome_state != NULL && !chrome_state->is_multi_install()) {
153 *is_valid = false;
154 LOG(ERROR)
155 << "Chrome Binaries are present yet Chrome is not multi-install.";
156 }
157
158 // Chrome Frame must be multi-install if Chrome is not present.
159 if (cf_state != NULL && chrome_state == NULL &&
160 !cf_state->is_multi_install()) {
161 *is_valid = false;
162 LOG(ERROR) << "Chrome Binaries are present without Chrome yet Chrome Frame "
163 "is not multi-install.";
164 }
165 }
166
167 // Validates the path to |setup_exe| for the product described by |ctx|.
168 void InstallationValidator::ValidateSetupPath(const ProductContext& ctx,
169 const FilePath& setup_exe,
170 const char* purpose,
171 bool* is_valid) {
172 DCHECK(is_valid);
173
174 BrowserDistribution* bins_dist = ctx.dist;
175 if (ctx.state.is_multi_install()) {
176 bins_dist = BrowserDistribution::GetSpecificDistribution(
177 BrowserDistribution::CHROME_BINARIES);
178 }
179
180 FilePath expected_path = installer::GetChromeInstallPath(ctx.system_install,
181 bins_dist);
182 expected_path = expected_path
183 .AppendASCII(ctx.state.version().GetString())
184 .Append(installer::kInstallerDir)
185 .Append(installer::kSetupExe);
186 if (!FilePath::CompareEqualIgnoreCase(expected_path.value(),
187 setup_exe.value())) {
188 *is_valid = false;
189 LOG(ERROR) << ctx.dist->GetApplicationName() << " path to " << purpose
190 << " is not " << expected_path.value() << ": "
191 << setup_exe.value();
192 }
193 }
194
195 // Validates that |command| meets the expectations described in |expected|.
196 void InstallationValidator::ValidateCommandExpectations(
197 const ProductContext& ctx,
198 const CommandLine& command,
199 const SwitchExpectations& expected,
200 const char* source,
201 bool* is_valid) {
202 for (SwitchExpectations::size_type i = 0, size = expected.size(); i < size;
203 ++i) {
204 const SwitchExpectations::value_type& expectation = expected[i];
205 if (command.HasSwitch(expectation.first) != expectation.second) {
206 *is_valid = false;
207 LOG(ERROR) << ctx.dist->GetApplicationName() << " " << source
208 << (expectation.second ? " is missing" : " has") << " \""
209 << expectation.first << "\""
210 << (expectation.second ? "" : " but shouldn't") << ": "
211 << command.command_line_string();
212 }
213 }
214 }
215
216 // Validates that |command|, originating from |source|, is formed properly for
217 // the product described by |ctx|
218 void InstallationValidator::ValidateUninstallCommand(const ProductContext& ctx,
219 const CommandLine& command,
220 const char* source,
221 bool* is_valid) {
222 DCHECK(is_valid);
223
224 ValidateSetupPath(ctx, command.GetProgram(), "uninstaller", is_valid);
225
226 const bool is_multi_install = ctx.state.is_multi_install();
227 SwitchExpectations expected;
228
229 expected.push_back(std::make_pair(std::string(switches::kUninstall), true));
230 expected.push_back(std::make_pair(std::string(switches::kSystemLevel),
231 ctx.system_install));
232 expected.push_back(std::make_pair(std::string(switches::kMultiInstall),
233 is_multi_install));
234 ctx.rules.AddUninstallSwitchExpectations(ctx.machine_state,
235 ctx.system_install,
236 ctx.state, &expected);
237
238 ValidateCommandExpectations(ctx, command, expected, source, is_valid);
239 }
240
241 // Validates the rename command for the product described by |ctx|.
242 void InstallationValidator::ValidateRenameCommand(const ProductContext& ctx,
243 bool* is_valid) {
244 DCHECK(is_valid);
245 DCHECK(!ctx.state.rename_cmd().empty());
246
247 CommandLine command = CommandLine::FromString(ctx.state.rename_cmd());
248
249 ValidateSetupPath(ctx, command.GetProgram(), "in-use renamer", is_valid);
250
251 SwitchExpectations expected;
252
253 expected.push_back(std::make_pair(std::string(switches::kRenameChromeExe),
254 true));
255 expected.push_back(std::make_pair(std::string(switches::kSystemLevel),
256 ctx.system_install));
257 expected.push_back(std::make_pair(std::string(switches::kMultiInstall),
258 ctx.state.is_multi_install()));
259
260 ValidateCommandExpectations(ctx, command, expected, "in-use renamer",
261 is_valid);
262 }
263
264 // Validates the "opv" and "cmd" values for the product described in |ctx|.
265 void InstallationValidator::ValidateOldVersionValues(
266 const ProductContext& ctx,
267 bool* is_valid) {
268 DCHECK(is_valid);
269
270 // opv and cmd must both be present or both absent
271 if (ctx.state.old_version() == NULL) {
272 if (!ctx.state.rename_cmd().empty()) {
273 *is_valid = false;
274 LOG(ERROR) << ctx.dist->GetApplicationName()
275 << " has a rename command but no opv: "
276 << ctx.state.rename_cmd();
277 }
278 } else {
279 if (ctx.state.rename_cmd().empty()) {
280 *is_valid = false;
281 LOG(ERROR) << ctx.dist->GetApplicationName()
282 << " has an opv but no rename command: "
283 << ctx.state.old_version()->GetString();
284 } else {
285 ValidateRenameCommand(ctx, is_valid);
286 }
287 }
288 }
289
290 // Validates the multi-install state of the product described in |ctx|.
291 void InstallationValidator::ValidateMultiInstallProduct(
292 const ProductContext& ctx,
293 bool* is_valid) {
294 DCHECK(is_valid);
295
296 const ProductState* binaries =
297 ctx.machine_state.GetProductState(ctx.system_install,
298 BrowserDistribution::CHROME_BINARIES);
299 DCHECK(binaries);
300
301 // Version must match that of binaries.
302 if (ctx.state.version().CompareTo(binaries->version()) != 0) {
303 *is_valid = false;
304 LOG(ERROR) << "Version of " << ctx.dist->GetApplicationName()
305 << " (" << ctx.state.version().GetString() << ") does not "
306 "match that of Chrome Binaries ("
307 << binaries->version().GetString() << ").";
308 }
309
310 // Channel value must match that of binaries.
311 if (!ctx.state.channel().Equals(binaries->channel())) {
312 *is_valid = false;
313 LOG(ERROR) << "Channel name of " << ctx.dist->GetApplicationName()
314 << " (" << ctx.state.channel().value()
315 << ") does not match that of Chrome Binaries ("
316 << binaries->channel().value() << ").";
317 }
318 }
319
320 // Validates the product described in |product_state| according to |rules|.
321 void InstallationValidator::ValidateProduct(
322 const InstallationState& machine_state,
323 bool system_install,
324 const ProductState& product_state,
325 const ProductRules& rules,
326 bool* is_valid) {
327 DCHECK(is_valid);
328 ProductContext ctx = {
329 machine_state,
330 system_install,
331 BrowserDistribution::GetSpecificDistribution(rules.distribution_type()),
332 product_state,
333 rules
334 };
335
336 ValidateUninstallCommand(ctx, product_state.uninstall_command(),
337 "Google Update uninstall command", is_valid);
338
339 ValidateOldVersionValues(ctx, is_valid);
340
341 if (product_state.is_multi_install())
342 ValidateMultiInstallProduct(ctx, is_valid);
343 }
344
345 // static
346 bool InstallationValidator::ValidateInstallationTypeForState(
347 const InstallationState& machine_state,
348 bool system_level,
349 InstallationType* type) {
350 DCHECK(type);
351 bool rock_on = true;
352 *type = NO_PRODUCTS;
353
354 // Does the system have any multi-installed products?
355 const ProductState* multi_state =
356 machine_state.GetProductState(system_level,
357 BrowserDistribution::CHROME_BINARIES);
358 if (multi_state != NULL)
359 ValidateBinaries(machine_state, system_level, *multi_state, &rock_on);
360
361 // Is Chrome installed?
362 const ProductState* product_state =
363 machine_state.GetProductState(system_level,
364 BrowserDistribution::CHROME_BROWSER);
365 if (product_state != NULL) {
366 ChromeRules chrome_rules;
367 ValidateProduct(machine_state, system_level, *product_state,
368 chrome_rules, &rock_on);
369 *type = static_cast<InstallationType>(
370 *type | (product_state->is_multi_install() ?
371 ProductBits::CHROME_MULTI :
372 ProductBits::CHROME_SINGLE));
373 }
374
375 // Is Chrome Frame installed?
376 product_state =
377 machine_state.GetProductState(system_level,
378 BrowserDistribution::CHROME_FRAME);
379 if (product_state != NULL) {
380 ChromeFrameRules chrome_frame_rules;
381 ValidateProduct(machine_state, system_level, *product_state,
382 chrome_frame_rules, &rock_on);
383 int cf_bit = !product_state->is_multi_install() ?
384 ProductBits::CHROME_FRAME_SINGLE :
385 (product_state->uninstall_command().HasSwitch(
386 switches::kChromeFrameReadyMode) ?
387 ProductBits::CHROME_FRAME_READY_MODE :
388 ProductBits::CHROME_FRAME_MULTI);
389 *type = static_cast<InstallationType>(*type | cf_bit);
390 }
391
392 DCHECK_NE(std::find(&kInstallationTypes[0],
393 &kInstallationTypes[arraysize(kInstallationTypes)],
394 *type),
395 &kInstallationTypes[arraysize(kInstallationTypes)])
396 << "Invalid combination of products found on system (" << *type << ")";
397
398 return rock_on;
399 }
400
401 // static
402 bool InstallationValidator::ValidateInstallationType(bool system_level,
403 InstallationType* type) {
404 DCHECK(type);
405 InstallationState machine_state;
406
407 machine_state.Initialize();
408
409 return ValidateInstallationTypeForState(machine_state, system_level, type);
410 }
411
412 } // namespace installer
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698