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

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

Issue 96193003: Uninstall multi-install Chrome Frame when updated. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: rebase to r237927 Created 7 years 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
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 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 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/setup_main.h" 5 #include "chrome/installer/setup/setup_main.h"
6 6
7 #include <windows.h> 7 #include <windows.h>
8 #include <msi.h> 8 #include <msi.h>
9 #include <shellapi.h> 9 #include <shellapi.h>
10 #include <shlobj.h> 10 #include <shlobj.h>
(...skipping 683 matching lines...) Expand 10 before | Expand all | Expand 10 after
694 if (!file_util::CreateTemporaryDirInDir(temp_path->path(), 694 if (!file_util::CreateTemporaryDirInDir(temp_path->path(),
695 installer::kInstallSourceDir, 695 installer::kInstallSourceDir,
696 unpack_path)) { 696 unpack_path)) {
697 PLOG(ERROR) << "Could not create temporary path for unpacked archive."; 697 PLOG(ERROR) << "Could not create temporary path for unpacked archive.";
698 return false; 698 return false;
699 } 699 }
700 700
701 return true; 701 return true;
702 } 702 }
703 703
704 installer::InstallStatus InstallProducts(
705 const InstallationState& original_state,
706 const CommandLine& cmd_line,
707 const MasterPreferences& prefs,
708 InstallerState* installer_state,
709 base::FilePath* installer_directory) {
710 DCHECK(installer_state);
711 const bool system_install = installer_state->system_install();
712 installer::InstallStatus install_status = installer::UNKNOWN_STATUS;
713 installer::ArchiveType archive_type = installer::UNKNOWN_ARCHIVE_TYPE;
714 bool delegated_to_existing = false;
715 installer_state->UpdateStage(installer::PRECONDITIONS);
716 // The stage provides more fine-grained information than -multifail, so remove
717 // the -multifail suffix from the Google Update "ap" value.
718 BrowserDistribution::GetSpecificDistribution(installer_state->state_type())->
719 UpdateInstallStatus(system_install, archive_type, install_status);
720 if (CheckPreInstallConditions(original_state, installer_state,
721 &install_status)) {
722 VLOG(1) << "Installing to " << installer_state->target_path().value();
723 install_status = InstallProductsHelper(
724 original_state, cmd_line, prefs, *installer_state,
725 installer_directory, &archive_type, &delegated_to_existing);
726 } else {
727 // CheckPreInstallConditions must set the status on failure.
728 DCHECK_NE(install_status, installer::UNKNOWN_STATUS);
729 }
730
731 // Delete the master preferences file if present. Note that we do not care
732 // about rollback here and we schedule for deletion on reboot if the delete
733 // fails. As such, we do not use DeleteTreeWorkItem.
734 if (cmd_line.HasSwitch(installer::switches::kInstallerData)) {
735 base::FilePath prefs_path(cmd_line.GetSwitchValuePath(
736 installer::switches::kInstallerData));
737 if (!base::DeleteFile(prefs_path, false)) {
738 LOG(ERROR) << "Failed deleting master preferences file "
739 << prefs_path.value()
740 << ", scheduling for deletion after reboot.";
741 ScheduleFileSystemEntityForDeletion(prefs_path);
742 }
743 }
744
745 // Early exit if this setup.exe delegated to another, since that one would
746 // have taken care of UpdateInstallStatus and UpdateStage.
747 if (delegated_to_existing)
748 return install_status;
749
750 const Products& products = installer_state->products();
751 for (Products::const_iterator it = products.begin(); it < products.end();
752 ++it) {
753 (*it)->distribution()->UpdateInstallStatus(
754 system_install, archive_type, install_status);
755 }
756
757 installer_state->UpdateStage(installer::NO_STAGE);
758 return install_status;
759 }
760
761 installer::InstallStatus UninstallProduct( 704 installer::InstallStatus UninstallProduct(
762 const InstallationState& original_state, 705 const InstallationState& original_state,
763 const InstallerState& installer_state, 706 const InstallerState& installer_state,
764 const CommandLine& cmd_line, 707 const CommandLine& cmd_line,
765 bool remove_all, 708 bool remove_all,
766 bool force_uninstall, 709 bool force_uninstall,
767 const Product& product) { 710 const Product& product) {
768 const ProductState* product_state = 711 const ProductState* product_state =
769 original_state.GetProductState(installer_state.system_install(), 712 original_state.GetProductState(installer_state.system_install(),
770 product.distribution()->GetType()); 713 product.distribution()->GetType());
(...skipping 90 matching lines...) Expand 10 before | Expand all | Expand 10 after
861 base::LaunchProcess(system_level_cmd, base::LaunchOptions(), NULL); 804 base::LaunchProcess(system_level_cmd, base::LaunchOptions(), NULL);
862 805
863 // Tell Google Update that an uninstall has taken place. 806 // Tell Google Update that an uninstall has taken place.
864 // Ignore the return value: success or failure of Google Update 807 // Ignore the return value: success or failure of Google Update
865 // has no bearing on the success or failure of Chrome's uninstallation. 808 // has no bearing on the success or failure of Chrome's uninstallation.
866 google_update::UninstallGoogleUpdate(installer_state.system_install()); 809 google_update::UninstallGoogleUpdate(installer_state.system_install());
867 810
868 return install_status; 811 return install_status;
869 } 812 }
870 813
814 // Uninstall the binaries if they are the only product present and they're not
815 // in-use.
816 void UninstallBinariesIfUnused(
817 const InstallationState& original_state,
818 const InstallerState& installer_state,
819 installer::InstallStatus* install_status) {
820 // Early exit if the binaries are still in use.
821 if (*install_status != installer::UNUSED_BINARIES ||
822 installer_state.AreBinariesInUse(original_state)) {
823 return;
824 }
825
826 LOG(INFO) << "Uninstalling unused binaries";
827 installer_state.UpdateStage(installer::UNINSTALLING_BINARIES);
828
829 // Simulate the uninstall as coming from the installed version.
830 const ProductState* binaries_state =
831 original_state.GetProductState(installer_state.system_install(),
832 BrowserDistribution::CHROME_BINARIES);
833 const CommandLine& uninstall_cmd(binaries_state->uninstall_command());
834 MasterPreferences uninstall_prefs(uninstall_cmd);
835 InstallerState uninstall_state;
836 uninstall_state.Initialize(uninstall_cmd, uninstall_prefs, original_state);
837
838 *install_status =
839 UninstallProducts(original_state, uninstall_state, uninstall_cmd);
840
841 // Report that the binaries were uninstalled if they were. This translates
842 // into a successful install return code.
843 if (IsUninstallSuccess(*install_status)) {
844 *install_status = installer::UNUSED_BINARIES_UNINSTALLED;
845 installer_state.WriteInstallerResult(*install_status, 0, NULL);
846 }
847 }
848
849 installer::InstallStatus InstallProducts(
850 const InstallationState& original_state,
851 const CommandLine& cmd_line,
852 const MasterPreferences& prefs,
853 InstallerState* installer_state,
854 base::FilePath* installer_directory) {
855 DCHECK(installer_state);
856 const bool system_install = installer_state->system_install();
857 installer::InstallStatus install_status = installer::UNKNOWN_STATUS;
858 installer::ArchiveType archive_type = installer::UNKNOWN_ARCHIVE_TYPE;
859 bool delegated_to_existing = false;
860 installer_state->UpdateStage(installer::PRECONDITIONS);
861 // The stage provides more fine-grained information than -multifail, so remove
862 // the -multifail suffix from the Google Update "ap" value.
863 BrowserDistribution::GetSpecificDistribution(installer_state->state_type())->
864 UpdateInstallStatus(system_install, archive_type, install_status);
865 if (CheckPreInstallConditions(original_state, installer_state,
866 &install_status)) {
867 VLOG(1) << "Installing to " << installer_state->target_path().value();
868 install_status = InstallProductsHelper(
869 original_state, cmd_line, prefs, *installer_state,
870 installer_directory, &archive_type, &delegated_to_existing);
871 } else {
872 // CheckPreInstallConditions must set the status on failure.
873 DCHECK_NE(install_status, installer::UNKNOWN_STATUS);
874 }
875
876 // Delete the master preferences file if present. Note that we do not care
877 // about rollback here and we schedule for deletion on reboot if the delete
878 // fails. As such, we do not use DeleteTreeWorkItem.
879 if (cmd_line.HasSwitch(installer::switches::kInstallerData)) {
880 base::FilePath prefs_path(cmd_line.GetSwitchValuePath(
881 installer::switches::kInstallerData));
882 if (!base::DeleteFile(prefs_path, false)) {
883 LOG(ERROR) << "Failed deleting master preferences file "
884 << prefs_path.value()
885 << ", scheduling for deletion after reboot.";
886 ScheduleFileSystemEntityForDeletion(prefs_path);
887 }
888 }
889
890 // Early exit if this setup.exe delegated to another, since that one would
891 // have taken care of UpdateInstallStatus and UpdateStage.
892 if (delegated_to_existing)
893 return install_status;
894
895 const Products& products = installer_state->products();
896 for (Products::const_iterator it = products.begin(); it < products.end();
897 ++it) {
898 (*it)->distribution()->UpdateInstallStatus(
899 system_install, archive_type, install_status);
900 }
901
902 UninstallBinariesIfUnused(original_state, *installer_state, &install_status);
903
904 installer_state->UpdateStage(installer::NO_STAGE);
905 return install_status;
906 }
907
871 installer::InstallStatus ShowEULADialog(const string16& inner_frame) { 908 installer::InstallStatus ShowEULADialog(const string16& inner_frame) {
872 VLOG(1) << "About to show EULA"; 909 VLOG(1) << "About to show EULA";
873 string16 eula_path = installer::GetLocalizedEulaResource(); 910 string16 eula_path = installer::GetLocalizedEulaResource();
874 if (eula_path.empty()) { 911 if (eula_path.empty()) {
875 LOG(ERROR) << "No EULA path available"; 912 LOG(ERROR) << "No EULA path available";
876 return installer::EULA_REJECTED; 913 return installer::EULA_REJECTED;
877 } 914 }
878 // Newer versions of the caller pass an inner frame parameter that must 915 // Newer versions of the caller pass an inner frame parameter that must
879 // be given to the html page being launched. 916 // be given to the html page being launched.
880 installer::EulaHTMLDialog dlg(eula_path, inner_frame); 917 installer::EulaHTMLDialog dlg(eula_path, inner_frame);
(...skipping 479 matching lines...) Expand 10 before | Expand all | Expand 10 after
1360 pipe_name += user_sid; 1397 pipe_name += user_sid;
1361 1398
1362 google_breakpad::ExceptionHandler* breakpad = 1399 google_breakpad::ExceptionHandler* breakpad =
1363 new google_breakpad::ExceptionHandler( 1400 new google_breakpad::ExceptionHandler(
1364 temp_directory.value(), NULL, NULL, NULL, 1401 temp_directory.value(), NULL, NULL, NULL,
1365 google_breakpad::ExceptionHandler::HANDLER_ALL, kLargerDumpType, 1402 google_breakpad::ExceptionHandler::HANDLER_ALL, kLargerDumpType,
1366 pipe_name.c_str(), GetCustomInfo(exe_path)); 1403 pipe_name.c_str(), GetCustomInfo(exe_path));
1367 return breakpad; 1404 return breakpad;
1368 } 1405 }
1369 1406
1407 // Uninstalls multi-install Chrome Frame if the current operation is a
1408 // multi-install install or update. The operation is performed directly rather
1409 // than delegated to the existing install since there is no facility in older
1410 // versions of setup.exe to uninstall GCF without touching the binaries. The
1411 // binaries will be uninstalled during later processing if they are not in-use
1412 // (see UninstallBinariesIfUnused). |original_state| and |installer_state| are
1413 // updated to reflect the state of the world following the operation.
1414 void UninstallMultiChromeFrameIfPresent(const CommandLine& cmd_line,
1415 const MasterPreferences& prefs,
1416 InstallationState* original_state,
1417 InstallerState* installer_state) {
1418 // Early exit if not installing or updating multi-install product(s).
1419 if (installer_state->operation() != InstallerState::MULTI_INSTALL &&
1420 installer_state->operation() != InstallerState::MULTI_UPDATE) {
1421 return;
1422 }
1423
1424 // Early exit if Chrome Frame is not present as multi-install.
1425 const ProductState* chrome_frame_state =
1426 original_state->GetProductState(installer_state->system_install(),
1427 BrowserDistribution::CHROME_FRAME);
1428 if (!chrome_frame_state || !chrome_frame_state->is_multi_install())
1429 return;
1430
1431 LOG(INFO) << "Uninstalling multi-install Chrome Frame.";
1432 installer_state->UpdateStage(installer::UNINSTALLING_CHROME_FRAME);
1433
1434 // Uninstall Chrome Frame without touching the multi-install binaries.
1435 // Simulate the uninstall as coming from the installed version.
1436 const CommandLine& uninstall_cmd(chrome_frame_state->uninstall_command());
1437 MasterPreferences uninstall_prefs(uninstall_cmd);
1438 InstallerState uninstall_state;
1439 uninstall_state.Initialize(uninstall_cmd, uninstall_prefs, *original_state);
1440 const Product* chrome_frame = uninstall_state.FindProduct(
robertshield 2013/11/29 18:50:25 s/chrome_frame/chrome_frame_product/ ?
grt (UTC plus 2) 2013/12/02 15:28:31 Done.
1441 BrowserDistribution::CHROME_FRAME);
1442 if (chrome_frame) {
1443 // No shared state should be left behind.
1444 const bool remove_all = true;
1445 // Don't accept no for an answer.
robertshield 2013/11/29 18:50:25 This also suppresses the UI right?
grt (UTC plus 2) 2013/12/02 15:28:31 I had thought it would, but it turns out that the
1446 const bool force_uninstall = true;
1447 installer::InstallStatus uninstall_status =
1448 installer::UninstallProduct(*original_state, uninstall_state,
1449 uninstall_cmd.GetProgram(), *chrome_frame,
1450 remove_all, force_uninstall, cmd_line);
1451
1452 VLOG(1) << "Uninstallation of Chrome Frame returned status "
1453 << uninstall_status;
1454 } else {
1455 LOG(ERROR) << "Chrome Frame not found for uninstall.";
1456 }
1457
1458 // Refresh state for the continuation of the original install/update.
1459 original_state->Initialize();
1460 installer_state->Initialize(cmd_line, prefs, *original_state);
1461 }
1462
1370 } // namespace 1463 } // namespace
1371 1464
1372 namespace installer { 1465 namespace installer {
1373 1466
1374 InstallStatus InstallProductsHelper( 1467 InstallStatus InstallProductsHelper(
1375 const InstallationState& original_state, 1468 const InstallationState& original_state,
1376 const CommandLine& cmd_line, 1469 const CommandLine& cmd_line,
1377 const MasterPreferences& prefs, 1470 const MasterPreferences& prefs,
1378 const InstallerState& installer_state, 1471 const InstallerState& installer_state,
1379 base::FilePath* installer_directory, 1472 base::FilePath* installer_directory,
(...skipping 388 matching lines...) Expand 10 before | Expand all | Expand 10 after
1768 InstallUtil::ExecuteExeAsAdmin(new_cmd, &exit_code); 1861 InstallUtil::ExecuteExeAsAdmin(new_cmd, &exit_code);
1769 return exit_code; 1862 return exit_code;
1770 } else { 1863 } else {
1771 LOG(ERROR) << "Non admin user can not install system level Chrome."; 1864 LOG(ERROR) << "Non admin user can not install system level Chrome.";
1772 installer_state.WriteInstallerResult(installer::INSUFFICIENT_RIGHTS, 1865 installer_state.WriteInstallerResult(installer::INSUFFICIENT_RIGHTS,
1773 IDS_INSTALL_INSUFFICIENT_RIGHTS_BASE, NULL); 1866 IDS_INSTALL_INSUFFICIENT_RIGHTS_BASE, NULL);
1774 return installer::INSUFFICIENT_RIGHTS; 1867 return installer::INSUFFICIENT_RIGHTS;
1775 } 1868 }
1776 } 1869 }
1777 1870
1871 UninstallMultiChromeFrameIfPresent(cmd_line, prefs,
1872 &original_state, &installer_state);
1873
1778 base::FilePath installer_directory; 1874 base::FilePath installer_directory;
1779 installer::InstallStatus install_status = installer::UNKNOWN_STATUS; 1875 installer::InstallStatus install_status = installer::UNKNOWN_STATUS;
1780 // If --uninstall option is not specified, we assume it is install case. 1876 // If --uninstall option is given, uninstall the identified product(s)
1781 if (!is_uninstall) { 1877 if (is_uninstall) {
1878 install_status =
1879 UninstallProducts(original_state, installer_state, cmd_line);
1880 } else {
1881 // If --uninstall option is not specified, we assume it is install case.
1782 install_status = 1882 install_status =
1783 InstallProducts(original_state, cmd_line, prefs, &installer_state, 1883 InstallProducts(original_state, cmd_line, prefs, &installer_state,
1784 &installer_directory); 1884 &installer_directory);
1785 } 1885 }
1786 // If --uninstall option is given or only the binaries are present and they're
1787 // not in-use, uninstall the identified product(s).
1788 if (is_uninstall || (install_status == installer::UNUSED_BINARIES &&
1789 !installer_state.AreBinariesInUse(original_state))) {
1790 install_status =
1791 UninstallProducts(original_state, installer_state, cmd_line);
1792 // Report that the binaries were uninstalled if they were. This translates
1793 // into a successful install return code.
1794 if (!is_uninstall && IsUninstallSuccess(install_status)) {
1795 install_status = installer::UNUSED_BINARIES_UNINSTALLED;
1796 installer_state.WriteInstallerResult(install_status, 0, NULL);
1797 }
1798 }
1799 1886
1800 // Validate that the machine is now in a good state following the operation. 1887 // Validate that the machine is now in a good state following the operation.
1801 // TODO(grt): change this to log at DFATAL once we're convinced that the 1888 // TODO(grt): change this to log at DFATAL once we're convinced that the
1802 // validator handles all cases properly. 1889 // validator handles all cases properly.
1803 InstallationValidator::InstallationType installation_type = 1890 InstallationValidator::InstallationType installation_type =
1804 InstallationValidator::NO_PRODUCTS; 1891 InstallationValidator::NO_PRODUCTS;
1805 LOG_IF(ERROR, 1892 LOG_IF(ERROR,
1806 !InstallationValidator::ValidateInstallationType(system_install, 1893 !InstallationValidator::ValidateInstallationType(system_install,
1807 &installation_type)); 1894 &installation_type));
1808 1895
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after
1859 // Call the newly updated setup.exe with kUncompressedArchive and 1946 // Call the newly updated setup.exe with kUncompressedArchive and
1860 // kMigrateChromeFrame to perform the migration. 1947 // kMigrateChromeFrame to perform the migration.
1861 LaunchChromeFrameMigrationProcess(*chrome_frame_state, cmd_line, 1948 LaunchChromeFrameMigrationProcess(*chrome_frame_state, cmd_line,
1862 installer_directory, system_install); 1949 installer_directory, system_install);
1863 } 1950 }
1864 1951
1865 VLOG(1) << "Installation complete, returning: " << return_code; 1952 VLOG(1) << "Installation complete, returning: " << return_code;
1866 1953
1867 return return_code; 1954 return return_code;
1868 } 1955 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698