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

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

Powered by Google App Engine
This is Rietveld 408576698