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

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

Issue 2589753002: Remove multi-install from chrome/installer/setup. (Closed)
Patch Set: revert util/product changes for now Created 4 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 // 4 //
5 // 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
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
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
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
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
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
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
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
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
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
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
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
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698