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