setup_main.cc revision a3f7b4e666c476898878fa745f637129375cd889
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 <windows.h> 6#include <msi.h> 7#include <shellapi.h> 8#include <shlobj.h> 9 10#include <string> 11 12#include "base/at_exit.h" 13#include "base/basictypes.h" 14#include "base/command_line.h" 15#include "base/file_util.h" 16#include "base/file_version_info.h" 17#include "base/files/file_path.h" 18#include "base/files/scoped_temp_dir.h" 19#include "base/path_service.h" 20#include "base/process/launch.h" 21#include "base/strings/string16.h" 22#include "base/strings/string_number_conversions.h" 23#include "base/strings/string_util.h" 24#include "base/strings/stringprintf.h" 25#include "base/strings/utf_string_conversions.h" 26#include "base/values.h" 27#include "base/win/registry.h" 28#include "base/win/scoped_com_initializer.h" 29#include "base/win/scoped_comptr.h" 30#include "base/win/scoped_handle.h" 31#include "base/win/win_util.h" 32#include "base/win/windows_version.h" 33#include "breakpad/src/client/windows/handler/exception_handler.h" 34#include "chrome/common/chrome_constants.h" 35#include "chrome/common/chrome_switches.h" 36#include "chrome/installer/setup/archive_patch_helper.h" 37#include "chrome/installer/setup/chrome_frame_quick_enable.h" 38#include "chrome/installer/setup/chrome_frame_ready_mode.h" 39#include "chrome/installer/setup/install.h" 40#include "chrome/installer/setup/install_worker.h" 41#include "chrome/installer/setup/setup_constants.h" 42#include "chrome/installer/setup/setup_util.h" 43#include "chrome/installer/setup/uninstall.h" 44#include "chrome/installer/util/browser_distribution.h" 45#include "chrome/installer/util/channel_info.h" 46#include "chrome/installer/util/delete_after_reboot_helper.h" 47#include "chrome/installer/util/delete_tree_work_item.h" 48#include "chrome/installer/util/eula_util.h" 49#include "chrome/installer/util/google_update_constants.h" 50#include "chrome/installer/util/google_update_settings.h" 51#include "chrome/installer/util/google_update_util.h" 52#include "chrome/installer/util/helper.h" 53#include "chrome/installer/util/html_dialog.h" 54#include "chrome/installer/util/install_util.h" 55#include "chrome/installer/util/installation_state.h" 56#include "chrome/installer/util/installation_validator.h" 57#include "chrome/installer/util/installer_state.h" 58#include "chrome/installer/util/l10n_string_util.h" 59#include "chrome/installer/util/logging_installer.h" 60#include "chrome/installer/util/lzma_util.h" 61#include "chrome/installer/util/master_preferences.h" 62#include "chrome/installer/util/master_preferences_constants.h" 63#include "chrome/installer/util/self_cleaning_temp_dir.h" 64#include "chrome/installer/util/shell_util.h" 65#include "chrome/installer/util/user_experiment.h" 66#include "chrome/installer/util/util_constants.h" 67 68#include "installer_util_strings.h" // NOLINT 69 70using installer::InstallerState; 71using installer::InstallationState; 72using installer::InstallationValidator; 73using installer::Product; 74using installer::ProductState; 75using installer::Products; 76using installer::MasterPreferences; 77 78const wchar_t kChromePipeName[] = L"\\\\.\\pipe\\ChromeCrashServices"; 79const wchar_t kGoogleUpdatePipeName[] = L"\\\\.\\pipe\\GoogleCrashServices\\"; 80const wchar_t kSystemPrincipalSid[] = L"S-1-5-18"; 81 82const MINIDUMP_TYPE kLargerDumpType = static_cast<MINIDUMP_TYPE>( 83 MiniDumpWithProcessThreadData | // Get PEB and TEB. 84 MiniDumpWithUnloadedModules | // Get unloaded modules when available. 85 MiniDumpWithIndirectlyReferencedMemory); // Get memory referenced by stack. 86 87namespace { 88 89// Returns NULL if no compressed archive is available for processing, otherwise 90// returns a patch helper configured to uncompress and patch. 91scoped_ptr<installer::ArchivePatchHelper> CreateChromeArchiveHelper( 92 const CommandLine& command_line, 93 const installer::InstallerState& installer_state, 94 const base::FilePath& working_directory) { 95 // A compressed archive is ordinarily given on the command line by the mini 96 // installer. If one was not given, look for chrome.packed.7z next to the 97 // running program. 98 base::FilePath compressed_archive( 99 command_line.GetSwitchValuePath(installer::switches::kInstallArchive)); 100 bool compressed_archive_specified = !compressed_archive.empty(); 101 if (!compressed_archive_specified) { 102 compressed_archive = 103 command_line.GetProgram().DirName().Append( 104 installer::kChromeCompressedArchive); 105 } 106 107 // Fail if no compressed archive is found. 108 if (!base::PathExists(compressed_archive)) { 109 if (compressed_archive_specified) { 110 LOG(ERROR) << installer::switches::kInstallArchive << "=" 111 << compressed_archive.value() << " not found."; 112 } 113 return scoped_ptr<installer::ArchivePatchHelper>(); 114 } 115 116 // chrome.7z is either extracted directly from the compressed archive into the 117 // working dir or is the target of patching in the working dir. 118 base::FilePath target(working_directory.Append(installer::kChromeArchive)); 119 DCHECK(!base::PathExists(target)); 120 121 // Specify an empty path for the patch source since it isn't yet known that 122 // one is needed. It will be supplied in UncompressAndPatchChromeArchive if it 123 // is. 124 return scoped_ptr<installer::ArchivePatchHelper>( 125 new installer::ArchivePatchHelper(working_directory, 126 compressed_archive, 127 base::FilePath(), 128 target)); 129} 130 131// Workhorse for producing an uncompressed archive (chrome.7z) given a 132// chrome.packed.7z containing either a patch file based on the version of 133// chrome being updated or the full uncompressed archive. Returns true on 134// success, in which case |archive_type| is populated based on what was found. 135// Returns false on failure, in which case |install_status| contains the error 136// code and the result is written to the registry (via WriteInstallerResult). 137bool UncompressAndPatchChromeArchive( 138 const installer::InstallationState& original_state, 139 const installer::InstallerState& installer_state, 140 installer::ArchivePatchHelper* archive_helper, 141 installer::ArchiveType* archive_type, 142 installer::InstallStatus* install_status) { 143 installer_state.UpdateStage(installer::UNCOMPRESSING); 144 if (!archive_helper->Uncompress(NULL)) { 145 *install_status = installer::UNCOMPRESSION_FAILED; 146 installer_state.WriteInstallerResult(*install_status, 147 IDS_INSTALL_UNCOMPRESSION_FAILED_BASE, 148 NULL); 149 return false; 150 } 151 152 // Short-circuit if uncompression produced the uncompressed archive rather 153 // than a patch file. 154 if (base::PathExists(archive_helper->target())) { 155 *archive_type = installer::FULL_ARCHIVE_TYPE; 156 return true; 157 } 158 159 // Find the installed version's archive to serve as the source for patching. 160 base::FilePath patch_source(installer::FindArchiveToPatch(original_state, 161 installer_state)); 162 if (patch_source.empty()) { 163 LOG(ERROR) << "Failed to find archive to patch."; 164 *install_status = installer::DIFF_PATCH_SOURCE_MISSING; 165 installer_state.WriteInstallerResult(*install_status, 166 IDS_INSTALL_UNCOMPRESSION_FAILED_BASE, 167 NULL); 168 return false; 169 } 170 archive_helper->set_patch_source(patch_source); 171 172 // Try courgette first. Failing that, try bspatch. 173 if ((installer_state.UpdateStage(installer::ENSEMBLE_PATCHING), 174 !archive_helper->EnsemblePatch()) && 175 (installer_state.UpdateStage(installer::BINARY_PATCHING), 176 !archive_helper->BinaryPatch())) { 177 *install_status = installer::APPLY_DIFF_PATCH_FAILED; 178 installer_state.WriteInstallerResult(*install_status, 179 IDS_INSTALL_UNCOMPRESSION_FAILED_BASE, 180 NULL); 181 return false; 182 } 183 184 *archive_type = installer::INCREMENTAL_ARCHIVE_TYPE; 185 return true; 186} 187 188// In multi-install, adds all products to |installer_state| that are 189// multi-installed and must be updated along with the products already present 190// in |installer_state|. 191void AddExistingMultiInstalls(const InstallationState& original_state, 192 InstallerState* installer_state) { 193 if (installer_state->is_multi_install()) { 194 for (size_t i = 0; i < BrowserDistribution::NUM_TYPES; ++i) { 195 BrowserDistribution::Type type = 196 static_cast<BrowserDistribution::Type>(i); 197 198 if (!installer_state->FindProduct(type)) { 199 const ProductState* state = 200 original_state.GetProductState(installer_state->system_install(), 201 type); 202 if ((state != NULL) && state->is_multi_install()) { 203 installer_state->AddProductFromState(type, *state); 204 VLOG(1) << "Product already installed and must be included: " 205 << BrowserDistribution::GetSpecificDistribution(type)-> 206 GetAppShortCutName(); 207 } 208 } 209 } 210 } 211} 212 213// This function is called when --rename-chrome-exe option is specified on 214// setup.exe command line. This function assumes an in-use update has happened 215// for Chrome so there should be a file called new_chrome.exe on the file 216// system and a key called 'opv' in the registry. This function will move 217// new_chrome.exe to chrome.exe and delete 'opv' key in one atomic operation. 218// This function also deletes elevation policies associated with the old version 219// if they exist. 220installer::InstallStatus RenameChromeExecutables( 221 const InstallationState& original_state, 222 InstallerState* installer_state) { 223 // See what products are already installed in multi mode. When we do the 224 // rename for multi installs, we must update all installations since they 225 // share the binaries. 226 AddExistingMultiInstalls(original_state, installer_state); 227 const base::FilePath &target_path = installer_state->target_path(); 228 base::FilePath chrome_exe(target_path.Append(installer::kChromeExe)); 229 base::FilePath chrome_new_exe(target_path.Append(installer::kChromeNewExe)); 230 base::FilePath chrome_old_exe(target_path.Append(installer::kChromeOldExe)); 231 232 // Create a temporary backup directory on the same volume as chrome.exe so 233 // that moving in-use files doesn't lead to trouble. 234 installer::SelfCleaningTempDir temp_path; 235 if (!temp_path.Initialize(target_path.DirName(), 236 installer::kInstallTempDir)) { 237 PLOG(ERROR) << "Failed to create Temp directory " 238 << target_path.DirName() 239 .Append(installer::kInstallTempDir).value(); 240 return installer::RENAME_FAILED; 241 } 242 scoped_ptr<WorkItemList> install_list(WorkItem::CreateWorkItemList()); 243 // Move chrome.exe to old_chrome.exe, then move new_chrome.exe to chrome.exe. 244 install_list->AddMoveTreeWorkItem(chrome_exe.value(), 245 chrome_old_exe.value(), 246 temp_path.path().value(), 247 WorkItem::ALWAYS_MOVE); 248 install_list->AddMoveTreeWorkItem(chrome_new_exe.value(), 249 chrome_exe.value(), 250 temp_path.path().value(), 251 WorkItem::ALWAYS_MOVE); 252 install_list->AddDeleteTreeWorkItem(chrome_new_exe, temp_path.path()); 253 // Delete an elevation policy associated with the old version, should one 254 // exist. 255 if (installer_state->FindProduct(BrowserDistribution::CHROME_FRAME)) { 256 installer::AddDeleteOldIELowRightsPolicyWorkItems(*installer_state, 257 install_list.get()); 258 } 259 // old_chrome.exe is still in use in most cases, so ignore failures here. 260 install_list->AddDeleteTreeWorkItem(chrome_old_exe, temp_path.path())-> 261 set_ignore_failure(true); 262 263 // Add work items to delete the "opv", "cpv", and "cmd" values from all 264 // products we're operating on (which including the multi-install binaries). 265 const Products& products = installer_state->products(); 266 HKEY reg_root = installer_state->root_key(); 267 string16 version_key; 268 for (Products::const_iterator it = products.begin(); it < products.end(); 269 ++it) { 270 version_key = (*it)->distribution()->GetVersionKey(); 271 install_list->AddDeleteRegValueWorkItem( 272 reg_root, version_key, google_update::kRegOldVersionField); 273 install_list->AddDeleteRegValueWorkItem( 274 reg_root, version_key, google_update::kRegCriticalVersionField); 275 install_list->AddDeleteRegValueWorkItem( 276 reg_root, version_key, google_update::kRegRenameCmdField); 277 } 278 installer::InstallStatus ret = installer::RENAME_SUCCESSFUL; 279 if (!install_list->Do()) { 280 LOG(ERROR) << "Renaming of executables failed. Rolling back any changes."; 281 install_list->Rollback(); 282 ret = installer::RENAME_FAILED; 283 } 284 // temp_path's dtor will take care of deleting or scheduling itself for 285 // deletion at reboot when this scope closes. 286 VLOG(1) << "Deleting temporary directory " << temp_path.path().value(); 287 288 return ret; 289} 290 291// For each product that is being updated (i.e., already installed at an earlier 292// version), see if that product has an update policy override that differs from 293// that for the binaries. If any are found, fail with an error indicating that 294// the Group Policy settings are in an inconsistent state. Do not do this test 295// for same-version installs, since it would be unkind to block attempts to 296// repair a corrupt installation. This function returns false when installation 297// should be halted, in which case |status| contains the relevant exit code and 298// the proper installer result has been written to the registry. 299bool CheckGroupPolicySettings(const InstallationState& original_state, 300 const InstallerState& installer_state, 301 const Version& new_version, 302 installer::InstallStatus* status) { 303#if !defined(GOOGLE_CHROME_BUILD) 304 // Chromium builds are not updated via Google Update, so there are no 305 // Group Policy settings to consult. 306 return true; 307#else 308 DCHECK(status); 309 310 // Single installs are always in good shape. 311 if (!installer_state.is_multi_install()) 312 return true; 313 314 bool settings_are_valid = true; 315 const bool is_system_install = installer_state.system_install(); 316 BrowserDistribution* const binaries_dist = 317 installer_state.multi_package_binaries_distribution(); 318 319 // Get the update policy for the binaries. 320 const GoogleUpdateSettings::UpdatePolicy binaries_policy = 321 GoogleUpdateSettings::GetAppUpdatePolicy(binaries_dist->GetAppGuid(), 322 NULL); 323 324 // Check for differing update policies for all of the products being updated. 325 const Products& products = installer_state.products(); 326 Products::const_iterator scan = products.begin(); 327 for (Products::const_iterator end = products.end(); scan != end; ++scan) { 328 BrowserDistribution* dist = (*scan)->distribution(); 329 const ProductState* product_state = 330 original_state.GetProductState(is_system_install, dist->GetType()); 331 // Is an earlier version of this product already installed? 332 if (product_state != NULL && 333 product_state->version().CompareTo(new_version) < 0) { 334 bool is_overridden = false; 335 GoogleUpdateSettings::UpdatePolicy app_policy = 336 GoogleUpdateSettings::GetAppUpdatePolicy(dist->GetAppGuid(), 337 &is_overridden); 338 if (is_overridden && app_policy != binaries_policy) { 339 LOG(ERROR) << "Found legacy Group Policy setting for " 340 << dist->GetAppShortCutName() << " (value: " << app_policy 341 << ") that does not match the setting for " 342 << binaries_dist->GetAppShortCutName() 343 << " (value: " << binaries_policy << ")."; 344 settings_are_valid = false; 345 } 346 } 347 } 348 349 if (!settings_are_valid) { 350 // TODO(grt): add " See http://goo.gl/+++ for details." to the end of this 351 // log message and to the IDS_INSTALL_INCONSISTENT_UPDATE_POLICY string once 352 // we have a help center article that explains why this error is being 353 // reported and how to resolve it. 354 LOG(ERROR) << "Cannot apply update on account of inconsistent " 355 "Google Update Group Policy settings. Use the Group Policy " 356 "Editor to set the update policy override for the " 357 << binaries_dist->GetAppShortCutName() 358 << " application and try again."; 359 *status = installer::INCONSISTENT_UPDATE_POLICY; 360 installer_state.WriteInstallerResult( 361 *status, IDS_INSTALL_INCONSISTENT_UPDATE_POLICY_BASE, NULL); 362 } 363 364 return settings_are_valid; 365#endif // defined(GOOGLE_CHROME_BUILD) 366} 367 368// If Chrome Frame is being installed by itself in multi-mode, non-ready-mode: 369// - If a non-multi Chrome Frame installation is present, fail. 370// If Chrome Frame is being installed by itself in multi-mode, ready-mode: 371// - If no Chrome installation is present, fail. 372// - If a Chrome installation is present, add it to the set of products to 373// install. 374// If Chrome Frame is being installed with Chrome in multi-mode, ready-mode: 375// - If a non-multi Chrome Frame installation is present, Chrome Frame is 376// removed from |installer_state|'s list of products (thereby preserving 377// the existing SxS install). 378// - If a multi Chrome Frame installation is present, its options are 379// preserved (i.e., the --ready-mode command-line option is ignored). 380// If any product is being installed in single-mode that already exists in 381// multi-mode, fail. 382bool CheckMultiInstallConditions(const InstallationState& original_state, 383 InstallerState* installer_state, 384 installer::InstallStatus* status) { 385 const Products& products = installer_state->products(); 386 DCHECK(products.size()); 387 388 const bool system_level = installer_state->system_install(); 389 390 if (installer_state->is_multi_install()) { 391 const Product* chrome = 392 installer_state->FindProduct(BrowserDistribution::CHROME_BROWSER); 393 const Product* app_host = 394 installer_state->FindProduct(BrowserDistribution::CHROME_APP_HOST); 395 const Product* binaries = 396 installer_state->FindProduct(BrowserDistribution::CHROME_BINARIES); 397 const Product* chrome_frame = 398 installer_state->FindProduct(BrowserDistribution::CHROME_FRAME); 399 const ProductState* cf_state = 400 original_state.GetProductState(system_level, 401 BrowserDistribution::CHROME_FRAME); 402 const ProductState* chrome_state = 403 original_state.GetProductState(system_level, 404 BrowserDistribution::CHROME_BROWSER); 405 406 if (!binaries) { 407 // This will only be hit if --multi-install is given with no products, or 408 // if the app host is being installed and doesn't need the binaries at 409 // user-level. 410 // The former case might be due to a request by an orphaned Application 411 // Host to re-install the binaries. Thus we add them to the installation. 412 // The latter case is fine and we let it be. 413 // If this is not an app host install and the binaries are not already 414 // present, the installation will fail later due to a lack of products to 415 // install. 416 if (app_host && !chrome && !chrome_frame && !cf_state && !chrome_state) { 417 DCHECK(!system_level); 418 // App Host may use Chrome/Chrome binaries at system-level. 419 if (original_state.GetProductState( 420 true, // system 421 BrowserDistribution::CHROME_BROWSER) || 422 original_state.GetProductState( 423 true, // system 424 BrowserDistribution::CHROME_BINARIES)) { 425 VLOG(1) << "Installing/updating App Launcher without binaries."; 426 } else { 427 // Somehow the binaries were present when the quick-enable app host 428 // command was run, but now they appear to be missing. 429 // Force binaries to be installed/updated. 430 scoped_ptr<Product> binaries_to_add(new Product( 431 BrowserDistribution::GetSpecificDistribution( 432 BrowserDistribution::CHROME_BINARIES))); 433 binaries_to_add->SetOption(installer::kOptionMultiInstall, true); 434 binaries = installer_state->AddProduct(&binaries_to_add); 435 VLOG(1) << 436 "Adding binaries for pre-existing App Launcher installation."; 437 } 438 } 439 440 return true; 441 } 442 443 if (chrome) { 444 if (chrome_frame && 445 chrome_frame->HasOption(installer::kOptionReadyMode)) { 446 // We're being asked to install Chrome with Chrome Frame in ready-mode. 447 // This is an optimistic operation: if a SxS install of Chrome Frame 448 // is already present, don't touch it; if a multi-install of Chrome 449 // Frame is present, preserve its settings (ready-mode). 450 if (cf_state) { 451 installer_state->RemoveProduct(chrome_frame); 452 chrome_frame = NULL; 453 if (cf_state->is_multi_install()) { 454 chrome_frame = installer_state->AddProductFromState( 455 BrowserDistribution::CHROME_FRAME, *cf_state); 456 VLOG(1) << "Upgrading existing multi-install Chrome Frame rather " 457 "than installing in ready-mode."; 458 } else { 459 VLOG(1) << "Skipping upgrade of single-install Chrome Frame rather " 460 "than installing in ready-mode."; 461 } 462 } else { 463 VLOG(1) << "Performing initial install of Chrome Frame ready-mode."; 464 } 465 } 466 } else if (chrome_state) { 467 // A product other than Chrome is being installed in multi-install mode, 468 // and Chrome is already present. Add Chrome to the set of products 469 // (making it multi-install in the process) so that it is updated, too. 470 scoped_ptr<Product> multi_chrome(new Product( 471 BrowserDistribution::GetSpecificDistribution( 472 BrowserDistribution::CHROME_BROWSER))); 473 multi_chrome->SetOption(installer::kOptionMultiInstall, true); 474 chrome = installer_state->AddProduct(&multi_chrome); 475 VLOG(1) << "Upgrading existing Chrome browser in multi-install mode."; 476 } else if (chrome_frame && 477 chrome_frame->HasOption(installer::kOptionReadyMode)) { 478 // Chrome Frame with ready-mode is to be installed, yet Chrome is 479 // neither installed nor being installed. Fail. 480 LOG(ERROR) << "Cannot install Chrome Frame in ready mode without Chrome."; 481 *status = installer::READY_MODE_REQUIRES_CHROME; 482 installer_state->WriteInstallerResult( 483 *status, IDS_INSTALL_READY_MODE_REQUIRES_CHROME_BASE, NULL); 484 return false; 485 } 486 487 // Fail if we're installing Chrome Frame when a single-install of it is 488 // already installed. 489 if (chrome_frame && cf_state && !cf_state->is_multi_install()) { 490 LOG(ERROR) << "Cannot migrate existing Chrome Frame installation to " 491 << "multi-install."; 492 *status = installer::NON_MULTI_INSTALLATION_EXISTS; 493 installer_state->WriteInstallerResult(*status, 494 IDS_INSTALL_NON_MULTI_INSTALLATION_EXISTS_BASE, NULL); 495 return false; 496 } 497 } else { 498 // This is a non-multi installation. 499 500 // Check for an existing installation of the product. 501 const ProductState* product_state = original_state.GetProductState( 502 system_level, products[0]->distribution()->GetType()); 503 if (product_state != NULL) { 504 // Block downgrades from multi-install to single-install. 505 if (product_state->is_multi_install()) { 506 LOG(ERROR) << "Multi-install " 507 << products[0]->distribution()->GetAppShortCutName() 508 << " exists; aborting single install."; 509 *status = installer::MULTI_INSTALLATION_EXISTS; 510 installer_state->WriteInstallerResult(*status, 511 IDS_INSTALL_MULTI_INSTALLATION_EXISTS_BASE, NULL); 512 return false; 513 } 514 } 515 } 516 517 return true; 518} 519 520// Checks app host pre-install conditions, specifically that this is a 521// user-level multi-install. When the pre-install conditions are not 522// satisfied, the result is written to the registry (via WriteInstallerResult), 523// |status| is set appropriately, and false is returned. 524bool CheckAppHostPreconditions(const InstallationState& original_state, 525 InstallerState* installer_state, 526 installer::InstallStatus* status) { 527 if (installer_state->FindProduct(BrowserDistribution::CHROME_APP_HOST)) { 528 if (!installer_state->is_multi_install()) { 529 LOG(DFATAL) << "App Launcher requires multi install"; 530 *status = installer::APP_HOST_REQUIRES_MULTI_INSTALL; 531 // No message string since there is nothing a user can do. 532 installer_state->WriteInstallerResult(*status, 0, NULL); 533 return false; 534 } 535 536 if (installer_state->system_install()) { 537 LOG(DFATAL) << "App Launcher may only be installed at user-level."; 538 *status = installer::APP_HOST_REQUIRES_USER_LEVEL; 539 // No message string since there is nothing a user can do. 540 installer_state->WriteInstallerResult(*status, 0, NULL); 541 return false; 542 } 543 } 544 545 return true; 546} 547 548// Checks for compatibility between the current state of the system and the 549// desired operation. Also applies policy that mutates the desired operation; 550// specifically, the |installer_state| object. 551// Also blocks simultaneous user-level and system-level installs. In the case 552// of trying to install user-level Chrome when system-level exists, the 553// existing system-level Chrome is launched. 554// When the pre-install conditions are not satisfied, the result is written to 555// the registry (via WriteInstallerResult), |status| is set appropriately, and 556// false is returned. 557bool CheckPreInstallConditions(const InstallationState& original_state, 558 InstallerState* installer_state, 559 installer::InstallStatus* status) { 560 if (!CheckAppHostPreconditions(original_state, installer_state, status)) { 561 DCHECK_NE(*status, installer::UNKNOWN_STATUS); 562 return false; 563 } 564 565 // See what products are already installed in multi mode. When we do multi 566 // installs, we must upgrade all installations since they share the binaries. 567 AddExistingMultiInstalls(original_state, installer_state); 568 569 if (!CheckMultiInstallConditions(original_state, installer_state, status)) { 570 DCHECK_NE(*status, installer::UNKNOWN_STATUS); 571 return false; 572 } 573 574 const Products& products = installer_state->products(); 575 if (products.empty()) { 576 // We haven't been given any products on which to operate. 577 LOG(ERROR) 578 << "Not given any products to install and no products found to update."; 579 *status = installer::CHROME_NOT_INSTALLED; 580 installer_state->WriteInstallerResult(*status, 581 IDS_INSTALL_NO_PRODUCTS_TO_UPDATE_BASE, NULL); 582 return false; 583 } 584 585 if (!installer_state->system_install()) { 586 // This is a user-level installation. Make sure that we are not installing 587 // on top of an existing system-level installation. 588 for (Products::const_iterator it = products.begin(); it < products.end(); 589 ++it) { 590 const Product& product = **it; 591 BrowserDistribution* browser_dist = product.distribution(); 592 593 // Skip over the binaries, as it's okay for them to be at both levels 594 // for different products. 595 if (browser_dist->GetType() == BrowserDistribution::CHROME_BINARIES) 596 continue; 597 598 const ProductState* user_level_product_state = 599 original_state.GetProductState(false, browser_dist->GetType()); 600 const ProductState* system_level_product_state = 601 original_state.GetProductState(true, browser_dist->GetType()); 602 603 // Allow upgrades to proceed so that out-of-date versions are not left 604 // around. 605 if (user_level_product_state) 606 continue; 607 608 // This is a new user-level install... 609 610 if (system_level_product_state) { 611 // ... and the product already exists at system-level. 612 LOG(ERROR) << "Already installed version " 613 << system_level_product_state->version().GetString() 614 << " at system-level conflicts with this one at user-level."; 615 if (product.is_chrome()) { 616 // Instruct Google Update to launch the existing system-level Chrome. 617 // There should be no error dialog. 618 base::FilePath install_path(installer::GetChromeInstallPath( 619 true, // system 620 browser_dist)); 621 if (install_path.empty()) { 622 // Give up if we failed to construct the install path. 623 *status = installer::OS_ERROR; 624 installer_state->WriteInstallerResult(*status, 625 IDS_INSTALL_OS_ERROR_BASE, 626 NULL); 627 } else { 628 *status = installer::EXISTING_VERSION_LAUNCHED; 629 base::FilePath chrome_exe = 630 install_path.Append(installer::kChromeExe); 631 CommandLine cmd(chrome_exe); 632 cmd.AppendSwitch(switches::kForceFirstRun); 633 installer_state->WriteInstallerResult(*status, 0, NULL); 634 VLOG(1) << "Launching existing system-level chrome instead."; 635 base::LaunchProcess(cmd, base::LaunchOptions(), NULL); 636 } 637 } else { 638 // Display an error message for other products. 639 *status = installer::SYSTEM_LEVEL_INSTALL_EXISTS; 640 installer_state->WriteInstallerResult( 641 *status, IDS_INSTALL_SYSTEM_LEVEL_EXISTS_BASE, NULL); 642 } 643 return false; 644 } 645 } 646 647 } else { // System-level install. 648 // --ensure-google-update-present is supported for user-level only. 649 // The flag is generic, but its primary use case involves App Host. 650 if (installer_state->ensure_google_update_present()) { 651 LOG(DFATAL) << "--" << installer::switches::kEnsureGoogleUpdatePresent 652 << " is supported for user-level only."; 653 *status = installer::APP_HOST_REQUIRES_USER_LEVEL; 654 // No message string since there is nothing a user can do. 655 installer_state->WriteInstallerResult(*status, 0, NULL); 656 return false; 657 } 658 } 659 660 return true; 661} 662 663// Initializes |temp_path| to "Temp" within the target directory, and 664// |unpack_path| to a random directory beginning with "source" within 665// |temp_path|. Returns false on error. 666bool CreateTemporaryAndUnpackDirectories( 667 const InstallerState& installer_state, 668 installer::SelfCleaningTempDir* temp_path, 669 base::FilePath* unpack_path) { 670 DCHECK(temp_path && unpack_path); 671 672 if (!temp_path->Initialize(installer_state.target_path().DirName(), 673 installer::kInstallTempDir)) { 674 PLOG(ERROR) << "Could not create temporary path."; 675 return false; 676 } 677 VLOG(1) << "Created path " << temp_path->path().value(); 678 679 if (!file_util::CreateTemporaryDirInDir(temp_path->path(), 680 installer::kInstallSourceDir, 681 unpack_path)) { 682 PLOG(ERROR) << "Could not create temporary path for unpacked archive."; 683 return false; 684 } 685 686 return true; 687} 688 689installer::InstallStatus InstallProductsHelper( 690 const InstallationState& original_state, 691 const CommandLine& cmd_line, 692 const MasterPreferences& prefs, 693 const InstallerState& installer_state, 694 installer::ArchiveType* archive_type, 695 bool* delegated_to_existing) { 696 DCHECK(archive_type); 697 DCHECK(delegated_to_existing); 698 const bool system_install = installer_state.system_install(); 699 installer::InstallStatus install_status = installer::UNKNOWN_STATUS; 700 701 // Drop to background processing mode if the process was started below the 702 // normal process priority class. 703 bool entered_background_mode = installer::AdjustProcessPriority(); 704 VLOG_IF(1, entered_background_mode) << "Entered background processing mode."; 705 706 // Create a temp folder where we will unpack Chrome archive. If it fails, 707 // then we are doomed, so return immediately and no cleanup is required. 708 installer::SelfCleaningTempDir temp_path; 709 base::FilePath unpack_path; 710 if (!CreateTemporaryAndUnpackDirectories(installer_state, &temp_path, 711 &unpack_path)) { 712 installer_state.WriteInstallerResult(installer::TEMP_DIR_FAILED, 713 IDS_INSTALL_TEMP_DIR_FAILED_BASE, 714 NULL); 715 return installer::TEMP_DIR_FAILED; 716 } 717 718 // Uncompress and optionally patch the archive if an uncompressed archive was 719 // not specified on the command line and a compressed archive is found. 720 *archive_type = installer::UNKNOWN_ARCHIVE_TYPE; 721 base::FilePath uncompressed_archive(cmd_line.GetSwitchValuePath( 722 installer::switches::kUncompressedArchive)); 723 if (uncompressed_archive.empty()) { 724 scoped_ptr<installer::ArchivePatchHelper> archive_helper( 725 CreateChromeArchiveHelper(cmd_line, installer_state, unpack_path)); 726 if (archive_helper) { 727 VLOG(1) << "Installing Chrome from compressed archive " 728 << archive_helper->compressed_archive().value(); 729 if (!UncompressAndPatchChromeArchive(original_state, 730 installer_state, 731 archive_helper.get(), 732 archive_type, 733 &install_status)) { 734 DCHECK_NE(install_status, installer::UNKNOWN_STATUS); 735 return install_status; 736 } 737 uncompressed_archive = archive_helper->target(); 738 DCHECK(!uncompressed_archive.empty()); 739 } 740 } 741 742 // Check for an uncompressed archive alongside the current executable if one 743 // was not given or generated. 744 if (uncompressed_archive.empty()) { 745 uncompressed_archive = 746 cmd_line.GetProgram().DirName().Append(installer::kChromeArchive); 747 } 748 749 if (*archive_type == installer::UNKNOWN_ARCHIVE_TYPE) { 750 // An archive was not uncompressed or patched above. 751 if (uncompressed_archive.empty() || 752 !base::PathExists(uncompressed_archive)) { 753 LOG(ERROR) << "Cannot install Chrome without an uncompressed archive."; 754 installer_state.WriteInstallerResult( 755 installer::INVALID_ARCHIVE, IDS_INSTALL_INVALID_ARCHIVE_BASE, NULL); 756 return installer::INVALID_ARCHIVE; 757 } 758 *archive_type = installer::FULL_ARCHIVE_TYPE; 759 } 760 761 // Unpack the uncompressed archive. 762 if (LzmaUtil::UnPackArchive(uncompressed_archive.value(), 763 unpack_path.value(), 764 NULL)) { 765 installer_state.WriteInstallerResult( 766 installer::UNCOMPRESSION_FAILED, 767 IDS_INSTALL_UNCOMPRESSION_FAILED_BASE, 768 NULL); 769 return installer::UNCOMPRESSION_FAILED; 770 } 771 772 VLOG(1) << "unpacked to " << unpack_path.value(); 773 base::FilePath src_path( 774 unpack_path.Append(installer::kInstallSourceChromeDir)); 775 scoped_ptr<Version> 776 installer_version(installer::GetMaxVersionFromArchiveDir(src_path)); 777 if (!installer_version.get()) { 778 LOG(ERROR) << "Did not find any valid version in installer."; 779 install_status = installer::INVALID_ARCHIVE; 780 installer_state.WriteInstallerResult(install_status, 781 IDS_INSTALL_INVALID_ARCHIVE_BASE, NULL); 782 } else { 783 VLOG(1) << "version to install: " << installer_version->GetString(); 784 bool proceed_with_installation = true; 785 786 if (installer_state.operation() == InstallerState::MULTI_INSTALL) { 787 // This is a new install of a multi-install product. Rather than give up 788 // in case a higher version of the binaries (including a single-install 789 // of Chrome, which can safely be migrated to multi-install by way of 790 // CheckMultiInstallConditions) is already installed, delegate to the 791 // installed setup.exe to install the product at hand. 792 base::FilePath setup_exe; 793 if (GetExistingHigherInstaller(original_state, system_install, 794 *installer_version, &setup_exe)) { 795 VLOG(1) << "Deferring to existing installer."; 796 installer_state.UpdateStage(installer::DEFERRING_TO_HIGHER_VERSION); 797 if (DeferToExistingInstall(setup_exe, cmd_line, installer_state, 798 temp_path.path(), &install_status)) { 799 *delegated_to_existing = true; 800 return install_status; 801 } 802 } 803 } 804 805 uint32 higher_products = 0; 806 COMPILE_ASSERT( 807 sizeof(higher_products) * 8 > BrowserDistribution::NUM_TYPES, 808 too_many_distribution_types_); 809 const Products& products = installer_state.products(); 810 for (Products::const_iterator it = products.begin(); it < products.end(); 811 ++it) { 812 const Product& product = **it; 813 const ProductState* product_state = 814 original_state.GetProductState(system_install, 815 product.distribution()->GetType()); 816 if (product_state != NULL && 817 (product_state->version().CompareTo(*installer_version) > 0)) { 818 LOG(ERROR) << "Higher version of " 819 << product.distribution()->GetAppShortCutName() 820 << " is already installed."; 821 higher_products |= (1 << product.distribution()->GetType()); 822 } 823 } 824 825 if (higher_products != 0) { 826 COMPILE_ASSERT(BrowserDistribution::NUM_TYPES == 4, 827 add_support_for_new_products_here_); 828 const uint32 kBrowserBit = 1 << BrowserDistribution::CHROME_BROWSER; 829 const uint32 kGCFBit = 1 << BrowserDistribution::CHROME_FRAME; 830 const uint32 kAppHostBit = 1 << BrowserDistribution::CHROME_APP_HOST; 831 int message_id = 0; 832 833 proceed_with_installation = false; 834 install_status = installer::HIGHER_VERSION_EXISTS; 835 switch (higher_products) { 836 case kBrowserBit: 837 message_id = IDS_INSTALL_HIGHER_VERSION_BASE; 838 break; 839 case kGCFBit: 840 message_id = IDS_INSTALL_HIGHER_VERSION_CF_BASE; 841 break; 842 case kGCFBit | kBrowserBit: 843 message_id = IDS_INSTALL_HIGHER_VERSION_CB_CF_BASE; 844 break; 845 default: 846 message_id = IDS_INSTALL_HIGHER_VERSION_APP_LAUNCHER_BASE; 847 break; 848 } 849 850 installer_state.WriteInstallerResult(install_status, message_id, NULL); 851 } 852 853 proceed_with_installation = 854 proceed_with_installation && 855 CheckGroupPolicySettings(original_state, installer_state, 856 *installer_version, &install_status); 857 858 if (proceed_with_installation) { 859 // If Google Update is absent at user-level, install it using the 860 // Google Update installer from an existing system-level installation. 861 // This is for quick-enable App Host install from a system-level 862 // Chrome Binaries installation. 863 if (!system_install && installer_state.ensure_google_update_present()) { 864 if (!google_update::EnsureUserLevelGoogleUpdatePresent()) { 865 LOG(ERROR) << "Failed to install Google Update"; 866 proceed_with_installation = false; 867 install_status = installer::INSTALL_OF_GOOGLE_UPDATE_FAILED; 868 installer_state.WriteInstallerResult(install_status, 0, NULL); 869 } 870 } 871 } 872 873 if (proceed_with_installation) { 874 base::FilePath prefs_source_path(cmd_line.GetSwitchValueNative( 875 installer::switches::kInstallerData)); 876 install_status = installer::InstallOrUpdateProduct( 877 original_state, installer_state, cmd_line.GetProgram(), 878 uncompressed_archive, temp_path.path(), src_path, prefs_source_path, 879 prefs, *installer_version); 880 881 int install_msg_base = IDS_INSTALL_FAILED_BASE; 882 string16 chrome_exe; 883 string16 quoted_chrome_exe; 884 if (install_status == installer::SAME_VERSION_REPAIR_FAILED) { 885 if (installer_state.FindProduct(BrowserDistribution::CHROME_FRAME)) { 886 install_msg_base = IDS_SAME_VERSION_REPAIR_FAILED_CF_BASE; 887 } else { 888 install_msg_base = IDS_SAME_VERSION_REPAIR_FAILED_BASE; 889 } 890 } else if (install_status != installer::INSTALL_FAILED) { 891 if (installer_state.target_path().empty()) { 892 // If we failed to construct install path, it means the OS call to 893 // get %ProgramFiles% or %AppData% failed. Report this as failure. 894 install_msg_base = IDS_INSTALL_OS_ERROR_BASE; 895 install_status = installer::OS_ERROR; 896 } else { 897 chrome_exe = installer_state.target_path() 898 .Append(installer::kChromeExe).value(); 899 quoted_chrome_exe = L"\"" + chrome_exe + L"\""; 900 install_msg_base = 0; 901 } 902 } 903 904 installer_state.UpdateStage(installer::FINISHING); 905 906 // Only do Chrome-specific stuff (like launching the browser) if 907 // Chrome was specifically requested (rather than being upgraded as 908 // part of a multi-install). 909 const Product* chrome_install = prefs.install_chrome() ? 910 installer_state.FindProduct(BrowserDistribution::CHROME_BROWSER) : 911 NULL; 912 913 bool do_not_register_for_update_launch = false; 914 if (chrome_install) { 915 prefs.GetBool( 916 installer::master_preferences::kDoNotRegisterForUpdateLaunch, 917 &do_not_register_for_update_launch); 918 } else { 919 do_not_register_for_update_launch = true; // Never register. 920 } 921 922 bool write_chrome_launch_string = 923 (!do_not_register_for_update_launch && 924 install_status != installer::IN_USE_UPDATED); 925 926 installer_state.WriteInstallerResult(install_status, install_msg_base, 927 write_chrome_launch_string ? "ed_chrome_exe : NULL); 928 929 if (install_status == installer::FIRST_INSTALL_SUCCESS) { 930 VLOG(1) << "First install successful."; 931 if (chrome_install) { 932 // We never want to launch Chrome in system level install mode. 933 bool do_not_launch_chrome = false; 934 prefs.GetBool( 935 installer::master_preferences::kDoNotLaunchChrome, 936 &do_not_launch_chrome); 937 if (!system_install && !do_not_launch_chrome) 938 chrome_install->LaunchChrome(installer_state.target_path()); 939 } 940 } else if ((install_status == installer::NEW_VERSION_UPDATED) || 941 (install_status == installer::IN_USE_UPDATED)) { 942 const Product* chrome = installer_state.FindProduct( 943 BrowserDistribution::CHROME_BROWSER); 944 if (chrome != NULL) { 945 DCHECK_NE(chrome_exe, string16()); 946 installer::RemoveChromeLegacyRegistryKeys(chrome->distribution(), 947 chrome_exe); 948 } 949 } 950 951 if (prefs.install_chrome_app_launcher() && 952 InstallUtil::GetInstallReturnCode(install_status) == 0) { 953 std::string webstore_item(google_update::GetUntrustedDataValue( 954 installer::kInstallFromWebstore)); 955 if (!webstore_item.empty()) { 956 bool success = installer::InstallFromWebstore(webstore_item); 957 VLOG_IF(1, !success) << "Failed to launch app installation."; 958 } 959 } 960 } 961 } 962 963 // There might be an experiment (for upgrade usually) that needs to happen. 964 // An experiment's outcome can include chrome's uninstallation. If that is 965 // the case we would not do that directly at this point but in another 966 // instance of setup.exe 967 // 968 // There is another way to reach this same function if this is a system 969 // level install. See HandleNonInstallCmdLineOptions(). 970 { 971 // If installation failed, use the path to the currently running setup. 972 // If installation succeeded, use the path to setup in the installer dir. 973 base::FilePath setup_path(cmd_line.GetProgram()); 974 if (InstallUtil::GetInstallReturnCode(install_status) == 0) { 975 setup_path = installer_state.GetInstallerDirectory(*installer_version) 976 .Append(setup_path.BaseName()); 977 } 978 const Products& products = installer_state.products(); 979 for (Products::const_iterator it = products.begin(); it < products.end(); 980 ++it) { 981 const Product& product = **it; 982 product.LaunchUserExperiment(setup_path, install_status, 983 system_install); 984 } 985 } 986 987 // temp_path's dtor will take care of deleting or scheduling itself for 988 // deletion at reboot when this scope closes. 989 VLOG(1) << "Deleting temporary directory " << temp_path.path().value(); 990 991 return install_status; 992} 993 994installer::InstallStatus InstallProducts( 995 const InstallationState& original_state, 996 const CommandLine& cmd_line, 997 const MasterPreferences& prefs, 998 InstallerState* installer_state) { 999 DCHECK(installer_state); 1000 const bool system_install = installer_state->system_install(); 1001 installer::InstallStatus install_status = installer::UNKNOWN_STATUS; 1002 installer::ArchiveType archive_type = installer::UNKNOWN_ARCHIVE_TYPE; 1003 bool delegated_to_existing = false; 1004 installer_state->UpdateStage(installer::PRECONDITIONS); 1005 // The stage provides more fine-grained information than -multifail, so remove 1006 // the -multifail suffix from the Google Update "ap" value. 1007 BrowserDistribution::GetSpecificDistribution(installer_state->state_type())-> 1008 UpdateInstallStatus(system_install, archive_type, install_status); 1009 if (CheckPreInstallConditions(original_state, installer_state, 1010 &install_status)) { 1011 VLOG(1) << "Installing to " << installer_state->target_path().value(); 1012 install_status = InstallProductsHelper( 1013 original_state, cmd_line, prefs, *installer_state, &archive_type, 1014 &delegated_to_existing); 1015 } else { 1016 // CheckPreInstallConditions must set the status on failure. 1017 DCHECK_NE(install_status, installer::UNKNOWN_STATUS); 1018 } 1019 1020 // Delete the master preferences file if present. Note that we do not care 1021 // about rollback here and we schedule for deletion on reboot if the delete 1022 // fails. As such, we do not use DeleteTreeWorkItem. 1023 if (cmd_line.HasSwitch(installer::switches::kInstallerData)) { 1024 base::FilePath prefs_path(cmd_line.GetSwitchValuePath( 1025 installer::switches::kInstallerData)); 1026 if (!base::DeleteFile(prefs_path, false)) { 1027 LOG(ERROR) << "Failed deleting master preferences file " 1028 << prefs_path.value() 1029 << ", scheduling for deletion after reboot."; 1030 ScheduleFileSystemEntityForDeletion(prefs_path.value().c_str()); 1031 } 1032 } 1033 1034 // Early exit if this setup.exe delegated to another, since that one would 1035 // have taken care of UpdateInstallStatus and UpdateStage. 1036 if (delegated_to_existing) 1037 return install_status; 1038 1039 const Products& products = installer_state->products(); 1040 for (Products::const_iterator it = products.begin(); it < products.end(); 1041 ++it) { 1042 (*it)->distribution()->UpdateInstallStatus( 1043 system_install, archive_type, install_status); 1044 } 1045 1046 installer_state->UpdateStage(installer::NO_STAGE); 1047 return install_status; 1048} 1049 1050installer::InstallStatus UninstallProduct( 1051 const InstallationState& original_state, 1052 const InstallerState& installer_state, 1053 const CommandLine& cmd_line, 1054 bool remove_all, 1055 bool force_uninstall, 1056 const Product& product) { 1057 const ProductState* product_state = 1058 original_state.GetProductState(installer_state.system_install(), 1059 product.distribution()->GetType()); 1060 if (product_state != NULL) { 1061 VLOG(1) << "version on the system: " 1062 << product_state->version().GetString(); 1063 } else if (!force_uninstall) { 1064 LOG(ERROR) << product.distribution()->GetAppShortCutName() 1065 << " not found for uninstall."; 1066 return installer::CHROME_NOT_INSTALLED; 1067 } 1068 1069 return installer::UninstallProduct( 1070 original_state, installer_state, cmd_line.GetProgram(), product, 1071 remove_all, force_uninstall, cmd_line); 1072} 1073 1074installer::InstallStatus UninstallProducts( 1075 const InstallationState& original_state, 1076 const InstallerState& installer_state, 1077 const CommandLine& cmd_line) { 1078 const Products& products = installer_state.products(); 1079 1080 // Decide whether Active Setup should be triggered and/or system-level Chrome 1081 // should be launched post-uninstall. This needs to be done outside the 1082 // UninstallProduct calls as some of them might terminate the processes 1083 // launched by a previous one otherwise... 1084 bool trigger_active_setup = false; 1085 // System-level Chrome will be launched via this command if its program gets 1086 // set below. 1087 CommandLine system_level_cmd(CommandLine::NO_PROGRAM); 1088 1089 const Product* chrome = 1090 installer_state.FindProduct(BrowserDistribution::CHROME_BROWSER); 1091 if (chrome) { 1092 // InstallerState::Initialize always puts Chrome first, and we rely on that 1093 // here for this reason: if Chrome is in-use, the user will be prompted to 1094 // confirm uninstallation. Upon cancel, we should not continue with the 1095 // other products. 1096 DCHECK(products[0]->is_chrome()); 1097 1098 if (cmd_line.HasSwitch(installer::switches::kSelfDestruct) && 1099 !installer_state.system_install()) { 1100 BrowserDistribution* dist = chrome->distribution(); 1101 const base::FilePath system_exe_path( 1102 installer::GetChromeInstallPath(true, dist) 1103 .Append(installer::kChromeExe)); 1104 system_level_cmd.SetProgram(system_exe_path); 1105 1106 base::FilePath first_run_sentinel; 1107 InstallUtil::GetSentinelFilePath( 1108 chrome::kFirstRunSentinel, dist, &first_run_sentinel); 1109 if (base::PathExists(first_run_sentinel)) { 1110 // If the Chrome being self-destructed has already undergone First Run, 1111 // trigger Active Setup and make sure the system-level Chrome doesn't go 1112 // through first run. 1113 trigger_active_setup = true; 1114 system_level_cmd.AppendSwitch(::switches::kNoFirstRun); 1115 } 1116 } 1117 } 1118 if (installer_state.FindProduct(BrowserDistribution::CHROME_BINARIES)) { 1119 // Chrome Binaries should be last; if something else is cancelled, they 1120 // should stay. 1121 DCHECK(products[products.size() - 1]->is_chrome_binaries()); 1122 } 1123 1124 installer::InstallStatus install_status = installer::UNINSTALL_SUCCESSFUL; 1125 installer::InstallStatus prod_status = installer::UNKNOWN_STATUS; 1126 const bool force = cmd_line.HasSwitch(installer::switches::kForceUninstall); 1127 const bool remove_all = !cmd_line.HasSwitch( 1128 installer::switches::kDoNotRemoveSharedItems); 1129 1130 for (Products::const_iterator it = products.begin(); 1131 install_status != installer::UNINSTALL_CANCELLED && it < products.end(); 1132 ++it) { 1133 prod_status = UninstallProduct(original_state, installer_state, 1134 cmd_line, remove_all, force, **it); 1135 if (prod_status != installer::UNINSTALL_SUCCESSFUL) 1136 install_status = prod_status; 1137 } 1138 1139 installer::CleanUpInstallationDirectoryAfterUninstall( 1140 original_state, installer_state, cmd_line, &install_status); 1141 1142 if (trigger_active_setup) 1143 InstallUtil::TriggerActiveSetupCommand(); 1144 1145 if (!system_level_cmd.GetProgram().empty()) 1146 base::LaunchProcess(system_level_cmd, base::LaunchOptions(), NULL); 1147 1148 // Tell Google Update that an uninstall has taken place. 1149 // Ignore the return value: success or failure of Google Update 1150 // has no bearing on the success or failure of Chrome's uninstallation. 1151 google_update::UninstallGoogleUpdate(installer_state.system_install()); 1152 1153 return install_status; 1154} 1155 1156installer::InstallStatus ShowEULADialog(const string16& inner_frame) { 1157 VLOG(1) << "About to show EULA"; 1158 string16 eula_path = installer::GetLocalizedEulaResource(); 1159 if (eula_path.empty()) { 1160 LOG(ERROR) << "No EULA path available"; 1161 return installer::EULA_REJECTED; 1162 } 1163 // Newer versions of the caller pass an inner frame parameter that must 1164 // be given to the html page being launched. 1165 installer::EulaHTMLDialog dlg(eula_path, inner_frame); 1166 installer::EulaHTMLDialog::Outcome outcome = dlg.ShowModal(); 1167 if (installer::EulaHTMLDialog::REJECTED == outcome) { 1168 LOG(ERROR) << "EULA rejected or EULA failure"; 1169 return installer::EULA_REJECTED; 1170 } 1171 if (installer::EulaHTMLDialog::ACCEPTED_OPT_IN == outcome) { 1172 VLOG(1) << "EULA accepted (opt-in)"; 1173 return installer::EULA_ACCEPTED_OPT_IN; 1174 } 1175 VLOG(1) << "EULA accepted (no opt-in)"; 1176 return installer::EULA_ACCEPTED; 1177} 1178 1179// Creates the sentinel indicating that the EULA was required and has been 1180// accepted. 1181bool CreateEULASentinel(BrowserDistribution* dist) { 1182 base::FilePath eula_sentinel; 1183 if (!InstallUtil::GetSentinelFilePath(installer::kEULASentinelFile, 1184 dist, &eula_sentinel)) { 1185 return false; 1186 } 1187 1188 return (file_util::CreateDirectory(eula_sentinel.DirName()) && 1189 file_util::WriteFile(eula_sentinel, "", 0) != -1); 1190} 1191 1192void ActivateMetroChrome() { 1193 // Check to see if we're per-user or not. Need to do this since we may 1194 // not have been invoked with --system-level even for a machine install. 1195 wchar_t exe_path[MAX_PATH * 2] = {}; 1196 GetModuleFileName(NULL, exe_path, arraysize(exe_path)); 1197 bool is_per_user_install = InstallUtil::IsPerUserInstall(exe_path); 1198 1199 string16 app_model_id = 1200 ShellUtil::GetBrowserModelId(BrowserDistribution::GetDistribution(), 1201 is_per_user_install); 1202 1203 base::win::ScopedComPtr<IApplicationActivationManager> activator; 1204 HRESULT hr = activator.CreateInstance(CLSID_ApplicationActivationManager); 1205 if (SUCCEEDED(hr)) { 1206 DWORD pid = 0; 1207 hr = activator->ActivateApplication( 1208 app_model_id.c_str(), L"open", AO_NONE, &pid); 1209 } 1210 1211 LOG_IF(ERROR, FAILED(hr)) << "Tried and failed to launch Metro Chrome. " 1212 << "hr=" << std::hex << hr; 1213} 1214 1215installer::InstallStatus RegisterDevChrome( 1216 const InstallationState& original_state, 1217 const InstallerState& installer_state, 1218 const CommandLine& cmd_line) { 1219 BrowserDistribution* chrome_dist = 1220 BrowserDistribution::GetSpecificDistribution( 1221 BrowserDistribution::CHROME_BROWSER); 1222 1223 // Only proceed with registering a dev chrome if no real Chrome installation 1224 // of the same distribution are present on this system. 1225 const ProductState* existing_chrome = 1226 original_state.GetProductState(false, 1227 BrowserDistribution::CHROME_BROWSER); 1228 if (!existing_chrome) { 1229 existing_chrome = 1230 original_state.GetProductState(true, BrowserDistribution::CHROME_BROWSER); 1231 } 1232 if (existing_chrome) { 1233 static const wchar_t kPleaseUninstallYourChromeMessage[] = 1234 L"You already have a full-installation (non-dev) of %1ls, please " 1235 L"uninstall it first using Add/Remove Programs in the control panel."; 1236 string16 name(chrome_dist->GetAppShortCutName()); 1237 string16 message(base::StringPrintf(kPleaseUninstallYourChromeMessage, 1238 name.c_str())); 1239 1240 LOG(ERROR) << "Aborting operation: another installation of " << name 1241 << " was found, as a last resort (if the product is not present " 1242 "in Add/Remove Programs), try executing: " 1243 << existing_chrome->uninstall_command().GetCommandLineString(); 1244 MessageBox(NULL, message.c_str(), NULL, MB_ICONERROR); 1245 return installer::INSTALL_FAILED; 1246 } 1247 1248 base::FilePath chrome_exe( 1249 cmd_line.GetSwitchValuePath(installer::switches::kRegisterDevChrome)); 1250 if (chrome_exe.empty()) 1251 chrome_exe = cmd_line.GetProgram().DirName().Append(installer::kChromeExe); 1252 if (!chrome_exe.IsAbsolute()) 1253 chrome_exe = base::MakeAbsoluteFilePath(chrome_exe); 1254 1255 installer::InstallStatus status = installer::FIRST_INSTALL_SUCCESS; 1256 if (base::PathExists(chrome_exe)) { 1257 Product chrome(chrome_dist); 1258 1259 // Create the Start menu shortcut and pin it to the taskbar. 1260 ShellUtil::ShortcutProperties shortcut_properties(ShellUtil::CURRENT_USER); 1261 chrome.AddDefaultShortcutProperties(chrome_exe, &shortcut_properties); 1262 shortcut_properties.set_dual_mode(true); 1263 shortcut_properties.set_pin_to_taskbar(true); 1264 ShellUtil::CreateOrUpdateShortcut( 1265 ShellUtil::SHORTCUT_LOCATION_START_MENU, chrome_dist, 1266 shortcut_properties, ShellUtil::SHELL_SHORTCUT_CREATE_ALWAYS); 1267 1268 // Register Chrome at user-level and make it default. 1269 scoped_ptr<WorkItemList> delegate_execute_list( 1270 WorkItem::CreateWorkItemList()); 1271 installer::AddDelegateExecuteWorkItems( 1272 installer_state, chrome_exe.DirName(), Version(), chrome, 1273 delegate_execute_list.get()); 1274 delegate_execute_list->Do(); 1275 if (ShellUtil::CanMakeChromeDefaultUnattended()) { 1276 ShellUtil::MakeChromeDefault( 1277 chrome_dist, ShellUtil::CURRENT_USER, chrome_exe.value(), true); 1278 } else { 1279 ShellUtil::ShowMakeChromeDefaultSystemUI(chrome_dist, chrome_exe.value()); 1280 } 1281 } else { 1282 LOG(ERROR) << "Path not found: " << chrome_exe.value(); 1283 status = installer::INSTALL_FAILED; 1284 } 1285 return status; 1286} 1287 1288// This method processes any command line options that make setup.exe do 1289// various tasks other than installation (renaming chrome.exe, showing eula 1290// among others). This function returns true if any such command line option 1291// has been found and processed (so setup.exe should exit at that point). 1292bool HandleNonInstallCmdLineOptions(const InstallationState& original_state, 1293 const CommandLine& cmd_line, 1294 InstallerState* installer_state, 1295 int* exit_code) { 1296 // TODO(gab): Add a local |status| variable which each block below sets; 1297 // only determine the |exit_code| from |status| at the end (this will allow 1298 // this method to validate that 1299 // (!handled || status != installer::UNKNOWN_STATUS)). 1300 bool handled = true; 1301 // TODO(tommi): Split these checks up into functions and use a data driven 1302 // map of switch->function. 1303 if (cmd_line.HasSwitch(installer::switches::kUpdateSetupExe)) { 1304 installer::InstallStatus status = installer::SETUP_PATCH_FAILED; 1305 // If --update-setup-exe command line option is given, we apply the given 1306 // patch to current exe, and store the resulting binary in the path 1307 // specified by --new-setup-exe. But we need to first unpack the file 1308 // given in --update-setup-exe. 1309 base::ScopedTempDir temp_path; 1310 if (!temp_path.CreateUniqueTempDir()) { 1311 PLOG(ERROR) << "Could not create temporary path."; 1312 } else { 1313 base::FilePath compressed_archive(cmd_line.GetSwitchValuePath( 1314 installer::switches::kUpdateSetupExe)); 1315 VLOG(1) << "Opening archive " << compressed_archive.value(); 1316 if (installer::ArchivePatchHelper::UncompressAndPatch( 1317 temp_path.path(), 1318 compressed_archive, 1319 cmd_line.GetProgram(), 1320 cmd_line.GetSwitchValuePath(installer::switches::kNewSetupExe))) { 1321 status = installer::NEW_VERSION_UPDATED; 1322 } 1323 if (!temp_path.Delete()) { 1324 // PLOG would be nice, but Delete() doesn't leave a meaningful value in 1325 // the Windows last-error code. 1326 LOG(WARNING) << "Scheduling temporary path " << temp_path.path().value() 1327 << " for deletion at reboot."; 1328 ScheduleDirectoryForDeletion(temp_path.path().value().c_str()); 1329 } 1330 } 1331 1332 *exit_code = InstallUtil::GetInstallReturnCode(status); 1333 if (*exit_code) { 1334 LOG(WARNING) << "setup.exe patching failed."; 1335 installer_state->WriteInstallerResult( 1336 status, IDS_SETUP_PATCH_FAILED_BASE, NULL); 1337 } 1338 // We will be exiting normally, so clear the stage indicator. 1339 installer_state->UpdateStage(installer::NO_STAGE); 1340 } else if (cmd_line.HasSwitch(installer::switches::kShowEula)) { 1341 // Check if we need to show the EULA. If it is passed as a command line 1342 // then the dialog is shown and regardless of the outcome setup exits here. 1343 string16 inner_frame = 1344 cmd_line.GetSwitchValueNative(installer::switches::kShowEula); 1345 *exit_code = ShowEULADialog(inner_frame); 1346 1347 if (installer::EULA_REJECTED != *exit_code) { 1348 if (GoogleUpdateSettings::SetEULAConsent( 1349 original_state, BrowserDistribution::GetDistribution(), true)) { 1350 CreateEULASentinel(BrowserDistribution::GetDistribution()); 1351 } 1352 // For a metro-originated launch, we now need to launch back into metro. 1353 if (cmd_line.HasSwitch(installer::switches::kShowEulaForMetro)) 1354 ActivateMetroChrome(); 1355 } 1356 } else if (cmd_line.HasSwitch(installer::switches::kConfigureUserSettings)) { 1357 // NOTE: Should the work done here, on kConfigureUserSettings, change: 1358 // kActiveSetupVersion in install_worker.cc needs to be increased for Active 1359 // Setup to invoke this again for all users of this install. 1360 const Product* chrome_install = 1361 installer_state->FindProduct(BrowserDistribution::CHROME_BROWSER); 1362 installer::InstallStatus status = installer::INVALID_STATE_FOR_OPTION; 1363 if (chrome_install && installer_state->system_install()) { 1364 bool force = 1365 cmd_line.HasSwitch(installer::switches::kForceConfigureUserSettings); 1366 installer::HandleActiveSetupForBrowser(installer_state->target_path(), 1367 *chrome_install, force); 1368 status = installer::INSTALL_REPAIRED; 1369 } else { 1370 LOG(DFATAL) << "chrome_install:" << chrome_install 1371 << ", system_install:" << installer_state->system_install(); 1372 } 1373 *exit_code = InstallUtil::GetInstallReturnCode(status); 1374 } else if (cmd_line.HasSwitch(installer::switches::kRegisterDevChrome)) { 1375 installer::InstallStatus status = RegisterDevChrome( 1376 original_state, *installer_state, cmd_line); 1377 *exit_code = InstallUtil::GetInstallReturnCode(status); 1378 } else if (cmd_line.HasSwitch(installer::switches::kRegisterChromeBrowser)) { 1379 installer::InstallStatus status = installer::UNKNOWN_STATUS; 1380 const Product* chrome_install = 1381 installer_state->FindProduct(BrowserDistribution::CHROME_BROWSER); 1382 if (chrome_install) { 1383 // If --register-chrome-browser option is specified, register all 1384 // Chrome protocol/file associations, as well as register it as a valid 1385 // browser for Start Menu->Internet shortcut. This switch will also 1386 // register Chrome as a valid handler for a set of URL protocols that 1387 // Chrome may become the default handler for, either by the user marking 1388 // Chrome as the default browser, through the Windows Default Programs 1389 // control panel settings, or through website use of 1390 // registerProtocolHandler. These protocols are found in 1391 // ShellUtil::kPotentialProtocolAssociations. 1392 // The --register-url-protocol will additionally register Chrome as a 1393 // potential handler for the supplied protocol, and is used if a website 1394 // registers a handler for a protocol not found in 1395 // ShellUtil::kPotentialProtocolAssociations. 1396 // These options should only be used when setup.exe is launched with admin 1397 // rights. We do not make any user specific changes with this option. 1398 DCHECK(IsUserAnAdmin()); 1399 string16 chrome_exe(cmd_line.GetSwitchValueNative( 1400 installer::switches::kRegisterChromeBrowser)); 1401 string16 suffix; 1402 if (cmd_line.HasSwitch( 1403 installer::switches::kRegisterChromeBrowserSuffix)) { 1404 suffix = cmd_line.GetSwitchValueNative( 1405 installer::switches::kRegisterChromeBrowserSuffix); 1406 } 1407 if (cmd_line.HasSwitch(installer::switches::kRegisterURLProtocol)) { 1408 string16 protocol = cmd_line.GetSwitchValueNative( 1409 installer::switches::kRegisterURLProtocol); 1410 // ShellUtil::RegisterChromeForProtocol performs all registration 1411 // done by ShellUtil::RegisterChromeBrowser, as well as registering 1412 // with Windows as capable of handling the supplied protocol. 1413 if (ShellUtil::RegisterChromeForProtocol( 1414 chrome_install->distribution(), chrome_exe, suffix, protocol, 1415 false)) 1416 status = installer::IN_USE_UPDATED; 1417 } else { 1418 if (ShellUtil::RegisterChromeBrowser(chrome_install->distribution(), 1419 chrome_exe, suffix, false)) 1420 status = installer::IN_USE_UPDATED; 1421 } 1422 } else { 1423 LOG(DFATAL) << "Can't register browser - Chrome distribution not found"; 1424 } 1425 *exit_code = InstallUtil::GetInstallReturnCode(status); 1426 } else if (cmd_line.HasSwitch(installer::switches::kRenameChromeExe)) { 1427 // If --rename-chrome-exe is specified, we want to rename the executables 1428 // and exit. 1429 *exit_code = RenameChromeExecutables(original_state, installer_state); 1430 } else if (cmd_line.HasSwitch( 1431 installer::switches::kRemoveChromeRegistration)) { 1432 // This is almost reverse of --register-chrome-browser option above. 1433 // Here we delete Chrome browser registration. This option should only 1434 // be used when setup.exe is launched with admin rights. We do not 1435 // make any user specific changes in this option. 1436 string16 suffix; 1437 if (cmd_line.HasSwitch( 1438 installer::switches::kRegisterChromeBrowserSuffix)) { 1439 suffix = cmd_line.GetSwitchValueNative( 1440 installer::switches::kRegisterChromeBrowserSuffix); 1441 } 1442 installer::InstallStatus tmp = installer::UNKNOWN_STATUS; 1443 const Product* chrome_install = 1444 installer_state->FindProduct(BrowserDistribution::CHROME_BROWSER); 1445 DCHECK(chrome_install); 1446 if (chrome_install) { 1447 installer::DeleteChromeRegistrationKeys(*installer_state, 1448 chrome_install->distribution(), HKEY_LOCAL_MACHINE, suffix, &tmp); 1449 } 1450 *exit_code = tmp; 1451 } else if (cmd_line.HasSwitch(installer::switches::kOnOsUpgrade)) { 1452 const Product* chrome_install = 1453 installer_state->FindProduct(BrowserDistribution::CHROME_BROWSER); 1454 installer::InstallStatus status = installer::INVALID_STATE_FOR_OPTION; 1455 if (chrome_install) { 1456 installer::HandleOsUpgradeForBrowser(*installer_state, 1457 *chrome_install); 1458 status = installer::INSTALL_REPAIRED; 1459 } else { 1460 LOG(DFATAL) << "Chrome product not found."; 1461 } 1462 *exit_code = InstallUtil::GetInstallReturnCode(status); 1463 } else if (cmd_line.HasSwitch(installer::switches::kQueryEULAAcceptance)) { 1464 *exit_code = installer::IsEULAAccepted(installer_state->system_install()); 1465 } else if (cmd_line.HasSwitch(installer::switches::kInactiveUserToast)) { 1466 // Launch the inactive user toast experiment. 1467 int flavor = -1; 1468 base::StringToInt(cmd_line.GetSwitchValueNative( 1469 installer::switches::kInactiveUserToast), &flavor); 1470 std::string experiment_group = 1471 cmd_line.GetSwitchValueASCII(installer::switches::kExperimentGroup); 1472 DCHECK_NE(-1, flavor); 1473 if (flavor == -1) { 1474 *exit_code = installer::UNKNOWN_STATUS; 1475 } else { 1476 // This code is called (via setup.exe relaunch) only if a product is known 1477 // to run user experiments, so no check is required. 1478 const Products& products = installer_state->products(); 1479 for (Products::const_iterator it = products.begin(); it < products.end(); 1480 ++it) { 1481 const Product& product = **it; 1482 installer::InactiveUserToastExperiment( 1483 flavor, ASCIIToUTF16(experiment_group), product, 1484 installer_state->target_path()); 1485 } 1486 } 1487 } else if (cmd_line.HasSwitch(installer::switches::kSystemLevelToast)) { 1488 const Products& products = installer_state->products(); 1489 for (Products::const_iterator it = products.begin(); it < products.end(); 1490 ++it) { 1491 const Product& product = **it; 1492 BrowserDistribution* browser_dist = product.distribution(); 1493 // We started as system-level and have been re-launched as user level 1494 // to continue with the toast experiment. 1495 Version installed_version; 1496 InstallUtil::GetChromeVersion(browser_dist, true, &installed_version); 1497 if (!installed_version.IsValid()) { 1498 LOG(ERROR) << "No installation of " 1499 << browser_dist->GetAppShortCutName() 1500 << " found for system-level toast."; 1501 } else { 1502 product.LaunchUserExperiment( 1503 cmd_line.GetProgram(), installer::REENTRY_SYS_UPDATE, true); 1504 } 1505 } 1506 } else if (cmd_line.HasSwitch( 1507 installer::switches::kChromeFrameReadyModeOptIn)) { 1508 *exit_code = InstallUtil::GetInstallReturnCode( 1509 installer::ChromeFrameReadyModeOptIn(original_state, *installer_state)); 1510 } else if (cmd_line.HasSwitch( 1511 installer::switches::kChromeFrameReadyModeTempOptOut)) { 1512 *exit_code = InstallUtil::GetInstallReturnCode( 1513 installer::ChromeFrameReadyModeTempOptOut(original_state, 1514 *installer_state)); 1515 } else if (cmd_line.HasSwitch( 1516 installer::switches::kChromeFrameReadyModeEndTempOptOut)) { 1517 *exit_code = InstallUtil::GetInstallReturnCode( 1518 installer::ChromeFrameReadyModeEndTempOptOut(original_state, 1519 *installer_state)); 1520 } else if (cmd_line.HasSwitch(installer::switches::kChromeFrameQuickEnable)) { 1521 *exit_code = installer::ChromeFrameQuickEnable(original_state, 1522 installer_state); 1523 } else if (cmd_line.HasSwitch(installer::switches::kPatch)) { 1524 const std::string patch_type_str( 1525 cmd_line.GetSwitchValueASCII(installer::switches::kPatch)); 1526 const base::FilePath input_file( 1527 cmd_line.GetSwitchValuePath(installer::switches::kInputFile)); 1528 const base::FilePath patch_file( 1529 cmd_line.GetSwitchValuePath(installer::switches::kPatchFile)); 1530 const base::FilePath output_file( 1531 cmd_line.GetSwitchValuePath(installer::switches::kOutputFile)); 1532 1533 if (patch_type_str == installer::kCourgette) { 1534 *exit_code = installer::CourgettePatchFiles(input_file, 1535 patch_file, 1536 output_file); 1537 } else if (patch_type_str == installer::kBsdiff) { 1538 *exit_code = installer::BsdiffPatchFiles(input_file, 1539 patch_file, 1540 output_file); 1541 } else { 1542 *exit_code = installer::PATCH_INVALID_ARGUMENTS; 1543 } 1544 } else { 1545 handled = false; 1546 } 1547 1548 return handled; 1549} 1550 1551bool ShowRebootDialog() { 1552 // Get a token for this process. 1553 HANDLE token; 1554 if (!OpenProcessToken(GetCurrentProcess(), 1555 TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, 1556 &token)) { 1557 LOG(ERROR) << "Failed to open token."; 1558 return false; 1559 } 1560 1561 // Use a ScopedHandle to keep track of and eventually close our handle. 1562 // TODO(robertshield): Add a Receive() method to base's ScopedHandle. 1563 base::win::ScopedHandle scoped_handle(token); 1564 1565 // Get the LUID for the shutdown privilege. 1566 TOKEN_PRIVILEGES tkp = {0}; 1567 LookupPrivilegeValue(NULL, SE_SHUTDOWN_NAME, &tkp.Privileges[0].Luid); 1568 tkp.PrivilegeCount = 1; 1569 tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; 1570 1571 // Get the shutdown privilege for this process. 1572 AdjustTokenPrivileges(token, FALSE, &tkp, 0, 1573 reinterpret_cast<PTOKEN_PRIVILEGES>(NULL), 0); 1574 if (GetLastError() != ERROR_SUCCESS) { 1575 LOG(ERROR) << "Unable to get shutdown privileges."; 1576 return false; 1577 } 1578 1579 // Popup a dialog that will prompt to reboot using the default system message. 1580 // TODO(robertshield): Add a localized, more specific string to the prompt. 1581 RestartDialog(NULL, NULL, EWX_REBOOT | EWX_FORCEIFHUNG); 1582 return true; 1583} 1584 1585// Returns the Custom information for the client identified by the exe path 1586// passed in. This information is used for crash reporting. 1587google_breakpad::CustomClientInfo* GetCustomInfo(const wchar_t* exe_path) { 1588 string16 product; 1589 string16 version; 1590 scoped_ptr<FileVersionInfo> version_info( 1591 FileVersionInfo::CreateFileVersionInfo(base::FilePath(exe_path))); 1592 if (version_info.get()) { 1593 version = version_info->product_version(); 1594 product = version_info->product_short_name(); 1595 } 1596 1597 if (version.empty()) 1598 version = L"0.1.0.0"; 1599 1600 if (product.empty()) 1601 product = L"Chrome Installer"; 1602 1603 static google_breakpad::CustomInfoEntry ver_entry(L"ver", version.c_str()); 1604 static google_breakpad::CustomInfoEntry prod_entry(L"prod", product.c_str()); 1605 static google_breakpad::CustomInfoEntry plat_entry(L"plat", L"Win32"); 1606 static google_breakpad::CustomInfoEntry type_entry(L"ptype", 1607 L"Chrome Installer"); 1608 static google_breakpad::CustomInfoEntry entries[] = { 1609 ver_entry, prod_entry, plat_entry, type_entry }; 1610 static google_breakpad::CustomClientInfo custom_info = { 1611 entries, arraysize(entries) }; 1612 return &custom_info; 1613} 1614 1615// Initialize crash reporting for this process. This involves connecting to 1616// breakpad, etc. 1617google_breakpad::ExceptionHandler* InitializeCrashReporting( 1618 bool system_install) { 1619 // Only report crashes if the user allows it. 1620 if (!GoogleUpdateSettings::GetCollectStatsConsent()) 1621 return NULL; 1622 1623 // Get the alternate dump directory. We use the temp path. 1624 base::FilePath temp_directory; 1625 if (!file_util::GetTempDir(&temp_directory) || temp_directory.empty()) 1626 return NULL; 1627 1628 wchar_t exe_path[MAX_PATH * 2] = {0}; 1629 GetModuleFileName(NULL, exe_path, arraysize(exe_path)); 1630 1631 // Build the pipe name. It can be either: 1632 // System-wide install: "NamedPipe\GoogleCrashServices\S-1-5-18" 1633 // Per-user install: "NamedPipe\GoogleCrashServices\<user SID>" 1634 string16 user_sid = kSystemPrincipalSid; 1635 1636 if (!system_install) { 1637 if (!base::win::GetUserSidString(&user_sid)) { 1638 return NULL; 1639 } 1640 } 1641 1642 string16 pipe_name = kGoogleUpdatePipeName; 1643 pipe_name += user_sid; 1644 1645 google_breakpad::ExceptionHandler* breakpad = 1646 new google_breakpad::ExceptionHandler( 1647 temp_directory.value(), NULL, NULL, NULL, 1648 google_breakpad::ExceptionHandler::HANDLER_ALL, kLargerDumpType, 1649 pipe_name.c_str(), GetCustomInfo(exe_path)); 1650 return breakpad; 1651} 1652 1653} // namespace 1654 1655int WINAPI wWinMain(HINSTANCE instance, HINSTANCE prev_instance, 1656 wchar_t* command_line, int show_command) { 1657 // The exit manager is in charge of calling the dtors of singletons. 1658 base::AtExitManager exit_manager; 1659 CommandLine::Init(0, NULL); 1660 1661 const MasterPreferences& prefs = MasterPreferences::ForCurrentProcess(); 1662 installer::InitInstallerLogging(prefs); 1663 1664 const CommandLine& cmd_line = *CommandLine::ForCurrentProcess(); 1665 VLOG(1) << "Command Line: " << cmd_line.GetCommandLineString(); 1666 1667 VLOG(1) << "multi install is " << prefs.is_multi_install(); 1668 bool system_install = false; 1669 prefs.GetBool(installer::master_preferences::kSystemLevel, &system_install); 1670 VLOG(1) << "system install is " << system_install; 1671 1672 google_breakpad::scoped_ptr<google_breakpad::ExceptionHandler> breakpad( 1673 InitializeCrashReporting(system_install)); 1674 1675 InstallationState original_state; 1676 original_state.Initialize(); 1677 1678 InstallerState installer_state; 1679 installer_state.Initialize(cmd_line, prefs, original_state); 1680 const bool is_uninstall = cmd_line.HasSwitch(installer::switches::kUninstall); 1681 1682 // Check to make sure current system is WinXP or later. If not, log 1683 // error message and get out. 1684 if (!InstallUtil::IsOSSupported()) { 1685 LOG(ERROR) << "Chrome only supports Windows XP or later."; 1686 installer_state.WriteInstallerResult( 1687 installer::OS_NOT_SUPPORTED, IDS_INSTALL_OS_NOT_SUPPORTED_BASE, NULL); 1688 return installer::OS_NOT_SUPPORTED; 1689 } 1690 1691 // Initialize COM for use later. 1692 base::win::ScopedCOMInitializer com_initializer; 1693 if (!com_initializer.succeeded()) { 1694 installer_state.WriteInstallerResult( 1695 installer::OS_ERROR, IDS_INSTALL_OS_ERROR_BASE, NULL); 1696 return installer::OS_ERROR; 1697 } 1698 1699 // Some command line options don't work with SxS install/uninstall 1700 if (InstallUtil::IsChromeSxSProcess()) { 1701 if (system_install || 1702 prefs.is_multi_install() || 1703 cmd_line.HasSwitch(installer::switches::kForceUninstall) || 1704 cmd_line.HasSwitch(installer::switches::kMakeChromeDefault) || 1705 cmd_line.HasSwitch(installer::switches::kRegisterChromeBrowser) || 1706 cmd_line.HasSwitch(installer::switches::kRemoveChromeRegistration) || 1707 cmd_line.HasSwitch(installer::switches::kInactiveUserToast) || 1708 cmd_line.HasSwitch(installer::switches::kSystemLevelToast) || 1709 cmd_line.HasSwitch(installer::switches::kChromeFrameQuickEnable)) { 1710 return installer::SXS_OPTION_NOT_SUPPORTED; 1711 } 1712 } 1713 1714 int exit_code = 0; 1715 if (HandleNonInstallCmdLineOptions( 1716 original_state, cmd_line, &installer_state, &exit_code)) { 1717 return exit_code; 1718 } 1719 1720 if (system_install && !IsUserAnAdmin()) { 1721 if (base::win::GetVersion() >= base::win::VERSION_VISTA && 1722 !cmd_line.HasSwitch(installer::switches::kRunAsAdmin)) { 1723 CommandLine new_cmd(CommandLine::NO_PROGRAM); 1724 new_cmd.AppendArguments(cmd_line, true); 1725 // Append --run-as-admin flag to let the new instance of setup.exe know 1726 // that we already tried to launch ourselves as admin. 1727 new_cmd.AppendSwitch(installer::switches::kRunAsAdmin); 1728 // If system_install became true due to an environment variable, append 1729 // it to the command line here since env vars may not propagate past the 1730 // elevation. 1731 if (!new_cmd.HasSwitch(installer::switches::kSystemLevel)) 1732 new_cmd.AppendSwitch(installer::switches::kSystemLevel); 1733 1734 DWORD exit_code = installer::UNKNOWN_STATUS; 1735 InstallUtil::ExecuteExeAsAdmin(new_cmd, &exit_code); 1736 return exit_code; 1737 } else { 1738 LOG(ERROR) << "Non admin user can not install system level Chrome."; 1739 installer_state.WriteInstallerResult(installer::INSUFFICIENT_RIGHTS, 1740 IDS_INSTALL_INSUFFICIENT_RIGHTS_BASE, NULL); 1741 return installer::INSUFFICIENT_RIGHTS; 1742 } 1743 } 1744 1745 installer::InstallStatus install_status = installer::UNKNOWN_STATUS; 1746 // If --uninstall option is given, uninstall the identified product(s) 1747 if (is_uninstall) { 1748 install_status = 1749 UninstallProducts(original_state, installer_state, cmd_line); 1750 } else { 1751 // If --uninstall option is not specified, we assume it is install case. 1752 install_status = 1753 InstallProducts(original_state, cmd_line, prefs, &installer_state); 1754 } 1755 1756 // Validate that the machine is now in a good state following the operation. 1757 // TODO(grt): change this to log at DFATAL once we're convinced that the 1758 // validator handles all cases properly. 1759 InstallationValidator::InstallationType installation_type = 1760 InstallationValidator::NO_PRODUCTS; 1761 LOG_IF(ERROR, 1762 !InstallationValidator::ValidateInstallationType(system_install, 1763 &installation_type)); 1764 1765 const Product* cf_install = 1766 installer_state.FindProduct(BrowserDistribution::CHROME_FRAME); 1767 1768 if (cf_install && 1769 !cmd_line.HasSwitch(installer::switches::kForceUninstall)) { 1770 if (install_status == installer::UNINSTALL_REQUIRES_REBOOT) { 1771 ShowRebootDialog(); 1772 } else if (is_uninstall) { 1773 // Only show the message box if Chrome Frame was the only product being 1774 // uninstalled. 1775 const Products& products = installer_state.products(); 1776 int num_products = 0; 1777 for (Products::const_iterator it = products.begin(); it < products.end(); 1778 ++it) { 1779 if (!(*it)->is_chrome_binaries()) 1780 ++num_products; 1781 } 1782 if (num_products == 1U) { 1783 ::MessageBoxW(NULL, 1784 installer::GetLocalizedString( 1785 IDS_UNINSTALL_COMPLETE_BASE).c_str(), 1786 cf_install->distribution()->GetAppShortCutName().c_str(), 1787 MB_OK); 1788 } 1789 } 1790 } 1791 1792 int return_code = 0; 1793 // MSI demands that custom actions always return 0 (ERROR_SUCCESS) or it will 1794 // rollback the action. If we're uninstalling we want to avoid this, so always 1795 // report success, squashing any more informative return codes. 1796 if (!(installer_state.is_msi() && is_uninstall)) 1797 // Note that we allow the status installer::UNINSTALL_REQUIRES_REBOOT 1798 // to pass through, since this is only returned on uninstall which is 1799 // never invoked directly by Google Update. 1800 return_code = InstallUtil::GetInstallReturnCode(install_status); 1801 1802 VLOG(1) << "Installation complete, returning: " << return_code; 1803 1804 return return_code; 1805} 1806