install.cc revision 5821806d5e7f356e8fa4b058a389a808ea183019
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/install.h" 6 7#include <windows.h> 8#include <shlobj.h> 9#include <time.h> 10#include <winuser.h> 11 12#include <string> 13 14#include "base/command_line.h" 15#include "base/file_path.h" 16#include "base/file_util.h" 17#include "base/logging.h" 18#include "base/memory/scoped_ptr.h" 19#include "base/path_service.h" 20#include "base/string_util.h" 21#include "base/stringprintf.h" 22#include "base/utf_string_conversions.h" 23#include "base/win/shortcut.h" 24#include "base/win/windows_version.h" 25#include "chrome/common/chrome_constants.h" 26#include "chrome/common/chrome_switches.h" 27#include "chrome/installer/setup/install_worker.h" 28#include "chrome/installer/setup/setup_constants.h" 29#include "chrome/installer/util/auto_launch_util.h" 30#include "chrome/installer/util/browser_distribution.h" 31#include "chrome/installer/util/create_reg_key_work_item.h" 32#include "chrome/installer/util/delete_after_reboot_helper.h" 33#include "chrome/installer/util/google_update_constants.h" 34#include "chrome/installer/util/helper.h" 35#include "chrome/installer/util/install_util.h" 36#include "chrome/installer/util/master_preferences.h" 37#include "chrome/installer/util/master_preferences_constants.h" 38#include "chrome/installer/util/set_reg_value_work_item.h" 39#include "chrome/installer/util/shell_util.h" 40#include "chrome/installer/util/util_constants.h" 41#include "chrome/installer/util/work_item_list.h" 42 43// Build-time generated include file. 44#include "registered_dlls.h" // NOLINT 45 46using installer::InstallerState; 47using installer::InstallationState; 48using installer::Product; 49 50namespace { 51 52void LogShortcutOperation(ShellUtil::ShortcutLocation location, 53 BrowserDistribution* dist, 54 const ShellUtil::ShortcutProperties& properties, 55 ShellUtil::ShortcutOperation operation, 56 bool failed) { 57 // ShellUtil::SHELL_SHORTCUT_UPDATE_EXISTING should not be used at install and 58 // thus this method does not handle logging a message for it. 59 DCHECK(operation != ShellUtil::SHELL_SHORTCUT_UPDATE_EXISTING); 60 std::string message; 61 if (failed) 62 message.append("Failed: "); 63 message.append( 64 (operation == ShellUtil::SHELL_SHORTCUT_CREATE_ALWAYS || 65 operation == ShellUtil::SHELL_SHORTCUT_CREATE_IF_NO_SYSTEM_LEVEL) ? 66 "Creating " : "Overwriting "); 67 if (failed && operation == ShellUtil::SHELL_SHORTCUT_REPLACE_EXISTING) 68 message.append("(maybe the shortcut doesn't exist?) "); 69 message.append((properties.level == ShellUtil::CURRENT_USER) ? "per-user " : 70 "all-users "); 71 switch (location) { 72 case ShellUtil::SHORTCUT_LOCATION_DESKTOP: 73 message.append("Desktop "); 74 break; 75 case ShellUtil::SHORTCUT_LOCATION_QUICK_LAUNCH: 76 message.append("Quick Launch "); 77 break; 78 case ShellUtil::SHORTCUT_LOCATION_START_MENU: 79 message.append("Start menu "); 80 break; 81 default: 82 NOTREACHED(); 83 } 84 85 message.push_back('"'); 86 if (properties.has_shortcut_name()) 87 message.append(UTF16ToUTF8(properties.shortcut_name)); 88 else 89 message.append(UTF16ToUTF8(dist->GetAppShortCutName())); 90 message.push_back('"'); 91 92 message.append(" shortcut to "); 93 message.append(UTF16ToUTF8(properties.target.value())); 94 if (properties.has_arguments()) 95 message.append(UTF16ToUTF8(properties.arguments)); 96 97 if (properties.pin_to_taskbar && 98 base::win::GetVersion() >= base::win::VERSION_WIN7) { 99 message.append(" and pinning to the taskbar."); 100 } else { 101 message.push_back('.'); 102 } 103 104 if (failed) 105 LOG(WARNING) << message; 106 else 107 VLOG(1) << message; 108} 109 110void ExecuteAndLogShortcutOperation( 111 ShellUtil::ShortcutLocation location, 112 BrowserDistribution* dist, 113 const ShellUtil::ShortcutProperties& properties, 114 ShellUtil::ShortcutOperation operation) { 115 LogShortcutOperation(location, dist, properties, operation, false); 116 if (!ShellUtil::CreateOrUpdateShortcut(location, dist, properties, 117 operation)) { 118 LogShortcutOperation(location, dist, properties, operation, true); 119 } 120} 121 122void AddChromeToMediaPlayerList() { 123 string16 reg_path(installer::kMediaPlayerRegPath); 124 // registry paths can also be appended like file system path 125 reg_path.push_back(FilePath::kSeparators[0]); 126 reg_path.append(installer::kChromeExe); 127 VLOG(1) << "Adding Chrome to Media player list at " << reg_path; 128 scoped_ptr<WorkItem> work_item(WorkItem::CreateCreateRegKeyWorkItem( 129 HKEY_LOCAL_MACHINE, reg_path)); 130 131 // if the operation fails we log the error but still continue 132 if (!work_item.get()->Do()) 133 LOG(ERROR) << "Could not add Chrome to media player inclusion list."; 134} 135 136// Copy master_preferences file provided to installer, in the same folder 137// as chrome.exe so Chrome first run can find it. This function will be called 138// only on the first install of Chrome. 139void CopyPreferenceFileForFirstRun(const InstallerState& installer_state, 140 const FilePath& prefs_source_path) { 141 FilePath prefs_dest_path(installer_state.target_path().AppendASCII( 142 installer::kDefaultMasterPrefs)); 143 if (!file_util::CopyFile(prefs_source_path, prefs_dest_path)) { 144 VLOG(1) << "Failed to copy master preferences from:" 145 << prefs_source_path.value() << " gle: " << ::GetLastError(); 146 } 147} 148 149// Returns true if the current process is running on the interactive window 150// station. This cares not whether the input desktop is the default or not 151// (i.e., the screen saver is running, or what have you). 152bool IsInteractiveProcess() { 153 static const wchar_t kWinSta0[] = L"WinSta0"; 154 HWINSTA window_station = ::GetProcessWindowStation(); 155 if (window_station == NULL) { 156 PLOG(ERROR) << "Failed to get window station"; 157 return false; 158 } 159 160 // Make the buffer one char longer and zero it to be certain it's terminated. 161 wchar_t name[arraysize(kWinSta0) + 1] = {}; 162 DWORD buffer_length = sizeof(kWinSta0); 163 DWORD name_length = 0; 164 return (GetUserObjectInformation(window_station, UOI_NAME, &name[0], 165 buffer_length, &name_length) && 166 name_length == buffer_length && 167 lstrcmpi(kWinSta0, name) == 0); 168} 169 170// This function installs a new version of Chrome to the specified location. 171// 172// setup_path: Path to the executable (setup.exe) as it will be copied 173// to Chrome install folder after install is complete 174// archive_path: Path to the archive (chrome.7z) as it will be copied 175// to Chrome install folder after install is complete 176// src_path: the path that contains a complete and unpacked Chrome package 177// to be installed. 178// temp_path: the path of working directory used during installation. This path 179// does not need to exist. 180// new_version: new Chrome version that needs to be installed 181// current_version: returns the current active version (if any) 182// 183// This function makes best effort to do installation in a transactional 184// manner. If failed it tries to rollback all changes on the file system 185// and registry. For example, if package exists before calling the 186// function, it rolls back all new file and directory changes under 187// package. If package does not exist before calling the function 188// (typical new install), the function creates package during install 189// and removes the whole directory during rollback. 190installer::InstallStatus InstallNewVersion( 191 const InstallationState& original_state, 192 const InstallerState& installer_state, 193 const FilePath& setup_path, 194 const FilePath& archive_path, 195 const FilePath& src_path, 196 const FilePath& temp_path, 197 const Version& new_version, 198 scoped_ptr<Version>* current_version) { 199 DCHECK(current_version); 200 201 installer_state.UpdateStage(installer::BUILDING); 202 203 current_version->reset(installer_state.GetCurrentVersion(original_state)); 204 scoped_ptr<WorkItemList> install_list(WorkItem::CreateWorkItemList()); 205 206 AddInstallWorkItems(original_state, 207 installer_state, 208 setup_path, 209 archive_path, 210 src_path, 211 temp_path, 212 current_version->get(), 213 new_version, 214 install_list.get()); 215 216 FilePath new_chrome_exe( 217 installer_state.target_path().Append(installer::kChromeNewExe)); 218 219 installer_state.UpdateStage(installer::EXECUTING); 220 221 if (!install_list->Do()) { 222 installer_state.UpdateStage(installer::ROLLINGBACK); 223 installer::InstallStatus result = 224 file_util::PathExists(new_chrome_exe) && current_version->get() && 225 new_version.Equals(*current_version->get()) ? 226 installer::SAME_VERSION_REPAIR_FAILED : 227 installer::INSTALL_FAILED; 228 LOG(ERROR) << "Install failed, rolling back... result: " << result; 229 install_list->Rollback(); 230 LOG(ERROR) << "Rollback complete. "; 231 return result; 232 } 233 234 installer_state.UpdateStage(installer::REFRESHING_POLICY); 235 236 installer::RefreshElevationPolicy(); 237 238 if (!current_version->get()) { 239 VLOG(1) << "First install of version " << new_version.GetString(); 240 return installer::FIRST_INSTALL_SUCCESS; 241 } 242 243 if (new_version.Equals(**current_version)) { 244 VLOG(1) << "Install repaired of version " << new_version.GetString(); 245 return installer::INSTALL_REPAIRED; 246 } 247 248 if (new_version.CompareTo(**current_version) > 0) { 249 if (file_util::PathExists(new_chrome_exe)) { 250 VLOG(1) << "Version updated to " << new_version.GetString() 251 << " while running " << (*current_version)->GetString(); 252 return installer::IN_USE_UPDATED; 253 } 254 VLOG(1) << "Version updated to " << new_version.GetString(); 255 return installer::NEW_VERSION_UPDATED; 256 } 257 258 LOG(ERROR) << "Not sure how we got here while updating" 259 << ", new version: " << new_version.GetString() 260 << ", old version: " << (*current_version)->GetString(); 261 262 return installer::INSTALL_FAILED; 263} 264 265// Deletes the old "Uninstall Google Chrome" shortcut in the Start menu and, if 266// this is a system-level install, also deletes the old Default user Quick 267// Launch shortcut. Both of these were created prior to Chrome 24; in Chrome 24, 268// the uninstall shortcut was removed and the Default user Quick Launch shortcut 269// was replaced by per-user shortcuts created via Active Setup. 270void CleanupLegacyShortcuts(const InstallerState& installer_state, 271 BrowserDistribution* dist, 272 const FilePath& chrome_exe) { 273 ShellUtil::ShellChange shortcut_level = installer_state.system_install() ? 274 ShellUtil::SYSTEM_LEVEL : ShellUtil::CURRENT_USER; 275 FilePath uninstall_shortcut_path; 276 ShellUtil::GetShortcutPath(ShellUtil::SHORTCUT_LOCATION_START_MENU, dist, 277 shortcut_level, &uninstall_shortcut_path); 278 uninstall_shortcut_path = uninstall_shortcut_path.Append( 279 dist->GetUninstallLinkName() + installer::kLnkExt); 280 file_util::Delete(uninstall_shortcut_path, false); 281 282 if (installer_state.system_install()) { 283 ShellUtil::RemoveShortcut( 284 ShellUtil::SHORTCUT_LOCATION_QUICK_LAUNCH, dist, chrome_exe.value(), 285 ShellUtil::SYSTEM_LEVEL, NULL); 286 } 287} 288 289// Returns the appropriate shortcut operations for App Launcher, 290// based on state of installation and master_preferences. 291installer::InstallShortcutOperation GetAppLauncherShortcutOperation( 292 const InstallationState& original_state, 293 const InstallerState& installer_state) { 294 const installer::ProductState* original_app_host_state = 295 original_state.GetProductState(installer_state.system_install(), 296 BrowserDistribution::CHROME_APP_HOST); 297 bool app_launcher_exists = original_app_host_state && 298 CommandLine(original_app_host_state->uninstall_command()) 299 .HasSwitch(installer::switches::kChromeAppLauncher); 300 if (!app_launcher_exists) 301 return installer::INSTALL_SHORTCUT_CREATE_ALL; 302 303 return installer::INSTALL_SHORTCUT_REPLACE_EXISTING; 304} 305 306} // end namespace 307 308namespace installer { 309 310void EscapeXmlAttributeValueInSingleQuotes(string16* att_value) { 311 ReplaceChars(*att_value, L"&", L"&", att_value); 312 ReplaceChars(*att_value, L"'", L"'", att_value); 313 ReplaceChars(*att_value, L"<", L"<", att_value); 314} 315 316bool CreateVisualElementsManifest(const FilePath& src_path, 317 const Version& version) { 318 // Construct the relative path to the versioned VisualElements directory. 319 string16 elements_dir(ASCIIToUTF16(version.GetString())); 320 elements_dir.push_back(FilePath::kSeparators[0]); 321 elements_dir.append(installer::kVisualElements); 322 323 // Some distributions of Chromium may not include visual elements. Only 324 // proceed if this distribution does. 325 if (!file_util::PathExists(src_path.Append(elements_dir))) { 326 VLOG(1) << "No visual elements found, not writing " 327 << installer::kVisualElementsManifest << " to " << src_path.value(); 328 return true; 329 } else { 330 // A printf_p-style format string for generating the visual elements 331 // manifest. Required arguments, in order, are: 332 // - Localized display name for the product. 333 // - Relative path to the VisualElements directory. 334 static const char kManifestTemplate[] = 335 "<Application>\r\n" 336 " <VisualElements\r\n" 337 " DisplayName='%1$ls'\r\n" 338 " Logo='%2$ls\\Logo.png'\r\n" 339 " SmallLogo='%2$ls\\SmallLogo.png'\r\n" 340 " ForegroundText='light'\r\n" 341 " BackgroundColor='#323232'>\r\n" 342 " <DefaultTile ShowName='allLogos'/>\r\n" 343 " <SplashScreen Image='%2$ls\\splash-620x300.png'/>\r\n" 344 " </VisualElements>\r\n" 345 "</Application>"; 346 347 const string16 manifest_template(ASCIIToUTF16(kManifestTemplate)); 348 349 BrowserDistribution* dist = BrowserDistribution::GetSpecificDistribution( 350 BrowserDistribution::CHROME_BROWSER); 351 // TODO(grt): http://crbug.com/75152 Write a reference to a localized 352 // resource for |display_name|. 353 string16 display_name(dist->GetAppShortCutName()); 354 EscapeXmlAttributeValueInSingleQuotes(&display_name); 355 356 // Fill the manifest with the desired values. 357 string16 manifest16(base::StringPrintf(manifest_template.c_str(), 358 display_name.c_str(), 359 elements_dir.c_str())); 360 361 // Write the manifest to |src_path|. 362 const std::string manifest(UTF16ToUTF8(manifest16)); 363 if (file_util::WriteFile( 364 src_path.Append(installer::kVisualElementsManifest), 365 manifest.c_str(), manifest.size())) { 366 VLOG(1) << "Successfully wrote " << installer::kVisualElementsManifest 367 << " to " << src_path.value(); 368 return true; 369 } else { 370 PLOG(ERROR) << "Error writing " << installer::kVisualElementsManifest 371 << " to " << src_path.value(); 372 return false; 373 } 374 } 375} 376 377// TODO(tommi): Change this function to use WorkItemList. 378void CreateOrUpdateShortcuts( 379 const FilePath& target, 380 const Product& product, 381 const MasterPreferences& prefs, 382 InstallShortcutLevel install_level, 383 InstallShortcutOperation install_operation) { 384 // Extract shortcut preferences from |prefs|. 385 bool do_not_create_desktop_shortcut = false; 386 bool do_not_create_quick_launch_shortcut = false; 387 bool alternate_desktop_shortcut = false; 388 prefs.GetBool(master_preferences::kDoNotCreateDesktopShortcut, 389 &do_not_create_desktop_shortcut); 390 prefs.GetBool(master_preferences::kDoNotCreateQuickLaunchShortcut, 391 &do_not_create_quick_launch_shortcut); 392 prefs.GetBool(master_preferences::kAltShortcutText, 393 &alternate_desktop_shortcut); 394 395 BrowserDistribution* dist = product.distribution(); 396 397 // The default operation on update is to overwrite shortcuts with the 398 // currently desired properties, but do so only for shortcuts that still 399 // exist. 400 ShellUtil::ShortcutOperation shortcut_operation; 401 switch (install_operation) { 402 case INSTALL_SHORTCUT_CREATE_ALL: 403 shortcut_operation = ShellUtil::SHELL_SHORTCUT_CREATE_ALWAYS; 404 break; 405 case INSTALL_SHORTCUT_CREATE_EACH_IF_NO_SYSTEM_LEVEL: 406 shortcut_operation = ShellUtil::SHELL_SHORTCUT_CREATE_IF_NO_SYSTEM_LEVEL; 407 break; 408 default: 409 DCHECK(install_operation == INSTALL_SHORTCUT_REPLACE_EXISTING); 410 shortcut_operation = ShellUtil::SHELL_SHORTCUT_REPLACE_EXISTING; 411 break; 412 } 413 414 // Shortcuts are always installed per-user unless specified. 415 ShellUtil::ShellChange shortcut_level = (install_level == ALL_USERS ? 416 ShellUtil::SYSTEM_LEVEL : ShellUtil::CURRENT_USER); 417 418 // |base_properties|: The basic properties to set on every shortcut installed 419 // (to be refined on a per-shortcut basis). 420 ShellUtil::ShortcutProperties base_properties(shortcut_level); 421 product.AddDefaultShortcutProperties(target, &base_properties); 422 423 if (!do_not_create_desktop_shortcut || 424 shortcut_operation == ShellUtil::SHELL_SHORTCUT_REPLACE_EXISTING) { 425 ShellUtil::ShortcutProperties desktop_properties(base_properties); 426 if (alternate_desktop_shortcut) 427 desktop_properties.set_shortcut_name(dist->GetAlternateApplicationName()); 428 ExecuteAndLogShortcutOperation( 429 ShellUtil::SHORTCUT_LOCATION_DESKTOP, dist, desktop_properties, 430 shortcut_operation); 431 432 // On update there is no harm in always trying to update the alternate 433 // Desktop shortcut. 434 if (!alternate_desktop_shortcut && 435 shortcut_operation == ShellUtil::SHELL_SHORTCUT_REPLACE_EXISTING) { 436 desktop_properties.set_shortcut_name(dist->GetAlternateApplicationName()); 437 ExecuteAndLogShortcutOperation( 438 ShellUtil::SHORTCUT_LOCATION_DESKTOP, dist, desktop_properties, 439 shortcut_operation); 440 } 441 } 442 443 if (!do_not_create_quick_launch_shortcut || 444 shortcut_operation == ShellUtil::SHELL_SHORTCUT_REPLACE_EXISTING) { 445 ExecuteAndLogShortcutOperation( 446 ShellUtil::SHORTCUT_LOCATION_QUICK_LAUNCH, dist, base_properties, 447 shortcut_operation); 448 } 449 450 ShellUtil::ShortcutProperties start_menu_properties(base_properties); 451 // IMPORTANT: Only the default (no arguments and default browserappid) browser 452 // shortcut in the Start menu (Start screen on Win8+) should be made dual 453 // mode. 454 start_menu_properties.set_dual_mode(true); 455 if (shortcut_operation == ShellUtil::SHELL_SHORTCUT_CREATE_ALWAYS || 456 shortcut_operation == 457 ShellUtil::SHELL_SHORTCUT_CREATE_IF_NO_SYSTEM_LEVEL) { 458 start_menu_properties.set_pin_to_taskbar(true); 459 } 460 ExecuteAndLogShortcutOperation(ShellUtil::SHORTCUT_LOCATION_START_MENU, 461 dist, start_menu_properties, 462 shortcut_operation); 463} 464 465void RegisterChromeOnMachine(const InstallerState& installer_state, 466 const Product& product, 467 bool make_chrome_default) { 468 DCHECK(product.is_chrome()); 469 470 // Try to add Chrome to Media Player shim inclusion list. We don't do any 471 // error checking here because this operation will fail if user doesn't 472 // have admin rights and we want to ignore the error. 473 AddChromeToMediaPlayerList(); 474 475 // Make Chrome the default browser if desired when possible. Otherwise, only 476 // register it with Windows. 477 BrowserDistribution* dist = product.distribution(); 478 const string16 chrome_exe( 479 installer_state.target_path().Append(installer::kChromeExe).value()); 480 VLOG(1) << "Registering Chrome as browser: " << chrome_exe; 481 if (make_chrome_default) { 482 if (ShellUtil::CanMakeChromeDefaultUnattended()) { 483 int level = ShellUtil::CURRENT_USER; 484 if (installer_state.system_install()) 485 level = level | ShellUtil::SYSTEM_LEVEL; 486 ShellUtil::MakeChromeDefault(dist, level, chrome_exe, true); 487 } else if (IsInteractiveProcess()) { 488 ShellUtil::ShowMakeChromeDefaultSystemUI(dist, chrome_exe); 489 } else { 490 ShellUtil::RegisterChromeBrowser(dist, chrome_exe, string16(), false); 491 } 492 } else { 493 ShellUtil::RegisterChromeBrowser(dist, chrome_exe, string16(), false); 494 } 495} 496 497InstallStatus InstallOrUpdateProduct( 498 const InstallationState& original_state, 499 const InstallerState& installer_state, 500 const FilePath& setup_path, 501 const FilePath& archive_path, 502 const FilePath& install_temp_path, 503 const FilePath& src_path, 504 const FilePath& prefs_path, 505 const MasterPreferences& prefs, 506 const Version& new_version) { 507 // TODO(robertshield): Removing the pending on-reboot moves should be done 508 // elsewhere. 509 // TODO(erikwright): Understand why this is Chrome Frame only and whether 510 // it also applies to App Host. Shouldn't it apply to any multi-install too? 511 const Products& products = installer_state.products(); 512 DCHECK(products.size()); 513 if (installer_state.FindProduct(BrowserDistribution::CHROME_FRAME)) { 514 // Make sure that we don't end up deleting installed files on next reboot. 515 if (!RemoveFromMovesPendingReboot( 516 installer_state.target_path().value().c_str())) { 517 LOG(ERROR) << "Error accessing pending moves value."; 518 } 519 } 520 521 // Create VisualElementManifest.xml in |src_path| (if required) so that it 522 // looks as if it had been extracted from the archive when calling 523 // InstallNewVersion() below. 524 installer_state.UpdateStage(installer::CREATING_VISUAL_MANIFEST); 525 CreateVisualElementsManifest(src_path, new_version); 526 527 scoped_ptr<Version> existing_version; 528 InstallStatus result = InstallNewVersion(original_state, installer_state, 529 setup_path, archive_path, src_path, install_temp_path, new_version, 530 &existing_version); 531 532 // TODO(robertshield): Everything below this line should instead be captured 533 // by WorkItems. 534 if (!InstallUtil::GetInstallReturnCode(result)) { 535 installer_state.UpdateStage(installer::UPDATING_CHANNELS); 536 537 // Update the modifiers on the channel values for the product(s) being 538 // installed and for the binaries in case of multi-install. 539 installer_state.UpdateChannels(); 540 541 installer_state.UpdateStage(installer::COPYING_PREFERENCES_FILE); 542 543 if (result == FIRST_INSTALL_SUCCESS && !prefs_path.empty()) 544 CopyPreferenceFileForFirstRun(installer_state, prefs_path); 545 546 installer_state.UpdateStage(installer::CREATING_SHORTCUTS); 547 548 const Product* app_launcher_product = 549 installer_state.FindProduct(BrowserDistribution::CHROME_APP_HOST); 550 // Creates shortcuts for App Launcher. 551 if (app_launcher_product && 552 app_launcher_product->HasOption(kOptionAppHostIsLauncher)) { 553 // TODO(huangs): Remove this check once we have system-level App Host. 554 DCHECK(!installer_state.system_install()); 555 const FilePath app_host_exe( 556 installer_state.target_path().Append(kChromeAppHostExe)); 557 InstallShortcutOperation app_launcher_shortcut_operation = 558 GetAppLauncherShortcutOperation(original_state, installer_state); 559 560 // Always install per-user shortcuts for App Launcher. 561 CreateOrUpdateShortcuts(app_host_exe, *app_launcher_product, prefs, 562 CURRENT_USER, app_launcher_shortcut_operation); 563 } 564 565 const Product* chrome_product = 566 installer_state.FindProduct(BrowserDistribution::CHROME_BROWSER); 567 // Creates shortcuts for Chrome. 568 if (chrome_product) { 569 BrowserDistribution* dist = chrome_product->distribution(); 570 const FilePath chrome_exe( 571 installer_state.target_path().Append(kChromeExe)); 572 CleanupLegacyShortcuts(installer_state, dist, chrome_exe); 573 574 InstallShortcutOperation install_operation = 575 INSTALL_SHORTCUT_REPLACE_EXISTING; 576 if (result == installer::FIRST_INSTALL_SUCCESS || 577 result == installer::INSTALL_REPAIRED) { 578 install_operation = INSTALL_SHORTCUT_CREATE_ALL; 579 } 580 581 if (installer_state.system_install()) { 582 // Update existing all-users shortcuts for legacy installs. 583 CreateOrUpdateShortcuts(chrome_exe, *chrome_product, prefs, ALL_USERS, 584 INSTALL_SHORTCUT_REPLACE_EXISTING); 585 } 586 // Always install per-user shortcuts (even on system-level installs where 587 // we do so for the installing user instead of waiting for Active Setup). 588 CreateOrUpdateShortcuts(chrome_exe, *chrome_product, prefs, CURRENT_USER, 589 install_operation); 590 } 591 592 if (chrome_product) { 593 // Register Chrome and, if requested, make Chrome the default browser. 594 installer_state.UpdateStage(installer::REGISTERING_CHROME); 595 596 bool make_chrome_default = false; 597 prefs.GetBool(master_preferences::kMakeChromeDefault, 598 &make_chrome_default); 599 600 // If this is not the user's first Chrome install, but they have chosen 601 // Chrome to become their default browser on the download page, we must 602 // force it here because the master_preferences file will not get copied 603 // into the build. 604 bool force_chrome_default_for_user = false; 605 if (result == NEW_VERSION_UPDATED || 606 result == INSTALL_REPAIRED) { 607 prefs.GetBool(master_preferences::kMakeChromeDefaultForUser, 608 &force_chrome_default_for_user); 609 } 610 611 RegisterChromeOnMachine(installer_state, *chrome_product, 612 make_chrome_default || force_chrome_default_for_user); 613 614 // Configure auto-launch. 615 if (result == FIRST_INSTALL_SUCCESS) { 616 installer_state.UpdateStage(installer::CONFIGURE_AUTO_LAUNCH); 617 618 // Add auto-launch key if specified in master_preferences. 619 bool auto_launch_chrome = false; 620 prefs.GetBool( 621 installer::master_preferences::kAutoLaunchChrome, 622 &auto_launch_chrome); 623 if (auto_launch_chrome) { 624 auto_launch_util::EnableForegroundStartAtLogin( 625 ASCIIToUTF16(chrome::kInitialProfile), 626 installer_state.target_path()); 627 } 628 } 629 } 630 631 installer_state.UpdateStage(installer::REMOVING_OLD_VERSIONS); 632 633 installer_state.RemoveOldVersionDirectories( 634 new_version, 635 existing_version.get(), 636 install_temp_path); 637 } 638 639 return result; 640} 641 642void HandleOsUpgradeForBrowser(const InstallerState& installer_state, 643 const Product& chrome) { 644 DCHECK(chrome.is_chrome()); 645 // Upon upgrading to Windows 8, we need to fix Chrome shortcuts and register 646 // Chrome, so that Metro Chrome would work if Chrome is the default browser. 647 if (base::win::GetVersion() >= base::win::VERSION_WIN8) { 648 VLOG(1) << "Updating and registering shortcuts."; 649 // Read master_preferences copied beside chrome.exe at install. 650 MasterPreferences prefs( 651 installer_state.target_path().AppendASCII(kDefaultMasterPrefs)); 652 653 // Unfortunately, if this is a system-level install, we can't update the 654 // shortcuts of each individual user (this only matters if this is an OS 655 // upgrade for XP/Vista to Win7+ as some properties are only set on 656 // shortcuts as of Win7). 657 // At least attempt to update potentially existing all-users shortcuts. 658 InstallShortcutLevel level = installer_state.system_install() ? 659 ALL_USERS : CURRENT_USER; 660 FilePath chrome_exe(installer_state.target_path().Append(kChromeExe)); 661 CreateOrUpdateShortcuts( 662 chrome_exe, chrome, prefs, level, INSTALL_SHORTCUT_REPLACE_EXISTING); 663 RegisterChromeOnMachine(installer_state, chrome, false); 664 } 665} 666 667// NOTE: Should the work done here, on Active Setup, change: kActiveSetupVersion 668// in install_worker.cc needs to be increased for Active Setup to invoke this 669// again for all users of this install. 670void HandleActiveSetupForBrowser(const FilePath& installation_root, 671 const Product& chrome, 672 bool force) { 673 DCHECK(chrome.is_chrome()); 674 // Only create shortcuts on Active Setup if the first run sentinel is not 675 // present for this user (as some shortcuts used to be installed on first 676 // run and this could otherwise re-install shortcuts for users that have 677 // already deleted them in the past). 678 FilePath first_run_sentinel; 679 InstallUtil::GetSentinelFilePath( 680 chrome::kFirstRunSentinel, chrome.distribution(), &first_run_sentinel); 681 InstallShortcutOperation install_operation = 682 (!force && file_util::PathExists(first_run_sentinel) ? 683 INSTALL_SHORTCUT_REPLACE_EXISTING : 684 INSTALL_SHORTCUT_CREATE_EACH_IF_NO_SYSTEM_LEVEL); 685 686 // Read master_preferences copied beside chrome.exe at install. 687 MasterPreferences prefs(installation_root.AppendASCII(kDefaultMasterPrefs)); 688 FilePath chrome_exe(installation_root.Append(kChromeExe)); 689 CreateOrUpdateShortcuts( 690 chrome_exe, chrome, prefs, CURRENT_USER, install_operation); 691} 692 693} // namespace installer 694