| 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> | 9 #include <windows.h> |
| 10 #include <stddef.h> | 10 #include <stddef.h> |
| 11 #include <stdint.h> | 11 #include <stdint.h> |
| 12 | 12 |
| 13 #include <memory> |
| 14 #include <string> |
| 13 #include <vector> | 15 #include <vector> |
| 14 | 16 |
| 15 #include "base/base_paths.h" | 17 #include "base/base_paths.h" |
| 16 #include "base/bind.h" | 18 #include "base/bind.h" |
| 17 #include "base/files/file_enumerator.h" | 19 #include "base/files/file_enumerator.h" |
| 18 #include "base/files/file_util.h" | 20 #include "base/files/file_util.h" |
| 19 #include "base/macros.h" | 21 #include "base/macros.h" |
| 20 #include "base/path_service.h" | 22 #include "base/path_service.h" |
| 21 #include "base/process/kill.h" | 23 #include "base/process/kill.h" |
| 22 #include "base/strings/string16.h" | 24 #include "base/strings/string16.h" |
| 23 #include "base/strings/string_number_conversions.h" | 25 #include "base/strings/string_number_conversions.h" |
| 24 #include "base/strings/string_util.h" | 26 #include "base/strings/string_util.h" |
| 25 #include "base/strings/utf_string_conversions.h" | 27 #include "base/strings/utf_string_conversions.h" |
| 26 #include "base/win/registry.h" | 28 #include "base/win/registry.h" |
| 27 #include "base/win/scoped_handle.h" | |
| 28 #include "base/win/shortcut.h" | 29 #include "base/win/shortcut.h" |
| 29 #include "base/win/windows_version.h" | 30 #include "base/win/windows_version.h" |
| 30 #include "chrome/common/chrome_constants.h" | 31 #include "chrome/common/chrome_constants.h" |
| 31 #include "chrome/common/chrome_paths.h" | 32 #include "chrome/common/chrome_paths.h" |
| 32 #include "chrome/common/chrome_result_codes.h" | 33 #include "chrome/common/chrome_result_codes.h" |
| 33 #include "chrome/installer/setup/install.h" | 34 #include "chrome/installer/setup/install.h" |
| 34 #include "chrome/installer/setup/install_worker.h" | 35 #include "chrome/installer/setup/install_worker.h" |
| 35 #include "chrome/installer/setup/installer_state.h" | 36 #include "chrome/installer/setup/installer_state.h" |
| 36 #include "chrome/installer/setup/setup_constants.h" | 37 #include "chrome/installer/setup/setup_constants.h" |
| 37 #include "chrome/installer/setup/setup_util.h" | 38 #include "chrome/installer/setup/setup_util.h" |
| (...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 72 if (base::DirectoryExists(temp_path)) { | 73 if (base::DirectoryExists(temp_path)) { |
| 73 SelfCleaningTempDir temp_dir; | 74 SelfCleaningTempDir temp_dir; |
| 74 if (!temp_dir.Initialize(target_path.DirName(), | 75 if (!temp_dir.Initialize(target_path.DirName(), |
| 75 installer::kInstallTempDir) || | 76 installer::kInstallTempDir) || |
| 76 !temp_dir.Delete()) { | 77 !temp_dir.Delete()) { |
| 77 LOG(ERROR) << "Failed to delete temp dir " << temp_path.value(); | 78 LOG(ERROR) << "Failed to delete temp dir " << temp_path.value(); |
| 78 } | 79 } |
| 79 } | 80 } |
| 80 } | 81 } |
| 81 | 82 |
| 82 // Iterates over the list of distribution types in |dist_types|, and | |
| 83 // adds to |update_list| the work item to update the corresponding "ap" | |
| 84 // registry value specified in |channel_info|. | |
| 85 void AddChannelValueUpdateWorkItems( | |
| 86 const InstallationState& original_state, | |
| 87 const InstallerState& installer_state, | |
| 88 const ChannelInfo& channel_info, | |
| 89 const std::vector<BrowserDistribution::Type>& dist_types, | |
| 90 WorkItemList* update_list) { | |
| 91 const bool system_level = installer_state.system_install(); | |
| 92 const HKEY reg_root = installer_state.root_key(); | |
| 93 for (size_t i = 0; i < dist_types.size(); ++i) { | |
| 94 BrowserDistribution::Type dist_type = dist_types[i]; | |
| 95 const ProductState* product_state = | |
| 96 original_state.GetProductState(system_level, dist_type); | |
| 97 // Only modify other products if they're installed and multi. | |
| 98 if (product_state != NULL && | |
| 99 product_state->is_multi_install() && | |
| 100 !product_state->channel().Equals(channel_info)) { | |
| 101 BrowserDistribution* other_dist = | |
| 102 BrowserDistribution::GetSpecificDistribution(dist_type); | |
| 103 update_list->AddSetRegValueWorkItem(reg_root, | |
| 104 other_dist->GetStateKey(), | |
| 105 KEY_WOW64_32KEY, | |
| 106 google_update::kRegApField, | |
| 107 channel_info.value(), | |
| 108 true); | |
| 109 } else { | |
| 110 LOG_IF(ERROR, | |
| 111 product_state != NULL && product_state->is_multi_install()) | |
| 112 << "Channel value for " | |
| 113 << BrowserDistribution::GetSpecificDistribution( | |
| 114 dist_type)->GetDisplayName() | |
| 115 << " is somehow already set to the desired new value of " | |
| 116 << channel_info.value(); | |
| 117 } | |
| 118 } | |
| 119 } | |
| 120 | |
| 121 // Makes appropriate changes to the Google Update "ap" value in the registry. | |
| 122 // Specifically, removes the flags associated with this product ("-chrome" or | |
| 123 // "-chromeframe") from the "ap" values for all other installed products and for | |
| 124 // the multi-installer package. | |
| 125 void ProcessGoogleUpdateItems(const InstallationState& original_state, | |
| 126 const InstallerState& installer_state, | |
| 127 const Product& product) { | |
| 128 DCHECK(installer_state.is_multi_install()); | |
| 129 const bool system_level = installer_state.system_install(); | |
| 130 BrowserDistribution* distribution = product.distribution(); | |
| 131 const ProductState* product_state = | |
| 132 original_state.GetNonVersionedProductState(system_level, | |
| 133 distribution->GetType()); | |
| 134 ChannelInfo channel_info; | |
| 135 | |
| 136 // Remove product's flags from the channel value. | |
| 137 channel_info.set_value(product_state->channel().value()); | |
| 138 const bool modified = product.SetChannelFlags(false, &channel_info); | |
| 139 | |
| 140 // Apply the new channel value to all other products and to the multi package. | |
| 141 if (modified) { | |
| 142 std::unique_ptr<WorkItemList> update_list(WorkItem::CreateWorkItemList()); | |
| 143 update_list->set_log_message("Channel Value Update"); | |
| 144 update_list->set_best_effort(true); | |
| 145 update_list->set_rollback_enabled(false); | |
| 146 std::vector<BrowserDistribution::Type> dist_types; | |
| 147 for (size_t i = 0; i < BrowserDistribution::NUM_TYPES; ++i) { | |
| 148 BrowserDistribution::Type other_dist_type = | |
| 149 static_cast<BrowserDistribution::Type>(i); | |
| 150 if (distribution->GetType() != other_dist_type) | |
| 151 dist_types.push_back(other_dist_type); | |
| 152 } | |
| 153 AddChannelValueUpdateWorkItems(original_state, installer_state, | |
| 154 channel_info, dist_types, | |
| 155 update_list.get()); | |
| 156 update_list->Do(); | |
| 157 } | |
| 158 } | |
| 159 | |
| 160 // Processes uninstall WorkItems from install_worker in no-rollback-list. | 83 // Processes uninstall WorkItems from install_worker in no-rollback-list. |
| 161 void ProcessChromeWorkItems(const InstallerState& installer_state, | 84 void ProcessChromeWorkItems(const InstallerState& installer_state, |
| 162 const Product& product) { | 85 const Product& product) { |
| 163 std::unique_ptr<WorkItemList> work_item_list(WorkItem::CreateWorkItemList()); | 86 std::unique_ptr<WorkItemList> work_item_list(WorkItem::CreateWorkItemList()); |
| 164 work_item_list->set_log_message( | 87 work_item_list->set_log_message( |
| 165 "Cleanup OS upgrade command and deprecated per-user registrations"); | 88 "Cleanup OS upgrade command and deprecated per-user registrations"); |
| 166 work_item_list->set_best_effort(true); | 89 work_item_list->set_best_effort(true); |
| 167 work_item_list->set_rollback_enabled(false); | 90 work_item_list->set_rollback_enabled(false); |
| 168 AddOsUpgradeWorkItems(installer_state, base::FilePath(), base::Version(), | 91 AddOsUpgradeWorkItems(installer_state, base::FilePath(), base::Version(), |
| 169 product, work_item_list.get()); | 92 product, work_item_list.get()); |
| 170 // Perform a best-effort cleanup of per-user keys. On system-level installs | 93 // Perform a best-effort cleanup of per-user keys. On system-level installs |
| 171 // this will only cleanup keys for the user running the uninstall but it was | 94 // this will only cleanup keys for the user running the uninstall but it was |
| 172 // considered that this was good enough (better than triggering Active Setup | 95 // considered that this was good enough (better than triggering Active Setup |
| 173 // for all users solely for this cleanup). | 96 // for all users solely for this cleanup). |
| 174 AddCleanupDeprecatedPerUserRegistrationsWorkItems(product, | 97 AddCleanupDeprecatedPerUserRegistrationsWorkItems(product, |
| 175 work_item_list.get()); | 98 work_item_list.get()); |
| 176 work_item_list->Do(); | 99 work_item_list->Do(); |
| 177 } | 100 } |
| 178 | 101 |
| 179 void ProcessIELowRightsPolicyWorkItems(const InstallerState& installer_state) { | |
| 180 std::unique_ptr<WorkItemList> work_items(WorkItem::CreateWorkItemList()); | |
| 181 work_items->set_log_message("Delete old IE low rights policy"); | |
| 182 work_items->set_best_effort(true); | |
| 183 work_items->set_rollback_enabled(false); | |
| 184 AddDeleteOldIELowRightsPolicyWorkItems(installer_state, work_items.get()); | |
| 185 work_items->Do(); | |
| 186 RefreshElevationPolicy(); | |
| 187 } | |
| 188 | |
| 189 void ClearRlzProductState() { | 102 void ClearRlzProductState() { |
| 190 const rlz_lib::AccessPoint points[] = {rlz_lib::CHROME_OMNIBOX, | 103 const rlz_lib::AccessPoint points[] = {rlz_lib::CHROME_OMNIBOX, |
| 191 rlz_lib::CHROME_HOME_PAGE, | 104 rlz_lib::CHROME_HOME_PAGE, |
| 192 rlz_lib::CHROME_APP_LIST, | 105 rlz_lib::CHROME_APP_LIST, |
| 193 rlz_lib::NO_ACCESS_POINT}; | 106 rlz_lib::NO_ACCESS_POINT}; |
| 194 | 107 |
| 195 rlz_lib::ClearProductState(rlz_lib::CHROME, points); | 108 rlz_lib::ClearProductState(rlz_lib::CHROME, points); |
| 196 | 109 |
| 197 // If chrome has been reactivated, clear all events for this brand as well. | 110 // If chrome has been reactivated, clear all events for this brand as well. |
| 198 base::string16 reactivation_brand_wide; | 111 base::string16 reactivation_brand_wide; |
| 199 if (GoogleUpdateSettings::GetReactivationBrand(&reactivation_brand_wide)) { | 112 if (GoogleUpdateSettings::GetReactivationBrand(&reactivation_brand_wide)) { |
| 200 std::string reactivation_brand(base::UTF16ToASCII(reactivation_brand_wide)); | 113 std::string reactivation_brand(base::UTF16ToASCII(reactivation_brand_wide)); |
| 201 rlz_lib::SupplementaryBranding branding(reactivation_brand.c_str()); | 114 rlz_lib::SupplementaryBranding branding(reactivation_brand.c_str()); |
| 202 rlz_lib::ClearProductState(rlz_lib::CHROME, points); | 115 rlz_lib::ClearProductState(rlz_lib::CHROME, points); |
| 203 } | 116 } |
| 204 } | 117 } |
| 205 | 118 |
| 206 // Returns whether setup.exe should be removed based on the original and | 119 // Removes all files from the installer directory. Returns false in case of an |
| 207 // installer states: | 120 // error. |
| 208 // * non-multi product being uninstalled: remove setup.exe | 121 bool RemoveInstallerFiles(const base::FilePath& installer_directory) { |
| 209 // * any multi product left: keep setup.exe | |
| 210 bool CheckShouldRemoveSetup(const InstallationState& original_state, | |
| 211 const InstallerState& installer_state) { | |
| 212 // If any multi-install product is left we must leave the installer and | |
| 213 // archive. | |
| 214 if (!installer_state.is_multi_install()) { | |
| 215 VLOG(1) << "Removing all installer files for a non-multi installation."; | |
| 216 } else { | |
| 217 // Loop through all known products... | |
| 218 for (size_t i = 0; i < BrowserDistribution::NUM_TYPES; ++i) { | |
| 219 BrowserDistribution::Type dist_type = | |
| 220 static_cast<BrowserDistribution::Type>(i); | |
| 221 const ProductState* product_state = original_state.GetProductState( | |
| 222 installer_state.system_install(), dist_type); | |
| 223 // If the product is installed, in multi mode, and is not part of the | |
| 224 // active uninstallation... | |
| 225 if (product_state && product_state->is_multi_install() && | |
| 226 !installer_state.FindProduct(dist_type)) { | |
| 227 // setup.exe will not be removed as there is a remaining multi-install | |
| 228 // product. | |
| 229 VLOG(1) << "Keeping all installer files due to a remaining " | |
| 230 << "multi-install product."; | |
| 231 return false; | |
| 232 } | |
| 233 } | |
| 234 VLOG(1) << "Removing all installer files."; | |
| 235 } | |
| 236 return true; | |
| 237 } | |
| 238 | |
| 239 // Removes all files from the installer directory, leaving setup.exe iff | |
| 240 // |remove_setup| is false. | |
| 241 // Returns false in case of an error. | |
| 242 bool RemoveInstallerFiles(const base::FilePath& installer_directory, | |
| 243 bool remove_setup) { | |
| 244 base::FileEnumerator file_enumerator( | 122 base::FileEnumerator file_enumerator( |
| 245 installer_directory, | 123 installer_directory, |
| 246 false, | 124 false, |
| 247 base::FileEnumerator::FILES | base::FileEnumerator::DIRECTORIES); | 125 base::FileEnumerator::FILES | base::FileEnumerator::DIRECTORIES); |
| 248 bool success = true; | 126 bool success = true; |
| 249 | 127 |
| 250 base::FilePath setup_exe_base_name(installer::kSetupExe); | |
| 251 | |
| 252 for (base::FilePath to_delete = file_enumerator.Next(); !to_delete.empty(); | 128 for (base::FilePath to_delete = file_enumerator.Next(); !to_delete.empty(); |
| 253 to_delete = file_enumerator.Next()) { | 129 to_delete = file_enumerator.Next()) { |
| 254 if (!remove_setup && to_delete.BaseName() == setup_exe_base_name) | |
| 255 continue; | |
| 256 | |
| 257 VLOG(1) << "Deleting installer path " << to_delete.value(); | 130 VLOG(1) << "Deleting installer path " << to_delete.value(); |
| 258 if (!base::DeleteFile(to_delete, true)) { | 131 if (!base::DeleteFile(to_delete, true)) { |
| 259 LOG(ERROR) << "Failed to delete path: " << to_delete.value(); | 132 LOG(ERROR) << "Failed to delete path: " << to_delete.value(); |
| 260 success = false; | 133 success = false; |
| 261 } | 134 } |
| 262 } | 135 } |
| 263 | 136 |
| 264 return success; | 137 return success; |
| 265 } | 138 } |
| 266 | 139 |
| 267 // Kills all Chrome processes, immediately. | 140 // Kills all Chrome processes, immediately. |
| 268 void CloseAllChromeProcesses() { | 141 void CloseAllChromeProcesses() { |
| 269 base::CleanupProcesses(installer::kChromeExe, base::TimeDelta(), | 142 base::CleanupProcesses(installer::kChromeExe, base::TimeDelta(), |
| 270 content::RESULT_CODE_HUNG, NULL); | 143 content::RESULT_CODE_HUNG, NULL); |
| 271 base::CleanupProcesses(installer::kNaClExe, base::TimeDelta(), | 144 base::CleanupProcesses(installer::kNaClExe, base::TimeDelta(), |
| 272 content::RESULT_CODE_HUNG, NULL); | 145 content::RESULT_CODE_HUNG, NULL); |
| 273 } | 146 } |
| 274 | 147 |
| 275 // Attempts to close the Chrome Frame helper process by sending WM_CLOSE | |
| 276 // messages to its window, or just killing it if that doesn't work. | |
| 277 void CloseChromeFrameHelperProcess() { | |
| 278 HWND window = FindWindow(installer::kChromeFrameHelperWndClass, NULL); | |
| 279 if (!::IsWindow(window)) | |
| 280 return; | |
| 281 | |
| 282 const DWORD kWaitMs = 3000; | |
| 283 | |
| 284 DWORD pid = 0; | |
| 285 ::GetWindowThreadProcessId(window, &pid); | |
| 286 DCHECK_NE(pid, 0U); | |
| 287 base::win::ScopedHandle process(::OpenProcess(SYNCHRONIZE, FALSE, pid)); | |
| 288 PLOG_IF(INFO, !process.IsValid()) << "Failed to open process: " << pid; | |
| 289 | |
| 290 bool kill = true; | |
| 291 if (SendMessageTimeout(window, WM_CLOSE, 0, 0, SMTO_BLOCK, kWaitMs, NULL) && | |
| 292 process.IsValid()) { | |
| 293 VLOG(1) << "Waiting for " << installer::kChromeFrameHelperExe; | |
| 294 DWORD wait = ::WaitForSingleObject(process.Get(), kWaitMs); | |
| 295 if (wait != WAIT_OBJECT_0) { | |
| 296 LOG(WARNING) << "Wait for " << installer::kChromeFrameHelperExe | |
| 297 << " to exit failed or timed out."; | |
| 298 } else { | |
| 299 kill = false; | |
| 300 VLOG(1) << installer::kChromeFrameHelperExe << " exited normally."; | |
| 301 } | |
| 302 } | |
| 303 | |
| 304 if (kill) { | |
| 305 VLOG(1) << installer::kChromeFrameHelperExe << " hung. Killing."; | |
| 306 base::CleanupProcesses(installer::kChromeFrameHelperExe, base::TimeDelta(), | |
| 307 content::RESULT_CODE_HUNG, NULL); | |
| 308 } | |
| 309 } | |
| 310 | |
| 311 // Updates shortcuts to |old_target_exe| that have non-empty args, making them | 148 // Updates shortcuts to |old_target_exe| that have non-empty args, making them |
| 312 // target |new_target_exe| instead. The non-empty args requirement is a | 149 // target |new_target_exe| instead. The non-empty args requirement is a |
| 313 // heuristic to determine whether a shortcut is "user-generated". This routine | 150 // heuristic to determine whether a shortcut is "user-generated". This routine |
| 314 // can only be called for user-level installs. | 151 // can only be called for user-level installs. |
| 315 void RetargetUserShortcutsWithArgs(const InstallerState& installer_state, | 152 void RetargetUserShortcutsWithArgs(const InstallerState& installer_state, |
| 316 const Product& product, | 153 const Product& product, |
| 317 const base::FilePath& old_target_exe, | 154 const base::FilePath& old_target_exe, |
| 318 const base::FilePath& new_target_exe) { | 155 const base::FilePath& new_target_exe) { |
| 319 if (installer_state.system_install()) { | 156 if (installer_state.system_install()) { |
| 320 NOTREACHED(); | 157 NOTREACHED(); |
| (...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 388 if (!base::IsDirectoryEmpty(path)) | 225 if (!base::IsDirectoryEmpty(path)) |
| 389 return DELETE_NOT_EMPTY; | 226 return DELETE_NOT_EMPTY; |
| 390 | 227 |
| 391 if (base::DeleteFile(path, true)) | 228 if (base::DeleteFile(path, true)) |
| 392 return DELETE_SUCCEEDED; | 229 return DELETE_SUCCEEDED; |
| 393 | 230 |
| 394 LOG(ERROR) << "Failed to delete folder: " << path.value(); | 231 LOG(ERROR) << "Failed to delete folder: " << path.value(); |
| 395 return DELETE_FAILED; | 232 return DELETE_FAILED; |
| 396 } | 233 } |
| 397 | 234 |
| 398 // Get the user data directory, which is *not* DIR_USER_DATA for Chrome Frame. | 235 // Get the user data directory. |
| 399 // TODO(grt): Remove Chrome Frame uninstall support when usage is low enough. | |
| 400 base::FilePath GetUserDataDir(const Product& product) { | 236 base::FilePath GetUserDataDir(const Product& product) { |
| 401 base::FilePath path; | 237 base::FilePath path; |
| 402 bool is_chrome_frame = product.is_chrome_frame(); | 238 if (!PathService::Get(chrome::DIR_USER_DATA, &path)) |
| 403 int key = is_chrome_frame ? base::DIR_LOCAL_APP_DATA : chrome::DIR_USER_DATA; | |
| 404 if (!PathService::Get(key, &path)) | |
| 405 return base::FilePath(); | 239 return base::FilePath(); |
| 406 if (is_chrome_frame) { | |
| 407 path = path.Append(product.distribution()->GetInstallSubDir()); | |
| 408 path = path.Append(chrome::kUserDataDirname); | |
| 409 } | |
| 410 return path; | 240 return path; |
| 411 } | 241 } |
| 412 | 242 |
| 413 // Creates a copy of the local state file and returns a path to the copy. | 243 // Creates a copy of the local state file and returns a path to the copy. |
| 414 base::FilePath BackupLocalStateFile(const base::FilePath& user_data_dir) { | 244 base::FilePath BackupLocalStateFile(const base::FilePath& user_data_dir) { |
| 415 base::FilePath backup; | 245 base::FilePath backup; |
| 416 base::FilePath state_file(user_data_dir.Append(chrome::kLocalStateFilename)); | 246 base::FilePath state_file(user_data_dir.Append(chrome::kLocalStateFilename)); |
| 417 if (!base::CreateTemporaryFile(&backup)) | 247 if (!base::CreateTemporaryFile(&backup)) |
| 418 LOG(ERROR) << "Failed to create temporary file for Local State."; | 248 LOG(ERROR) << "Failed to create temporary file for Local State."; |
| 419 else | 249 else |
| 420 base::CopyFile(state_file, backup); | 250 base::CopyFile(state_file, backup); |
| 421 return backup; | 251 return backup; |
| 422 } | 252 } |
| 423 | 253 |
| 424 // Deletes a given user data directory as well as the containing product | 254 // Deletes a given user data directory as well as the containing product |
| 425 // directories if they are empty (e.g., "Google\Chrome"). | 255 // directories if they are empty (e.g., "Google\Chrome"). |
| 426 DeleteResult DeleteUserDataDir(const base::FilePath& user_data_dir, | 256 DeleteResult DeleteUserDataDir(const base::FilePath& user_data_dir) { |
| 427 bool schedule_on_failure) { | |
| 428 if (user_data_dir.empty()) | 257 if (user_data_dir.empty()) |
| 429 return DELETE_SUCCEEDED; | 258 return DELETE_SUCCEEDED; |
| 430 | 259 |
| 431 DeleteResult result = DELETE_SUCCEEDED; | 260 DeleteResult result = DELETE_SUCCEEDED; |
| 432 VLOG(1) << "Deleting user profile " << user_data_dir.value(); | 261 VLOG(1) << "Deleting user profile " << user_data_dir.value(); |
| 433 if (!base::DeleteFile(user_data_dir, true)) { | 262 if (!base::DeleteFile(user_data_dir, true)) { |
| 434 LOG(ERROR) << "Failed to delete user profile dir: " | 263 LOG(ERROR) << "Failed to delete user profile dir: " |
| 435 << user_data_dir.value(); | 264 << user_data_dir.value(); |
| 436 if (schedule_on_failure) { | 265 result = DELETE_FAILED; |
| 437 ScheduleDirectoryForDeletion(user_data_dir); | |
| 438 result = DELETE_REQUIRES_REBOOT; | |
| 439 } else { | |
| 440 result = DELETE_FAILED; | |
| 441 } | |
| 442 } | 266 } |
| 443 | 267 |
| 444 if (result == DELETE_REQUIRES_REBOOT) { | 268 const base::FilePath product_dir1(user_data_dir.DirName()); |
| 445 ScheduleParentAndGrandparentForDeletion(user_data_dir); | 269 if (!product_dir1.empty() && |
| 446 } else { | 270 DeleteEmptyDir(product_dir1) == DELETE_SUCCEEDED) { |
| 447 const base::FilePath product_dir1(user_data_dir.DirName()); | 271 const base::FilePath product_dir2(product_dir1.DirName()); |
| 448 if (!product_dir1.empty() && | 272 if (!product_dir2.empty()) |
| 449 DeleteEmptyDir(product_dir1) == DELETE_SUCCEEDED) { | 273 DeleteEmptyDir(product_dir2); |
| 450 const base::FilePath product_dir2(product_dir1.DirName()); | |
| 451 if (!product_dir2.empty()) | |
| 452 DeleteEmptyDir(product_dir2); | |
| 453 } | |
| 454 } | 274 } |
| 455 | 275 |
| 456 return result; | 276 return result; |
| 457 } | 277 } |
| 458 | 278 |
| 459 // Moves setup to a temporary file, outside of the install folder. Also attempts | 279 // Moves setup to a temporary file, outside of the install folder. Also attempts |
| 460 // to change the current directory to the TMP directory. On Windows, each | 280 // to change the current directory to the TMP directory. On Windows, each |
| 461 // process has a handle to its CWD. If setup.exe's CWD happens to be within the | 281 // process has a handle to its CWD. If setup.exe's CWD happens to be within the |
| 462 // install directory, deletion will fail as a result of the open handle. | 282 // install directory, deletion will fail as a result of the open handle. |
| 463 bool MoveSetupOutOfInstallFolder(const InstallerState& installer_state, | 283 bool MoveSetupOutOfInstallFolder(const InstallerState& installer_state, |
| (...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 545 if (!installer_directory.empty() && | 365 if (!installer_directory.empty() && |
| 546 (to_delete == installer_directory || | 366 (to_delete == installer_directory || |
| 547 installer_directory.IsParent(to_delete) || | 367 installer_directory.IsParent(to_delete) || |
| 548 to_delete.IsParent(installer_directory))) { | 368 to_delete.IsParent(installer_directory))) { |
| 549 continue; | 369 continue; |
| 550 } | 370 } |
| 551 | 371 |
| 552 VLOG(1) << "Deleting install path " << to_delete.value(); | 372 VLOG(1) << "Deleting install path " << to_delete.value(); |
| 553 if (!base::DeleteFile(to_delete, true)) { | 373 if (!base::DeleteFile(to_delete, true)) { |
| 554 LOG(ERROR) << "Failed to delete path (1st try): " << to_delete.value(); | 374 LOG(ERROR) << "Failed to delete path (1st try): " << to_delete.value(); |
| 555 if (installer_state.FindProduct(BrowserDistribution::CHROME_FRAME)) { | 375 // Try closing any running Chrome processes and deleting files once |
| 556 // We don't try killing Chrome processes for Chrome Frame builds since | 376 // again. |
| 557 // that is unlikely to help. Instead, schedule files for deletion and | 377 CloseAllChromeProcesses(); |
| 558 // return a value that will trigger a reboot prompt. | 378 if (!base::DeleteFile(to_delete, true)) { |
| 559 base::FileEnumerator::FileInfo find_info = file_enumerator.GetInfo(); | 379 LOG(ERROR) << "Failed to delete path (2nd try): " << to_delete.value(); |
| 560 if (find_info.IsDirectory()) | 380 result = DELETE_FAILED; |
| 561 ScheduleDirectoryForDeletion(to_delete); | 381 break; |
| 562 else | |
| 563 ScheduleFileSystemEntityForDeletion(to_delete); | |
| 564 result = DELETE_REQUIRES_REBOOT; | |
| 565 } else { | |
| 566 // Try closing any running Chrome processes and deleting files once | |
| 567 // again. | |
| 568 CloseAllChromeProcesses(); | |
| 569 if (!base::DeleteFile(to_delete, true)) { | |
| 570 LOG(ERROR) << "Failed to delete path (2nd try): " | |
| 571 << to_delete.value(); | |
| 572 result = DELETE_FAILED; | |
| 573 break; | |
| 574 } | |
| 575 } | 382 } |
| 576 } | 383 } |
| 577 } | 384 } |
| 578 | 385 |
| 579 return result; | 386 return result; |
| 580 } | 387 } |
| 581 | 388 |
| 582 // This method checks if Chrome is currently running or if the user has | 389 // This method checks if Chrome is currently running or if the user has |
| 583 // cancelled the uninstall operation by clicking Cancel on the confirmation | 390 // cancelled the uninstall operation by clicking Cancel on the confirmation |
| 584 // box that Chrome pops up. | 391 // box that Chrome pops up. |
| (...skipping 24 matching lines...) Expand all Loading... |
| 609 | 416 |
| 610 if (exit_code == chrome::RESULT_CODE_UNINSTALL_DELETE_PROFILE) | 417 if (exit_code == chrome::RESULT_CODE_UNINSTALL_DELETE_PROFILE) |
| 611 return installer::UNINSTALL_DELETE_PROFILE; | 418 return installer::UNINSTALL_DELETE_PROFILE; |
| 612 } else { | 419 } else { |
| 613 PLOG(ERROR) << "Failed to launch chrome.exe for uninstall confirmation."; | 420 PLOG(ERROR) << "Failed to launch chrome.exe for uninstall confirmation."; |
| 614 } | 421 } |
| 615 | 422 |
| 616 return installer::UNINSTALL_CONFIRMED; | 423 return installer::UNINSTALL_CONFIRMED; |
| 617 } | 424 } |
| 618 | 425 |
| 619 bool ShouldDeleteProfile(const InstallerState& installer_state, | 426 bool ShouldDeleteProfile(const base::CommandLine& cmd_line, |
| 620 const base::CommandLine& cmd_line, | 427 InstallStatus status) { |
| 621 InstallStatus status, | 428 return status == installer::UNINSTALL_DELETE_PROFILE || |
| 622 const Product& product) { | 429 cmd_line.HasSwitch(installer::switches::kDeleteProfile); |
| 623 bool should_delete = false; | |
| 624 | |
| 625 // Chrome Frame uninstallations always want to delete the profile (we have no | |
| 626 // UI to prompt otherwise and the profile stores no useful data anyway) | |
| 627 // unless they are managed by MSI. MSI uninstalls will explicitly include | |
| 628 // the --delete-profile flag to distinguish them from MSI upgrades. | |
| 629 if (product.is_chrome_frame() && !installer_state.is_msi()) { | |
| 630 should_delete = true; | |
| 631 } else if (product.is_chrome()) { | |
| 632 should_delete = | |
| 633 status == installer::UNINSTALL_DELETE_PROFILE || | |
| 634 cmd_line.HasSwitch(installer::switches::kDeleteProfile); | |
| 635 } | |
| 636 | |
| 637 return should_delete; | |
| 638 } | 430 } |
| 639 | 431 |
| 640 // Removes XP-era filetype registration making Chrome the default browser. | 432 // Removes XP-era filetype registration making Chrome the default browser. |
| 641 // MSDN (see http://msdn.microsoft.com/library/windows/desktop/cc144148.aspx) | 433 // MSDN (see http://msdn.microsoft.com/library/windows/desktop/cc144148.aspx) |
| 642 // tells us not to do this, but certain applications break following | 434 // tells us not to do this, but certain applications break following |
| 643 // uninstallation if we don't. | 435 // uninstallation if we don't. |
| 644 void RemoveFiletypeRegistration(const InstallerState& installer_state, | 436 void RemoveFiletypeRegistration(const InstallerState& installer_state, |
| 645 HKEY root, | 437 HKEY root, |
| 646 const base::string16& browser_entry_suffix) { | 438 const base::string16& browser_entry_suffix) { |
| 647 base::string16 classes_path(ShellUtil::kRegClasses); | 439 base::string16 classes_path(ShellUtil::kRegClasses); |
| (...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 726 // Removes Active Setup entries from the registry. This cannot be done through | 518 // Removes Active Setup entries from the registry. This cannot be done through |
| 727 // a work items list as usual because of different paths based on conditionals, | 519 // a work items list as usual because of different paths based on conditionals, |
| 728 // but otherwise respects the no rollback/best effort uninstall mentality. | 520 // but otherwise respects the no rollback/best effort uninstall mentality. |
| 729 // This will only apply for system-level installs of Chrome/Chromium and will be | 521 // This will only apply for system-level installs of Chrome/Chromium and will be |
| 730 // a no-op for all other types of installs. | 522 // a no-op for all other types of installs. |
| 731 void UninstallActiveSetupEntries(const InstallerState& installer_state, | 523 void UninstallActiveSetupEntries(const InstallerState& installer_state, |
| 732 const Product& product) { | 524 const Product& product) { |
| 733 VLOG(1) << "Uninstalling registry entries for Active Setup."; | 525 VLOG(1) << "Uninstalling registry entries for Active Setup."; |
| 734 BrowserDistribution* distribution = product.distribution(); | 526 BrowserDistribution* distribution = product.distribution(); |
| 735 | 527 |
| 736 if (!product.is_chrome() || !installer_state.system_install()) { | 528 if (!installer_state.system_install()) { |
| 737 const char* install_level = | 529 VLOG(1) << "No Active Setup processing to do for user-level " |
| 738 installer_state.system_install() ? "system" : "user"; | 530 << distribution->GetDisplayName(); |
| 739 VLOG(1) << "No Active Setup processing to do for " << install_level | |
| 740 << "-level " << distribution->GetDisplayName(); | |
| 741 return; | 531 return; |
| 742 } | 532 } |
| 743 | 533 |
| 744 const base::string16 active_setup_path( | 534 const base::string16 active_setup_path( |
| 745 InstallUtil::GetActiveSetupPath(distribution)); | 535 InstallUtil::GetActiveSetupPath(distribution)); |
| 746 InstallUtil::DeleteRegistryKey(HKEY_LOCAL_MACHINE, active_setup_path, | 536 InstallUtil::DeleteRegistryKey(HKEY_LOCAL_MACHINE, active_setup_path, |
| 747 WorkItem::kWow64Default); | 537 WorkItem::kWow64Default); |
| 748 | 538 |
| 749 // Windows leaves keys behind in HKCU\\Software\\(Wow6432Node\\)?Microsoft\\ | 539 // Windows leaves keys behind in HKCU\\Software\\(Wow6432Node\\)?Microsoft\\ |
| 750 // Active Setup\\Installed Components\\{guid} | 540 // Active Setup\\Installed Components\\{guid} |
| (...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 796 #endif | 586 #endif |
| 797 InstallUtil::DeleteRegistryKey(HKEY_CURRENT_USER, | 587 InstallUtil::DeleteRegistryKey(HKEY_CURRENT_USER, |
| 798 kRegistryFinchListPath, | 588 kRegistryFinchListPath, |
| 799 0); // wow64_access | 589 0); // wow64_access |
| 800 } | 590 } |
| 801 | 591 |
| 802 // Removes the persistent state for |distribution| for the current user. Note: | 592 // Removes the persistent state for |distribution| for the current user. Note: |
| 803 // this will not remove the state for users other than the one uninstalling | 593 // this will not remove the state for users other than the one uninstalling |
| 804 // Chrome on a system-level install; see RemoveBlacklistState for details. | 594 // Chrome on a system-level install; see RemoveBlacklistState for details. |
| 805 void RemoveDistributionRegistryState(BrowserDistribution* distribution) { | 595 void RemoveDistributionRegistryState(BrowserDistribution* distribution) { |
| 806 // Binaries do not store per-user state. | 596 static const base::char16* const kKeysToPreserve[] = { |
| 807 if (distribution->GetType() != BrowserDistribution::CHROME_BINARIES) { | 597 L"Extensions", L"NativeMessagingHosts", |
| 808 static const base::char16* const kKeysToPreserve[] = { | 598 }; |
| 809 L"Extensions", | 599 // Delete the contents of the distribution key except for those parts used by |
| 810 L"NativeMessagingHosts", | 600 // outsiders to configure Chrome. |
| 811 }; | 601 DeleteRegistryKeyPartial( |
| 812 // Delete the contents of the distribution key except for those parts used | 602 HKEY_CURRENT_USER, distribution->GetRegistryPath(), |
| 813 // by outsiders to configure Chrome. | 603 std::vector<base::string16>( |
| 814 DeleteRegistryKeyPartial( | 604 &kKeysToPreserve[0], |
| 815 HKEY_CURRENT_USER, distribution->GetRegistryPath(), | 605 &kKeysToPreserve[arraysize(kKeysToPreserve) - 1])); |
| 816 std::vector<base::string16>( | |
| 817 &kKeysToPreserve[0], | |
| 818 &kKeysToPreserve[arraysize(kKeysToPreserve) - 1])); | |
| 819 } | |
| 820 } | 606 } |
| 821 | 607 |
| 822 } // namespace | 608 } // namespace |
| 823 | 609 |
| 824 DeleteResult DeleteChromeDirectoriesIfEmpty( | 610 DeleteResult DeleteChromeDirectoriesIfEmpty( |
| 825 const base::FilePath& application_directory) { | 611 const base::FilePath& application_directory) { |
| 826 DeleteResult result(DeleteEmptyDir(application_directory)); | 612 DeleteResult result(DeleteEmptyDir(application_directory)); |
| 827 if (result == DELETE_SUCCEEDED) { | 613 if (result == DELETE_SUCCEEDED) { |
| 828 // Now check and delete if the parent directories are empty | 614 // Now check and delete if the parent directories are empty |
| 829 // For example Google\Chrome or Chromium | 615 // For example Google\Chrome or Chromium |
| (...skipping 204 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1034 const base::FilePath& setup_exe, | 820 const base::FilePath& setup_exe, |
| 1035 const Product& product, | 821 const Product& product, |
| 1036 bool remove_all, | 822 bool remove_all, |
| 1037 bool force_uninstall, | 823 bool force_uninstall, |
| 1038 const base::CommandLine& cmd_line) { | 824 const base::CommandLine& cmd_line) { |
| 1039 InstallStatus status = installer::UNINSTALL_CONFIRMED; | 825 InstallStatus status = installer::UNINSTALL_CONFIRMED; |
| 1040 BrowserDistribution* browser_dist = product.distribution(); | 826 BrowserDistribution* browser_dist = product.distribution(); |
| 1041 const base::FilePath chrome_exe( | 827 const base::FilePath chrome_exe( |
| 1042 installer_state.target_path().Append(installer::kChromeExe)); | 828 installer_state.target_path().Append(installer::kChromeExe)); |
| 1043 | 829 |
| 1044 bool is_chrome = product.is_chrome(); | |
| 1045 | |
| 1046 VLOG(1) << "UninstallProduct: " << browser_dist->GetDisplayName(); | 830 VLOG(1) << "UninstallProduct: " << browser_dist->GetDisplayName(); |
| 1047 | 831 |
| 1048 if (force_uninstall) { | 832 if (force_uninstall) { |
| 1049 // Since --force-uninstall command line option is used, we are going to | 833 // Since --force-uninstall command line option is used, we are going to |
| 1050 // do silent uninstall. Try to close all running Chrome instances. | 834 // do silent uninstall. Try to close all running Chrome instances. |
| 1051 // NOTE: We don't do this for Chrome Frame. | 835 CloseAllChromeProcesses(); |
| 1052 if (is_chrome) | 836 } else { |
| 1053 CloseAllChromeProcesses(); | |
| 1054 } else if (is_chrome) { | |
| 1055 // no --force-uninstall so lets show some UI dialog boxes. | 837 // no --force-uninstall so lets show some UI dialog boxes. |
| 1056 status = IsChromeActiveOrUserCancelled(installer_state, product); | 838 status = IsChromeActiveOrUserCancelled(installer_state, product); |
| 1057 if (status != installer::UNINSTALL_CONFIRMED && | 839 if (status != installer::UNINSTALL_CONFIRMED && |
| 1058 status != installer::UNINSTALL_DELETE_PROFILE) | 840 status != installer::UNINSTALL_DELETE_PROFILE) |
| 1059 return status; | 841 return status; |
| 1060 | 842 |
| 1061 const base::string16 suffix( | 843 const base::string16 suffix( |
| 1062 ShellUtil::GetCurrentInstallationSuffix(browser_dist, chrome_exe)); | 844 ShellUtil::GetCurrentInstallationSuffix(browser_dist, chrome_exe)); |
| 1063 | 845 |
| 1064 // Check if we need admin rights to cleanup HKLM (the conditions for | 846 // Check if we need admin rights to cleanup HKLM (the conditions for |
| (...skipping 17 matching lines...) Expand all Loading... |
| 1082 new_cmd.AppendSwitch(installer::switches::kRemoveChromeRegistration); | 864 new_cmd.AppendSwitch(installer::switches::kRemoveChromeRegistration); |
| 1083 if (!suffix.empty()) { | 865 if (!suffix.empty()) { |
| 1084 new_cmd.AppendSwitchNative( | 866 new_cmd.AppendSwitchNative( |
| 1085 installer::switches::kRegisterChromeBrowserSuffix, suffix); | 867 installer::switches::kRegisterChromeBrowserSuffix, suffix); |
| 1086 } | 868 } |
| 1087 DWORD exit_code = installer::UNKNOWN_STATUS; | 869 DWORD exit_code = installer::UNKNOWN_STATUS; |
| 1088 InstallUtil::ExecuteExeAsAdmin(new_cmd, &exit_code); | 870 InstallUtil::ExecuteExeAsAdmin(new_cmd, &exit_code); |
| 1089 } | 871 } |
| 1090 } | 872 } |
| 1091 | 873 |
| 1092 if (is_chrome) { | 874 // Chrome is not in use so lets uninstall Chrome by deleting various files |
| 1093 // Chrome is not in use so lets uninstall Chrome by deleting various files | 875 // and registry entries. Here we will just make best effort and keep going |
| 1094 // and registry entries. Here we will just make best effort and keep going | 876 // in case of errors. |
| 1095 // in case of errors. | 877 ClearRlzProductState(); |
| 1096 ClearRlzProductState(); | |
| 1097 | 878 |
| 1098 auto_launch_util::DisableBackgroundStartAtLogin(); | 879 auto_launch_util::DisableBackgroundStartAtLogin(); |
| 1099 | 880 |
| 1100 // If user-level chrome is self-destructing as a result of encountering a | 881 // If user-level chrome is self-destructing as a result of encountering a |
| 1101 // system-level chrome, retarget owned non-default shortcuts (app shortcuts, | 882 // system-level chrome, retarget owned non-default shortcuts (app shortcuts, |
| 1102 // profile shortcuts, etc.) to the system-level chrome. | 883 // profile shortcuts, etc.) to the system-level chrome. |
| 1103 if (cmd_line.HasSwitch(installer::switches::kSelfDestruct) && | 884 if (cmd_line.HasSwitch(installer::switches::kSelfDestruct) && |
| 1104 !installer_state.system_install()) { | 885 !installer_state.system_install()) { |
| 1105 const base::FilePath system_chrome_path( | 886 const base::FilePath system_chrome_path( |
| 1106 GetChromeInstallPath(true, browser_dist). | 887 GetChromeInstallPath(true, browser_dist).Append(installer::kChromeExe)); |
| 1107 Append(installer::kChromeExe)); | 888 VLOG(1) << "Retargeting user-generated Chrome shortcuts."; |
| 1108 VLOG(1) << "Retargeting user-generated Chrome shortcuts."; | 889 if (base::PathExists(system_chrome_path)) { |
| 1109 if (base::PathExists(system_chrome_path)) { | 890 RetargetUserShortcutsWithArgs(installer_state, product, chrome_exe, |
| 1110 RetargetUserShortcutsWithArgs(installer_state, product, chrome_exe, | 891 system_chrome_path); |
| 1111 system_chrome_path); | 892 } else { |
| 1112 } else { | 893 LOG(ERROR) << "Retarget failed: system-level Chrome not found."; |
| 1113 LOG(ERROR) << "Retarget failed: system-level Chrome not found."; | |
| 1114 } | |
| 1115 } | 894 } |
| 895 } |
| 1116 | 896 |
| 1117 DeleteShortcuts(installer_state, product, chrome_exe); | 897 DeleteShortcuts(installer_state, product, chrome_exe); |
| 1118 } | |
| 1119 | 898 |
| 1120 // Delete the registry keys (Uninstall key and Version key). | 899 // Delete the registry keys (Uninstall key and Version key). |
| 1121 HKEY reg_root = installer_state.root_key(); | 900 HKEY reg_root = installer_state.root_key(); |
| 1122 | 901 |
| 1123 // Note that we must retrieve the distribution-specific data before deleting | 902 // Note that we must retrieve the distribution-specific data before deleting |
| 1124 // product.GetVersionKey(). | 903 // product.GetVersionKey(). |
| 1125 base::string16 distribution_data(browser_dist->GetDistributionData(reg_root)); | 904 base::string16 distribution_data(browser_dist->GetDistributionData(reg_root)); |
| 1126 | 905 |
| 1127 // Remove Control Panel uninstall link. | 906 // Remove Control Panel uninstall link. |
| 1128 if (product.ShouldCreateUninstallEntry()) { | 907 if (product.ShouldCreateUninstallEntry()) { |
| 1129 InstallUtil::DeleteRegistryKey( | 908 InstallUtil::DeleteRegistryKey( |
| 1130 reg_root, browser_dist->GetUninstallRegPath(), KEY_WOW64_32KEY); | 909 reg_root, browser_dist->GetUninstallRegPath(), KEY_WOW64_32KEY); |
| 1131 } | 910 } |
| 1132 | 911 |
| 1133 // Remove Omaha product key. | 912 // Remove Omaha product key. |
| 1134 InstallUtil::DeleteRegistryKey( | 913 InstallUtil::DeleteRegistryKey( |
| 1135 reg_root, browser_dist->GetVersionKey(), KEY_WOW64_32KEY); | 914 reg_root, browser_dist->GetVersionKey(), KEY_WOW64_32KEY); |
| 1136 | 915 |
| 1137 // Also try to delete the MSI value in the ClientState key (it might not be | 916 // Also try to delete the MSI value in the ClientState key (it might not be |
| 1138 // there). This is due to a Google Update behaviour where an uninstall and a | 917 // there). This is due to a Google Update behaviour where an uninstall and a |
| 1139 // rapid reinstall might result in stale values from the old ClientState key | 918 // rapid reinstall might result in stale values from the old ClientState key |
| 1140 // being picked up on reinstall. | 919 // being picked up on reinstall. |
| 1141 product.SetMsiMarker(installer_state.system_install(), false); | 920 product.SetMsiMarker(installer_state.system_install(), false); |
| 1142 | 921 |
| 1143 InstallStatus ret = installer::UNKNOWN_STATUS; | 922 InstallStatus ret = installer::UNKNOWN_STATUS; |
| 1144 | 923 |
| 1145 if (is_chrome) { | 924 const base::string16 suffix( |
| 1146 const base::string16 suffix( | 925 ShellUtil::GetCurrentInstallationSuffix(browser_dist, chrome_exe)); |
| 1147 ShellUtil::GetCurrentInstallationSuffix(browser_dist, chrome_exe)); | |
| 1148 | 926 |
| 1149 // Remove all Chrome registration keys. | 927 // Remove all Chrome registration keys. |
| 1150 // Registration data is put in HKCU for both system level and user level | 928 // Registration data is put in HKCU for both system level and user level |
| 1151 // installs. | 929 // installs. |
| 930 DeleteChromeRegistrationKeys(installer_state, browser_dist, HKEY_CURRENT_USER, |
| 931 suffix, &ret); |
| 932 |
| 933 // If the user's Chrome is registered with a suffix: it is possible that old |
| 934 // unsuffixed registrations were left in HKCU (e.g. if this install was |
| 935 // previously installed with no suffix in HKCU (old suffix rules if the user |
| 936 // is not an admin (or declined UAC at first run)) and later had to be |
| 937 // suffixed when fully registered in HKLM (e.g. when later making Chrome |
| 938 // default through the UI)). |
| 939 // Remove remaining HKCU entries with no suffix if any. |
| 940 if (!suffix.empty()) { |
| 1152 DeleteChromeRegistrationKeys(installer_state, browser_dist, | 941 DeleteChromeRegistrationKeys(installer_state, browser_dist, |
| 1153 HKEY_CURRENT_USER, suffix, &ret); | 942 HKEY_CURRENT_USER, base::string16(), &ret); |
| 1154 | 943 |
| 1155 // If the user's Chrome is registered with a suffix: it is possible that old | 944 // For similar reasons it is possible in very few installs (from |
| 1156 // unsuffixed registrations were left in HKCU (e.g. if this install was | 945 // 21.0.1180.0 and fixed shortly after) to be installed with the new-style |
| 1157 // previously installed with no suffix in HKCU (old suffix rules if the user | 946 // suffix, but have some old-style suffix registrations left behind. |
| 1158 // is not an admin (or declined UAC at first run)) and later had to be | 947 base::string16 old_style_suffix; |
| 1159 // suffixed when fully registered in HKLM (e.g. when later making Chrome | 948 if (ShellUtil::GetOldUserSpecificRegistrySuffix(&old_style_suffix) && |
| 1160 // default through the UI)). | 949 suffix != old_style_suffix) { |
| 1161 // Remove remaining HKCU entries with no suffix if any. | |
| 1162 if (!suffix.empty()) { | |
| 1163 DeleteChromeRegistrationKeys(installer_state, browser_dist, | 950 DeleteChromeRegistrationKeys(installer_state, browser_dist, |
| 1164 HKEY_CURRENT_USER, base::string16(), &ret); | 951 HKEY_CURRENT_USER, old_style_suffix, &ret); |
| 1165 | |
| 1166 // For similar reasons it is possible in very few installs (from | |
| 1167 // 21.0.1180.0 and fixed shortly after) to be installed with the new-style | |
| 1168 // suffix, but have some old-style suffix registrations left behind. | |
| 1169 base::string16 old_style_suffix; | |
| 1170 if (ShellUtil::GetOldUserSpecificRegistrySuffix(&old_style_suffix) && | |
| 1171 suffix != old_style_suffix) { | |
| 1172 DeleteChromeRegistrationKeys(installer_state, browser_dist, | |
| 1173 HKEY_CURRENT_USER, old_style_suffix, &ret); | |
| 1174 } | |
| 1175 } | 952 } |
| 1176 | 953 |
| 1177 // Chrome is registered in HKLM for all system-level installs and for | 954 // Chrome is registered in HKLM for all system-level installs and for |
| 1178 // user-level installs for which Chrome has been made the default browser. | 955 // user-level installs for which Chrome has been made the default browser. |
| 1179 // Always remove the HKLM registration for system-level installs. For | 956 // Always remove the HKLM registration for system-level installs. For |
| 1180 // user-level installs, only remove it if both: 1) this uninstall isn't a | 957 // user-level installs, only remove it if both: 1) this uninstall isn't a |
| 1181 // self destruct following the installation of a system-level Chrome | 958 // self destruct following the installation of a system-level Chrome |
| 1182 // (because the system-level Chrome owns the HKLM registration now), and 2) | 959 // (because the system-level Chrome owns the HKLM registration now), and 2) |
| 1183 // this user has made Chrome their default browser (i.e. has shell | 960 // this user has made Chrome their default browser (i.e. has shell |
| 1184 // integration entries registered with |suffix| (note: |suffix| will be the | 961 // integration entries registered with |suffix| (note: |suffix| will be the |
| (...skipping 18 matching lines...) Expand all Loading... |
| 1203 | 980 |
| 1204 UninstallFirewallRules(browser_dist, chrome_exe); | 981 UninstallFirewallRules(browser_dist, chrome_exe); |
| 1205 | 982 |
| 1206 RemoveBlacklistState(); | 983 RemoveBlacklistState(); |
| 1207 | 984 |
| 1208 // Notify the shell that associations have changed since Chrome was likely | 985 // Notify the shell that associations have changed since Chrome was likely |
| 1209 // unregistered. | 986 // unregistered. |
| 1210 SHChangeNotify(SHCNE_ASSOCCHANGED, SHCNF_IDLIST, NULL, NULL); | 987 SHChangeNotify(SHCNE_ASSOCCHANGED, SHCNF_IDLIST, NULL, NULL); |
| 1211 } | 988 } |
| 1212 | 989 |
| 1213 if (installer_state.is_multi_install()) | |
| 1214 ProcessGoogleUpdateItems(original_state, installer_state, product); | |
| 1215 | |
| 1216 // Get the state of the installed product (if any) | 990 // Get the state of the installed product (if any) |
| 1217 const ProductState* product_state = | 991 const ProductState* product_state = |
| 1218 original_state.GetProductState(installer_state.system_install(), | 992 original_state.GetProductState(installer_state.system_install(), |
| 1219 browser_dist->GetType()); | 993 browser_dist->GetType()); |
| 1220 | 994 |
| 1221 // Delete shared registry keys as well (these require admin rights) if | 995 // Delete shared registry keys as well (these require admin rights) if |
| 1222 // remove_all option is specified. | 996 // remove_all option is specified. |
| 1223 if (remove_all) { | 997 if (remove_all) { |
| 1224 if (!InstallUtil::IsChromeSxSProcess() && is_chrome) { | 998 if (!InstallUtil::IsChromeSxSProcess()) { |
| 1225 // Delete media player registry key that exists only in HKLM. | 999 // Delete media player registry key that exists only in HKLM. We don't |
| 1226 // We don't delete this key in SxS uninstall or Chrome Frame uninstall | 1000 // delete this key in SxS uninstall as we never set the key for it. |
| 1227 // as we never set the key for those products. | |
| 1228 base::string16 reg_path(installer::kMediaPlayerRegPath); | 1001 base::string16 reg_path(installer::kMediaPlayerRegPath); |
| 1229 reg_path.push_back(base::FilePath::kSeparators[0]); | 1002 reg_path.push_back(base::FilePath::kSeparators[0]); |
| 1230 reg_path.append(installer::kChromeExe); | 1003 reg_path.append(installer::kChromeExe); |
| 1231 InstallUtil::DeleteRegistryKey(HKEY_LOCAL_MACHINE, reg_path, | 1004 InstallUtil::DeleteRegistryKey(HKEY_LOCAL_MACHINE, reg_path, |
| 1232 WorkItem::kWow64Default); | 1005 WorkItem::kWow64Default); |
| 1233 | 1006 |
| 1234 // Remove the event log provider registration as we are going to delete | 1007 // Remove the event log provider registration as we are going to delete |
| 1235 // the file which serves the resources anyways. | 1008 // the file which serves the resources anyways. |
| 1236 DeRegisterEventLogProvider(); | 1009 DeRegisterEventLogProvider(); |
| 1237 } | 1010 } |
| 1238 | |
| 1239 // Unregister any dll servers that we may have registered for this | |
| 1240 // product. | |
| 1241 if (product_state) { | |
| 1242 std::vector<base::FilePath> com_dll_list; | |
| 1243 product.AddComDllList(&com_dll_list); | |
| 1244 base::FilePath dll_folder = installer_state.target_path().AppendASCII( | |
| 1245 product_state->version().GetString()); | |
| 1246 | |
| 1247 std::unique_ptr<WorkItemList> unreg_work_item_list( | |
| 1248 WorkItem::CreateWorkItemList()); | |
| 1249 | |
| 1250 AddRegisterComDllWorkItems(dll_folder, | |
| 1251 com_dll_list, | |
| 1252 installer_state.system_install(), | |
| 1253 false, // Unregister | |
| 1254 true, // May fail | |
| 1255 unreg_work_item_list.get()); | |
| 1256 unreg_work_item_list->Do(); | |
| 1257 } | |
| 1258 | |
| 1259 if (product.is_chrome_frame()) | |
| 1260 ProcessIELowRightsPolicyWorkItems(installer_state); | |
| 1261 } | |
| 1262 | |
| 1263 // Close any Chrome Frame helper processes that may be running. | |
| 1264 if (product.is_chrome_frame()) { | |
| 1265 VLOG(1) << "Closing the Chrome Frame helper process"; | |
| 1266 CloseChromeFrameHelperProcess(); | |
| 1267 } | 1011 } |
| 1268 | 1012 |
| 1269 // Finally delete all the files from Chrome folder after moving setup.exe | 1013 // Finally delete all the files from Chrome folder after moving setup.exe |
| 1270 // and the user's Local State to a temp location. | 1014 // and the user's Local State to a temp location. |
| 1271 bool delete_profile = ShouldDeleteProfile(installer_state, cmd_line, status, | 1015 bool delete_profile = ShouldDeleteProfile(cmd_line, status); |
| 1272 product); | |
| 1273 ret = installer::UNINSTALL_SUCCESSFUL; | 1016 ret = installer::UNINSTALL_SUCCESSFUL; |
| 1274 | 1017 |
| 1275 // When deleting files, we must make sure that we're either a "single" | |
| 1276 // (aka non-multi) installation or we are the Chrome Binaries. | |
| 1277 | |
| 1278 base::FilePath user_data_dir(GetUserDataDir(product)); | 1018 base::FilePath user_data_dir(GetUserDataDir(product)); |
| 1279 base::FilePath backup_state_file; | 1019 base::FilePath backup_state_file; |
| 1280 if (!user_data_dir.empty()) { | 1020 if (!user_data_dir.empty()) { |
| 1281 backup_state_file = BackupLocalStateFile(user_data_dir); | 1021 backup_state_file = BackupLocalStateFile(user_data_dir); |
| 1282 } else { | 1022 } else { |
| 1283 LOG(ERROR) << "Could not retrieve the user's profile directory."; | 1023 LOG(ERROR) << "Could not retrieve the user's profile directory."; |
| 1284 ret = installer::UNINSTALL_FAILED; | 1024 ret = installer::UNINSTALL_FAILED; |
| 1285 delete_profile = false; | 1025 delete_profile = false; |
| 1286 } | 1026 } |
| 1287 | 1027 |
| 1288 if (!installer_state.is_multi_install() || product.is_chrome_binaries()) { | 1028 DeleteResult delete_result = DeleteChromeFilesAndFolders( |
| 1289 DeleteResult delete_result = DeleteChromeFilesAndFolders( | 1029 installer_state, base::MakeAbsoluteFilePath(setup_exe)); |
| 1290 installer_state, base::MakeAbsoluteFilePath(setup_exe)); | 1030 if (delete_result == DELETE_FAILED) |
| 1291 if (delete_result == DELETE_FAILED) { | 1031 ret = installer::UNINSTALL_FAILED; |
| 1292 ret = installer::UNINSTALL_FAILED; | 1032 else if (delete_result == DELETE_REQUIRES_REBOOT) |
| 1293 } else if (delete_result == DELETE_REQUIRES_REBOOT) { | 1033 ret = installer::UNINSTALL_REQUIRES_REBOOT; |
| 1294 ret = installer::UNINSTALL_REQUIRES_REBOOT; | |
| 1295 } | |
| 1296 } | |
| 1297 | 1034 |
| 1298 if (delete_profile) { | 1035 if (delete_profile) { |
| 1299 DeleteUserDataDir(user_data_dir, product.is_chrome_frame()); | 1036 DeleteUserDataDir(user_data_dir); |
| 1300 RemoveDistributionRegistryState(browser_dist); | 1037 RemoveDistributionRegistryState(browser_dist); |
| 1301 } | 1038 } |
| 1302 | 1039 |
| 1303 if (!force_uninstall && product_state) { | 1040 if (!force_uninstall && product_state) { |
| 1304 VLOG(1) << "Uninstallation complete. Launching post-uninstall operations."; | 1041 VLOG(1) << "Uninstallation complete. Launching post-uninstall operations."; |
| 1305 browser_dist->DoPostUninstallOperations(product_state->version(), | 1042 browser_dist->DoPostUninstallOperations(product_state->version(), |
| 1306 backup_state_file, distribution_data); | 1043 backup_state_file, distribution_data); |
| 1307 } | 1044 } |
| 1308 | 1045 |
| 1309 // Try and delete the preserved local state once the post-install | 1046 // Try and delete the preserved local state once the post-install |
| (...skipping 18 matching lines...) Expand all Loading... |
| 1328 LOG(ERROR) << "No installation destination path."; | 1065 LOG(ERROR) << "No installation destination path."; |
| 1329 *uninstall_status = UNINSTALL_FAILED; | 1066 *uninstall_status = UNINSTALL_FAILED; |
| 1330 return; | 1067 return; |
| 1331 } | 1068 } |
| 1332 if (!target_path.IsParent(base::MakeAbsoluteFilePath(setup_exe))) { | 1069 if (!target_path.IsParent(base::MakeAbsoluteFilePath(setup_exe))) { |
| 1333 VLOG(1) << "setup.exe is not in target path. Skipping installer cleanup."; | 1070 VLOG(1) << "setup.exe is not in target path. Skipping installer cleanup."; |
| 1334 return; | 1071 return; |
| 1335 } | 1072 } |
| 1336 base::FilePath install_directory(setup_exe.DirName()); | 1073 base::FilePath install_directory(setup_exe.DirName()); |
| 1337 | 1074 |
| 1338 bool remove_setup = CheckShouldRemoveSetup(original_state, installer_state); | 1075 VLOG(1) << "Removing all installer files."; |
| 1339 | 1076 |
| 1340 if (remove_setup) { | 1077 // In order to be able to remove the folder in which we're running, we need to |
| 1341 // In order to be able to remove the folder in which we're running, we | 1078 // move setup.exe out of the install folder. |
| 1342 // need to move setup.exe out of the install folder. | 1079 // TODO(tommi): What if the temp folder is on a different volume? |
| 1343 // TODO(tommi): What if the temp folder is on a different volume? | 1080 MoveSetupOutOfInstallFolder(installer_state, setup_exe); |
| 1344 MoveSetupOutOfInstallFolder(installer_state, setup_exe); | |
| 1345 } | |
| 1346 | 1081 |
| 1347 // Remove files from "...\<product>\Application\<version>\Installer" | 1082 // Remove files from "...\<product>\Application\<version>\Installer" |
| 1348 if (!RemoveInstallerFiles(install_directory, remove_setup)) { | 1083 if (!RemoveInstallerFiles(install_directory)) { |
| 1349 *uninstall_status = UNINSTALL_FAILED; | 1084 *uninstall_status = UNINSTALL_FAILED; |
| 1350 return; | 1085 return; |
| 1351 } | 1086 } |
| 1352 | 1087 |
| 1353 if (!remove_setup) | |
| 1354 return; | |
| 1355 | |
| 1356 // Try to remove the empty directory hierarchy. | 1088 // Try to remove the empty directory hierarchy. |
| 1357 | 1089 |
| 1358 // Delete "...\<product>\Application\<version>\Installer" | 1090 // Delete "...\<product>\Application\<version>\Installer" |
| 1359 if (DeleteEmptyDir(install_directory) != DELETE_SUCCEEDED) { | 1091 if (DeleteEmptyDir(install_directory) != DELETE_SUCCEEDED) { |
| 1360 *uninstall_status = UNINSTALL_FAILED; | 1092 *uninstall_status = UNINSTALL_FAILED; |
| 1361 return; | 1093 return; |
| 1362 } | 1094 } |
| 1363 | 1095 |
| 1364 // Delete "...\<product>\Application\<version>" | 1096 // Delete "...\<product>\Application\<version>" |
| 1365 DeleteResult delete_result = DeleteEmptyDir(install_directory.DirName()); | 1097 DeleteResult delete_result = DeleteEmptyDir(install_directory.DirName()); |
| (...skipping 11 matching lines...) Expand all Loading... |
| 1377 // If we need a reboot to continue, schedule the parent directories for | 1109 // If we need a reboot to continue, schedule the parent directories for |
| 1378 // deletion unconditionally. If they are not empty, the session manager | 1110 // deletion unconditionally. If they are not empty, the session manager |
| 1379 // will not delete them on reboot. | 1111 // will not delete them on reboot. |
| 1380 ScheduleParentAndGrandparentForDeletion(target_path); | 1112 ScheduleParentAndGrandparentForDeletion(target_path); |
| 1381 } else if (DeleteChromeDirectoriesIfEmpty(target_path) == DELETE_FAILED) { | 1113 } else if (DeleteChromeDirectoriesIfEmpty(target_path) == DELETE_FAILED) { |
| 1382 *uninstall_status = UNINSTALL_FAILED; | 1114 *uninstall_status = UNINSTALL_FAILED; |
| 1383 } | 1115 } |
| 1384 } | 1116 } |
| 1385 | 1117 |
| 1386 } // namespace installer | 1118 } // namespace installer |
| OLD | NEW |