| 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 <windows.h> |
| 10 |
| 9 #include <vector> | 11 #include <vector> |
| 10 | 12 |
| 11 #include "base/file_util.h" | 13 #include "base/file_util.h" |
| 12 #include "base/path_service.h" | 14 #include "base/path_service.h" |
| 13 #include "base/process_util.h" | 15 #include "base/process_util.h" |
| 16 #include "base/string16.h" |
| 14 #include "base/string_number_conversions.h" | 17 #include "base/string_number_conversions.h" |
| 15 #include "base/string_util.h" | 18 #include "base/string_util.h" |
| 16 #include "base/utf_string_conversions.h" | 19 #include "base/utf_string_conversions.h" |
| 17 #include "base/win/registry.h" | 20 #include "base/win/registry.h" |
| 18 #include "base/win/scoped_handle.h" | 21 #include "base/win/scoped_handle.h" |
| 19 #include "base/win/windows_version.h" | 22 #include "base/win/windows_version.h" |
| 20 #include "chrome/common/chrome_constants.h" | 23 #include "chrome/common/chrome_constants.h" |
| 21 #include "chrome/common/chrome_paths_internal.h" | 24 #include "chrome/common/chrome_paths_internal.h" |
| 22 #include "chrome/common/chrome_result_codes.h" | 25 #include "chrome/common/chrome_result_codes.h" |
| 23 #include "chrome/installer/setup/install.h" | 26 #include "chrome/installer/setup/install.h" |
| (...skipping 706 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 730 // corresponding BrowserDistribution implementations do not publish | 733 // corresponding BrowserDistribution implementations do not publish |
| 731 // DelegateExecute data via an implementation of GetDelegateExecuteHandlerData. | 734 // DelegateExecute data via an implementation of GetDelegateExecuteHandlerData. |
| 732 bool ProcessDelegateExecuteWorkItems(const InstallerState& installer_state, | 735 bool ProcessDelegateExecuteWorkItems(const InstallerState& installer_state, |
| 733 const Product& product) { | 736 const Product& product) { |
| 734 scoped_ptr<WorkItemList> item_list(WorkItem::CreateNoRollbackWorkItemList()); | 737 scoped_ptr<WorkItemList> item_list(WorkItem::CreateNoRollbackWorkItemList()); |
| 735 AddDelegateExecuteWorkItems(installer_state, FilePath(), Version(), product, | 738 AddDelegateExecuteWorkItems(installer_state, FilePath(), Version(), product, |
| 736 item_list.get()); | 739 item_list.get()); |
| 737 return item_list->Do(); | 740 return item_list->Do(); |
| 738 } | 741 } |
| 739 | 742 |
| 743 // Removes Active Setup entries from the registry. This cannot be done through |
| 744 // a work items list as usual because of different paths based on conditionals, |
| 745 // but otherwise respects the no rollback/best effort uninstall mentality. |
| 746 // This will only apply for system-level installs of Chrome/Chromium and will be |
| 747 // a no-op for all other types of installs. |
| 748 void UninstallActiveSetupEntries(const InstallerState& installer_state, |
| 749 const Product& product) { |
| 750 VLOG(1) << "Uninstalling registry entries for ActiveSetup."; |
| 751 BrowserDistribution* distribution = product.distribution(); |
| 752 |
| 753 if (!product.is_chrome() || !installer_state.system_install()) { |
| 754 const char* install_level = |
| 755 installer_state.system_install() ? "system" : "user"; |
| 756 VLOG(1) << "No Active Setup processing to do for " << install_level |
| 757 << "-level " << distribution->GetAppShortCutName(); |
| 758 return; |
| 759 } |
| 760 |
| 761 const string16 active_setup_path(GetActiveSetupPath(distribution)); |
| 762 InstallUtil::DeleteRegistryKey(HKEY_LOCAL_MACHINE, active_setup_path); |
| 763 |
| 764 // Windows leaves keys behind in HKCU\\Software\\(Wow6432Node\\)?Microsoft\\ |
| 765 // Active Setup\\Installed Components\\{guid} |
| 766 // for every user that logged in since system-level Chrome was installed. |
| 767 // This is a problem because Windows compares the value of the Version subkey |
| 768 // in there with the value of the Version subkey in the matching HKLM entries |
| 769 // before running Chrome's Active Setup so if Chrome was to be reinstalled |
| 770 // with a lesser version (e.g. switching back to a more stable channel), the |
| 771 // affected users would not have Chrome's Active Setup called until Chrome |
| 772 // eventually updated passed that user's registered Version. |
| 773 // |
| 774 // It is however very hard to delete those values as the registry hives for |
| 775 // other users are not loaded by default under HKEY_USERS (unless a user is |
| 776 // logged on or has a process impersonating him). |
| 777 // |
| 778 // Following our best effort uninstall practices, try to delete the value in |
| 779 // all users hives. If a given user's hive is not loaded, try to load it to |
| 780 // proceed with the deletion (failure to do so is ignored). |
| 781 |
| 782 static const wchar_t kProfileList[] = |
| 783 L"Software\\Microsoft\\Windows NT\\CurrentVersion\\ProfileList\\"; |
| 784 |
| 785 // Windows automatically adds Wow6432Node when creating/deleting the HKLM key, |
| 786 // but doesn't seem to do so when manually deleting the user-level keys it |
| 787 // created. |
| 788 string16 alternate_active_setup_path(active_setup_path); |
| 789 alternate_active_setup_path.insert(arraysize("Software\\") - 1, |
| 790 L"Wow6432Node\\"); |
| 791 |
| 792 // These two privileges are required by RegLoadKey() and RegUnloadKey() below. |
| 793 ScopedTokenPrivilege se_restore_name_privilege(SE_RESTORE_NAME); |
| 794 ScopedTokenPrivilege se_backup_name_privilege(SE_BACKUP_NAME); |
| 795 if (!se_restore_name_privilege.is_enabled() || |
| 796 !se_backup_name_privilege.is_enabled()) { |
| 797 // This is not a critical failure as those privileges aren't required to |
| 798 // clean hives that are already loaded, but attempts to LoadRegKey() below |
| 799 // will fail. |
| 800 LOG(WARNING) << "Failed to enable privileges required to load registry " |
| 801 "hives."; |
| 802 } |
| 803 |
| 804 for (base::win::RegistryKeyIterator it(HKEY_LOCAL_MACHINE, kProfileList); |
| 805 it.Valid(); ++it) { |
| 806 const wchar_t* profile_sid = it.Name(); |
| 807 |
| 808 // First check if this user's registry hive needs to be loaded in |
| 809 // HKEY_USERS. |
| 810 base::win::RegKey user_reg_root_probe( |
| 811 HKEY_USERS, profile_sid, KEY_READ); |
| 812 bool loaded_hive = false; |
| 813 if (!user_reg_root_probe.Valid()) { |
| 814 VLOG(1) << "Attempting to load registry hive for " << profile_sid; |
| 815 |
| 816 string16 reg_profile_info_path(kProfileList); |
| 817 reg_profile_info_path.append(profile_sid); |
| 818 base::win::RegKey reg_profile_info_key( |
| 819 HKEY_LOCAL_MACHINE, reg_profile_info_path.c_str(), KEY_READ); |
| 820 |
| 821 string16 profile_path; |
| 822 LONG result = reg_profile_info_key.ReadValue(L"ProfileImagePath", |
| 823 &profile_path); |
| 824 if (result != ERROR_SUCCESS) { |
| 825 LOG(ERROR) << "Error reading ProfileImagePath: " << result; |
| 826 continue; |
| 827 } |
| 828 FilePath registry_hive_file(profile_path); |
| 829 registry_hive_file = registry_hive_file.AppendASCII("NTUSER.DAT"); |
| 830 |
| 831 result = RegLoadKey(HKEY_USERS, profile_sid, |
| 832 registry_hive_file.value().c_str()); |
| 833 if (result != ERROR_SUCCESS) { |
| 834 LOG(ERROR) << "Error loading registry hive: " << result; |
| 835 continue; |
| 836 } |
| 837 |
| 838 VLOG(1) << "Loaded registry hive for " << profile_sid; |
| 839 loaded_hive = true; |
| 840 } |
| 841 |
| 842 base::win::RegKey user_reg_root( |
| 843 HKEY_USERS, profile_sid, KEY_ALL_ACCESS); |
| 844 |
| 845 LONG result = user_reg_root.DeleteKey(active_setup_path.c_str()); |
| 846 if (result != ERROR_SUCCESS) { |
| 847 result = user_reg_root.DeleteKey(alternate_active_setup_path.c_str()); |
| 848 if (result != ERROR_SUCCESS && result != ERROR_FILE_NOT_FOUND) { |
| 849 LOG(ERROR) << "Failed to delete key at " << active_setup_path |
| 850 << " and at " << alternate_active_setup_path |
| 851 << ", result: " << result; |
| 852 } |
| 853 } |
| 854 |
| 855 if (loaded_hive) { |
| 856 user_reg_root.Close(); |
| 857 if (RegUnLoadKey(HKEY_USERS, profile_sid) == ERROR_SUCCESS) |
| 858 VLOG(1) << "Unloaded registry hive for " << profile_sid; |
| 859 else |
| 860 LOG(ERROR) << "Error unloading registry hive for " << profile_sid; |
| 861 } |
| 862 } |
| 863 } |
| 864 |
| 740 bool ProcessChromeFrameWorkItems(const InstallationState& original_state, | 865 bool ProcessChromeFrameWorkItems(const InstallationState& original_state, |
| 741 const InstallerState& installer_state, | 866 const InstallerState& installer_state, |
| 742 const FilePath& setup_path, | 867 const FilePath& setup_path, |
| 743 const Product& product) { | 868 const Product& product) { |
| 744 if (!product.is_chrome_frame()) | 869 if (!product.is_chrome_frame()) |
| 745 return false; | 870 return false; |
| 746 | 871 |
| 747 scoped_ptr<WorkItemList> item_list(WorkItem::CreateNoRollbackWorkItemList()); | 872 scoped_ptr<WorkItemList> item_list(WorkItem::CreateNoRollbackWorkItemList()); |
| 748 AddChromeFrameWorkItems(original_state, installer_state, setup_path, | 873 AddChromeFrameWorkItems(original_state, installer_state, setup_path, |
| 749 Version(), product, item_list.get()); | 874 Version(), product, item_list.get()); |
| (...skipping 144 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 894 // !|remove_all| for now). | 1019 // !|remove_all| for now). |
| 895 if (installer_state.system_install() || | 1020 if (installer_state.system_install() || |
| 896 (remove_all && | 1021 (remove_all && |
| 897 ShellUtil::QuickIsChromeRegisteredInHKLM( | 1022 ShellUtil::QuickIsChromeRegisteredInHKLM( |
| 898 browser_dist, chrome_exe, suffix))) { | 1023 browser_dist, chrome_exe, suffix))) { |
| 899 DeleteChromeRegistrationKeys(browser_dist, HKEY_LOCAL_MACHINE, suffix, | 1024 DeleteChromeRegistrationKeys(browser_dist, HKEY_LOCAL_MACHINE, suffix, |
| 900 installer_state.target_path(), &ret); | 1025 installer_state.target_path(), &ret); |
| 901 } | 1026 } |
| 902 | 1027 |
| 903 ProcessDelegateExecuteWorkItems(installer_state, product); | 1028 ProcessDelegateExecuteWorkItems(installer_state, product); |
| 1029 |
| 1030 UninstallActiveSetupEntries(installer_state, product); |
| 904 } | 1031 } |
| 905 | 1032 |
| 906 if (product.is_chrome_frame()) { | 1033 if (product.is_chrome_frame()) { |
| 907 ProcessChromeFrameWorkItems(original_state, installer_state, setup_path, | 1034 ProcessChromeFrameWorkItems(original_state, installer_state, setup_path, |
| 908 product); | 1035 product); |
| 909 } | 1036 } |
| 910 | 1037 |
| 911 if (installer_state.is_multi_install()) | 1038 if (installer_state.is_multi_install()) |
| 912 ProcessGoogleUpdateItems(original_state, installer_state, product); | 1039 ProcessGoogleUpdateItems(original_state, installer_state, product); |
| 913 | 1040 |
| (...skipping 95 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1009 | 1136 |
| 1010 // Try and delete the preserved local state once the post-install | 1137 // Try and delete the preserved local state once the post-install |
| 1011 // operations are complete. | 1138 // operations are complete. |
| 1012 if (!backup_state_file.empty()) | 1139 if (!backup_state_file.empty()) |
| 1013 file_util::Delete(backup_state_file, false); | 1140 file_util::Delete(backup_state_file, false); |
| 1014 | 1141 |
| 1015 return ret; | 1142 return ret; |
| 1016 } | 1143 } |
| 1017 | 1144 |
| 1018 } // namespace installer | 1145 } // namespace installer |
| OLD | NEW |