OLD | NEW |
---|---|
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 // | 4 // |
5 // This file defines the methods useful for uninstalling Chrome. | 5 // This file defines the methods useful for uninstalling Chrome. |
6 | 6 |
7 #include "chrome/installer/setup/uninstall.h" | 7 #include "chrome/installer/setup/uninstall.h" |
8 | 8 |
9 #include <windows.h> | 9 #include <windows.h> |
10 #include <stddef.h> | 10 #include <stddef.h> |
11 #include <stdint.h> | 11 #include <stdint.h> |
12 | 12 |
13 #include <memory> | |
14 #include <string> | |
13 #include <vector> | 15 #include <vector> |
14 | 16 |
15 #include "base/base_paths.h" | 17 #include "base/base_paths.h" |
16 #include "base/bind.h" | 18 #include "base/bind.h" |
17 #include "base/files/file_enumerator.h" | 19 #include "base/files/file_enumerator.h" |
18 #include "base/files/file_util.h" | 20 #include "base/files/file_util.h" |
19 #include "base/macros.h" | 21 #include "base/macros.h" |
20 #include "base/path_service.h" | 22 #include "base/path_service.h" |
21 #include "base/process/kill.h" | 23 #include "base/process/kill.h" |
22 #include "base/strings/string16.h" | 24 #include "base/strings/string16.h" |
23 #include "base/strings/string_number_conversions.h" | 25 #include "base/strings/string_number_conversions.h" |
24 #include "base/strings/string_util.h" | 26 #include "base/strings/string_util.h" |
25 #include "base/strings/utf_string_conversions.h" | 27 #include "base/strings/utf_string_conversions.h" |
26 #include "base/win/registry.h" | 28 #include "base/win/registry.h" |
27 #include "base/win/scoped_handle.h" | 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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 |
OLD | NEW |