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