| OLD | NEW |
| 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 // This file defines the methods useful for uninstalling Chrome. | 5 // This file defines the methods useful for uninstalling Chrome. |
| 6 | 6 |
| 7 #include "chrome/installer/setup/uninstall.h" | 7 #include "chrome/installer/setup/uninstall.h" |
| 8 | 8 |
| 9 #include <vector> | 9 #include <vector> |
| 10 | 10 |
| (...skipping 202 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 213 } | 213 } |
| 214 } | 214 } |
| 215 | 215 |
| 216 if (kill) { | 216 if (kill) { |
| 217 VLOG(1) << installer::kChromeFrameHelperExe << " hung. Killing."; | 217 VLOG(1) << installer::kChromeFrameHelperExe << " hung. Killing."; |
| 218 base::CleanupProcesses(installer::kChromeFrameHelperExe, 0, | 218 base::CleanupProcesses(installer::kChromeFrameHelperExe, 0, |
| 219 content::RESULT_CODE_HUNG, NULL); | 219 content::RESULT_CODE_HUNG, NULL); |
| 220 } | 220 } |
| 221 } | 221 } |
| 222 | 222 |
| 223 // This method tries to figure out if current user has registered Chrome. | |
| 224 // It returns true iff there is a registered browser that will launch the | |
| 225 // same chrome.exe as the current installation. | |
| 226 bool CurrentUserHasDefaultBrowser(const InstallerState& installer_state) { | |
| 227 using base::win::RegistryKeyIterator; | |
| 228 const HKEY root = HKEY_LOCAL_MACHINE; | |
| 229 InstallUtil::ProgramCompare open_command_pred( | |
| 230 installer_state.target_path().Append(kChromeExe)); | |
| 231 string16 client_open_path; | |
| 232 RegKey client_open_key; | |
| 233 string16 reg_exe; | |
| 234 for (RegistryKeyIterator iter(root, ShellUtil::kRegStartMenuInternet); | |
| 235 iter.Valid(); ++iter) { | |
| 236 client_open_path.assign(ShellUtil::kRegStartMenuInternet) | |
| 237 .append(1, L'\\') | |
| 238 .append(iter.Name()) | |
| 239 .append(ShellUtil::kRegShellOpen); | |
| 240 if (client_open_key.Open(root, client_open_path.c_str(), | |
| 241 KEY_QUERY_VALUE) == ERROR_SUCCESS && | |
| 242 client_open_key.ReadValue(L"", ®_exe) == ERROR_SUCCESS && | |
| 243 open_command_pred.Evaluate(reg_exe)) { | |
| 244 return true; | |
| 245 } | |
| 246 } | |
| 247 return false; | |
| 248 } | |
| 249 | |
| 250 // This method deletes Chrome shortcut folder from Windows Start menu. It | 223 // This method deletes Chrome shortcut folder from Windows Start menu. It |
| 251 // checks system_uninstall to see if the shortcut is in all users start menu | 224 // checks system_uninstall to see if the shortcut is in all users start menu |
| 252 // or current user start menu. | 225 // or current user start menu. |
| 253 // We try to remove the standard desktop shortcut but if that fails we try | 226 // We try to remove the standard desktop shortcut but if that fails we try |
| 254 // to remove the alternate desktop shortcut. Only one of them should be | 227 // to remove the alternate desktop shortcut. Only one of them should be |
| 255 // present in a given install but at this point we don't know which one. | 228 // present in a given install but at this point we don't know which one. |
| 256 void DeleteChromeShortcuts(const InstallerState& installer_state, | 229 void DeleteChromeShortcuts(const InstallerState& installer_state, |
| 257 const Product& product) { | 230 const Product& product) { |
| 258 if (!product.is_chrome()) { | 231 if (!product.is_chrome()) { |
| 259 VLOG(1) << __FUNCTION__ " called for non-CHROME distribution"; | 232 VLOG(1) << __FUNCTION__ " called for non-CHROME distribution"; |
| (...skipping 397 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 657 } | 630 } |
| 658 | 631 |
| 659 // Note that we do not attempt to delete filetype associations since MSDN | 632 // Note that we do not attempt to delete filetype associations since MSDN |
| 660 // says "Windows respects the Default value only if the ProgID found there is | 633 // says "Windows respects the Default value only if the ProgID found there is |
| 661 // a registered ProgID. If the ProgID is unregistered, it is ignored." | 634 // a registered ProgID. If the ProgID is unregistered, it is ignored." |
| 662 | 635 |
| 663 *exit_code = installer::UNINSTALL_SUCCESSFUL; | 636 *exit_code = installer::UNINSTALL_SUCCESSFUL; |
| 664 return true; | 637 return true; |
| 665 } | 638 } |
| 666 | 639 |
| 667 void RemoveChromeLegacyRegistryKeys(BrowserDistribution* dist) { | 640 void RemoveChromeLegacyRegistryKeys(BrowserDistribution* dist, |
| 641 const string16& chrome_exe) { |
| 668 // We used to register Chrome to handle crx files, but this turned out | 642 // We used to register Chrome to handle crx files, but this turned out |
| 669 // to be not worth the hassle. Remove these old registry entries if | 643 // to be not worth the hassle. Remove these old registry entries if |
| 670 // they exist. See: http://codereview.chromium.org/210007 | 644 // they exist. See: http://codereview.chromium.org/210007 |
| 671 | 645 |
| 672 #if defined(GOOGLE_CHROME_BUILD) | 646 #if defined(GOOGLE_CHROME_BUILD) |
| 673 const wchar_t kChromeExtProgId[] = L"ChromeExt"; | 647 const wchar_t kChromeExtProgId[] = L"ChromeExt"; |
| 674 #else | 648 #else |
| 675 const wchar_t kChromeExtProgId[] = L"ChromiumExt"; | 649 const wchar_t kChromeExtProgId[] = L"ChromiumExt"; |
| 676 #endif | 650 #endif |
| 677 | 651 |
| 678 HKEY roots[] = { HKEY_LOCAL_MACHINE, HKEY_CURRENT_USER }; | 652 HKEY roots[] = { HKEY_LOCAL_MACHINE, HKEY_CURRENT_USER }; |
| 679 for (size_t i = 0; i < arraysize(roots); ++i) { | 653 for (size_t i = 0; i < arraysize(roots); ++i) { |
| 680 string16 suffix; | 654 string16 suffix; |
| 681 if (roots[i] == HKEY_LOCAL_MACHINE && | 655 if (roots[i] == HKEY_LOCAL_MACHINE) |
| 682 !ShellUtil::GetUserSpecificDefaultBrowserSuffix(dist, &suffix)) | 656 suffix = ShellUtil::GetCurrentInstallationSuffix(dist, chrome_exe); |
| 683 suffix = L""; | |
| 684 | 657 |
| 685 // Delete Software\Classes\ChromeExt, | 658 // Delete Software\Classes\ChromeExt, |
| 686 string16 ext_prog_id(ShellUtil::kRegClasses); | 659 string16 ext_prog_id(ShellUtil::kRegClasses); |
| 687 ext_prog_id.push_back(FilePath::kSeparators[0]); | 660 ext_prog_id.push_back(FilePath::kSeparators[0]); |
| 688 ext_prog_id.append(kChromeExtProgId); | 661 ext_prog_id.append(kChromeExtProgId); |
| 689 ext_prog_id.append(suffix); | 662 ext_prog_id.append(suffix); |
| 690 InstallUtil::DeleteRegistryKey(roots[i], ext_prog_id); | 663 InstallUtil::DeleteRegistryKey(roots[i], ext_prog_id); |
| 691 | 664 |
| 692 // Delete Software\Classes\.crx, | 665 // Delete Software\Classes\.crx, |
| 693 string16 ext_association(ShellUtil::kRegClasses); | 666 string16 ext_association(ShellUtil::kRegClasses); |
| (...skipping 29 matching lines...) Expand all Loading... |
| 723 } | 696 } |
| 724 | 697 |
| 725 InstallStatus UninstallProduct(const InstallationState& original_state, | 698 InstallStatus UninstallProduct(const InstallationState& original_state, |
| 726 const InstallerState& installer_state, | 699 const InstallerState& installer_state, |
| 727 const FilePath& setup_path, | 700 const FilePath& setup_path, |
| 728 const Product& product, | 701 const Product& product, |
| 729 bool remove_all, | 702 bool remove_all, |
| 730 bool force_uninstall, | 703 bool force_uninstall, |
| 731 const CommandLine& cmd_line) { | 704 const CommandLine& cmd_line) { |
| 732 InstallStatus status = installer::UNINSTALL_CONFIRMED; | 705 InstallStatus status = installer::UNINSTALL_CONFIRMED; |
| 733 string16 suffix; | 706 BrowserDistribution* browser_dist = product.distribution(); |
| 734 if (!ShellUtil::GetUserSpecificDefaultBrowserSuffix(product.distribution(), | 707 const string16 chrome_exe( |
| 735 &suffix)) | 708 installer_state.target_path().Append(installer::kChromeExe).value()); |
| 736 suffix = L""; | |
| 737 | 709 |
| 738 BrowserDistribution* browser_dist = product.distribution(); | 710 const string16 suffix(ShellUtil::GetCurrentInstallationSuffix(browser_dist, |
| 711 chrome_exe)); |
| 712 |
| 739 bool is_chrome = product.is_chrome(); | 713 bool is_chrome = product.is_chrome(); |
| 740 | 714 |
| 741 VLOG(1) << "UninstallProduct: " << browser_dist->GetApplicationName(); | 715 VLOG(1) << "UninstallProduct: " << browser_dist->GetApplicationName(); |
| 742 | 716 |
| 743 if (force_uninstall) { | 717 if (force_uninstall) { |
| 744 // Since --force-uninstall command line option is used, we are going to | 718 // Since --force-uninstall command line option is used, we are going to |
| 745 // do silent uninstall. Try to close all running Chrome instances. | 719 // do silent uninstall. Try to close all running Chrome instances. |
| 746 // NOTE: We don't do this for Chrome Frame. | 720 // NOTE: We don't do this for Chrome Frame. |
| 747 if (is_chrome) | 721 if (is_chrome) |
| 748 CloseAllChromeProcesses(); | 722 CloseAllChromeProcesses(); |
| 749 } else if (is_chrome) { | 723 } else if (is_chrome) { |
| 750 // no --force-uninstall so lets show some UI dialog boxes. | 724 // no --force-uninstall so lets show some UI dialog boxes. |
| 751 status = IsChromeActiveOrUserCancelled(installer_state, product); | 725 status = IsChromeActiveOrUserCancelled(installer_state, product); |
| 752 if (status != installer::UNINSTALL_CONFIRMED && | 726 if (status != installer::UNINSTALL_CONFIRMED && |
| 753 status != installer::UNINSTALL_DELETE_PROFILE) | 727 status != installer::UNINSTALL_DELETE_PROFILE) |
| 754 return status; | 728 return status; |
| 755 | 729 |
| 756 // Check if we need admin rights to cleanup HKLM. If we do, try to launch | 730 // Check if we need admin rights to cleanup HKLM (the conditions for |
| 757 // another uninstaller (silent) in elevated mode to do HKLM cleanup. | 731 // requiring a cleanup are the same as the conditions to do the actual |
| 732 // cleanup where DeleteChromeRegistrationKeys() is invoked for |
| 733 // HKEY_LOCAL_MACHINE below). If we do, try to launch another uninstaller |
| 734 // (silent) in elevated mode to do HKLM cleanup. |
| 758 // And continue uninstalling in the current process also to do HKCU cleanup. | 735 // And continue uninstalling in the current process also to do HKCU cleanup. |
| 759 if (remove_all && | 736 if (remove_all && |
| 760 (!suffix.empty() || CurrentUserHasDefaultBrowser(installer_state)) && | 737 ShellUtil::QuickIsChromeRegisteredInHKLM( |
| 738 browser_dist, chrome_exe, suffix) && |
| 761 !::IsUserAnAdmin() && | 739 !::IsUserAnAdmin() && |
| 762 base::win::GetVersion() >= base::win::VERSION_VISTA && | 740 base::win::GetVersion() >= base::win::VERSION_VISTA && |
| 763 !cmd_line.HasSwitch(installer::switches::kRunAsAdmin)) { | 741 !cmd_line.HasSwitch(installer::switches::kRunAsAdmin)) { |
| 764 CommandLine new_cmd(CommandLine::NO_PROGRAM); | 742 CommandLine new_cmd(CommandLine::NO_PROGRAM); |
| 765 new_cmd.AppendArguments(cmd_line, true); | 743 new_cmd.AppendArguments(cmd_line, true); |
| 766 // Append --run-as-admin flag to let the new instance of setup.exe know | 744 // Append --run-as-admin flag to let the new instance of setup.exe know |
| 767 // that we already tried to launch ourselves as admin. | 745 // that we already tried to launch ourselves as admin. |
| 768 new_cmd.AppendSwitch(installer::switches::kRunAsAdmin); | 746 new_cmd.AppendSwitch(installer::switches::kRunAsAdmin); |
| 769 // Append --remove-chrome-registration to remove registry keys only. | 747 // Append --remove-chrome-registration to remove registry keys only. |
| 770 new_cmd.AppendSwitch(installer::switches::kRemoveChromeRegistration); | 748 new_cmd.AppendSwitch(installer::switches::kRemoveChromeRegistration); |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 804 // Also try to delete the MSI value in the ClientState key (it might not be | 782 // Also try to delete the MSI value in the ClientState key (it might not be |
| 805 // there). This is due to a Google Update behaviour where an uninstall and a | 783 // there). This is due to a Google Update behaviour where an uninstall and a |
| 806 // rapid reinstall might result in stale values from the old ClientState key | 784 // rapid reinstall might result in stale values from the old ClientState key |
| 807 // being picked up on reinstall. | 785 // being picked up on reinstall. |
| 808 product.SetMsiMarker(installer_state.system_install(), false); | 786 product.SetMsiMarker(installer_state.system_install(), false); |
| 809 | 787 |
| 810 // Remove all Chrome registration keys. | 788 // Remove all Chrome registration keys. |
| 811 // Registration data is put in HKCU for both system level and user level | 789 // Registration data is put in HKCU for both system level and user level |
| 812 // installs. | 790 // installs. |
| 813 InstallStatus ret = installer::UNKNOWN_STATUS; | 791 InstallStatus ret = installer::UNKNOWN_STATUS; |
| 814 DeleteChromeRegistrationKeys(product.distribution(), HKEY_CURRENT_USER, | 792 DeleteChromeRegistrationKeys(browser_dist, HKEY_CURRENT_USER, suffix, |
| 815 suffix, installer_state.target_path(), &ret); | 793 installer_state.target_path(), &ret); |
| 794 |
| 795 // If the user's Chrome is registered with a suffix: it is possible that old |
| 796 // unsuffixed registrations were left in HKCU (e.g. if this install was |
| 797 // previously installed with no suffix in HKCU (old suffix rules if the user |
| 798 // is not an admin (or declined UAC at first run)) and later had to be |
| 799 // suffixed when fully registered in HKLM (e.g. when later making Chrome |
| 800 // default through the UI)). |
| 801 // Remove remaining HKCU entries with no suffix if any. |
| 802 if (!suffix.empty()) { |
| 803 DeleteChromeRegistrationKeys(browser_dist, HKEY_CURRENT_USER, string16(), |
| 804 installer_state.target_path(), &ret); |
| 805 } |
| 816 | 806 |
| 817 // Chrome is registered in HKLM for all system-level installs and for | 807 // Chrome is registered in HKLM for all system-level installs and for |
| 818 // user-level installs for which Chrome has been made the default browser. | 808 // user-level installs for which Chrome has been made the default browser. |
| 819 // Always remove the HKLM registration for system-level installs. For | 809 // Always remove the HKLM registration for system-level installs. For |
| 820 // user-level installs, only remove it if both: 1) this uninstall isn't a | 810 // user-level installs, only remove it if both: 1) this uninstall isn't a self |
| 821 // self-destruct following the installation of system-level Chrome (because | 811 // destruct following the installation of a system-level Chrome (because the |
| 822 // the system-level Chrome owns the HKLM registration now), and 2) this user | 812 // system-level Chrome owns the HKLM registration now), and 2) this user has |
| 823 // had made Chrome their default browser. | 813 // made Chrome their default browser (i.e. has system entries registered with |
| 814 // |suffix| (note: |suffix| will be the empty string if required as it is |
| 815 // obtained by GetCurrentInstallationSuffix() above)). |
| 816 // TODO(gab): This can still leave parts of a suffixed install behind. To be |
| 817 // able to remove them we would need to be able to remove only suffixed |
| 818 // entries (as it is now some of the system entries are unsuffixed; thus |
| 819 // removing suffixed installs is prohibited in HKLM if !|remove_all| for now). |
| 824 if (installer_state.system_install() || | 820 if (installer_state.system_install() || |
| 825 (remove_all && | 821 (remove_all && |
| 826 (!suffix.empty() || CurrentUserHasDefaultBrowser(installer_state)))) { | 822 ShellUtil::QuickIsChromeRegisteredInHKLM( |
| 827 DeleteChromeRegistrationKeys(product.distribution(), HKEY_LOCAL_MACHINE, | 823 browser_dist, chrome_exe, suffix))) { |
| 828 suffix, installer_state.target_path(), &ret); | 824 DeleteChromeRegistrationKeys(browser_dist, HKEY_LOCAL_MACHINE, suffix, |
| 825 installer_state.target_path(), &ret); |
| 829 } | 826 } |
| 830 | 827 |
| 831 ProcessDelegateExecuteWorkItems(installer_state, product); | 828 ProcessDelegateExecuteWorkItems(installer_state, product); |
| 832 | 829 |
| 833 if (!is_chrome) { | 830 if (!is_chrome) { |
| 834 ProcessChromeFrameWorkItems(original_state, installer_state, setup_path, | 831 ProcessChromeFrameWorkItems(original_state, installer_state, setup_path, |
| 835 product); | 832 product); |
| 836 } | 833 } |
| 837 | 834 |
| 838 if (installer_state.is_multi_install()) | 835 if (installer_state.is_multi_install()) |
| (...skipping 113 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 952 | 949 |
| 953 // Try and delete the preserved local state once the post-install | 950 // Try and delete the preserved local state once the post-install |
| 954 // operations are complete. | 951 // operations are complete. |
| 955 if (!backup_state_file.empty()) | 952 if (!backup_state_file.empty()) |
| 956 file_util::Delete(backup_state_file, false); | 953 file_util::Delete(backup_state_file, false); |
| 957 | 954 |
| 958 return ret; | 955 return ret; |
| 959 } | 956 } |
| 960 | 957 |
| 961 } // namespace installer | 958 } // namespace installer |
| OLD | NEW |