Chromium Code Reviews| 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 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 Loading... | |
| 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"", ®_exe) == ERROR_SUCCESS && reg_exe.length() > 2) { | 180 if (key.ReadValue(L"", ®_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 Loading... | |
| 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 Loading... | |
| 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(®_path, installer::kChromeExe); | 675 file_util::AppendToPath(®_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 | |
| OLD | NEW |