OLD | NEW |
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2011 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 "base/file_util.h" | 9 #include "base/file_util.h" |
10 #include "base/path_service.h" | 10 #include "base/path_service.h" |
(...skipping 11 matching lines...) Expand all Loading... |
22 #include "chrome/installer/setup/setup_constants.h" | 22 #include "chrome/installer/setup/setup_constants.h" |
23 #include "chrome/installer/util/browser_distribution.h" | 23 #include "chrome/installer/util/browser_distribution.h" |
24 #include "chrome/installer/util/channel_info.h" | 24 #include "chrome/installer/util/channel_info.h" |
25 #include "chrome/installer/util/delete_after_reboot_helper.h" | 25 #include "chrome/installer/util/delete_after_reboot_helper.h" |
26 #include "chrome/installer/util/google_update_constants.h" | 26 #include "chrome/installer/util/google_update_constants.h" |
27 #include "chrome/installer/util/helper.h" | 27 #include "chrome/installer/util/helper.h" |
28 #include "chrome/installer/util/install_util.h" | 28 #include "chrome/installer/util/install_util.h" |
29 #include "chrome/installer/util/installation_state.h" | 29 #include "chrome/installer/util/installation_state.h" |
30 #include "chrome/installer/util/installer_state.h" | 30 #include "chrome/installer/util/installer_state.h" |
31 #include "chrome/installer/util/logging_installer.h" | 31 #include "chrome/installer/util/logging_installer.h" |
32 #include "chrome/installer/util/package_properties.h" | |
33 #include "chrome/installer/util/shell_util.h" | 32 #include "chrome/installer/util/shell_util.h" |
34 #include "chrome/installer/util/util_constants.h" | 33 #include "chrome/installer/util/util_constants.h" |
35 | 34 |
36 // Build-time generated include file. | 35 // Build-time generated include file. |
37 #include "registered_dlls.h" // NOLINT | 36 #include "registered_dlls.h" // NOLINT |
38 | 37 |
39 using base::win::RegKey; | 38 using base::win::RegKey; |
40 using installer::InstallStatus; | 39 using installer::InstallStatus; |
| 40 using installer::MasterPreferences; |
41 | 41 |
42 namespace { | 42 namespace { |
43 | 43 |
44 // Makes appropriate changes to the Google Update "ap" value in the registry. | 44 // Makes appropriate changes to the Google Update "ap" value in the registry. |
45 // Specifically, removes the flags associated with this product ("-chrome" or | 45 // Specifically, removes the flags associated with this product ("-chrome" or |
46 // "-chromeframe[-CEEE][-readymode]") from the "ap" values for all other | 46 // "-chromeframe[-CEEE][-readymode]") from the "ap" values for all other |
47 // installed products and for the multi-installer package. | 47 // installed products and for the multi-installer package. |
48 void ProcessGoogleUpdateItems( | 48 void ProcessGoogleUpdateItems( |
49 const installer::InstallationState& original_state, | 49 const installer::InstallationState& original_state, |
| 50 const installer::InstallerState& installer_state, |
50 const installer::Product& product) { | 51 const installer::Product& product) { |
51 const bool system_level = product.system_level(); | 52 DCHECK(installer_state.is_multi_install()); |
| 53 const bool system_level = installer_state.system_install(); |
52 BrowserDistribution* distribution = product.distribution(); | 54 BrowserDistribution* distribution = product.distribution(); |
53 const HKEY reg_root = system_level ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER; | 55 const HKEY reg_root = installer_state.root_key(); |
54 const installer::ProductState* product_state = | 56 const installer::ProductState* product_state = |
55 original_state.GetProductState(system_level, distribution->GetType()); | 57 original_state.GetProductState(system_level, distribution->GetType()); |
56 DCHECK(product_state != NULL); | 58 DCHECK(product_state != NULL); |
57 installer::ChannelInfo channel_info; | 59 installer::ChannelInfo channel_info; |
58 | 60 |
59 // Remove product's flags from the channel value. | 61 // Remove product's flags from the channel value. |
60 channel_info.set_value(product_state->channel().value()); | 62 channel_info.set_value(product_state->channel().value()); |
61 const bool modified = distribution->SetChannelFlags(false, &channel_info); | 63 const bool modified = product.SetChannelFlags(false, &channel_info); |
62 | 64 |
63 // Apply the new channel value to all other products and to the multi package. | 65 // Apply the new channel value to all other products and to the multi package. |
64 if (modified) { | 66 if (modified) { |
65 BrowserDistribution::Type other_dist_type = | 67 BrowserDistribution::Type other_dist_types[] = { |
66 (distribution->GetType() == BrowserDistribution::CHROME_BROWSER) ? | 68 (distribution->GetType() == BrowserDistribution::CHROME_BROWSER) ? |
67 BrowserDistribution::CHROME_FRAME : | 69 BrowserDistribution::CHROME_FRAME : |
68 BrowserDistribution::CHROME_BROWSER; | 70 BrowserDistribution::CHROME_BROWSER, |
69 BrowserDistribution* other_dist = | 71 BrowserDistribution::CHROME_BINARIES |
70 BrowserDistribution::GetSpecificDistribution(other_dist_type, | 72 }; |
71 installer::MasterPreferences::ForCurrentProcess()); | |
72 scoped_ptr<WorkItemList> | 73 scoped_ptr<WorkItemList> |
73 update_list(WorkItem::CreateNoRollbackWorkItemList()); | 74 update_list(WorkItem::CreateNoRollbackWorkItemList()); |
74 | 75 |
75 product_state = original_state.GetProductState(system_level, | 76 for (int i = 0; i < arraysize(other_dist_types); ++i) { |
76 other_dist_type); | 77 BrowserDistribution::Type other_dist_type = other_dist_types[i]; |
77 if (installer::IsInstalledAsMulti(system_level, other_dist) && | 78 product_state = |
78 !product_state->channel().Equals(channel_info)) { | 79 original_state.GetProductState(system_level, other_dist_type); |
79 update_list->AddSetRegValueWorkItem(reg_root, other_dist->GetStateKey(), | 80 // Only modify other products if they're installed and multi. |
80 google_update::kRegApField, channel_info.value(), true); | 81 if (product_state != NULL && |
81 } else { | 82 product_state->is_multi_install() && |
82 VLOG(1) << other_dist->GetApplicationName() | 83 !product_state->channel().Equals(channel_info)) { |
83 << "'s ap value is unexpectedly up to date."; | 84 BrowserDistribution* other_dist = |
84 } | 85 BrowserDistribution::GetSpecificDistribution(other_dist_type); |
85 | 86 update_list->AddSetRegValueWorkItem(reg_root, other_dist->GetStateKey(), |
86 product_state = original_state.GetMultiPackageState(system_level); | 87 google_update::kRegApField, channel_info.value(), true); |
87 DCHECK(product_state != NULL); | 88 } else { |
88 if (!product_state->channel().Equals(channel_info)) { | 89 LOG_IF(DFATAL, |
89 update_list->AddSetRegValueWorkItem(reg_root, | 90 product_state != NULL && product_state->is_multi_install()) |
90 product.package().properties()->GetStateKey(), | 91 << "Channel value for " |
91 google_update::kRegApField, channel_info.value(), true); | 92 << BrowserDistribution::GetSpecificDistribution( |
92 } else { | 93 other_dist_type)->GetAppShortCutName() |
93 VLOG(1) << "Multi-install package's ap value is unexpectedly up to date."; | 94 << " is somehow already set to the desired new value of " |
| 95 << channel_info.value(); |
| 96 } |
94 } | 97 } |
95 | 98 |
96 bool success = update_list->Do(); | 99 bool success = update_list->Do(); |
97 LOG_IF(ERROR, !success) << "Failed updating channel values."; | 100 LOG_IF(ERROR, !success) << "Failed updating channel values."; |
98 } | 101 } |
99 } | 102 } |
100 | 103 |
101 } // namespace | 104 } // namespace |
102 | 105 |
103 namespace installer { | 106 namespace installer { |
(...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
168 VLOG(1) << installer::kChromeFrameHelperExe << " hung. Killing."; | 171 VLOG(1) << installer::kChromeFrameHelperExe << " hung. Killing."; |
169 base::CleanupProcesses(installer::kChromeFrameHelperExe, 0, | 172 base::CleanupProcesses(installer::kChromeFrameHelperExe, 0, |
170 ResultCodes::HUNG, NULL); | 173 ResultCodes::HUNG, NULL); |
171 } | 174 } |
172 } | 175 } |
173 | 176 |
174 // This method tries to figure out if current user has registered Chrome. | 177 // This method tries to figure out if current user has registered Chrome. |
175 // It returns true iff: | 178 // It returns true iff: |
176 // - Software\Clients\StartMenuInternet\Chromium\"" key has a valid value. | 179 // - Software\Clients\StartMenuInternet\Chromium\"" key has a valid value. |
177 // - The value is same as chrome.exe path for the current installation. | 180 // - The value is same as chrome.exe path for the current installation. |
178 bool CurrentUserHasDefaultBrowser(const Product& product) { | 181 bool CurrentUserHasDefaultBrowser(const InstallerState& installer_state, |
| 182 const Product& product) { |
179 std::wstring reg_key(ShellUtil::kRegStartMenuInternet); | 183 std::wstring reg_key(ShellUtil::kRegStartMenuInternet); |
180 reg_key.append(L"\\" + product.distribution()->GetApplicationName() + | 184 reg_key.append(1, L'\\') |
181 ShellUtil::kRegShellOpen); | 185 .append(product.distribution()->GetApplicationName()) |
| 186 .append(ShellUtil::kRegShellOpen); |
182 RegKey key(HKEY_LOCAL_MACHINE, reg_key.c_str(), KEY_READ); | 187 RegKey key(HKEY_LOCAL_MACHINE, reg_key.c_str(), KEY_READ); |
183 std::wstring reg_exe; | 188 std::wstring reg_exe; |
184 if (key.ReadValue(L"", ®_exe) == ERROR_SUCCESS && reg_exe.length() > 2) { | 189 if (key.ReadValue(L"", ®_exe) == ERROR_SUCCESS && reg_exe.length() > 2) { |
185 FilePath chrome_exe(product.package().path() | 190 FilePath chrome_exe(installer_state.target_path() |
186 .Append(installer::kChromeExe)); | 191 .Append(installer::kChromeExe)); |
187 // The path in the registry will always have quotes. | 192 // The path in the registry will always have quotes. |
188 reg_exe = reg_exe.substr(1, reg_exe.length() - 2); | 193 reg_exe = reg_exe.substr(1, reg_exe.length() - 2); |
189 if (FilePath::CompareEqualIgnoreCase(reg_exe, chrome_exe.value())) | 194 if (FilePath::CompareEqualIgnoreCase(reg_exe, chrome_exe.value())) |
190 return true; | 195 return true; |
191 } | 196 } |
192 | 197 |
193 return false; | 198 return false; |
194 } | 199 } |
195 | 200 |
196 // This method deletes Chrome shortcut folder from Windows Start menu. It | 201 // This method deletes Chrome shortcut folder from Windows Start menu. It |
197 // checks system_uninstall to see if the shortcut is in all users start menu | 202 // checks system_uninstall to see if the shortcut is in all users start menu |
198 // or current user start menu. | 203 // or current user start menu. |
199 // We try to remove the standard desktop shortcut but if that fails we try | 204 // We try to remove the standard desktop shortcut but if that fails we try |
200 // to remove the alternate desktop shortcut. Only one of them should be | 205 // to remove the alternate desktop shortcut. Only one of them should be |
201 // present in a given install but at this point we don't know which one. | 206 // present in a given install but at this point we don't know which one. |
202 void DeleteChromeShortcuts(const Product& product) { | 207 void DeleteChromeShortcuts(const InstallerState& installer_state, |
| 208 const Product& product) { |
203 if (!product.is_chrome()) { | 209 if (!product.is_chrome()) { |
204 VLOG(1) << __FUNCTION__ " called for non-CHROME distribution"; | 210 VLOG(1) << __FUNCTION__ " called for non-CHROME distribution"; |
205 return; | 211 return; |
206 } | 212 } |
207 | 213 |
208 FilePath shortcut_path; | 214 FilePath shortcut_path; |
209 if (product.system_level()) { | 215 if (installer_state.system_install()) { |
210 PathService::Get(base::DIR_COMMON_START_MENU, &shortcut_path); | 216 PathService::Get(base::DIR_COMMON_START_MENU, &shortcut_path); |
211 if (!ShellUtil::RemoveChromeDesktopShortcut(product.distribution(), | 217 if (!ShellUtil::RemoveChromeDesktopShortcut(product.distribution(), |
212 ShellUtil::CURRENT_USER | ShellUtil::SYSTEM_LEVEL, false)) { | 218 ShellUtil::CURRENT_USER | ShellUtil::SYSTEM_LEVEL, false)) { |
213 ShellUtil::RemoveChromeDesktopShortcut(product.distribution(), | 219 ShellUtil::RemoveChromeDesktopShortcut(product.distribution(), |
214 ShellUtil::CURRENT_USER | ShellUtil::SYSTEM_LEVEL, true); | 220 ShellUtil::CURRENT_USER | ShellUtil::SYSTEM_LEVEL, true); |
215 } | 221 } |
216 | 222 |
217 ShellUtil::RemoveChromeQuickLaunchShortcut(product.distribution(), | 223 ShellUtil::RemoveChromeQuickLaunchShortcut(product.distribution(), |
218 ShellUtil::CURRENT_USER | ShellUtil::SYSTEM_LEVEL); | 224 ShellUtil::CURRENT_USER | ShellUtil::SYSTEM_LEVEL); |
219 } else { | 225 } else { |
(...skipping 105 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
325 | 331 |
326 if (result == DELETE_REQUIRES_REBOOT) { | 332 if (result == DELETE_REQUIRES_REBOOT) { |
327 ScheduleParentAndGrandparentForDeletion(user_local_state); | 333 ScheduleParentAndGrandparentForDeletion(user_local_state); |
328 } else { | 334 } else { |
329 DeleteEmptyParentDir(user_local_state); | 335 DeleteEmptyParentDir(user_local_state); |
330 } | 336 } |
331 | 337 |
332 return result; | 338 return result; |
333 } | 339 } |
334 | 340 |
335 bool MoveSetupOutOfInstallFolder(const Package& package, | 341 bool MoveSetupOutOfInstallFolder(const InstallerState& installer_state, |
336 const FilePath& setup_path, | 342 const FilePath& setup_path, |
337 const Version& installed_version) { | 343 const Version& installed_version) { |
338 bool ret = false; | 344 bool ret = false; |
339 FilePath setup_exe(package.GetInstallerDirectory(installed_version) | 345 FilePath setup_exe(installer_state.GetInstallerDirectory(installed_version) |
340 .Append(setup_path.BaseName())); | 346 .Append(setup_path.BaseName())); |
341 FilePath temp_file; | 347 FilePath temp_file; |
342 if (!file_util::CreateTemporaryFile(&temp_file)) { | 348 if (!file_util::CreateTemporaryFile(&temp_file)) { |
343 LOG(ERROR) << "Failed to create temporary file for setup.exe."; | 349 LOG(ERROR) << "Failed to create temporary file for setup.exe."; |
344 } else { | 350 } else { |
345 VLOG(1) << "Attempting to move setup to: " << temp_file.value(); | 351 VLOG(1) << "Attempting to move setup to: " << temp_file.value(); |
346 ret = file_util::Move(setup_exe, temp_file); | 352 ret = file_util::Move(setup_exe, temp_file); |
347 LOG_IF(ERROR, !ret) << "Failed to move setup to " << temp_file.value(); | 353 LOG_IF(ERROR, !ret) << "Failed to move setup to " << temp_file.value(); |
348 } | 354 } |
349 return ret; | 355 return ret; |
350 } | 356 } |
351 | 357 |
352 DeleteResult DeleteFilesAndFolders(const Package& package, | 358 DeleteResult DeleteFilesAndFolders(const InstallerState& installer_state, |
353 const Version& installed_version) { | 359 const Version& installed_version) { |
354 VLOG(1) << "DeleteFilesAndFolders: " << package.path().value(); | 360 VLOG(1) << "DeleteFilesAndFolders: " << installer_state.target_path().value(); |
355 if (package.path().empty()) { | 361 if (installer_state.target_path().empty()) { |
356 LOG(ERROR) << "Could not get installation destination path."; | 362 LOG(ERROR) << "Could not get installation destination path."; |
357 return DELETE_FAILED; // Nothing else we can do to uninstall, so we return. | 363 return DELETE_FAILED; // Nothing else we can do to uninstall, so we return. |
358 } | 364 } |
359 | 365 |
360 DeleteResult result = DELETE_SUCCEEDED; | 366 DeleteResult result = DELETE_SUCCEEDED; |
361 | 367 |
362 VLOG(1) << "Deleting install path " << package.path().value(); | 368 VLOG(1) << "Deleting install path " << installer_state.target_path().value(); |
363 if (!file_util::Delete(package.path(), true)) { | 369 if (!file_util::Delete(installer_state.target_path(), true)) { |
364 LOG(ERROR) << "Failed to delete folder (1st try): " | 370 LOG(ERROR) << "Failed to delete folder (1st try): " |
365 << package.path().value(); | 371 << installer_state.target_path().value(); |
366 if (FindProduct(package.products(), | 372 if (installer_state.FindProduct(BrowserDistribution::CHROME_FRAME)) { |
367 BrowserDistribution::CHROME_FRAME)) { | |
368 // We don't try killing Chrome processes for Chrome Frame builds since | 373 // We don't try killing Chrome processes for Chrome Frame builds since |
369 // that is unlikely to help. Instead, schedule files for deletion and | 374 // that is unlikely to help. Instead, schedule files for deletion and |
370 // return a value that will trigger a reboot prompt. | 375 // return a value that will trigger a reboot prompt. |
371 ScheduleDirectoryForDeletion(package.path().value().c_str()); | 376 ScheduleDirectoryForDeletion( |
| 377 installer_state.target_path().value().c_str()); |
372 result = DELETE_REQUIRES_REBOOT; | 378 result = DELETE_REQUIRES_REBOOT; |
373 } else { | 379 } else { |
374 // Try closing any running chrome processes and deleting files once again. | 380 // Try closing any running chrome processes and deleting files once again. |
375 CloseAllChromeProcesses(); | 381 CloseAllChromeProcesses(); |
376 if (!file_util::Delete(package.path(), true)) { | 382 if (!file_util::Delete(installer_state.target_path(), true)) { |
377 LOG(ERROR) << "Failed to delete folder (2nd try): " | 383 LOG(ERROR) << "Failed to delete folder (2nd try): " |
378 << package.path().value(); | 384 << installer_state.target_path().value(); |
379 result = DELETE_FAILED; | 385 result = DELETE_FAILED; |
380 } | 386 } |
381 } | 387 } |
382 } | 388 } |
383 | 389 |
384 if (result == DELETE_REQUIRES_REBOOT) { | 390 if (result == DELETE_REQUIRES_REBOOT) { |
385 // If we need a reboot to continue, schedule the parent directories for | 391 // If we need a reboot to continue, schedule the parent directories for |
386 // deletion unconditionally. If they are not empty, the session manager | 392 // deletion unconditionally. If they are not empty, the session manager |
387 // will not delete them on reboot. | 393 // will not delete them on reboot. |
388 ScheduleParentAndGrandparentForDeletion(package.path()); | 394 ScheduleParentAndGrandparentForDeletion(installer_state.target_path()); |
389 } else { | 395 } else { |
390 // Now check and delete if the parent directories are empty | 396 // Now check and delete if the parent directories are empty |
391 // For example Google\Chrome or Chromium | 397 // For example Google\Chrome or Chromium |
392 DeleteEmptyParentDir(package.path()); | 398 DeleteEmptyParentDir(installer_state.target_path()); |
393 } | 399 } |
394 return result; | 400 return result; |
395 } | 401 } |
396 | 402 |
397 // This method checks if Chrome is currently running or if the user has | 403 // This method checks if Chrome is currently running or if the user has |
398 // cancelled the uninstall operation by clicking Cancel on the confirmation | 404 // cancelled the uninstall operation by clicking Cancel on the confirmation |
399 // box that Chrome pops up. | 405 // box that Chrome pops up. |
400 InstallStatus IsChromeActiveOrUserCancelled(const Product& product) { | 406 InstallStatus IsChromeActiveOrUserCancelled( |
| 407 const InstallerState& installer_state, |
| 408 const Product& product) { |
401 int32 exit_code = ResultCodes::NORMAL_EXIT; | 409 int32 exit_code = ResultCodes::NORMAL_EXIT; |
402 CommandLine options(CommandLine::NO_PROGRAM); | 410 CommandLine options(CommandLine::NO_PROGRAM); |
403 options.AppendSwitch(installer::switches::kUninstall); | 411 options.AppendSwitch(installer::switches::kUninstall); |
404 | 412 |
405 // Here we want to save user from frustration (in case of Chrome crashes) | 413 // Here we want to save user from frustration (in case of Chrome crashes) |
406 // and continue with the uninstallation as long as chrome.exe process exit | 414 // and continue with the uninstallation as long as chrome.exe process exit |
407 // code is NOT one of the following: | 415 // code is NOT one of the following: |
408 // - UNINSTALL_CHROME_ALIVE - chrome.exe is currently running | 416 // - UNINSTALL_CHROME_ALIVE - chrome.exe is currently running |
409 // - UNINSTALL_USER_CANCEL - User cancelled uninstallation | 417 // - UNINSTALL_USER_CANCEL - User cancelled uninstallation |
410 // - HUNG - chrome.exe was killed by HuntForZombieProcesses() (until we can | 418 // - HUNG - chrome.exe was killed by HuntForZombieProcesses() (until we can |
411 // give this method some brains and not kill chrome.exe launched | 419 // give this method some brains and not kill chrome.exe launched |
412 // by us, we will not uninstall if we get this return code). | 420 // by us, we will not uninstall if we get this return code). |
413 VLOG(1) << "Launching Chrome to do uninstall tasks."; | 421 VLOG(1) << "Launching Chrome to do uninstall tasks."; |
414 if (product.LaunchChromeAndWait(options, &exit_code)) { | 422 if (product.LaunchChromeAndWait(installer_state.target_path(), options, |
| 423 &exit_code)) { |
415 VLOG(1) << "chrome.exe launched for uninstall confirmation returned: " | 424 VLOG(1) << "chrome.exe launched for uninstall confirmation returned: " |
416 << exit_code; | 425 << exit_code; |
417 if ((exit_code == ResultCodes::UNINSTALL_CHROME_ALIVE) || | 426 if ((exit_code == ResultCodes::UNINSTALL_CHROME_ALIVE) || |
418 (exit_code == ResultCodes::UNINSTALL_USER_CANCEL) || | 427 (exit_code == ResultCodes::UNINSTALL_USER_CANCEL) || |
419 (exit_code == ResultCodes::HUNG)) | 428 (exit_code == ResultCodes::HUNG)) |
420 return installer::UNINSTALL_CANCELLED; | 429 return installer::UNINSTALL_CANCELLED; |
421 | 430 |
422 if (exit_code == ResultCodes::UNINSTALL_DELETE_PROFILE) | 431 if (exit_code == ResultCodes::UNINSTALL_DELETE_PROFILE) |
423 return installer::UNINSTALL_DELETE_PROFILE; | 432 return installer::UNINSTALL_DELETE_PROFILE; |
424 } else { | 433 } else { |
425 PLOG(ERROR) << "Failed to launch chrome.exe for uninstall confirmation."; | 434 PLOG(ERROR) << "Failed to launch chrome.exe for uninstall confirmation."; |
426 } | 435 } |
427 | 436 |
428 return installer::UNINSTALL_CONFIRMED; | 437 return installer::UNINSTALL_CONFIRMED; |
429 } | 438 } |
430 | 439 |
431 bool ShouldDeleteProfile(const CommandLine& cmd_line, InstallStatus status, | 440 bool ShouldDeleteProfile(const InstallerState& installer_state, |
| 441 const CommandLine& cmd_line, InstallStatus status, |
432 const Product& product) { | 442 const Product& product) { |
433 bool should_delete = false; | 443 bool should_delete = false; |
434 | 444 |
435 // Chrome Frame uninstallations always want to delete the profile (we have no | 445 // Chrome Frame uninstallations always want to delete the profile (we have no |
436 // UI to prompt otherwise and the profile stores no useful data anyway) | 446 // UI to prompt otherwise and the profile stores no useful data anyway) |
437 // unless they are managed by MSI. MSI uninstalls will explicitly include | 447 // unless they are managed by MSI. MSI uninstalls will explicitly include |
438 // the --delete-profile flag to distinguish them from MSI upgrades. | 448 // the --delete-profile flag to distinguish them from MSI upgrades. |
439 if (!product.is_chrome() && !product.IsMsi()) { | 449 if (!product.is_chrome() && !installer_state.is_msi()) { |
440 should_delete = true; | 450 should_delete = true; |
441 } else { | 451 } else { |
442 should_delete = | 452 should_delete = |
443 status == installer::UNINSTALL_DELETE_PROFILE || | 453 status == installer::UNINSTALL_DELETE_PROFILE || |
444 cmd_line.HasSwitch(installer::switches::kDeleteProfile); | 454 cmd_line.HasSwitch(installer::switches::kDeleteProfile); |
445 } | 455 } |
446 | 456 |
447 return should_delete; | 457 return should_delete; |
448 } | 458 } |
449 | 459 |
(...skipping 85 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
535 InstallUtil::DeleteRegistryKey(key, ext_prog_id); | 545 InstallUtil::DeleteRegistryKey(key, ext_prog_id); |
536 | 546 |
537 // Delete Software\Classes\.crx, | 547 // Delete Software\Classes\.crx, |
538 std::wstring ext_association(ShellUtil::kRegClasses); | 548 std::wstring ext_association(ShellUtil::kRegClasses); |
539 ext_association.append(L"\\"); | 549 ext_association.append(L"\\"); |
540 ext_association.append(chrome::kExtensionFileExtension); | 550 ext_association.append(chrome::kExtensionFileExtension); |
541 InstallUtil::DeleteRegistryKey(key, ext_association); | 551 InstallUtil::DeleteRegistryKey(key, ext_association); |
542 } | 552 } |
543 } | 553 } |
544 | 554 |
545 bool ProcessChromeFrameWorkItems(const FilePath& setup_path, | 555 bool ProcessChromeFrameWorkItems(const InstallationState& original_state, |
546 const Product& product, | 556 const InstallerState& installer_state, |
547 const ProductState* product_state) { | 557 const FilePath& setup_path, |
| 558 const Product& product) { |
548 if (!product.is_chrome_frame()) | 559 if (!product.is_chrome_frame()) |
549 return false; | 560 return false; |
550 | 561 |
551 DCHECK(product_state != NULL); | |
552 scoped_ptr<WorkItemList> item_list(WorkItem::CreateWorkItemList()); | 562 scoped_ptr<WorkItemList> item_list(WorkItem::CreateWorkItemList()); |
553 AddChromeFrameWorkItems(false, setup_path, product_state->version(), product, | 563 AddChromeFrameWorkItems(original_state, installer_state, setup_path, |
554 item_list.get()); | 564 Version(), product, item_list.get()); |
555 return item_list->Do(); | 565 return item_list->Do(); |
556 } | 566 } |
557 | 567 |
558 InstallStatus UninstallProduct(const InstallationState& original_state, | 568 InstallStatus UninstallProduct(const InstallationState& original_state, |
559 const InstallerState& installer_state, | 569 const InstallerState& installer_state, |
560 const FilePath& setup_path, | 570 const FilePath& setup_path, |
561 const Product& product, | 571 const Product& product, |
562 bool remove_all, | 572 bool remove_all, |
563 bool force_uninstall, | 573 bool force_uninstall, |
564 const CommandLine& cmd_line) { | 574 const CommandLine& cmd_line) { |
565 InstallStatus status = installer::UNINSTALL_CONFIRMED; | 575 InstallStatus status = installer::UNINSTALL_CONFIRMED; |
566 std::wstring suffix; | 576 std::wstring suffix; |
567 if (!ShellUtil::GetUserSpecificDefaultBrowserSuffix(product.distribution(), | 577 if (!ShellUtil::GetUserSpecificDefaultBrowserSuffix(product.distribution(), |
568 &suffix)) | 578 &suffix)) |
569 suffix = L""; | 579 suffix = L""; |
570 | 580 |
571 BrowserDistribution* browser_dist = product.distribution(); | 581 BrowserDistribution* browser_dist = product.distribution(); |
572 bool is_chrome = product.is_chrome(); | 582 bool is_chrome = product.is_chrome(); |
573 | 583 |
574 VLOG(1) << "UninstallProduct: " << browser_dist->GetApplicationName(); | 584 VLOG(1) << "UninstallProduct: " << browser_dist->GetApplicationName(); |
575 | 585 |
576 if (force_uninstall) { | 586 if (force_uninstall) { |
577 // Since --force-uninstall command line option is used, we are going to | 587 // Since --force-uninstall command line option is used, we are going to |
578 // do silent uninstall. Try to close all running Chrome instances. | 588 // do silent uninstall. Try to close all running Chrome instances. |
579 // NOTE: We don't do this for Chrome Frame or CEEE. | 589 // NOTE: We don't do this for Chrome Frame or CEEE. |
580 if (is_chrome) | 590 if (is_chrome) |
581 CloseAllChromeProcesses(); | 591 CloseAllChromeProcesses(); |
582 } else if (is_chrome) { | 592 } else if (is_chrome) { |
583 // no --force-uninstall so lets show some UI dialog boxes. | 593 // no --force-uninstall so lets show some UI dialog boxes. |
584 status = IsChromeActiveOrUserCancelled(product); | 594 status = IsChromeActiveOrUserCancelled(installer_state, product); |
585 if (status != installer::UNINSTALL_CONFIRMED && | 595 if (status != installer::UNINSTALL_CONFIRMED && |
586 status != installer::UNINSTALL_DELETE_PROFILE) | 596 status != installer::UNINSTALL_DELETE_PROFILE) |
587 return status; | 597 return status; |
588 | 598 |
589 // Check if we need admin rights to cleanup HKLM. If we do, try to launch | 599 // Check if we need admin rights to cleanup HKLM. If we do, try to launch |
590 // another uninstaller (silent) in elevated mode to do HKLM cleanup. | 600 // another uninstaller (silent) in elevated mode to do HKLM cleanup. |
591 // And continue uninstalling in the current process also to do HKCU cleanup. | 601 // And continue uninstalling in the current process also to do HKCU cleanup. |
592 if (remove_all && | 602 if (remove_all && |
593 (!suffix.empty() || CurrentUserHasDefaultBrowser(product)) && | 603 (!suffix.empty() || |
| 604 CurrentUserHasDefaultBrowser(installer_state, product)) && |
594 !::IsUserAnAdmin() && | 605 !::IsUserAnAdmin() && |
595 base::win::GetVersion() >= base::win::VERSION_VISTA && | 606 base::win::GetVersion() >= base::win::VERSION_VISTA && |
596 !cmd_line.HasSwitch(installer::switches::kRunAsAdmin)) { | 607 !cmd_line.HasSwitch(installer::switches::kRunAsAdmin)) { |
597 CommandLine new_cmd(CommandLine::NO_PROGRAM); | 608 CommandLine new_cmd(CommandLine::NO_PROGRAM); |
598 new_cmd.AppendArguments(cmd_line, true); | 609 new_cmd.AppendArguments(cmd_line, true); |
599 // Append --run-as-admin flag to let the new instance of setup.exe know | 610 // Append --run-as-admin flag to let the new instance of setup.exe know |
600 // that we already tried to launch ourselves as admin. | 611 // that we already tried to launch ourselves as admin. |
601 new_cmd.AppendSwitch(installer::switches::kRunAsAdmin); | 612 new_cmd.AppendSwitch(installer::switches::kRunAsAdmin); |
602 // Append --remove-chrome-registration to remove registry keys only. | 613 // Append --remove-chrome-registration to remove registry keys only. |
603 new_cmd.AppendSwitch(installer::switches::kRemoveChromeRegistration); | 614 new_cmd.AppendSwitch(installer::switches::kRemoveChromeRegistration); |
604 if (!suffix.empty()) { | 615 if (!suffix.empty()) { |
605 new_cmd.AppendSwitchNative( | 616 new_cmd.AppendSwitchNative( |
606 installer::switches::kRegisterChromeBrowserSuffix, suffix); | 617 installer::switches::kRegisterChromeBrowserSuffix, suffix); |
607 } | 618 } |
608 DWORD exit_code = installer::UNKNOWN_STATUS; | 619 DWORD exit_code = installer::UNKNOWN_STATUS; |
609 InstallUtil::ExecuteExeAsAdmin(new_cmd, &exit_code); | 620 InstallUtil::ExecuteExeAsAdmin(new_cmd, &exit_code); |
610 } | 621 } |
611 } | 622 } |
612 | 623 |
613 // Chrome is not in use so lets uninstall Chrome by deleting various files | 624 // Chrome is not in use so lets uninstall Chrome by deleting various files |
614 // and registry entries. Here we will just make best effort and keep going | 625 // and registry entries. Here we will just make best effort and keep going |
615 // in case of errors. | 626 // in case of errors. |
616 | 627 |
617 // First delete shortcuts from Start->Programs, Desktop & Quick Launch. | 628 // First delete shortcuts from Start->Programs, Desktop & Quick Launch. |
618 DeleteChromeShortcuts(product); | 629 DeleteChromeShortcuts(installer_state, product); |
619 | 630 |
620 // Delete the registry keys (Uninstall key and Version key). | 631 // Delete the registry keys (Uninstall key and Version key). |
621 HKEY reg_root = product.system_level() ? HKEY_LOCAL_MACHINE : | 632 HKEY reg_root = installer_state.root_key(); |
622 HKEY_CURRENT_USER; | |
623 RegKey key(reg_root, L"", KEY_ALL_ACCESS); | 633 RegKey key(reg_root, L"", KEY_ALL_ACCESS); |
624 | 634 |
625 // Note that we must retrieve the distribution-specific data before deleting | 635 // Note that we must retrieve the distribution-specific data before deleting |
626 // product.GetVersionKey(). | 636 // product.GetVersionKey(). |
627 std::wstring distribution_data(browser_dist->GetDistributionData(reg_root)); | 637 std::wstring distribution_data(browser_dist->GetDistributionData(reg_root)); |
628 | 638 |
629 // Remove Control Panel uninstall link and Omaha product key. | 639 // Remove Control Panel uninstall link and Omaha product key. |
630 InstallUtil::DeleteRegistryKey(key, browser_dist->GetUninstallRegPath()); | 640 InstallUtil::DeleteRegistryKey(key, browser_dist->GetUninstallRegPath()); |
631 InstallUtil::DeleteRegistryKey(key, browser_dist->GetVersionKey()); | 641 InstallUtil::DeleteRegistryKey(key, browser_dist->GetVersionKey()); |
632 | 642 |
633 // Also try to delete the MSI value in the ClientState key (it might not be | 643 // Also try to delete the MSI value in the ClientState key (it might not be |
634 // there). This is due to a Google Update behaviour where an uninstall and a | 644 // there). This is due to a Google Update behaviour where an uninstall and a |
635 // rapid reinstall might result in stale values from the old ClientState key | 645 // rapid reinstall might result in stale values from the old ClientState key |
636 // being picked up on reinstall. | 646 // being picked up on reinstall. |
637 product.SetMsiMarker(false); | 647 product.SetMsiMarker(installer_state.system_install(), false); |
638 | 648 |
639 // Remove all Chrome registration keys. | 649 // Remove all Chrome registration keys. |
640 InstallStatus ret = installer::UNKNOWN_STATUS; | 650 InstallStatus ret = installer::UNKNOWN_STATUS; |
641 DeleteChromeRegistrationKeys(product.distribution(), reg_root, suffix, ret); | 651 DeleteChromeRegistrationKeys(product.distribution(), reg_root, suffix, ret); |
642 | 652 |
| 653 if (!is_chrome) { |
| 654 ProcessChromeFrameWorkItems(original_state, installer_state, setup_path, |
| 655 product); |
| 656 } |
| 657 |
| 658 if (installer_state.is_multi_install()) |
| 659 ProcessGoogleUpdateItems(original_state, installer_state, product); |
| 660 |
| 661 // For user level install also we end up creating some keys in HKLM if user |
| 662 // sets Chrome as default browser. So delete those as well (needs admin). |
| 663 if (remove_all && !installer_state.system_install() && |
| 664 (!suffix.empty() || CurrentUserHasDefaultBrowser(installer_state, |
| 665 product))) { |
| 666 DeleteChromeRegistrationKeys(product.distribution(), HKEY_LOCAL_MACHINE, |
| 667 suffix, ret); |
| 668 } |
| 669 |
643 // Get the state of the installed product (if any) | 670 // Get the state of the installed product (if any) |
644 const ProductState* product_state = | 671 const ProductState* product_state = |
645 original_state.GetProductState(installer_state.system_install(), | 672 original_state.GetProductState(installer_state.system_install(), |
646 browser_dist->GetType()); | 673 browser_dist->GetType()); |
647 | 674 |
648 if (!is_chrome) | |
649 ProcessChromeFrameWorkItems(setup_path, product, product_state); | |
650 | |
651 if (product.package().multi_install()) | |
652 ProcessGoogleUpdateItems(original_state, product); | |
653 | |
654 // For user level install also we end up creating some keys in HKLM if user | |
655 // sets Chrome as default browser. So delete those as well (needs admin). | |
656 if (remove_all && !product.system_level() && | |
657 (!suffix.empty() || CurrentUserHasDefaultBrowser(product))) { | |
658 DeleteChromeRegistrationKeys(product.distribution(), HKEY_LOCAL_MACHINE, | |
659 suffix, ret); | |
660 } | |
661 | |
662 // Delete shared registry keys as well (these require admin rights) if | 675 // Delete shared registry keys as well (these require admin rights) if |
663 // remove_all option is specified. | 676 // remove_all option is specified. |
664 if (remove_all) { | 677 if (remove_all) { |
665 if (!InstallUtil::IsChromeSxSProcess() && is_chrome) { | 678 if (!InstallUtil::IsChromeSxSProcess() && is_chrome) { |
666 // Delete media player registry key that exists only in HKLM. | 679 // Delete media player registry key that exists only in HKLM. |
667 // We don't delete this key in SxS uninstall or Chrome Frame uninstall | 680 // We don't delete this key in SxS uninstall or Chrome Frame uninstall |
668 // as we never set the key for those products. | 681 // as we never set the key for those products. |
669 RegKey hklm_key(HKEY_LOCAL_MACHINE, L"", KEY_ALL_ACCESS); | 682 RegKey hklm_key(HKEY_LOCAL_MACHINE, L"", KEY_ALL_ACCESS); |
670 std::wstring reg_path(installer::kMediaPlayerRegPath); | 683 std::wstring reg_path(installer::kMediaPlayerRegPath); |
671 file_util::AppendToPath(®_path, installer::kChromeExe); | 684 file_util::AppendToPath(®_path, installer::kChromeExe); |
672 InstallUtil::DeleteRegistryKey(hklm_key, reg_path); | 685 InstallUtil::DeleteRegistryKey(hklm_key, reg_path); |
673 } | 686 } |
674 | 687 |
675 // Unregister any dll servers that we may have registered for this | 688 // Unregister any dll servers that we may have registered for this |
676 // product. | 689 // product. |
677 if (product_state != NULL) { | 690 if (product_state != NULL) { |
678 std::vector<FilePath> com_dll_list(browser_dist->GetComDllList()); | 691 std::vector<FilePath> com_dll_list; |
679 FilePath dll_folder = product.package().path().Append( | 692 product.AddComDllList(&com_dll_list); |
| 693 FilePath dll_folder = installer_state.target_path().Append( |
680 UTF8ToWide(product_state->version().GetString())); | 694 UTF8ToWide(product_state->version().GetString())); |
681 | 695 |
682 scoped_ptr<WorkItemList> unreg_work_item_list( | 696 scoped_ptr<WorkItemList> unreg_work_item_list( |
683 WorkItem::CreateWorkItemList()); | 697 WorkItem::CreateWorkItemList()); |
684 | 698 |
685 | 699 |
686 AddRegisterComDllWorkItems(dll_folder, | 700 AddRegisterComDllWorkItems(dll_folder, |
687 com_dll_list, | 701 com_dll_list, |
688 product.system_level(), | 702 installer_state.system_install(), |
689 false, // Unregister | 703 false, // Unregister |
690 true, // May fail | 704 true, // May fail |
691 unreg_work_item_list.get()); | 705 unreg_work_item_list.get()); |
692 unreg_work_item_list->Do(); | 706 unreg_work_item_list->Do(); |
693 } | 707 } |
694 } | 708 } |
695 | 709 |
696 // Close any Chrome Frame helper processes that may be running. | 710 // Close any Chrome Frame helper processes that may be running. |
697 if (product.is_chrome_frame()) { | 711 if (product.is_chrome_frame()) { |
698 VLOG(1) << "Closing the Chrome Frame helper process"; | 712 VLOG(1) << "Closing the Chrome Frame helper process"; |
699 CloseChromeFrameHelperProcess(); | 713 CloseChromeFrameHelperProcess(); |
700 } | 714 } |
701 | 715 |
702 if (product_state == NULL) | 716 if (product_state == NULL) |
703 return installer::UNINSTALL_SUCCESSFUL; | 717 return installer::UNINSTALL_SUCCESSFUL; |
704 | 718 |
705 // Finally delete all the files from Chrome folder after moving setup.exe | 719 // Finally delete all the files from Chrome folder after moving setup.exe |
706 // and the user's Local State to a temp location. | 720 // and the user's Local State to a temp location. |
707 bool delete_profile = ShouldDeleteProfile(cmd_line, status, product); | 721 bool delete_profile = ShouldDeleteProfile(installer_state, cmd_line, status, |
| 722 product); |
708 ret = installer::UNINSTALL_SUCCESSFUL; | 723 ret = installer::UNINSTALL_SUCCESSFUL; |
709 | 724 |
710 // When deleting files, we must make sure that we're either a "single" | 725 // When deleting files, we must make sure that we're either a "single" |
711 // (aka non-multi) installation or, in the case of multi, that no other | 726 // (aka non-multi) installation or, in the case of multi, that no other |
712 // "multi" products share the binaries we are about to delete. | 727 // "multi" products share the binaries we are about to delete. |
713 | 728 |
714 bool can_delete_files; | 729 bool can_delete_files = true; |
715 if (product.package().multi_install()) { | 730 if (installer_state.is_multi_install()) { |
716 can_delete_files = | 731 BrowserDistribution::Type types[] = { |
717 (product.package().GetMultiInstallDependencyCount() == 0); | 732 BrowserDistribution::CHROME_BROWSER, |
| 733 BrowserDistribution::CHROME_FRAME |
| 734 }; |
| 735 ProductState prod_state; |
| 736 for (int i = 0; i < arraysize(types); ++i) { |
| 737 if (prod_state.Initialize(installer_state.system_install(), types[i]) && |
| 738 prod_state.is_multi_install()) { |
| 739 can_delete_files = false; |
| 740 break; |
| 741 } |
| 742 } |
718 LOG(INFO) << (can_delete_files ? "Shared binaries will be deleted." : | 743 LOG(INFO) << (can_delete_files ? "Shared binaries will be deleted." : |
719 "Shared binaries still in use."); | 744 "Shared binaries still in use."); |
720 PackageProperties* props = product.package().properties(); | 745 if (can_delete_files) { |
721 if (can_delete_files && props->ReceivesUpdates()) { | 746 BrowserDistribution* multi_dist = |
722 InstallUtil::DeleteRegistryKey(key, props->GetVersionKey()); | 747 installer_state.multi_package_binaries_distribution(); |
| 748 InstallUtil::DeleteRegistryKey(key, multi_dist->GetVersionKey()); |
723 } | 749 } |
724 } else { | |
725 can_delete_files = true; | |
726 } | 750 } |
727 | 751 |
728 FilePath backup_state_file(BackupLocalStateFile( | 752 FilePath backup_state_file(BackupLocalStateFile( |
729 GetLocalStateFolder(product))); | 753 GetLocalStateFolder(product))); |
730 | 754 |
731 DeleteResult delete_result = DELETE_SUCCEEDED; | 755 DeleteResult delete_result = DELETE_SUCCEEDED; |
732 if (can_delete_files) { | 756 if (can_delete_files) { |
733 // In order to be able to remove the folder in which we're running, we | 757 // In order to be able to remove the folder in which we're running, we |
734 // need to move setup.exe out of the install folder. | 758 // need to move setup.exe out of the install folder. |
735 // TODO(tommi): What if the temp folder is on a different volume? | 759 // TODO(tommi): What if the temp folder is on a different volume? |
736 MoveSetupOutOfInstallFolder(product.package(), setup_path, | 760 MoveSetupOutOfInstallFolder(installer_state, setup_path, |
737 product_state->version()); | 761 product_state->version()); |
738 delete_result = DeleteFilesAndFolders(product.package(), | 762 delete_result = DeleteFilesAndFolders(installer_state, |
739 product_state->version()); | 763 product_state->version()); |
740 } | 764 } |
741 | 765 |
742 if (delete_profile) | 766 if (delete_profile) |
743 DeleteLocalState(product); | 767 DeleteLocalState(product); |
744 | 768 |
745 if (delete_result == DELETE_FAILED) { | 769 if (delete_result == DELETE_FAILED) { |
746 ret = installer::UNINSTALL_FAILED; | 770 ret = installer::UNINSTALL_FAILED; |
747 } else if (delete_result == DELETE_REQUIRES_REBOOT) { | 771 } else if (delete_result == DELETE_REQUIRES_REBOOT) { |
748 ret = installer::UNINSTALL_REQUIRES_REBOOT; | 772 ret = installer::UNINSTALL_REQUIRES_REBOOT; |
749 } | 773 } |
750 | 774 |
751 if (!force_uninstall) { | 775 if (!force_uninstall) { |
752 VLOG(1) << "Uninstallation complete. Launching Uninstall survey."; | 776 VLOG(1) << "Uninstallation complete. Launching Uninstall survey."; |
753 browser_dist->DoPostUninstallOperations(product_state->version(), | 777 browser_dist->DoPostUninstallOperations(product_state->version(), |
754 backup_state_file, distribution_data); | 778 backup_state_file, distribution_data); |
755 } | 779 } |
756 | 780 |
757 // Try and delete the preserved local state once the post-install | 781 // Try and delete the preserved local state once the post-install |
758 // operations are complete. | 782 // operations are complete. |
759 if (!backup_state_file.empty()) | 783 if (!backup_state_file.empty()) |
760 file_util::Delete(backup_state_file, false); | 784 file_util::Delete(backup_state_file, false); |
761 | 785 |
762 return ret; | 786 return ret; |
763 } | 787 } |
764 | 788 |
765 } // namespace installer | 789 } // namespace installer |
766 | |
OLD | NEW |