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

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

Issue 6288009: More installer refactoring in the interest of fixing some bugs and cleaning t... (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
OLDNEW
1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2010 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "chrome/installer/util/installer_state.h" 5 #include "chrome/installer/util/installer_state.h"
6 6
7 #include <algorithm>
8 #include <functional>
9 #include <utility>
10
11 #include "base/command_line.h"
12 #include "base/file_util.h"
7 #include "base/logging.h" 13 #include "base/logging.h"
14 #include "base/scoped_ptr.h"
15 #include "base/string_util.h"
16 #include "base/utf_string_conversions.h"
17 #include "chrome/installer/util/delete_tree_work_item.h"
18 #include "chrome/installer/util/helper.h"
8 #include "chrome/installer/util/installation_state.h" 19 #include "chrome/installer/util/installation_state.h"
9 #include "chrome/installer/util/master_preferences.h" 20 #include "chrome/installer/util/master_preferences.h"
10 #include "chrome/installer/util/master_preferences_constants.h" 21 #include "chrome/installer/util/master_preferences_constants.h"
11 #include "chrome/installer/util/package_properties.h" 22 #include "chrome/installer/util/product.h"
23 #include "chrome/installer/util/work_item.h"
12 24
13 namespace installer { 25 namespace installer {
14 26
15 bool InstallerState::IsMultiInstallUpdate(const MasterPreferences& prefs, 27 bool InstallerState::IsMultiInstallUpdate(const MasterPreferences& prefs,
16 const InstallationState& machine_state) { 28 const InstallationState& machine_state) {
17 // First, is the package present? 29 // First, is the package present?
18 const ProductState* package = 30 const ProductState* package =
19 machine_state.GetMultiPackageState(system_install_); 31 machine_state.GetProductState(level_ == SYSTEM_LEVEL,
32 BrowserDistribution::CHROME_BINARIES);
20 if (package == NULL) { 33 if (package == NULL) {
21 // The multi-install package has not been installed, so it certainly isn't 34 // The multi-install package has not been installed, so it certainly isn't
22 // being updated. 35 // being updated.
23 return false; 36 return false;
24 } 37 }
25 38
26 BrowserDistribution::Type types[2]; 39 BrowserDistribution::Type types[2];
27 size_t num_types = 0; 40 size_t num_types = 0;
28 if (prefs.install_chrome()) 41 if (prefs.install_chrome())
29 types[num_types++] = BrowserDistribution::CHROME_BROWSER; 42 types[num_types++] = BrowserDistribution::CHROME_BROWSER;
30 if (prefs.install_chrome_frame()) 43 if (prefs.install_chrome_frame())
31 types[num_types++] = BrowserDistribution::CHROME_FRAME; 44 types[num_types++] = BrowserDistribution::CHROME_FRAME;
32 45
33 for (const BrowserDistribution::Type* scan = &types[0], 46 for (const BrowserDistribution::Type* scan = &types[0],
34 *end = &types[num_types]; scan != end; ++scan) { 47 *end = &types[num_types]; scan != end; ++scan) {
35 const ProductState* product = 48 const ProductState* product =
36 machine_state.GetProductState(system_install_, *scan); 49 machine_state.GetProductState(level_ == SYSTEM_LEVEL, *scan);
37 if (product == NULL) { 50 if (product == NULL) {
38 VLOG(2) << "It seems that distribution type " << *scan 51 VLOG(2) << "It seems that distribution type " << *scan
39 << " is being installed for the first time."; 52 << " is being installed for the first time.";
40 return false; 53 return false;
41 } 54 }
42 if (!product->channel().Equals(package->channel())) { 55 if (!product->channel().Equals(package->channel())) {
43 VLOG(2) << "It seems that distribution type " << *scan 56 VLOG(2) << "It seems that distribution type " << *scan
44 << " is being over installed."; 57 << " is being over installed.";
45 return false; 58 return false;
46 } 59 }
47 } 60 }
48 61
49 VLOG(2) << "It seems that the package is being updated."; 62 VLOG(2) << "It seems that the package is being updated.";
50 63
51 return true; 64 return true;
52 } 65 }
53 66
54 InstallerState::InstallerState() : operation_(UNINITIALIZED) { 67 InstallerState::InstallerState()
55 } 68 : operation_(UNINITIALIZED),
56 69 multi_package_distribution_(NULL),
57 void InstallerState::Initialize(const MasterPreferences& prefs, 70 level_(UNKNOWN_LEVEL),
71 package_type_(UNKNOWN_PACKAGE_TYPE),
72 root_key_(NULL),
73 msi_(false),
74 verbose_logging_(false) {
75 }
76
77 InstallerState::InstallerState(Level level)
78 : operation_(UNINITIALIZED),
79 multi_package_distribution_(NULL),
80 level_(UNKNOWN_LEVEL),
81 package_type_(UNKNOWN_PACKAGE_TYPE),
82 root_key_(NULL),
83 msi_(false),
84 verbose_logging_(false) {
85 // Use set_level() so that root_key_ is updated properly.
86 set_level(level);
87 }
88
89 void InstallerState::Initialize(const CommandLine& command_line,
90 const MasterPreferences& prefs,
58 const InstallationState& machine_state) { 91 const InstallationState& machine_state) {
59 if (!prefs.GetBool(installer::master_preferences::kSystemLevel, 92 bool pref_bool;
60 &system_install_)) 93 if (!prefs.GetBool(master_preferences::kSystemLevel, &pref_bool))
61 system_install_ = false; 94 pref_bool = false;
95 set_level(pref_bool ? SYSTEM_LEVEL : USER_LEVEL);
96
97 if (!prefs.GetBool(master_preferences::kVerboseLogging, &verbose_logging_))
98 verbose_logging_ = false;
99
100 if (!prefs.GetBool(master_preferences::kMultiInstall, &pref_bool))
101 pref_bool = false;
102 set_package_type(pref_bool ? MULTI_PACKAGE : SINGLE_PACKAGE);
103
104 if (!prefs.GetBool(master_preferences::kMsi, &msi_))
105 msi_ = false;
106
107 const bool is_uninstall = command_line.HasSwitch(switches::kUninstall);
108
109 if (prefs.install_chrome()) {
110 Product* p =
111 AddProductFromPreferences(BrowserDistribution::CHROME_BROWSER, prefs,
112 machine_state);
113 VLOG(1) << (is_uninstall ? "Uninstall" : "Install")
114 << " distribution: " << p->distribution()->GetApplicationName();
115 }
116 if (prefs.install_chrome_frame()) {
117 Product* p =
118 AddProductFromPreferences(BrowserDistribution::CHROME_FRAME, prefs,
119 machine_state);
120 VLOG(1) << (is_uninstall ? "Uninstall" : "Install")
121 << " distribution: " << p->distribution()->GetApplicationName();
122 }
62 123
63 BrowserDistribution* operand = NULL; 124 BrowserDistribution* operand = NULL;
64 125
65 if (!prefs.is_multi_install()) { 126 if (is_uninstall) {
127 operation_ = UNINSTALL;
128 } else if (!prefs.is_multi_install()) {
66 // For a single-install, the current browser dist is the operand. 129 // For a single-install, the current browser dist is the operand.
67 operand = BrowserDistribution::GetDistribution(); 130 operand = BrowserDistribution::GetDistribution();
68 operation_ = SINGLE_INSTALL_OR_UPDATE; 131 operation_ = SINGLE_INSTALL_OR_UPDATE;
69 } else if (IsMultiInstallUpdate(prefs, machine_state)) { 132 } else if (IsMultiInstallUpdate(prefs, machine_state)) {
70 // Updates driven by Google Update take place under the multi-installer's 133 // Updates driven by Google Update take place under the multi-installer's
71 // app guid. 134 // app guid.
72 installer::ActivePackageProperties package_properties; 135 operand = multi_package_distribution_;
73 operation_ = MULTI_UPDATE; 136 operation_ = MULTI_UPDATE;
74 state_key_ = package_properties.GetStateKey();
75 } else { 137 } else {
76 // Initial and over installs will always take place under one of the 138 // Initial and over installs will always take place under one of the
77 // product app guids. Chrome Frame's will be used if only Chrome Frame 139 // product app guids. Chrome Frame's will be used if only Chrome Frame
78 // is being installed. In all other cases, Chrome's is used. 140 // is being installed. In all other cases, Chrome's is used.
141 operation_ = MULTI_INSTALL;
142 }
143
144 if (operand == NULL) {
79 operand = BrowserDistribution::GetSpecificDistribution( 145 operand = BrowserDistribution::GetSpecificDistribution(
80 prefs.install_chrome() ? 146 prefs.install_chrome() ?
81 BrowserDistribution::CHROME_BROWSER : 147 BrowserDistribution::CHROME_BROWSER :
82 BrowserDistribution::CHROME_FRAME, 148 BrowserDistribution::CHROME_FRAME);
83 prefs); 149 }
84 operation_ = MULTI_INSTALL; 150
85 } 151 state_key_ = operand->GetStateKey();
86 152 }
87 if (operand != NULL) { 153
88 state_key_ = operand->GetStateKey(); 154 void InstallerState::set_level(Level level) {
89 } 155 level_ = level;
156 switch (level) {
157 case USER_LEVEL:
158 root_key_ = HKEY_CURRENT_USER;
159 break;
160 case SYSTEM_LEVEL:
161 root_key_ = HKEY_LOCAL_MACHINE;
162 break;
163 default:
164 DCHECK(level == UNKNOWN_LEVEL);
165 level_ = UNKNOWN_LEVEL;
166 root_key_ = NULL;
167 break;
168 }
169 }
170
171 void InstallerState::set_package_type(PackageType type) {
172 package_type_ = type;
173 switch (type) {
174 case SINGLE_PACKAGE:
175 multi_package_distribution_ = NULL;
176 break;
177 case MULTI_PACKAGE:
178 multi_package_distribution_ =
179 BrowserDistribution::GetSpecificDistribution(
180 BrowserDistribution::CHROME_BINARIES);
181 break;
182 default:
183 DCHECK(type == UNKNOWN_PACKAGE_TYPE);
184 package_type_ = UNKNOWN_PACKAGE_TYPE;
185 multi_package_distribution_ = NULL;
186 break;
187 }
188 }
189
190 // Returns the Chrome binaries directory for multi-install or |dist|'s directory
191 // otherwise.
192 FilePath InstallerState::GetDefaultProductInstallPath(
193 BrowserDistribution* dist) const {
194 DCHECK(dist);
195 DCHECK(package_type_ != UNKNOWN_PACKAGE_TYPE);
196
197 if (package_type_ == SINGLE_PACKAGE) {
198 return GetChromeInstallPath(system_install(), dist);
199 } else {
200 return GetChromeInstallPath(system_install(),
201 BrowserDistribution::GetSpecificDistribution(
202 BrowserDistribution::CHROME_BINARIES));
203 }
204 }
205
206 // Evaluates a product's eligibility for participation in this operation.
207 // We never expect these checks to fail, hence they all terminate the process in
208 // debug builds. See the log messages for details.
209 bool InstallerState::CanAddProduct(const Product& product,
210 const FilePath* product_dir) const {
211 switch (package_type_) {
212 case SINGLE_PACKAGE:
213 if (!products_.empty()) {
214 LOG(DFATAL) << "Cannot process more than one single-install product.";
215 return false;
216 }
217 break;
218 case MULTI_PACKAGE:
219 if (!product.HasOption(kOptionMultiInstall)) {
220 LOG(DFATAL) << "Cannot process a single-install product with a "
221 "multi-install state.";
222 return false;
223 }
224 if (FindProduct(product.distribution()->GetType()) != NULL) {
225 LOG(DFATAL) << "Cannot process more than one product of the same type.";
226 return false;
227 }
228 if (!target_path_.empty()) {
229 FilePath default_dir;
230 if (product_dir == NULL)
231 default_dir = GetDefaultProductInstallPath(product.distribution());
232 if (!FilePath::CompareEqualIgnoreCase(
233 (product_dir == NULL ? default_dir : *product_dir).value(),
234 target_path_.value())) {
235 LOG(DFATAL) << "Cannot process products in different directories.";
236 return false;
237 }
238 }
239 break;
240 default:
241 DCHECK_EQ(UNKNOWN_PACKAGE_TYPE, package_type_);
242 break;
243 }
244 return true;
245 }
246
247 // Adds |product|, installed in |product_dir| to this object's collection. If
248 // |product_dir| is NULL, the product's default install location is used.
249 // Returns NULL if |product| is incompatible with this object. Otherwise,
250 // returns a pointer to the product (ownership is held by this object).
251 Product* InstallerState::AddProductInDirectory(const FilePath* product_dir,
252 scoped_ptr<Product>* product) {
253 DCHECK(product != NULL);
254 DCHECK(product->get() != NULL);
255 const Product& the_product = *product->get();
256
257 if (!CanAddProduct(the_product, product_dir))
258 return NULL;
259
260 if (package_type_ == UNKNOWN_PACKAGE_TYPE) {
261 set_package_type(the_product.HasOption(kOptionMultiInstall) ?
262 MULTI_PACKAGE : SINGLE_PACKAGE);
263 }
264
265 if (target_path_.empty()) {
266 if (product_dir == NULL)
267 target_path_ = GetDefaultProductInstallPath(the_product.distribution());
268 else
269 target_path_ = *product_dir;
270 }
271
272 if (state_key_.empty())
273 state_key_ = the_product.distribution()->GetStateKey();
274
275 products_.push_back(product->release());
276 return products_[products_->size() - 1];
277 }
278
279 Product* InstallerState::AddProduct(scoped_ptr<Product>* product) {
280 return AddProductInDirectory(NULL, product);
281 }
282
283 // Adds a product of type |distribution_type| constructed on the basis of
284 // |prefs|, setting this object's msi flag if the product is represented in
285 // |machine_state| and is msi-installed. Returns the product that was added,
286 // or NULL if |state| is incompatible with this object. Ownership is not passed
287 // to the caller.
288 Product* InstallerState::AddProductFromPreferences(
289 BrowserDistribution::Type distribution_type,
290 const MasterPreferences& prefs,
291 const InstallationState& machine_state) {
292 scoped_ptr<Product> product_ptr(
293 new Product(BrowserDistribution::GetSpecificDistribution(
294 distribution_type)));
295 product_ptr->InitializeFromPreferences(prefs);
296
297 Product* product = AddProductInDirectory(NULL, &product_ptr);
298
299 if (product != NULL && !msi_) {
300 const ProductState* product_state = machine_state.GetProductState(
301 system_install(), distribution_type);
302 if (product_state != NULL)
303 msi_ = product_state->is_msi();
304 }
305
306 return product;
307 }
308
309 Product* InstallerState::AddProductFromState(
310 BrowserDistribution::Type type,
311 const ProductState& state) {
312 scoped_ptr<Product> product_ptr(
313 new Product(BrowserDistribution::GetSpecificDistribution(type)));
314 product_ptr->InitializeFromUninstallCommand(state.uninstall_command());
315
316 // Strip off <version>/Installer/setup.exe; see GetInstallerDirectory().
317 FilePath product_dir = state.GetSetupPath().DirName().DirName().DirName();
318
319 Product* product = AddProductInDirectory(&product_dir, &product_ptr);
320
321 if (product != NULL)
322 msi_ |= state.is_msi();
323
324 return product;
325 }
326
327 bool InstallerState::system_install() const {
328 DCHECK(level_ == USER_LEVEL || level_ == SYSTEM_LEVEL);
329 return level_ == SYSTEM_LEVEL;
330 }
331
332 bool InstallerState::is_multi_install() const {
333 DCHECK(package_type_ == SINGLE_PACKAGE || package_type_ == MULTI_PACKAGE);
334 return package_type_ != SINGLE_PACKAGE;
335 }
336
337 bool InstallerState::RemoveProduct(const Product* product) {
338 ScopedVector<Product>::iterator it =
339 std::find(products_.begin(), products_.end(), product);
340 if (it != products_.end()) {
341 products_->erase(it);
342 return true;
343 }
344 return false;
345 }
346
347 const Product* InstallerState::FindProduct(
348 BrowserDistribution::Type distribution_type) const {
349 for (Products::const_iterator scan = products_.begin(), end = products_.end();
350 scan != end; ++scan) {
351 if ((*scan)->is_type(distribution_type))
352 return *scan;
353 }
354 return NULL;
355 }
356
357 Version* InstallerState::GetCurrentVersion(
358 const InstallationState& machine_state) const {
359 DCHECK(!products_.empty());
360 scoped_ptr<Version> current_version;
361 const BrowserDistribution::Type prod_type = (package_type_ == MULTI_PACKAGE) ?
362 BrowserDistribution::CHROME_BINARIES :
363 products_[0]->distribution()->GetType();
364 const ProductState* product_state =
365 machine_state.GetProductState(level_ == SYSTEM_LEVEL, prod_type);
366
367 if (product_state != NULL) {
368 const Version* version = NULL;
369
370 // Be aware that there might be a pending "new_chrome.exe" already in the
371 // installation path. If so, we use old_version, which holds the version of
372 // "chrome.exe" itself.
373 if (file_util::PathExists(target_path().Append(kChromeNewExe)))
374 version = product_state->old_version();
375
376 if (version == NULL)
377 version = &product_state->version();
378
379 current_version.reset(version->Clone());
380 }
381
382 return current_version.release();
383 }
384
385 FilePath InstallerState::GetInstallerDirectory(const Version& version) const {
386 return target_path().Append(ASCIIToWide(version.GetString()))
387 .Append(kInstallerDir);
388 }
389
390 void InstallerState::RemoveOldVersionDirectories(
391 const Version& latest_version) const {
392 file_util::FileEnumerator version_enum(target_path(), false,
393 file_util::FileEnumerator::DIRECTORIES);
394 scoped_ptr<Version> version;
395 std::vector<FilePath> key_files;
396
397 // We try to delete all directories whose versions are lower than
398 // latest_version.
399 FilePath next_version = version_enum.Next();
400 while (!next_version.empty()) {
401 file_util::FileEnumerator::FindInfo find_data = {0};
402 version_enum.GetFindInfo(&find_data);
403 VLOG(1) << "directory found: " << find_data.cFileName;
404 version.reset(Version::GetVersionFromString(
405 WideToASCII(find_data.cFileName)));
406 if (version.get() && latest_version.CompareTo(*version) > 0) {
407 key_files.clear();
408 std::for_each(products_.begin(), products_.end(),
409 std::bind2nd(std::mem_fun(&Product::AddKeyFiles),
410 &key_files));
411 const std::vector<FilePath>::iterator end = key_files.end();
412 for (std::vector<FilePath>::iterator scan = key_files.begin();
413 scan != end; ++scan) {
414 *scan = next_version.Append(*scan);
415 }
416
417 VLOG(1) << "Deleting directory: " << next_version.value();
418
419 scoped_ptr<WorkItem> item(
420 WorkItem::CreateDeleteTreeWorkItem(next_version, key_files));
421 if (!item->Do())
422 item->Rollback();
423 }
424
425 next_version = version_enum.Next();
426 }
427 }
428
429 void InstallerState::AddComDllList(std::vector<FilePath>* com_dll_list) const {
430 std::for_each(products_.begin(), products_.end(),
431 std::bind2nd(std::mem_fun(&Product::AddComDllList),
432 com_dll_list));
433 }
434
435 bool InstallerState::SetChannelFlags(bool set,
436 ChannelInfo* channel_info) const {
437 bool modified = false;
438 for (Products::const_iterator scan = products_.begin(), end = products_.end();
439 scan != end; ++scan) {
440 modified |= (*scan)->SetChannelFlags(set, channel_info);
441 }
442 return modified;
90 } 443 }
91 444
92 } // namespace installer 445 } // namespace installer
OLDNEW
« no previous file with comments | « chrome/installer/util/installer_state.h ('k') | chrome/installer/util/installer_state_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698