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

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

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

Powered by Google App Engine
This is Rietveld 408576698