| 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> |
| (...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 72 if (base::DirectoryExists(temp_path)) { | 72 if (base::DirectoryExists(temp_path)) { |
| 73 SelfCleaningTempDir temp_dir; | 73 SelfCleaningTempDir temp_dir; |
| 74 if (!temp_dir.Initialize(target_path.DirName(), | 74 if (!temp_dir.Initialize(target_path.DirName(), |
| 75 installer::kInstallTempDir) || | 75 installer::kInstallTempDir) || |
| 76 !temp_dir.Delete()) { | 76 !temp_dir.Delete()) { |
| 77 LOG(ERROR) << "Failed to delete temp dir " << temp_path.value(); | 77 LOG(ERROR) << "Failed to delete temp dir " << temp_path.value(); |
| 78 } | 78 } |
| 79 } | 79 } |
| 80 } | 80 } |
| 81 | 81 |
| 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. | 82 // Processes uninstall WorkItems from install_worker in no-rollback-list. |
| 161 void ProcessChromeWorkItems(const InstallerState& installer_state, | 83 void ProcessChromeWorkItems(const InstallerState& installer_state, |
| 162 const Product& product) { | 84 const Product& product) { |
| 163 std::unique_ptr<WorkItemList> work_item_list(WorkItem::CreateWorkItemList()); | 85 std::unique_ptr<WorkItemList> work_item_list(WorkItem::CreateWorkItemList()); |
| 164 work_item_list->set_log_message( | 86 work_item_list->set_log_message( |
| 165 "Cleanup OS upgrade command and deprecated per-user registrations"); | 87 "Cleanup OS upgrade command and deprecated per-user registrations"); |
| 166 work_item_list->set_best_effort(true); | 88 work_item_list->set_best_effort(true); |
| 167 work_item_list->set_rollback_enabled(false); | 89 work_item_list->set_rollback_enabled(false); |
| 168 AddOsUpgradeWorkItems(installer_state, base::FilePath(), base::Version(), | 90 AddOsUpgradeWorkItems(installer_state, base::FilePath(), base::Version(), |
| 169 product, work_item_list.get()); | 91 product, work_item_list.get()); |
| 170 // Perform a best-effort cleanup of per-user keys. On system-level installs | 92 // 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 | 93 // 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 | 94 // considered that this was good enough (better than triggering Active Setup |
| 173 // for all users solely for this cleanup). | 95 // for all users solely for this cleanup). |
| 174 AddCleanupDeprecatedPerUserRegistrationsWorkItems(product, | 96 AddCleanupDeprecatedPerUserRegistrationsWorkItems(product, |
| 175 work_item_list.get()); | 97 work_item_list.get()); |
| 176 work_item_list->Do(); | 98 work_item_list->Do(); |
| 177 } | 99 } |
| 178 | 100 |
| 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() { | 101 void ClearRlzProductState() { |
| 190 const rlz_lib::AccessPoint points[] = {rlz_lib::CHROME_OMNIBOX, | 102 const rlz_lib::AccessPoint points[] = {rlz_lib::CHROME_OMNIBOX, |
| 191 rlz_lib::CHROME_HOME_PAGE, | 103 rlz_lib::CHROME_HOME_PAGE, |
| 192 rlz_lib::CHROME_APP_LIST, | 104 rlz_lib::CHROME_APP_LIST, |
| 193 rlz_lib::NO_ACCESS_POINT}; | 105 rlz_lib::NO_ACCESS_POINT}; |
| 194 | 106 |
| 195 rlz_lib::ClearProductState(rlz_lib::CHROME, points); | 107 rlz_lib::ClearProductState(rlz_lib::CHROME, points); |
| 196 | 108 |
| 197 // If chrome has been reactivated, clear all events for this brand as well. | 109 // If chrome has been reactivated, clear all events for this brand as well. |
| 198 base::string16 reactivation_brand_wide; | 110 base::string16 reactivation_brand_wide; |
| 199 if (GoogleUpdateSettings::GetReactivationBrand(&reactivation_brand_wide)) { | 111 if (GoogleUpdateSettings::GetReactivationBrand(&reactivation_brand_wide)) { |
| 200 std::string reactivation_brand(base::UTF16ToASCII(reactivation_brand_wide)); | 112 std::string reactivation_brand(base::UTF16ToASCII(reactivation_brand_wide)); |
| 201 rlz_lib::SupplementaryBranding branding(reactivation_brand.c_str()); | 113 rlz_lib::SupplementaryBranding branding(reactivation_brand.c_str()); |
| 202 rlz_lib::ClearProductState(rlz_lib::CHROME, points); | 114 rlz_lib::ClearProductState(rlz_lib::CHROME, points); |
| 203 } | 115 } |
| 204 } | 116 } |
| 205 | 117 |
| 206 // Returns whether setup.exe should be removed based on the original and | 118 // Removes all files from the installer directory. Returns false in case of an |
| 207 // installer states: | 119 // error. |
| 208 // * non-multi product being uninstalled: remove setup.exe | 120 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( | 121 base::FileEnumerator file_enumerator( |
| 245 installer_directory, | 122 installer_directory, |
| 246 false, | 123 false, |
| 247 base::FileEnumerator::FILES | base::FileEnumerator::DIRECTORIES); | 124 base::FileEnumerator::FILES | base::FileEnumerator::DIRECTORIES); |
| 248 bool success = true; | 125 bool success = true; |
| 249 | 126 |
| 250 base::FilePath setup_exe_base_name(installer::kSetupExe); | 127 base::FilePath setup_exe_base_name(installer::kSetupExe); |
| 251 | 128 |
| 252 for (base::FilePath to_delete = file_enumerator.Next(); !to_delete.empty(); | 129 for (base::FilePath to_delete = file_enumerator.Next(); !to_delete.empty(); |
| 253 to_delete = file_enumerator.Next()) { | 130 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(); | 131 VLOG(1) << "Deleting installer path " << to_delete.value(); |
| 258 if (!base::DeleteFile(to_delete, true)) { | 132 if (!base::DeleteFile(to_delete, true)) { |
| 259 LOG(ERROR) << "Failed to delete path: " << to_delete.value(); | 133 LOG(ERROR) << "Failed to delete path: " << to_delete.value(); |
| 260 success = false; | 134 success = false; |
| 261 } | 135 } |
| 262 } | 136 } |
| 263 | 137 |
| 264 return success; | 138 return success; |
| 265 } | 139 } |
| 266 | 140 |
| 267 // Kills all Chrome processes, immediately. | 141 // Kills all Chrome processes, immediately. |
| 268 void CloseAllChromeProcesses() { | 142 void CloseAllChromeProcesses() { |
| 269 base::CleanupProcesses(installer::kChromeExe, base::TimeDelta(), | 143 base::CleanupProcesses(installer::kChromeExe, base::TimeDelta(), |
| 270 content::RESULT_CODE_HUNG, NULL); | 144 content::RESULT_CODE_HUNG, NULL); |
| 271 base::CleanupProcesses(installer::kNaClExe, base::TimeDelta(), | 145 base::CleanupProcesses(installer::kNaClExe, base::TimeDelta(), |
| 272 content::RESULT_CODE_HUNG, NULL); | 146 content::RESULT_CODE_HUNG, NULL); |
| 273 } | 147 } |
| 274 | 148 |
| 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 | 149 // 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 | 150 // target |new_target_exe| instead. The non-empty args requirement is a |
| 313 // heuristic to determine whether a shortcut is "user-generated". This routine | 151 // heuristic to determine whether a shortcut is "user-generated". This routine |
| 314 // can only be called for user-level installs. | 152 // can only be called for user-level installs. |
| 315 void RetargetUserShortcutsWithArgs(const InstallerState& installer_state, | 153 void RetargetUserShortcutsWithArgs(const InstallerState& installer_state, |
| 316 const Product& product, | 154 const Product& product, |
| 317 const base::FilePath& old_target_exe, | 155 const base::FilePath& old_target_exe, |
| 318 const base::FilePath& new_target_exe) { | 156 const base::FilePath& new_target_exe) { |
| 319 if (installer_state.system_install()) { | 157 if (installer_state.system_install()) { |
| 320 NOTREACHED(); | 158 NOTREACHED(); |
| (...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 388 if (!base::IsDirectoryEmpty(path)) | 226 if (!base::IsDirectoryEmpty(path)) |
| 389 return DELETE_NOT_EMPTY; | 227 return DELETE_NOT_EMPTY; |
| 390 | 228 |
| 391 if (base::DeleteFile(path, true)) | 229 if (base::DeleteFile(path, true)) |
| 392 return DELETE_SUCCEEDED; | 230 return DELETE_SUCCEEDED; |
| 393 | 231 |
| 394 LOG(ERROR) << "Failed to delete folder: " << path.value(); | 232 LOG(ERROR) << "Failed to delete folder: " << path.value(); |
| 395 return DELETE_FAILED; | 233 return DELETE_FAILED; |
| 396 } | 234 } |
| 397 | 235 |
| 398 // Get the user data directory, which is *not* DIR_USER_DATA for Chrome Frame. | 236 // 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) { | 237 base::FilePath GetUserDataDir(const Product& product) { |
| 401 base::FilePath path; | 238 base::FilePath path; |
| 402 bool is_chrome_frame = product.is_chrome_frame(); | 239 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(); | 240 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; | 241 return path; |
| 411 } | 242 } |
| 412 | 243 |
| 413 // Creates a copy of the local state file and returns a path to the copy. | 244 // 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) { | 245 base::FilePath BackupLocalStateFile(const base::FilePath& user_data_dir) { |
| 415 base::FilePath backup; | 246 base::FilePath backup; |
| 416 base::FilePath state_file(user_data_dir.Append(chrome::kLocalStateFilename)); | 247 base::FilePath state_file(user_data_dir.Append(chrome::kLocalStateFilename)); |
| 417 if (!base::CreateTemporaryFile(&backup)) | 248 if (!base::CreateTemporaryFile(&backup)) |
| 418 LOG(ERROR) << "Failed to create temporary file for Local State."; | 249 LOG(ERROR) << "Failed to create temporary file for Local State."; |
| 419 else | 250 else |
| 420 base::CopyFile(state_file, backup); | 251 base::CopyFile(state_file, backup); |
| 421 return backup; | 252 return backup; |
| 422 } | 253 } |
| 423 | 254 |
| 424 // Deletes a given user data directory as well as the containing product | 255 // Deletes a given user data directory as well as the containing product |
| 425 // directories if they are empty (e.g., "Google\Chrome"). | 256 // directories if they are empty (e.g., "Google\Chrome"). |
| 426 DeleteResult DeleteUserDataDir(const base::FilePath& user_data_dir, | 257 DeleteResult DeleteUserDataDir(const base::FilePath& user_data_dir) { |
| 427 bool schedule_on_failure) { | |
| 428 if (user_data_dir.empty()) | 258 if (user_data_dir.empty()) |
| 429 return DELETE_SUCCEEDED; | 259 return DELETE_SUCCEEDED; |
| 430 | 260 |
| 431 DeleteResult result = DELETE_SUCCEEDED; | 261 DeleteResult result = DELETE_SUCCEEDED; |
| 432 VLOG(1) << "Deleting user profile " << user_data_dir.value(); | 262 VLOG(1) << "Deleting user profile " << user_data_dir.value(); |
| 433 if (!base::DeleteFile(user_data_dir, true)) { | 263 if (!base::DeleteFile(user_data_dir, true)) { |
| 434 LOG(ERROR) << "Failed to delete user profile dir: " | 264 LOG(ERROR) << "Failed to delete user profile dir: " |
| 435 << user_data_dir.value(); | 265 << user_data_dir.value(); |
| 436 if (schedule_on_failure) { | 266 result = DELETE_FAILED; |
| 437 ScheduleDirectoryForDeletion(user_data_dir); | |
| 438 result = DELETE_REQUIRES_REBOOT; | |
| 439 } else { | |
| 440 result = DELETE_FAILED; | |
| 441 } | |
| 442 } | 267 } |
| 443 | 268 |
| 444 if (result == DELETE_REQUIRES_REBOOT) { | 269 const base::FilePath product_dir1(user_data_dir.DirName()); |
| 445 ScheduleParentAndGrandparentForDeletion(user_data_dir); | 270 if (!product_dir1.empty() && |
| 446 } else { | 271 DeleteEmptyDir(product_dir1) == DELETE_SUCCEEDED) { |
| 447 const base::FilePath product_dir1(user_data_dir.DirName()); | 272 const base::FilePath product_dir2(product_dir1.DirName()); |
| 448 if (!product_dir1.empty() && | 273 if (!product_dir2.empty()) |
| 449 DeleteEmptyDir(product_dir1) == DELETE_SUCCEEDED) { | 274 DeleteEmptyDir(product_dir2); |
| 450 const base::FilePath product_dir2(product_dir1.DirName()); | |
| 451 if (!product_dir2.empty()) | |
| 452 DeleteEmptyDir(product_dir2); | |
| 453 } | |
| 454 } | 275 } |
| 455 | 276 |
| 456 return result; | 277 return result; |
| 457 } | 278 } |
| 458 | 279 |
| 459 // Moves setup to a temporary file, outside of the install folder. Also attempts | 280 // 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 | 281 // 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 | 282 // 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. | 283 // install directory, deletion will fail as a result of the open handle. |
| 463 bool MoveSetupOutOfInstallFolder(const InstallerState& installer_state, | 284 bool MoveSetupOutOfInstallFolder(const InstallerState& installer_state, |
| (...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 545 if (!installer_directory.empty() && | 366 if (!installer_directory.empty() && |
| 546 (to_delete == installer_directory || | 367 (to_delete == installer_directory || |
| 547 installer_directory.IsParent(to_delete) || | 368 installer_directory.IsParent(to_delete) || |
| 548 to_delete.IsParent(installer_directory))) { | 369 to_delete.IsParent(installer_directory))) { |
| 549 continue; | 370 continue; |
| 550 } | 371 } |
| 551 | 372 |
| 552 VLOG(1) << "Deleting install path " << to_delete.value(); | 373 VLOG(1) << "Deleting install path " << to_delete.value(); |
| 553 if (!base::DeleteFile(to_delete, true)) { | 374 if (!base::DeleteFile(to_delete, true)) { |
| 554 LOG(ERROR) << "Failed to delete path (1st try): " << to_delete.value(); | 375 LOG(ERROR) << "Failed to delete path (1st try): " << to_delete.value(); |
| 555 if (installer_state.FindProduct(BrowserDistribution::CHROME_FRAME)) { | 376 // Try closing any running Chrome processes and deleting files once |
| 556 // We don't try killing Chrome processes for Chrome Frame builds since | 377 // again. |
| 557 // that is unlikely to help. Instead, schedule files for deletion and | 378 CloseAllChromeProcesses(); |
| 558 // return a value that will trigger a reboot prompt. | 379 if (!base::DeleteFile(to_delete, true)) { |
| 559 base::FileEnumerator::FileInfo find_info = file_enumerator.GetInfo(); | 380 LOG(ERROR) << "Failed to delete path (2nd try): " << to_delete.value(); |
| 560 if (find_info.IsDirectory()) | 381 result = DELETE_FAILED; |
| 561 ScheduleDirectoryForDeletion(to_delete); | 382 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 } | 383 } |
| 576 } | 384 } |
| 577 } | 385 } |
| 578 | 386 |
| 579 return result; | 387 return result; |
| 580 } | 388 } |
| 581 | 389 |
| 582 // This method checks if Chrome is currently running or if the user has | 390 // This method checks if Chrome is currently running or if the user has |
| 583 // cancelled the uninstall operation by clicking Cancel on the confirmation | 391 // cancelled the uninstall operation by clicking Cancel on the confirmation |
| 584 // box that Chrome pops up. | 392 // box that Chrome pops up. |
| (...skipping 24 matching lines...) Expand all Loading... |
| 609 | 417 |
| 610 if (exit_code == chrome::RESULT_CODE_UNINSTALL_DELETE_PROFILE) | 418 if (exit_code == chrome::RESULT_CODE_UNINSTALL_DELETE_PROFILE) |
| 611 return installer::UNINSTALL_DELETE_PROFILE; | 419 return installer::UNINSTALL_DELETE_PROFILE; |
| 612 } else { | 420 } else { |
| 613 PLOG(ERROR) << "Failed to launch chrome.exe for uninstall confirmation."; | 421 PLOG(ERROR) << "Failed to launch chrome.exe for uninstall confirmation."; |
| 614 } | 422 } |
| 615 | 423 |
| 616 return installer::UNINSTALL_CONFIRMED; | 424 return installer::UNINSTALL_CONFIRMED; |
| 617 } | 425 } |
| 618 | 426 |
| 619 bool ShouldDeleteProfile(const InstallerState& installer_state, | 427 bool ShouldDeleteProfile(const base::CommandLine& cmd_line, |
| 620 const base::CommandLine& cmd_line, | 428 InstallStatus status) { |
| 621 InstallStatus status, | 429 return status == installer::UNINSTALL_DELETE_PROFILE || |
| 622 const Product& product) { | 430 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 } | 431 } |
| 639 | 432 |
| 640 // Removes XP-era filetype registration making Chrome the default browser. | 433 // Removes XP-era filetype registration making Chrome the default browser. |
| 641 // MSDN (see http://msdn.microsoft.com/library/windows/desktop/cc144148.aspx) | 434 // MSDN (see http://msdn.microsoft.com/library/windows/desktop/cc144148.aspx) |
| 642 // tells us not to do this, but certain applications break following | 435 // tells us not to do this, but certain applications break following |
| 643 // uninstallation if we don't. | 436 // uninstallation if we don't. |
| 644 void RemoveFiletypeRegistration(const InstallerState& installer_state, | 437 void RemoveFiletypeRegistration(const InstallerState& installer_state, |
| 645 HKEY root, | 438 HKEY root, |
| 646 const base::string16& browser_entry_suffix) { | 439 const base::string16& browser_entry_suffix) { |
| 647 base::string16 classes_path(ShellUtil::kRegClasses); | 440 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 | 519 // 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, | 520 // a work items list as usual because of different paths based on conditionals, |
| 728 // but otherwise respects the no rollback/best effort uninstall mentality. | 521 // 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 | 522 // This will only apply for system-level installs of Chrome/Chromium and will be |
| 730 // a no-op for all other types of installs. | 523 // a no-op for all other types of installs. |
| 731 void UninstallActiveSetupEntries(const InstallerState& installer_state, | 524 void UninstallActiveSetupEntries(const InstallerState& installer_state, |
| 732 const Product& product) { | 525 const Product& product) { |
| 733 VLOG(1) << "Uninstalling registry entries for Active Setup."; | 526 VLOG(1) << "Uninstalling registry entries for Active Setup."; |
| 734 BrowserDistribution* distribution = product.distribution(); | 527 BrowserDistribution* distribution = product.distribution(); |
| 735 | 528 |
| 736 if (!product.is_chrome() || !installer_state.system_install()) { | 529 if (!installer_state.system_install()) { |
| 737 const char* install_level = | 530 const char* install_level = |
| 738 installer_state.system_install() ? "system" : "user"; | 531 installer_state.system_install() ? "system" : "user"; |
| 739 VLOG(1) << "No Active Setup processing to do for " << install_level | 532 VLOG(1) << "No Active Setup processing to do for " << install_level |
| 740 << "-level " << distribution->GetDisplayName(); | 533 << "-level " << distribution->GetDisplayName(); |
| 741 return; | 534 return; |
| 742 } | 535 } |
| 743 | 536 |
| 744 const base::string16 active_setup_path( | 537 const base::string16 active_setup_path( |
| 745 InstallUtil::GetActiveSetupPath(distribution)); | 538 InstallUtil::GetActiveSetupPath(distribution)); |
| 746 InstallUtil::DeleteRegistryKey(HKEY_LOCAL_MACHINE, active_setup_path, | 539 InstallUtil::DeleteRegistryKey(HKEY_LOCAL_MACHINE, active_setup_path, |
| (...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 796 #endif | 589 #endif |
| 797 InstallUtil::DeleteRegistryKey(HKEY_CURRENT_USER, | 590 InstallUtil::DeleteRegistryKey(HKEY_CURRENT_USER, |
| 798 kRegistryFinchListPath, | 591 kRegistryFinchListPath, |
| 799 0); // wow64_access | 592 0); // wow64_access |
| 800 } | 593 } |
| 801 | 594 |
| 802 // Removes the persistent state for |distribution| for the current user. Note: | 595 // 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 | 596 // this will not remove the state for users other than the one uninstalling |
| 804 // Chrome on a system-level install; see RemoveBlacklistState for details. | 597 // Chrome on a system-level install; see RemoveBlacklistState for details. |
| 805 void RemoveDistributionRegistryState(BrowserDistribution* distribution) { | 598 void RemoveDistributionRegistryState(BrowserDistribution* distribution) { |
| 806 // Binaries do not store per-user state. | 599 static const base::char16* const kKeysToPreserve[] = { |
| 807 if (distribution->GetType() != BrowserDistribution::CHROME_BINARIES) { | 600 L"Extensions", L"NativeMessagingHosts", |
| 808 static const base::char16* const kKeysToPreserve[] = { | 601 }; |
| 809 L"Extensions", | 602 // Delete the contents of the distribution key except for those parts used by |
| 810 L"NativeMessagingHosts", | 603 // outsiders to configure Chrome. |
| 811 }; | 604 DeleteRegistryKeyPartial( |
| 812 // Delete the contents of the distribution key except for those parts used | 605 HKEY_CURRENT_USER, distribution->GetRegistryPath(), |
| 813 // by outsiders to configure Chrome. | 606 std::vector<base::string16>( |
| 814 DeleteRegistryKeyPartial( | 607 &kKeysToPreserve[0], |
| 815 HKEY_CURRENT_USER, distribution->GetRegistryPath(), | 608 &kKeysToPreserve[arraysize(kKeysToPreserve) - 1])); |
| 816 std::vector<base::string16>( | |
| 817 &kKeysToPreserve[0], | |
| 818 &kKeysToPreserve[arraysize(kKeysToPreserve) - 1])); | |
| 819 } | |
| 820 } | 609 } |
| 821 | 610 |
| 822 } // namespace | 611 } // namespace |
| 823 | 612 |
| 824 DeleteResult DeleteChromeDirectoriesIfEmpty( | 613 DeleteResult DeleteChromeDirectoriesIfEmpty( |
| 825 const base::FilePath& application_directory) { | 614 const base::FilePath& application_directory) { |
| 826 DeleteResult result(DeleteEmptyDir(application_directory)); | 615 DeleteResult result(DeleteEmptyDir(application_directory)); |
| 827 if (result == DELETE_SUCCEEDED) { | 616 if (result == DELETE_SUCCEEDED) { |
| 828 // Now check and delete if the parent directories are empty | 617 // Now check and delete if the parent directories are empty |
| 829 // For example Google\Chrome or Chromium | 618 // 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, | 823 const base::FilePath& setup_exe, |
| 1035 const Product& product, | 824 const Product& product, |
| 1036 bool remove_all, | 825 bool remove_all, |
| 1037 bool force_uninstall, | 826 bool force_uninstall, |
| 1038 const base::CommandLine& cmd_line) { | 827 const base::CommandLine& cmd_line) { |
| 1039 InstallStatus status = installer::UNINSTALL_CONFIRMED; | 828 InstallStatus status = installer::UNINSTALL_CONFIRMED; |
| 1040 BrowserDistribution* browser_dist = product.distribution(); | 829 BrowserDistribution* browser_dist = product.distribution(); |
| 1041 const base::FilePath chrome_exe( | 830 const base::FilePath chrome_exe( |
| 1042 installer_state.target_path().Append(installer::kChromeExe)); | 831 installer_state.target_path().Append(installer::kChromeExe)); |
| 1043 | 832 |
| 1044 bool is_chrome = product.is_chrome(); | |
| 1045 | |
| 1046 VLOG(1) << "UninstallProduct: " << browser_dist->GetDisplayName(); | 833 VLOG(1) << "UninstallProduct: " << browser_dist->GetDisplayName(); |
| 1047 | 834 |
| 1048 if (force_uninstall) { | 835 if (force_uninstall) { |
| 1049 // Since --force-uninstall command line option is used, we are going to | 836 // Since --force-uninstall command line option is used, we are going to |
| 1050 // do silent uninstall. Try to close all running Chrome instances. | 837 // do silent uninstall. Try to close all running Chrome instances. |
| 1051 // NOTE: We don't do this for Chrome Frame. | 838 CloseAllChromeProcesses(); |
| 1052 if (is_chrome) | 839 } else { |
| 1053 CloseAllChromeProcesses(); | |
| 1054 } else if (is_chrome) { | |
| 1055 // no --force-uninstall so lets show some UI dialog boxes. | 840 // no --force-uninstall so lets show some UI dialog boxes. |
| 1056 status = IsChromeActiveOrUserCancelled(installer_state, product); | 841 status = IsChromeActiveOrUserCancelled(installer_state, product); |
| 1057 if (status != installer::UNINSTALL_CONFIRMED && | 842 if (status != installer::UNINSTALL_CONFIRMED && |
| 1058 status != installer::UNINSTALL_DELETE_PROFILE) | 843 status != installer::UNINSTALL_DELETE_PROFILE) |
| 1059 return status; | 844 return status; |
| 1060 | 845 |
| 1061 const base::string16 suffix( | 846 const base::string16 suffix( |
| 1062 ShellUtil::GetCurrentInstallationSuffix(browser_dist, chrome_exe)); | 847 ShellUtil::GetCurrentInstallationSuffix(browser_dist, chrome_exe)); |
| 1063 | 848 |
| 1064 // Check if we need admin rights to cleanup HKLM (the conditions for | 849 // 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); | 867 new_cmd.AppendSwitch(installer::switches::kRemoveChromeRegistration); |
| 1083 if (!suffix.empty()) { | 868 if (!suffix.empty()) { |
| 1084 new_cmd.AppendSwitchNative( | 869 new_cmd.AppendSwitchNative( |
| 1085 installer::switches::kRegisterChromeBrowserSuffix, suffix); | 870 installer::switches::kRegisterChromeBrowserSuffix, suffix); |
| 1086 } | 871 } |
| 1087 DWORD exit_code = installer::UNKNOWN_STATUS; | 872 DWORD exit_code = installer::UNKNOWN_STATUS; |
| 1088 InstallUtil::ExecuteExeAsAdmin(new_cmd, &exit_code); | 873 InstallUtil::ExecuteExeAsAdmin(new_cmd, &exit_code); |
| 1089 } | 874 } |
| 1090 } | 875 } |
| 1091 | 876 |
| 1092 if (is_chrome) { | 877 // 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 | 878 // 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 | 879 // in case of errors. |
| 1095 // in case of errors. | 880 ClearRlzProductState(); |
| 1096 ClearRlzProductState(); | |
| 1097 | 881 |
| 1098 auto_launch_util::DisableBackgroundStartAtLogin(); | 882 auto_launch_util::DisableBackgroundStartAtLogin(); |
| 1099 | 883 |
| 1100 // If user-level chrome is self-destructing as a result of encountering a | 884 // If user-level chrome is self-destructing as a result of encountering a |
| 1101 // system-level chrome, retarget owned non-default shortcuts (app shortcuts, | 885 // system-level chrome, retarget owned non-default shortcuts (app shortcuts, |
| 1102 // profile shortcuts, etc.) to the system-level chrome. | 886 // profile shortcuts, etc.) to the system-level chrome. |
| 1103 if (cmd_line.HasSwitch(installer::switches::kSelfDestruct) && | 887 if (cmd_line.HasSwitch(installer::switches::kSelfDestruct) && |
| 1104 !installer_state.system_install()) { | 888 !installer_state.system_install()) { |
| 1105 const base::FilePath system_chrome_path( | 889 const base::FilePath system_chrome_path( |
| 1106 GetChromeInstallPath(true, browser_dist). | 890 GetChromeInstallPath(true, browser_dist).Append(installer::kChromeExe)); |
| 1107 Append(installer::kChromeExe)); | 891 VLOG(1) << "Retargeting user-generated Chrome shortcuts."; |
| 1108 VLOG(1) << "Retargeting user-generated Chrome shortcuts."; | 892 if (base::PathExists(system_chrome_path)) { |
| 1109 if (base::PathExists(system_chrome_path)) { | 893 RetargetUserShortcutsWithArgs(installer_state, product, chrome_exe, |
| 1110 RetargetUserShortcutsWithArgs(installer_state, product, chrome_exe, | 894 system_chrome_path); |
| 1111 system_chrome_path); | 895 } else { |
| 1112 } else { | 896 LOG(ERROR) << "Retarget failed: system-level Chrome not found."; |
| 1113 LOG(ERROR) << "Retarget failed: system-level Chrome not found."; | |
| 1114 } | |
| 1115 } | 897 } |
| 898 } |
| 1116 | 899 |
| 1117 DeleteShortcuts(installer_state, product, chrome_exe); | 900 DeleteShortcuts(installer_state, product, chrome_exe); |
| 1118 } | |
| 1119 | 901 |
| 1120 // Delete the registry keys (Uninstall key and Version key). | 902 // Delete the registry keys (Uninstall key and Version key). |
| 1121 HKEY reg_root = installer_state.root_key(); | 903 HKEY reg_root = installer_state.root_key(); |
| 1122 | 904 |
| 1123 // Note that we must retrieve the distribution-specific data before deleting | 905 // Note that we must retrieve the distribution-specific data before deleting |
| 1124 // product.GetVersionKey(). | 906 // product.GetVersionKey(). |
| 1125 base::string16 distribution_data(browser_dist->GetDistributionData(reg_root)); | 907 base::string16 distribution_data(browser_dist->GetDistributionData(reg_root)); |
| 1126 | 908 |
| 1127 // Remove Control Panel uninstall link. | 909 // Remove Control Panel uninstall link. |
| 1128 if (product.ShouldCreateUninstallEntry()) { | 910 if (product.ShouldCreateUninstallEntry()) { |
| 1129 InstallUtil::DeleteRegistryKey( | 911 InstallUtil::DeleteRegistryKey( |
| 1130 reg_root, browser_dist->GetUninstallRegPath(), KEY_WOW64_32KEY); | 912 reg_root, browser_dist->GetUninstallRegPath(), KEY_WOW64_32KEY); |
| 1131 } | 913 } |
| 1132 | 914 |
| 1133 // Remove Omaha product key. | 915 // Remove Omaha product key. |
| 1134 InstallUtil::DeleteRegistryKey( | 916 InstallUtil::DeleteRegistryKey( |
| 1135 reg_root, browser_dist->GetVersionKey(), KEY_WOW64_32KEY); | 917 reg_root, browser_dist->GetVersionKey(), KEY_WOW64_32KEY); |
| 1136 | 918 |
| 1137 // Also try to delete the MSI value in the ClientState key (it might not be | 919 // 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 | 920 // 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 | 921 // rapid reinstall might result in stale values from the old ClientState key |
| 1140 // being picked up on reinstall. | 922 // being picked up on reinstall. |
| 1141 product.SetMsiMarker(installer_state.system_install(), false); | 923 product.SetMsiMarker(installer_state.system_install(), false); |
| 1142 | 924 |
| 1143 InstallStatus ret = installer::UNKNOWN_STATUS; | 925 InstallStatus ret = installer::UNKNOWN_STATUS; |
| 1144 | 926 |
| 1145 if (is_chrome) { | 927 const base::string16 suffix( |
| 1146 const base::string16 suffix( | 928 ShellUtil::GetCurrentInstallationSuffix(browser_dist, chrome_exe)); |
| 1147 ShellUtil::GetCurrentInstallationSuffix(browser_dist, chrome_exe)); | |
| 1148 | 929 |
| 1149 // Remove all Chrome registration keys. | 930 // Remove all Chrome registration keys. |
| 1150 // Registration data is put in HKCU for both system level and user level | 931 // Registration data is put in HKCU for both system level and user level |
| 1151 // installs. | 932 // installs. |
| 933 DeleteChromeRegistrationKeys(installer_state, browser_dist, HKEY_CURRENT_USER, |
| 934 suffix, &ret); |
| 935 |
| 936 // If the user's Chrome is registered with a suffix: it is possible that old |
| 937 // unsuffixed registrations were left in HKCU (e.g. if this install was |
| 938 // previously installed with no suffix in HKCU (old suffix rules if the user |
| 939 // is not an admin (or declined UAC at first run)) and later had to be |
| 940 // suffixed when fully registered in HKLM (e.g. when later making Chrome |
| 941 // default through the UI)). |
| 942 // Remove remaining HKCU entries with no suffix if any. |
| 943 if (!suffix.empty()) { |
| 1152 DeleteChromeRegistrationKeys(installer_state, browser_dist, | 944 DeleteChromeRegistrationKeys(installer_state, browser_dist, |
| 1153 HKEY_CURRENT_USER, suffix, &ret); | 945 HKEY_CURRENT_USER, base::string16(), &ret); |
| 1154 | 946 |
| 1155 // If the user's Chrome is registered with a suffix: it is possible that old | 947 // For similar reasons it is possible in very few installs (from |
| 1156 // unsuffixed registrations were left in HKCU (e.g. if this install was | 948 // 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 | 949 // 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 | 950 base::string16 old_style_suffix; |
| 1159 // suffixed when fully registered in HKLM (e.g. when later making Chrome | 951 if (ShellUtil::GetOldUserSpecificRegistrySuffix(&old_style_suffix) && |
| 1160 // default through the UI)). | 952 suffix != old_style_suffix) { |
| 1161 // Remove remaining HKCU entries with no suffix if any. | |
| 1162 if (!suffix.empty()) { | |
| 1163 DeleteChromeRegistrationKeys(installer_state, browser_dist, | 953 DeleteChromeRegistrationKeys(installer_state, browser_dist, |
| 1164 HKEY_CURRENT_USER, base::string16(), &ret); | 954 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 } | 955 } |
| 1176 | 956 |
| 1177 // Chrome is registered in HKLM for all system-level installs and for | 957 // 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. | 958 // user-level installs for which Chrome has been made the default browser. |
| 1179 // Always remove the HKLM registration for system-level installs. For | 959 // 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 | 960 // 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 | 961 // self destruct following the installation of a system-level Chrome |
| 1182 // (because the system-level Chrome owns the HKLM registration now), and 2) | 962 // (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 | 963 // this user has made Chrome their default browser (i.e. has shell |
| 1184 // integration entries registered with |suffix| (note: |suffix| will be the | 964 // integration entries registered with |suffix| (note: |suffix| will be the |
| (...skipping 18 matching lines...) Expand all Loading... |
| 1203 | 983 |
| 1204 UninstallFirewallRules(browser_dist, chrome_exe); | 984 UninstallFirewallRules(browser_dist, chrome_exe); |
| 1205 | 985 |
| 1206 RemoveBlacklistState(); | 986 RemoveBlacklistState(); |
| 1207 | 987 |
| 1208 // Notify the shell that associations have changed since Chrome was likely | 988 // Notify the shell that associations have changed since Chrome was likely |
| 1209 // unregistered. | 989 // unregistered. |
| 1210 SHChangeNotify(SHCNE_ASSOCCHANGED, SHCNF_IDLIST, NULL, NULL); | 990 SHChangeNotify(SHCNE_ASSOCCHANGED, SHCNF_IDLIST, NULL, NULL); |
| 1211 } | 991 } |
| 1212 | 992 |
| 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) | 993 // Get the state of the installed product (if any) |
| 1217 const ProductState* product_state = | 994 const ProductState* product_state = |
| 1218 original_state.GetProductState(installer_state.system_install(), | 995 original_state.GetProductState(installer_state.system_install(), |
| 1219 browser_dist->GetType()); | 996 browser_dist->GetType()); |
| 1220 | 997 |
| 1221 // Delete shared registry keys as well (these require admin rights) if | 998 // Delete shared registry keys as well (these require admin rights) if |
| 1222 // remove_all option is specified. | 999 // remove_all option is specified. |
| 1223 if (remove_all) { | 1000 if (remove_all) { |
| 1224 if (!InstallUtil::IsChromeSxSProcess() && is_chrome) { | 1001 if (!InstallUtil::IsChromeSxSProcess()) { |
| 1225 // Delete media player registry key that exists only in HKLM. | 1002 // 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 | 1003 // 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); | 1004 base::string16 reg_path(installer::kMediaPlayerRegPath); |
| 1229 reg_path.push_back(base::FilePath::kSeparators[0]); | 1005 reg_path.push_back(base::FilePath::kSeparators[0]); |
| 1230 reg_path.append(installer::kChromeExe); | 1006 reg_path.append(installer::kChromeExe); |
| 1231 InstallUtil::DeleteRegistryKey(HKEY_LOCAL_MACHINE, reg_path, | 1007 InstallUtil::DeleteRegistryKey(HKEY_LOCAL_MACHINE, reg_path, |
| 1232 WorkItem::kWow64Default); | 1008 WorkItem::kWow64Default); |
| 1233 | 1009 |
| 1234 // Remove the event log provider registration as we are going to delete | 1010 // Remove the event log provider registration as we are going to delete |
| 1235 // the file which serves the resources anyways. | 1011 // the file which serves the resources anyways. |
| 1236 DeRegisterEventLogProvider(); | 1012 DeRegisterEventLogProvider(); |
| 1237 } | 1013 } |
| 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 } | 1014 } |
| 1268 | 1015 |
| 1269 // Finally delete all the files from Chrome folder after moving setup.exe | 1016 // Finally delete all the files from Chrome folder after moving setup.exe |
| 1270 // and the user's Local State to a temp location. | 1017 // and the user's Local State to a temp location. |
| 1271 bool delete_profile = ShouldDeleteProfile(installer_state, cmd_line, status, | 1018 bool delete_profile = ShouldDeleteProfile(cmd_line, status); |
| 1272 product); | |
| 1273 ret = installer::UNINSTALL_SUCCESSFUL; | 1019 ret = installer::UNINSTALL_SUCCESSFUL; |
| 1274 | 1020 |
| 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)); | 1021 base::FilePath user_data_dir(GetUserDataDir(product)); |
| 1279 base::FilePath backup_state_file; | 1022 base::FilePath backup_state_file; |
| 1280 if (!user_data_dir.empty()) { | 1023 if (!user_data_dir.empty()) { |
| 1281 backup_state_file = BackupLocalStateFile(user_data_dir); | 1024 backup_state_file = BackupLocalStateFile(user_data_dir); |
| 1282 } else { | 1025 } else { |
| 1283 LOG(ERROR) << "Could not retrieve the user's profile directory."; | 1026 LOG(ERROR) << "Could not retrieve the user's profile directory."; |
| 1284 ret = installer::UNINSTALL_FAILED; | 1027 ret = installer::UNINSTALL_FAILED; |
| 1285 delete_profile = false; | 1028 delete_profile = false; |
| 1286 } | 1029 } |
| 1287 | 1030 |
| 1288 if (!installer_state.is_multi_install() || product.is_chrome_binaries()) { | 1031 DeleteResult delete_result = DeleteChromeFilesAndFolders( |
| 1289 DeleteResult delete_result = DeleteChromeFilesAndFolders( | 1032 installer_state, base::MakeAbsoluteFilePath(setup_exe)); |
| 1290 installer_state, base::MakeAbsoluteFilePath(setup_exe)); | 1033 if (delete_result == DELETE_FAILED) |
| 1291 if (delete_result == DELETE_FAILED) { | 1034 ret = installer::UNINSTALL_FAILED; |
| 1292 ret = installer::UNINSTALL_FAILED; | 1035 else if (delete_result == DELETE_REQUIRES_REBOOT) |
| 1293 } else if (delete_result == DELETE_REQUIRES_REBOOT) { | 1036 ret = installer::UNINSTALL_REQUIRES_REBOOT; |
| 1294 ret = installer::UNINSTALL_REQUIRES_REBOOT; | |
| 1295 } | |
| 1296 } | |
| 1297 | 1037 |
| 1298 if (delete_profile) { | 1038 if (delete_profile) { |
| 1299 DeleteUserDataDir(user_data_dir, product.is_chrome_frame()); | 1039 DeleteUserDataDir(user_data_dir); |
| 1300 RemoveDistributionRegistryState(browser_dist); | 1040 RemoveDistributionRegistryState(browser_dist); |
| 1301 } | 1041 } |
| 1302 | 1042 |
| 1303 if (!force_uninstall && product_state) { | 1043 if (!force_uninstall && product_state) { |
| 1304 VLOG(1) << "Uninstallation complete. Launching post-uninstall operations."; | 1044 VLOG(1) << "Uninstallation complete. Launching post-uninstall operations."; |
| 1305 browser_dist->DoPostUninstallOperations(product_state->version(), | 1045 browser_dist->DoPostUninstallOperations(product_state->version(), |
| 1306 backup_state_file, distribution_data); | 1046 backup_state_file, distribution_data); |
| 1307 } | 1047 } |
| 1308 | 1048 |
| 1309 // Try and delete the preserved local state once the post-install | 1049 // 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."; | 1068 LOG(ERROR) << "No installation destination path."; |
| 1329 *uninstall_status = UNINSTALL_FAILED; | 1069 *uninstall_status = UNINSTALL_FAILED; |
| 1330 return; | 1070 return; |
| 1331 } | 1071 } |
| 1332 if (!target_path.IsParent(base::MakeAbsoluteFilePath(setup_exe))) { | 1072 if (!target_path.IsParent(base::MakeAbsoluteFilePath(setup_exe))) { |
| 1333 VLOG(1) << "setup.exe is not in target path. Skipping installer cleanup."; | 1073 VLOG(1) << "setup.exe is not in target path. Skipping installer cleanup."; |
| 1334 return; | 1074 return; |
| 1335 } | 1075 } |
| 1336 base::FilePath install_directory(setup_exe.DirName()); | 1076 base::FilePath install_directory(setup_exe.DirName()); |
| 1337 | 1077 |
| 1338 bool remove_setup = CheckShouldRemoveSetup(original_state, installer_state); | 1078 // In order to be able to remove the folder in which we're running, we need to |
| 1339 | 1079 // move setup.exe out of the install folder. |
| 1340 if (remove_setup) { | 1080 // TODO(tommi): What if the temp folder is on a different volume? |
| 1341 // In order to be able to remove the folder in which we're running, we | 1081 MoveSetupOutOfInstallFolder(installer_state, setup_exe); |
| 1342 // need to move setup.exe out of the install folder. | |
| 1343 // TODO(tommi): What if the temp folder is on a different volume? | |
| 1344 MoveSetupOutOfInstallFolder(installer_state, setup_exe); | |
| 1345 } | |
| 1346 | 1082 |
| 1347 // Remove files from "...\<product>\Application\<version>\Installer" | 1083 // Remove files from "...\<product>\Application\<version>\Installer" |
| 1348 if (!RemoveInstallerFiles(install_directory, remove_setup)) { | 1084 if (!RemoveInstallerFiles(install_directory)) { |
| 1349 *uninstall_status = UNINSTALL_FAILED; | 1085 *uninstall_status = UNINSTALL_FAILED; |
| 1350 return; | 1086 return; |
| 1351 } | 1087 } |
| 1352 | 1088 |
| 1353 if (!remove_setup) | |
| 1354 return; | |
| 1355 | |
| 1356 // Try to remove the empty directory hierarchy. | 1089 // Try to remove the empty directory hierarchy. |
| 1357 | 1090 |
| 1358 // Delete "...\<product>\Application\<version>\Installer" | 1091 // Delete "...\<product>\Application\<version>\Installer" |
| 1359 if (DeleteEmptyDir(install_directory) != DELETE_SUCCEEDED) { | 1092 if (DeleteEmptyDir(install_directory) != DELETE_SUCCEEDED) { |
| 1360 *uninstall_status = UNINSTALL_FAILED; | 1093 *uninstall_status = UNINSTALL_FAILED; |
| 1361 return; | 1094 return; |
| 1362 } | 1095 } |
| 1363 | 1096 |
| 1364 // Delete "...\<product>\Application\<version>" | 1097 // Delete "...\<product>\Application\<version>" |
| 1365 DeleteResult delete_result = DeleteEmptyDir(install_directory.DirName()); | 1098 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 | 1110 // If we need a reboot to continue, schedule the parent directories for |
| 1378 // deletion unconditionally. If they are not empty, the session manager | 1111 // deletion unconditionally. If they are not empty, the session manager |
| 1379 // will not delete them on reboot. | 1112 // will not delete them on reboot. |
| 1380 ScheduleParentAndGrandparentForDeletion(target_path); | 1113 ScheduleParentAndGrandparentForDeletion(target_path); |
| 1381 } else if (DeleteChromeDirectoriesIfEmpty(target_path) == DELETE_FAILED) { | 1114 } else if (DeleteChromeDirectoriesIfEmpty(target_path) == DELETE_FAILED) { |
| 1382 *uninstall_status = UNINSTALL_FAILED; | 1115 *uninstall_status = UNINSTALL_FAILED; |
| 1383 } | 1116 } |
| 1384 } | 1117 } |
| 1385 | 1118 |
| 1386 } // namespace installer | 1119 } // namespace installer |
| OLD | NEW |