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

Side by Side Diff: chrome/installer/setup/install.cc

Issue 6153003: Refactor install.cc into the work item parts and the non-work item parts. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src/
Patch Set: PostMergeTest3AddingMissingFile Created 9 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « chrome/installer/setup/install.h ('k') | chrome/installer/setup/install_worker.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "chrome/installer/setup/install.h" 5 #include "chrome/installer/setup/install.h"
6 6
7 #include <shlobj.h> 7 #include <shlobj.h>
8 #include <time.h> 8 #include <time.h>
9 #include <vector> 9 #include <vector>
10 10
11 #include "base/command_line.h" 11 #include "base/command_line.h"
12 #include "base/file_path.h" 12 #include "base/file_path.h"
13 #include "base/file_util.h" 13 #include "base/file_util.h"
14 #include "base/logging.h" 14 #include "base/logging.h"
15 #include "base/path_service.h" 15 #include "base/path_service.h"
16 #include "base/scoped_ptr.h" 16 #include "base/scoped_ptr.h"
17 #include "base/string_util.h" 17 #include "base/string_util.h"
18 #include "base/utf_string_conversions.h" 18 #include "base/utf_string_conversions.h"
19 #include "base/win/registry.h" 19 #include "base/win/registry.h"
20 #include "chrome/installer/setup/setup_constants.h" 20 #include "chrome/installer/setup/setup_constants.h"
21 #include "chrome/installer/setup/install_worker.h"
21 #include "chrome/installer/util/browser_distribution.h" 22 #include "chrome/installer/util/browser_distribution.h"
22 #include "chrome/installer/util/channel_info.h" 23 #include "chrome/installer/util/channel_info.h"
23 #include "chrome/installer/util/chrome_frame_distribution.h" 24 #include "chrome/installer/util/chrome_frame_distribution.h"
24 #include "chrome/installer/util/conditional_work_item_list.h" 25 #include "chrome/installer/util/conditional_work_item_list.h"
25 #include "chrome/installer/util/create_reg_key_work_item.h" 26 #include "chrome/installer/util/create_reg_key_work_item.h"
26 #include "chrome/installer/util/delete_after_reboot_helper.h" 27 #include "chrome/installer/util/delete_after_reboot_helper.h"
27 #include "chrome/installer/util/google_update_constants.h" 28 #include "chrome/installer/util/google_update_constants.h"
28 #include "chrome/installer/util/helper.h" 29 #include "chrome/installer/util/helper.h"
29 #include "chrome/installer/util/install_util.h" 30 #include "chrome/installer/util/install_util.h"
30 #include "chrome/installer/util/installation_state.h" 31 #include "chrome/installer/util/installation_state.h"
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after
85 temp_path.value(), WorkItem::ALWAYS); 86 temp_path.value(), WorkItem::ALWAYS);
86 if (package.system_level()) { 87 if (package.system_level()) {
87 install_list->AddCopyTreeWorkItem(archive_path.value(), archive_dst.value(), 88 install_list->AddCopyTreeWorkItem(archive_path.value(), archive_dst.value(),
88 temp_path.value(), WorkItem::ALWAYS); 89 temp_path.value(), WorkItem::ALWAYS);
89 } else { 90 } else {
90 install_list->AddMoveTreeWorkItem(archive_path.value(), archive_dst.value(), 91 install_list->AddMoveTreeWorkItem(archive_path.value(), archive_dst.value(),
91 temp_path.value()); 92 temp_path.value());
92 } 93 }
93 } 94 }
94 95
95 void AppendUninstallCommandLineFlags(CommandLine* uninstall_cmd,
96 const Product& product) {
97 DCHECK(uninstall_cmd);
98
99 uninstall_cmd->AppendSwitch(installer::switches::kUninstall);
100
101 // Append the product-specific uninstall flags.
102 product.distribution()->AppendUninstallCommandLineFlags(uninstall_cmd);
103 if (product.IsMsi()) {
104 uninstall_cmd->AppendSwitch(installer::switches::kMsi);
105 // See comment in uninstall.cc where we check for the kDeleteProfile switch.
106 if (product.is_chrome_frame()) {
107 uninstall_cmd->AppendSwitch(installer::switches::kDeleteProfile);
108 }
109 }
110 if (product.system_level())
111 uninstall_cmd->AppendSwitch(installer::switches::kSystemLevel);
112
113 // Propagate switches obtained from preferences as well.
114 const MasterPreferences& prefs = MasterPreferences::ForCurrentProcess();
115 if (prefs.is_multi_install()) {
116 uninstall_cmd->AppendSwitch(installer::switches::kMultiInstall);
117 }
118 bool value = false;
119 if (prefs.GetBool(installer::master_preferences::kVerboseLogging,
120 &value) && value)
121 uninstall_cmd->AppendSwitch(installer::switches::kVerboseLogging);
122 }
123
124 // Adds work items that make registry adjustments for Google Update. When a 96 // Adds work items that make registry adjustments for Google Update. When a
125 // product is installed (including overinstall), Google Update will write the 97 // product is installed (including overinstall), Google Update will write the
126 // channel ("ap") value into either Chrome or Chrome Frame's ClientState key. 98 // channel ("ap") value into either Chrome or Chrome Frame's ClientState key.
127 // In the multi-install case, this value is used as the basis upon which the 99 // In the multi-install case, this value is used as the basis upon which the
128 // package's channel value is built (by adding the ordered list of installed 100 // package's channel value is built (by adding the ordered list of installed
129 // products and their options). 101 // products and their options).
130 void AddGoogleUpdateWorkItems(const InstallationState& original_state, 102 void AddGoogleUpdateWorkItems(const InstallationState& original_state,
131 const InstallerState& installer_state, 103 const InstallerState& installer_state,
132 const Package& package, 104 const Package& package,
133 WorkItemList* install_list) { 105 WorkItemList* install_list) {
(...skipping 254 matching lines...) Expand 10 before | Expand all | Expand 10 after
388 ret = ShellUtil::CreateChromeQuickLaunchShortcut( 360 ret = ShellUtil::CreateChromeQuickLaunchShortcut(
389 product.distribution(), chrome_exe.value(), ShellUtil::CURRENT_USER, 361 product.distribution(), chrome_exe.value(), ShellUtil::CURRENT_USER,
390 create_all_shortcut); 362 create_all_shortcut);
391 } 363 }
392 } 364 }
393 } 365 }
394 366
395 return ret; 367 return ret;
396 } 368 }
397 369
398 // Local helper to call AddRegisterComDllWorkItems for all DLLs in a set of
399 // products managed by a given package.
400 void AddRegisterComDllWorkItemsForPackage(const Package& package,
401 const Version* old_version,
402 const Version& new_version,
403 WorkItemList* work_item_list) {
404 // First collect the list of DLLs to be registered from each product.
405 const Products& products = package.products();
406 Products::const_iterator product_iter(products.begin());
407 std::vector<FilePath> com_dll_list;
408 for (; product_iter != products.end(); ++product_iter) {
409 BrowserDistribution* dist = product_iter->get()->distribution();
410 std::vector<FilePath> dist_dll_list(dist->GetComDllList());
411 com_dll_list.insert(com_dll_list.end(), dist_dll_list.begin(),
412 dist_dll_list.end());
413 }
414
415 // Then, if we got some, attempt to unregister the DLLs from the old
416 // version directory and then re-register them in the new one.
417 // Note that if we are migrating the install directory then we will not
418 // successfully unregister the old DLLs.
419 // TODO(robertshield): See whether we need to fix the migration case.
420 // TODO(robertshield): If we ever remove a DLL from a product, this will
421 // not unregister it on update. We should build the unregistration list from
422 // saved state instead of assuming it is the same as the registration list.
423 if (!com_dll_list.empty()) {
424 if (old_version) {
425 FilePath old_dll_path(
426 package.path().Append(UTF8ToWide(old_version->GetString())));
427
428 installer::AddRegisterComDllWorkItems(old_dll_path,
429 com_dll_list,
430 package.system_level(),
431 false, // Unregister
432 true, // May fail
433 work_item_list);
434 }
435
436 FilePath dll_path(
437 package.path().Append(UTF8ToWide(new_version.GetString())));
438 installer::AddRegisterComDllWorkItems(dll_path,
439 com_dll_list,
440 package.system_level(),
441 true, // Register
442 false, // Must succeed.
443 work_item_list);
444 }
445 }
446
447 // After a successful copying of all the files, this function is called to
448 // do a few post install tasks:
449 // - Handle the case of in-use-update by updating "opv" (old version) key or
450 // deleting it if not required.
451 // - Register any new dlls and unregister old dlls.
452 // - If this is an MSI install, ensures that the MSI marker is set, and sets
453 // it if not.
454 // If these operations are successful, the function returns true, otherwise
455 // false.
456 bool AppendPostInstallTasks(bool multi_install,
457 const FilePath& setup_path,
458 const FilePath& new_chrome_exe,
459 const Version* current_version,
460 const Version& new_version,
461 const Package& package,
462 WorkItemList* post_install_task_list) {
463 DCHECK(post_install_task_list);
464 HKEY root = package.system_level() ? HKEY_LOCAL_MACHINE :
465 HKEY_CURRENT_USER;
466 const Products& products = package.products();
467
468
469 // Append work items that will only be executed if this was an update.
470 // We update the 'opv' key with the current version that is active and 'cmd'
471 // key with the rename command to run.
472 {
473 scoped_ptr<WorkItemList> in_use_update_work_items(
474 WorkItem::CreateConditionalWorkItemList(
475 new ConditionRunIfFileExists(new_chrome_exe)));
476 in_use_update_work_items->set_log_message("InUseUpdateWorkItemList");
477
478 FilePath installer_path(package.GetInstallerDirectory(new_version)
479 .Append(setup_path.BaseName()));
480
481 CommandLine rename(installer_path);
482 rename.AppendSwitch(installer::switches::kRenameChromeExe);
483 if (package.system_level())
484 rename.AppendSwitch(installer::switches::kSystemLevel);
485
486 if (InstallUtil::IsChromeSxSProcess())
487 rename.AppendSwitch(installer::switches::kChromeSxS);
488
489 if (multi_install)
490 rename.AppendSwitch(installer::switches::kMultiInstall);
491
492 std::wstring version_key;
493 for (size_t i = 0; i < products.size(); ++i) {
494 BrowserDistribution* dist = products[i]->distribution();
495 version_key = dist->GetVersionKey();
496
497 if (current_version != NULL) {
498 in_use_update_work_items->AddSetRegValueWorkItem(root, version_key,
499 google_update::kRegOldVersionField,
500 UTF8ToWide(current_version->GetString()), true);
501 }
502
503 // Adding this registry entry for all products is overkill.
504 // However, as it stands, we don't have a way to know which distribution
505 // will check the key and run the command, so we add it for all.
506 // After the first run, the subsequent runs should just be noops.
507 // (see Upgrade::SwapNewChromeExeIfPresent).
508 in_use_update_work_items->AddSetRegValueWorkItem(
509 root,
510 version_key,
511 google_update::kRegRenameCmdField,
512 rename.command_line_string(),
513 true);
514 }
515
516 if (multi_install) {
517 PackageProperties* props = package.properties();
518 if (props->ReceivesUpdates() && current_version != NULL) {
519 in_use_update_work_items->AddSetRegValueWorkItem(
520 root,
521 props->GetVersionKey(),
522 google_update::kRegOldVersionField,
523 UTF8ToWide(current_version->GetString()),
524 true);
525 // TODO(tommi): We should move the rename command here. We also need to
526 // update Upgrade::SwapNewChromeExeIfPresent.
527 }
528 }
529
530 post_install_task_list->AddWorkItem(in_use_update_work_items.release());
531 }
532
533
534 // Append work items that will be executed if this was NOT an in-use update.
535 {
536 scoped_ptr<WorkItemList> regular_update_work_items(
537 WorkItem::CreateConditionalWorkItemList(
538 new Not(new ConditionRunIfFileExists(new_chrome_exe))));
539 regular_update_work_items->set_log_message(
540 "RegularUpdateWorkItemList");
541
542 // Since this was not an in-use-update, delete 'opv' and 'cmd' keys.
543 for (size_t i = 0; i < products.size(); ++i) {
544 BrowserDistribution* dist = products[i]->distribution();
545 std::wstring version_key(dist->GetVersionKey());
546 regular_update_work_items->AddDeleteRegValueWorkItem(root, version_key,
547 google_update::kRegOldVersionField,
548 REG_SZ);
549 regular_update_work_items->AddDeleteRegValueWorkItem(root, version_key,
550 google_update::kRegRenameCmdField,
551 REG_SZ);
552 }
553
554 post_install_task_list->AddWorkItem(regular_update_work_items.release());
555 }
556
557 AddRegisterComDllWorkItemsForPackage(package, current_version, new_version,
558 post_install_task_list);
559
560 for (size_t i = 0; i < products.size(); ++i) {
561 const Product* product = products[i];
562 // If we're told that we're an MSI install, make sure to set the marker
563 // in the client state key so that future updates do the right thing.
564 if (product->IsMsi()) {
565 AddSetMsiMarkerWorkItem(*product, true, post_install_task_list);
566
567 // We want MSI installs to take over the Add/Remove Programs shortcut.
568 // Make a best-effort attempt to delete any shortcuts left over from
569 // previous non-MSI installations for the same type of install (system or
570 // per user).
571 AddDeleteUninstallShortcutsForMSIWorkItems(*product,
572 post_install_task_list);
573 }
574 }
575
576 return true;
577 }
578
579 // This method tells if we are running on 64 bit platform so that we can copy
580 // one extra exe. If the API call to determine 64 bit fails, we play it safe
581 // and return true anyway so that the executable can be copied.
582 bool Is64bit() {
583 typedef BOOL (WINAPI *WOW_FUNC)(HANDLE, PBOOL);
584 BOOL is64 = FALSE;
585
586 HANDLE handle = GetCurrentProcess();
587 HMODULE module = GetModuleHandle(L"kernel32.dll");
588 WOW_FUNC p = reinterpret_cast<WOW_FUNC>(GetProcAddress(module,
589 "IsWow64Process"));
590 if ((p != NULL) && (!(p)(handle, &is64) || (is64 != FALSE))) {
591 return true;
592 }
593
594 return false;
595 }
596 370
597 void RegisterChromeOnMachine(const Product& product, 371 void RegisterChromeOnMachine(const Product& product,
598 bool make_chrome_default) { 372 bool make_chrome_default) {
599 DCHECK(product.is_chrome()); 373 DCHECK(product.is_chrome());
600 374
601 // Try to add Chrome to Media Player shim inclusion list. We don't do any 375 // Try to add Chrome to Media Player shim inclusion list. We don't do any
602 // error checking here because this operation will fail if user doesn't 376 // error checking here because this operation will fail if user doesn't
603 // have admin rights and we want to ignore the error. 377 // have admin rights and we want to ignore the error.
604 AddChromeToMediaPlayerList(); 378 AddChromeToMediaPlayerList();
605 379
606 // Is --make-chrome-default option is given we make Chrome default browser 380 // Is --make-chrome-default option is given we make Chrome default browser
607 // otherwise we only register it on the machine as a valid browser. 381 // otherwise we only register it on the machine as a valid browser.
608 FilePath chrome_exe( 382 FilePath chrome_exe(
609 product.package().path().Append(installer::kChromeExe)); 383 product.package().path().Append(installer::kChromeExe));
610 VLOG(1) << "Registering Chrome as browser: " << chrome_exe.value(); 384 VLOG(1) << "Registering Chrome as browser: " << chrome_exe.value();
611 if (make_chrome_default) { 385 if (make_chrome_default) {
612 int level = ShellUtil::CURRENT_USER; 386 int level = ShellUtil::CURRENT_USER;
613 if (product.system_level()) 387 if (product.system_level())
614 level = level | ShellUtil::SYSTEM_LEVEL; 388 level = level | ShellUtil::SYSTEM_LEVEL;
615 ShellUtil::MakeChromeDefault(product.distribution(), level, 389 ShellUtil::MakeChromeDefault(product.distribution(), level,
616 chrome_exe.value(), true); 390 chrome_exe.value(), true);
617 } else { 391 } else {
618 ShellUtil::RegisterChromeBrowser(product.distribution(), chrome_exe.value(), 392 ShellUtil::RegisterChromeBrowser(product.distribution(), chrome_exe.value(),
619 L"", false); 393 L"", false);
620 } 394 }
621 } 395 }
622 396
623 // Create Version key for a product (if not already present) and sets the new
624 // product version as the last step.
625 void AddVersionKeyWorkItems(HKEY root,
626 const Product& product,
627 const Version& new_version,
628 WorkItemList* list) {
629 // Create Version key for each distribution (if not already present) and set
630 // the new product version as the last step.
631 std::wstring version_key(product.distribution()->GetVersionKey());
632 list->AddCreateRegKeyWorkItem(root, version_key);
633
634 std::wstring product_name(product.distribution()->GetAppShortCutName());
635 list->AddSetRegValueWorkItem(root, version_key, google_update::kRegNameField,
636 product_name, true); // overwrite name also
637 list->AddSetRegValueWorkItem(root, version_key,
638 google_update::kRegOopcrashesField,
639 static_cast<DWORD>(1),
640 false); // set during first install
641 list->AddSetRegValueWorkItem(root, version_key,
642 google_update::kRegVersionField,
643 UTF8ToWide(new_version.GetString()),
644 true); // overwrite version
645 }
646
647 void AddProductSpecificWorkItems(bool install,
648 const FilePath& setup_path,
649 const Version& new_version,
650 const Package& package,
651 WorkItemList* list) {
652 const Products& products = package.products();
653 for (size_t i = 0; i < products.size(); ++i) {
654 const Product& p = *products[i];
655 if (p.is_chrome_frame()) {
656 AddChromeFrameWorkItems(install, setup_path, new_version, p, list);
657 }
658 }
659 }
660
661 // This function installs a new version of Chrome to the specified location. 397 // This function installs a new version of Chrome to the specified location.
662 // 398 //
663 // setup_path: Path to the executable (setup.exe) as it will be copied 399 // setup_path: Path to the executable (setup.exe) as it will be copied
664 // to Chrome install folder after install is complete 400 // to Chrome install folder after install is complete
665 // archive_path: Path to the archive (chrome.7z) as it will be copied 401 // archive_path: Path to the archive (chrome.7z) as it will be copied
666 // to Chrome install folder after install is complete 402 // to Chrome install folder after install is complete
667 // src_path: the path that contains a complete and unpacked Chrome package 403 // src_path: the path that contains a complete and unpacked Chrome package
668 // to be installed. 404 // to be installed.
669 // temp_dir: the path of working directory used during installation. This path 405 // temp_dir: the path of working directory used during installation. This path
670 // does not need to exist. 406 // does not need to exist.
671 // new_version: new Chrome version that needs to be installed 407 // new_version: new Chrome version that needs to be installed
672 // oldest_installed_version: returns the oldest active version (if any) 408 // current_version: returns the current active version (if any)
673 // 409 //
674 // This function makes best effort to do installation in a transactional 410 // This function makes best effort to do installation in a transactional
675 // manner. If failed it tries to rollback all changes on the file system 411 // manner. If failed it tries to rollback all changes on the file system
676 // and registry. For example, if package exists before calling the 412 // and registry. For example, if package exists before calling the
677 // function, it rolls back all new file and directory changes under 413 // function, it rolls back all new file and directory changes under
678 // package. If package does not exist before calling the function 414 // package. If package does not exist before calling the function
679 // (typical new install), the function creates package during install 415 // (typical new install), the function creates package during install
680 // and removes the whole directory during rollback. 416 // and removes the whole directory during rollback.
681 installer::InstallStatus InstallNewVersion( 417 installer::InstallStatus InstallNewVersion(
682 const InstallationState& original_state, 418 const InstallationState& original_state,
683 const InstallerState& installer_state, 419 const InstallerState& installer_state,
684 bool multi_install, 420 bool multi_install,
685 const FilePath& setup_path, 421 const FilePath& setup_path,
686 const FilePath& archive_path, 422 const FilePath& archive_path,
687 const FilePath& src_path, 423 const FilePath& src_path,
688 const FilePath& temp_dir, 424 const FilePath& temp_dir,
689 const Version& new_version, 425 const Version& new_version,
690 scoped_ptr<Version>* current_version, 426 scoped_ptr<Version>* current_version,
691 const Package& package) { 427 const Package& package) {
692 DCHECK(current_version); 428 DCHECK(current_version);
693 429
694 const Products& products = package.products(); 430 current_version->reset(package.GetCurrentVersion());
695 DCHECK(products.size()); 431 scoped_ptr<WorkItemList> install_list(WorkItem::CreateWorkItemList());
696 432
697 if (FindProduct(products, BrowserDistribution::CHROME_FRAME)) { 433 AddInstallWorkItems(original_state,
698 // Make sure that we don't end up deleting installed files on next reboot. 434 installer_state,
699 if (!RemoveFromMovesPendingReboot(package.path().value().c_str())) { 435 multi_install,
700 LOG(ERROR) << "Error accessing pending moves value."; 436 setup_path,
701 } 437 archive_path,
702 } 438 src_path,
439 temp_dir,
440 new_version,
441 current_version,
442 package,
443 install_list.get());
703 444
704 current_version->reset(package.GetCurrentVersion());
705
706 scoped_ptr<WorkItemList> install_list(WorkItem::CreateWorkItemList());
707 // A temp directory that work items need and the actual install directory.
708 install_list->AddCreateDirWorkItem(temp_dir);
709 install_list->AddCreateDirWorkItem(package.path());
710
711 // Delete any new_chrome.exe if present (we will end up creating a new one
712 // if required) and then copy chrome.exe
713 FilePath new_chrome_exe( 445 FilePath new_chrome_exe(
714 package.path().Append(installer::kChromeNewExe)); 446 package.path().Append(installer::kChromeNewExe));
715 447
716 install_list->AddDeleteTreeWorkItem(new_chrome_exe);
717 install_list->AddCopyTreeWorkItem(
718 src_path.Append(installer::kChromeExe).value(),
719 package.path().Append(installer::kChromeExe).value(),
720 temp_dir.value(), WorkItem::NEW_NAME_IF_IN_USE, new_chrome_exe.value());
721
722 // Extra executable for 64 bit systems.
723 if (Is64bit()) {
724 install_list->AddCopyTreeWorkItem(
725 src_path.Append(installer::kWowHelperExe).value(),
726 package.path().Append(installer::kWowHelperExe).value(),
727 temp_dir.value(), WorkItem::ALWAYS);
728 }
729
730 // If it is system level install copy the version folder (since we want to
731 // take the permissions of %ProgramFiles% folder) otherwise just move it.
732 if (package.system_level()) {
733 install_list->AddCopyTreeWorkItem(
734 src_path.Append(UTF8ToWide(new_version.GetString())).value(),
735 package.path().Append(UTF8ToWide(new_version.GetString())).value(),
736 temp_dir.value(), WorkItem::ALWAYS);
737 } else {
738 install_list->AddMoveTreeWorkItem(
739 src_path.Append(UTF8ToWide(new_version.GetString())).value(),
740 package.path().Append(UTF8ToWide(new_version.GetString())).value(),
741 temp_dir.value());
742 }
743
744 // Copy the default Dictionaries only if the folder doesn't exist already.
745 install_list->AddCopyTreeWorkItem(
746 src_path.Append(installer::kDictionaries).value(),
747 package.path().Append(installer::kDictionaries).value(),
748 temp_dir.value(), WorkItem::IF_NOT_PRESENT);
749
750 // Delete any old_chrome.exe if present.
751 install_list->AddDeleteTreeWorkItem(
752 package.path().Append(installer::kChromeOldExe));
753
754 // Copy installer in install directory and
755 // add shortcut in Control Panel->Add/Remove Programs.
756 AddInstallerCopyTasks(setup_path, archive_path, temp_dir, new_version,
757 install_list.get(), package);
758
759 HKEY root = package.system_level() ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER;
760
761 for (size_t i = 0; i < products.size(); ++i) {
762 const Product* product = products[i];
763
764 AddUninstallShortcutWorkItems(setup_path, new_version, install_list.get(),
765 *product);
766
767 AddVersionKeyWorkItems(root, *product, new_version, install_list.get());
768 }
769
770 if (multi_install) {
771 PackageProperties* props = package.properties();
772 if (props->ReceivesUpdates()) {
773 std::wstring version_key(props->GetVersionKey());
774 install_list->AddCreateRegKeyWorkItem(root, version_key);
775 install_list->AddSetRegValueWorkItem(root, version_key,
776 google_update::kRegVersionField,
777 UTF8ToWide(new_version.GetString()),
778 true); // overwrite version
779 install_list->AddSetRegValueWorkItem(root, version_key,
780 google_update::kRegNameField,
781 ASCIIToWide(installer::PackageProperties::kPackageProductName),
782 true); // overwrite name also
783 }
784 }
785
786 // Add any remaining work items that involve special settings for
787 // each product.
788 AddProductSpecificWorkItems(true, setup_path, new_version, package,
789 install_list.get());
790
791 AddGoogleUpdateWorkItems(original_state, installer_state, package,
792 install_list.get());
793
794 // Append the tasks that run after the installation.
795 AppendPostInstallTasks(multi_install,
796 setup_path,
797 new_chrome_exe,
798 current_version->get(),
799 new_version,
800 package,
801 install_list.get());
802
803 if (!install_list->Do()) { 448 if (!install_list->Do()) {
804 installer::InstallStatus result = 449 installer::InstallStatus result =
805 file_util::PathExists(new_chrome_exe) && current_version->get() && 450 file_util::PathExists(new_chrome_exe) && current_version->get() &&
806 new_version.Equals(**current_version) ? 451 new_version.Equals(*current_version->get()) ?
807 installer::SAME_VERSION_REPAIR_FAILED : 452 installer::SAME_VERSION_REPAIR_FAILED :
808 installer::INSTALL_FAILED; 453 installer::INSTALL_FAILED;
809 LOG(ERROR) << "Install failed, rolling back... result: " << result; 454 LOG(ERROR) << "Install failed, rolling back... result: " << result;
810 install_list->Rollback(); 455 install_list->Rollback();
811 LOG(ERROR) << "Rollback complete. "; 456 LOG(ERROR) << "Rollback complete. ";
812 return result; 457 return result;
813 } 458 }
814 459
815 if (!current_version->get()) { 460 if (!current_version->get()) {
816 VLOG(1) << "First install of version " << new_version.GetString(); 461 VLOG(1) << "First install of version " << new_version.GetString();
(...skipping 29 matching lines...) Expand all
846 installer::InstallStatus InstallOrUpdateProduct( 491 installer::InstallStatus InstallOrUpdateProduct(
847 const InstallationState& original_state, 492 const InstallationState& original_state,
848 const InstallerState& installer_state, 493 const InstallerState& installer_state,
849 const FilePath& setup_path, const FilePath& archive_path, 494 const FilePath& setup_path, const FilePath& archive_path,
850 const FilePath& install_temp_path, const FilePath& prefs_path, 495 const FilePath& install_temp_path, const FilePath& prefs_path,
851 const installer::MasterPreferences& prefs, const Version& new_version, 496 const installer::MasterPreferences& prefs, const Version& new_version,
852 const Package& install) { 497 const Package& install) {
853 FilePath src_path(install_temp_path); 498 FilePath src_path(install_temp_path);
854 src_path = src_path.Append(kInstallSourceDir).Append(kInstallSourceChromeDir); 499 src_path = src_path.Append(kInstallSourceDir).Append(kInstallSourceChromeDir);
855 500
501 // TODO(robertshield): Removing the pending on-reboot moves should be done
502 // elsewhere.
503 const Products& products = install.products();
504 DCHECK(products.size());
505 if (FindProduct(products, BrowserDistribution::CHROME_FRAME)) {
506 // Make sure that we don't end up deleting installed files on next reboot.
507 if (!RemoveFromMovesPendingReboot(install.path().value().c_str())) {
508 LOG(ERROR) << "Error accessing pending moves value.";
509 }
510 }
511
856 scoped_ptr<Version> existing_version; 512 scoped_ptr<Version> existing_version;
857 installer::InstallStatus result = InstallNewVersion(original_state, 513 installer::InstallStatus result = InstallNewVersion(original_state,
858 installer_state, prefs.is_multi_install(), setup_path, archive_path, 514 installer_state, prefs.is_multi_install(), setup_path, archive_path,
859 src_path, install_temp_path, new_version, &existing_version, install); 515 src_path, install_temp_path, new_version, &existing_version, install);
860 516
517 // TODO(robertshield): Everything below this line should instead be captured
518 // by WorkItems.
861 if (!InstallUtil::GetInstallReturnCode(result)) { 519 if (!InstallUtil::GetInstallReturnCode(result)) {
862 if (result == installer::FIRST_INSTALL_SUCCESS && !prefs_path.empty()) 520 if (result == installer::FIRST_INSTALL_SUCCESS && !prefs_path.empty())
863 CopyPreferenceFileForFirstRun(install, prefs_path); 521 CopyPreferenceFileForFirstRun(install, prefs_path);
864 522
865 bool do_not_create_shortcuts = false; 523 bool do_not_create_shortcuts = false;
866 prefs.GetBool(installer::master_preferences::kDoNotCreateShortcuts, 524 prefs.GetBool(installer::master_preferences::kDoNotCreateShortcuts,
867 &do_not_create_shortcuts); 525 &do_not_create_shortcuts);
868 526
869 // Currently this only creates shortcuts for Chrome, but for other products 527 // Currently this only creates shortcuts for Chrome, but for other products
870 // we might want to create shortcuts. 528 // we might want to create shortcuts.
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after
903 make_chrome_default || force_chrome_default_for_user); 561 make_chrome_default || force_chrome_default_for_user);
904 } 562 }
905 563
906 install.RemoveOldVersionDirectories(existing_version.get() ? 564 install.RemoveOldVersionDirectories(existing_version.get() ?
907 *existing_version.get() : new_version); 565 *existing_version.get() : new_version);
908 } 566 }
909 567
910 return result; 568 return result;
911 } 569 }
912 570
913 void AddRegisterComDllWorkItems(const FilePath& dll_folder,
914 const std::vector<FilePath>& dll_list,
915 bool system_level,
916 bool do_register,
917 bool ignore_failures,
918 WorkItemList* work_item_list) {
919 DCHECK(work_item_list);
920 if (dll_list.empty()) {
921 VLOG(1) << "No COM DLLs to register";
922 } else {
923 std::vector<FilePath>::const_iterator dll_iter(dll_list.begin());
924 for (; dll_iter != dll_list.end(); ++dll_iter) {
925 FilePath dll_path = dll_folder.Append(*dll_iter);
926 WorkItem* work_item = work_item_list->AddSelfRegWorkItem(
927 dll_path.value(), do_register, !system_level);
928 DCHECK(work_item);
929 work_item->set_ignore_failure(ignore_failures);
930 }
931 }
932 }
933
934 void AddSetMsiMarkerWorkItem(const Product& product,
935 bool set,
936 WorkItemList* work_item_list) {
937 DCHECK(work_item_list);
938 BrowserDistribution* dist = product.distribution();
939 HKEY reg_root = product.system_level() ? HKEY_LOCAL_MACHINE :
940 HKEY_CURRENT_USER;
941 DWORD msi_value = set ? 1 : 0;
942 WorkItem* set_msi_work_item = work_item_list->AddSetRegValueWorkItem(
943 reg_root, dist->GetStateKey(), google_update::kRegMSIField,
944 msi_value, true);
945 DCHECK(set_msi_work_item);
946 set_msi_work_item->set_ignore_failure(true);
947 set_msi_work_item->set_log_message("Could not write MSI marker!");
948 }
949
950 void AddUninstallShortcutWorkItems(const FilePath& setup_path,
951 const Version& new_version,
952 WorkItemList* install_list,
953 const Product& product) {
954 HKEY reg_root = product.system_level() ? HKEY_LOCAL_MACHINE :
955 HKEY_CURRENT_USER;
956 BrowserDistribution* browser_dist = product.distribution();
957 DCHECK(browser_dist);
958
959 // When we are installed via an MSI, we need to store our uninstall strings
960 // in the Google Update client state key. We do this even for non-MSI
961 // managed installs to avoid breaking the edge case whereby an MSI-managed
962 // install is updated by a non-msi installer (which would confuse the MSI
963 // machinery if these strings were not also updated).
964 // Do not quote the command line for the MSI invocation.
965 FilePath install_path(product.package().path());
966 FilePath installer_path(
967 product.package().GetInstallerDirectory(new_version));
968 installer_path = installer_path.Append(setup_path.BaseName());
969
970 CommandLine uninstall_arguments(CommandLine::NO_PROGRAM);
971 AppendUninstallCommandLineFlags(&uninstall_arguments, product);
972
973 if (product.is_chrome()) {
974 // The Chrome uninstallation command serves as the master uninstall
975 // command for Chrome + all other products (i.e. Chrome Frame) that do
976 // not have an uninstall entry in the Add/Remove Programs dialog.
977 const Products& products = product.package().products();
978 for (size_t i = 0; i < products.size(); ++i) {
979 const Product& p = *products[i];
980 if (!p.is_chrome() && !p.ShouldCreateUninstallEntry()) {
981 p.distribution()->AppendUninstallCommandLineFlags(&uninstall_arguments);
982 }
983 }
984 }
985
986 std::wstring update_state_key(browser_dist->GetStateKey());
987 install_list->AddCreateRegKeyWorkItem(reg_root, update_state_key);
988 install_list->AddSetRegValueWorkItem(reg_root, update_state_key,
989 installer::kUninstallStringField, installer_path.value(), true);
990 install_list->AddSetRegValueWorkItem(reg_root, update_state_key,
991 installer::kUninstallArgumentsField,
992 uninstall_arguments.command_line_string(), true);
993
994 if (product.ShouldCreateUninstallEntry()) {
995 // We need to quote the command line for the Add/Remove Programs dialog.
996 CommandLine quoted_uninstall_cmd(installer_path);
997 DCHECK_EQ(quoted_uninstall_cmd.command_line_string()[0], '"');
998 quoted_uninstall_cmd.AppendArguments(uninstall_arguments, false);
999
1000 std::wstring uninstall_reg = browser_dist->GetUninstallRegPath();
1001 install_list->AddCreateRegKeyWorkItem(reg_root, uninstall_reg);
1002 install_list->AddSetRegValueWorkItem(reg_root, uninstall_reg,
1003 installer::kUninstallDisplayNameField,
1004 browser_dist->GetAppShortCutName(), true);
1005 install_list->AddSetRegValueWorkItem(reg_root,
1006 uninstall_reg, installer::kUninstallStringField,
1007 quoted_uninstall_cmd.command_line_string(), true);
1008 install_list->AddSetRegValueWorkItem(reg_root,
1009 uninstall_reg,
1010 L"InstallLocation",
1011 install_path.value(),
1012 true);
1013
1014 // DisplayIcon, NoModify and NoRepair
1015 FilePath chrome_icon(install_path.Append(installer::kChromeExe));
1016 ShellUtil::GetChromeIcon(product.distribution(), chrome_icon.value());
1017 install_list->AddSetRegValueWorkItem(reg_root, uninstall_reg,
1018 L"DisplayIcon", chrome_icon.value(),
1019 true);
1020 install_list->AddSetRegValueWorkItem(reg_root, uninstall_reg,
1021 L"NoModify", static_cast<DWORD>(1),
1022 true);
1023 install_list->AddSetRegValueWorkItem(reg_root, uninstall_reg,
1024 L"NoRepair", static_cast<DWORD>(1),
1025 true);
1026
1027 install_list->AddSetRegValueWorkItem(reg_root, uninstall_reg,
1028 L"Publisher",
1029 browser_dist->GetPublisherName(),
1030 true);
1031 install_list->AddSetRegValueWorkItem(reg_root, uninstall_reg,
1032 L"Version",
1033 UTF8ToWide(new_version.GetString()),
1034 true);
1035 install_list->AddSetRegValueWorkItem(reg_root, uninstall_reg,
1036 L"DisplayVersion",
1037 UTF8ToWide(new_version.GetString()),
1038 true);
1039 time_t rawtime = time(NULL);
1040 struct tm timeinfo = {0};
1041 localtime_s(&timeinfo, &rawtime);
1042 wchar_t buffer[9];
1043 if (wcsftime(buffer, 9, L"%Y%m%d", &timeinfo) == 8) {
1044 install_list->AddSetRegValueWorkItem(reg_root, uninstall_reg,
1045 L"InstallDate",
1046 buffer, false);
1047 }
1048 }
1049 }
1050
1051 void AddChromeFrameWorkItems(bool install,
1052 const FilePath& setup_path,
1053 const Version& new_version,
1054 const Product& product,
1055 WorkItemList* list) {
1056 DCHECK(product.is_chrome_frame());
1057 if (!product.package().multi_install()) {
1058 VLOG(1) << "Not adding GCF specific work items for single install.";
1059 return;
1060 }
1061
1062 const MasterPreferences& prefs = MasterPreferences::ForCurrentProcess();
1063
1064 BrowserDistribution* cf = BrowserDistribution::GetSpecificDistribution(
1065 BrowserDistribution::CHROME_FRAME, prefs);
1066 std::wstring version_key(cf->GetVersionKey());
1067
1068 // TODO(tommi): This assumes we know exactly how ShouldCreateUninstallEntry
1069 // is implemented. Since there is logic in ChromeFrameDistribution for how
1070 // to determine when this is enabled, this is how we have to figure out if
1071 // this feature is enabled right now, but it's a hack and we need a cleaner
1072 // way to figure this out.
1073 // Note that we cannot just check the master preferences for
1074 // kChromeFrameReadyMode, since there are other things that need to be correct
1075 // in the environment in order to enable this feature.
1076 bool ready_mode = !product.distribution()->ShouldCreateUninstallEntry();
1077
1078 HKEY root = product.package().system_level() ? HKEY_LOCAL_MACHINE :
1079 HKEY_CURRENT_USER;
1080 bool update_chrome_uninstall_command = false;
1081 if (ready_mode) {
1082 // If GCF is being installed in ready mode, we write an entry to the
1083 // multi-install state key. If the value already exists, we will not
1084 // overwrite it since the user might have opted out.
1085 list->AddCreateRegKeyWorkItem(root,
1086 product.package().properties()->GetStateKey());
1087 list->AddSetRegValueWorkItem(root,
1088 product.package().properties()->GetStateKey(),
1089 installer::kChromeFrameReadyModeField,
1090 static_cast<int64>(install ? 1 : 0), // The value we want to set.
1091 install ? false : true); // Overwrite existing value.
1092 if (install) {
1093 FilePath installer_path(product.package()
1094 .GetInstallerDirectory(new_version).Append(setup_path.BaseName()));
1095
1096 CommandLine basic_cl(installer_path);
1097 basic_cl.AppendSwitch(installer::switches::kChromeFrame);
1098 basic_cl.AppendSwitch(installer::switches::kMultiInstall);
1099
1100 if (product.package().system_level())
1101 basic_cl.AppendSwitch(installer::switches::kSystemLevel);
1102
1103 if (InstallUtil::IsChromeSxSProcess())
1104 basic_cl.AppendSwitch(installer::switches::kChromeSxS);
1105
1106 CommandLine temp_opt_out(basic_cl);
1107 temp_opt_out.AppendSwitch(
1108 installer::switches::kChromeFrameReadyModeTempOptOut);
1109
1110 CommandLine end_temp_opt_out(basic_cl);
1111 end_temp_opt_out.AppendSwitch(
1112 installer::switches::kChromeFrameReadyModeEndTempOptOut);
1113
1114 CommandLine opt_out(installer_path);
1115 AppendUninstallCommandLineFlags(&opt_out, product);
1116 // Force Uninstall silences the prompt to reboot to complete uninstall.
1117 opt_out.AppendSwitch(installer::switches::kForceUninstall);
1118
1119 CommandLine opt_in(basic_cl);
1120 opt_in.AppendSwitch(
1121 installer::switches::kChromeFrameReadyModeOptIn);
1122
1123 list->AddSetRegValueWorkItem(root, version_key,
1124 google_update::kRegCFTempOptOutCmdField,
1125 temp_opt_out.command_line_string(), true);
1126 list->AddSetRegValueWorkItem(root, version_key,
1127 google_update::kRegCFEndTempOptOutCmdField,
1128 end_temp_opt_out.command_line_string(),
1129 true);
1130 list->AddSetRegValueWorkItem(root, version_key,
1131 google_update::kRegCFOptOutCmdField,
1132 opt_out.command_line_string(), true);
1133 list->AddSetRegValueWorkItem(root, version_key,
1134 google_update::kRegCFOptInCmdField,
1135 opt_in.command_line_string(), true);
1136 } else {
1137 // If Chrome is not also being uninstalled, we need to update its command
1138 // line so that it doesn't include uninstalling Chrome Frame now.
1139 update_chrome_uninstall_command =
1140 (installer::FindProduct(product.package().products(),
1141 BrowserDistribution::CHROME_BROWSER) == NULL);
1142 }
1143 } else {
1144 // It doesn't matter here if we're installing or uninstalling Chrome Frame.
1145 // If ready mode isn't specified on the command line for installs, we need
1146 // to delete the ready mode flag from the registry if it exists - this
1147 // constitutes an opt-in for the user. If we're uninstalling CF and ready
1148 // mode isn't specified on the command line, that means that CF wasn't
1149 // installed with ready mode enabled (the --ready-mode switch should be set
1150 // in the registry) so deleting the value should have no effect.
1151 // In both cases (install/uninstall), we need to make sure that Chrome's
1152 // uninstallation command line does not include the --chrome-frame switch
1153 // so that uninstalling Chrome will no longer uninstall Chrome Frame.
1154
1155 if (RegKey(root, product.package().properties()->GetStateKey().c_str(),
1156 KEY_QUERY_VALUE).Valid()) {
1157 list->AddDeleteRegValueWorkItem(root,
1158 product.package().properties()->GetStateKey(),
1159 installer::kChromeFrameReadyModeField, REG_QWORD);
1160 }
1161
1162 const Product* chrome = installer::FindProduct(product.package().products(),
1163 BrowserDistribution::CHROME_BROWSER);
1164 if (chrome) {
1165 // Chrome is already a part of this installation run, so we can assume
1166 // that the uninstallation arguments will be updated correctly.
1167 } else {
1168 // Chrome is not a part of this installation run, so we have to explicitly
1169 // check if Chrome is installed, and if so, update its uninstallation
1170 // command lines.
1171 BrowserDistribution* dist = BrowserDistribution::GetSpecificDistribution(
1172 BrowserDistribution::CHROME_BROWSER,
1173 MasterPreferences::ForCurrentProcess());
1174 update_chrome_uninstall_command =
1175 IsInstalledAsMulti(product.system_level(), dist);
1176 }
1177 }
1178
1179 if (!ready_mode || !install) {
1180 list->AddDeleteRegValueWorkItem(root, version_key,
1181 google_update::kRegCFTempOptOutCmdField,
1182 REG_SZ);
1183 list->AddDeleteRegValueWorkItem(root, version_key,
1184 google_update::kRegCFEndTempOptOutCmdField,
1185 REG_SZ);
1186 list->AddDeleteRegValueWorkItem(root, version_key,
1187 google_update::kRegCFOptOutCmdField,
1188 REG_SZ);
1189 list->AddDeleteRegValueWorkItem(root, version_key,
1190 google_update::kRegCFOptInCmdField, REG_SZ);
1191 }
1192
1193 if (update_chrome_uninstall_command) {
1194 // Chrome is not a part of this installation run, so we have to explicitly
1195 // check if Chrome is installed, and if so, update its uninstallation
1196 // command lines.
1197 BrowserDistribution* chrome_dist =
1198 BrowserDistribution::GetSpecificDistribution(
1199 BrowserDistribution::CHROME_BROWSER, prefs);
1200 const Package& pack = product.package();
1201 scoped_refptr<Package> package(new Package(pack.multi_install(),
1202 pack.system_level(), pack.path(), pack.properties()));
1203 scoped_refptr<Product> chrome_product(new Product(chrome_dist, package));
1204 AddUninstallShortcutWorkItems(setup_path, new_version, list,
1205 *chrome_product.get());
1206 }
1207 }
1208
1209 } // namespace installer 571 } // namespace installer
OLDNEW
« no previous file with comments | « chrome/installer/setup/install.h ('k') | chrome/installer/setup/install_worker.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698