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

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

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

Powered by Google App Engine
This is Rietveld 408576698