This source file includes following definitions.
- DeleteInstallTempDir
- AddChannelValueUpdateWorkItems
- ProcessGoogleUpdateItems
- ProcessOnOsUpgradeWorkItems
- ProcessIELowRightsPolicyWorkItems
- ClearRlzProductState
- CheckShouldRemoveSetupAndArchive
- RemoveInstallerFiles
- CloseAllChromeProcesses
- CloseChromeFrameHelperProcess
- RetargetUserShortcutsWithArgs
- DeleteShortcuts
- ScheduleParentAndGrandparentForDeletion
- DeleteEmptyDir
- GetUserDataDir
- BackupLocalStateFile
- DeleteUserDataDir
- MoveSetupOutOfInstallFolder
- DeleteAppHostFilesAndFolders
- DeleteChromeFilesAndFolders
- IsChromeActiveOrUserCancelled
- ShouldDeleteProfile
- RemoveFiletypeRegistration
- ProcessDelegateExecuteWorkItems
- UninstallActiveSetupEntries
- DeleteChromeDirectoriesIfEmpty
- DeleteChromeRegistrationKeys
- RemoveChromeLegacyRegistryKeys
- UninstallProduct
- CleanUpInstallationDirectoryAfterUninstall
#include "chrome/installer/setup/uninstall.h"
#include <windows.h>
#include <vector>
#include "base/base_paths.h"
#include "base/file_util.h"
#include "base/files/file_enumerator.h"
#include "base/path_service.h"
#include "base/process/kill.h"
#include "base/strings/string16.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
#include "base/win/registry.h"
#include "base/win/scoped_handle.h"
#include "base/win/shortcut.h"
#include "base/win/windows_version.h"
#include "chrome/common/chrome_constants.h"
#include "chrome/common/chrome_paths_internal.h"
#include "chrome/common/chrome_result_codes.h"
#include "chrome/installer/launcher_support/chrome_launcher_support.h"
#include "chrome/installer/setup/install.h"
#include "chrome/installer/setup/install_worker.h"
#include "chrome/installer/setup/setup_constants.h"
#include "chrome/installer/setup/setup_util.h"
#include "chrome/installer/util/auto_launch_util.h"
#include "chrome/installer/util/browser_distribution.h"
#include "chrome/installer/util/channel_info.h"
#include "chrome/installer/util/delete_after_reboot_helper.h"
#include "chrome/installer/util/google_update_constants.h"
#include "chrome/installer/util/google_update_settings.h"
#include "chrome/installer/util/helper.h"
#include "chrome/installer/util/install_util.h"
#include "chrome/installer/util/installation_state.h"
#include "chrome/installer/util/installer_state.h"
#include "chrome/installer/util/logging_installer.h"
#include "chrome/installer/util/self_cleaning_temp_dir.h"
#include "chrome/installer/util/shell_util.h"
#include "chrome/installer/util/util_constants.h"
#include "content/public/common/result_codes.h"
#include "extensions/common/constants.h"
#include "rlz/lib/rlz_lib.h"
using base::win::RegKey;
namespace installer {
namespace {
void DeleteInstallTempDir(const base::FilePath& target_path) {
  base::FilePath temp_path(target_path.DirName().Append(
      installer::kInstallTempDir));
  if (base::DirectoryExists(temp_path)) {
    SelfCleaningTempDir temp_dir;
    if (!temp_dir.Initialize(target_path.DirName(),
                             installer::kInstallTempDir) ||
        !temp_dir.Delete()) {
      LOG(ERROR) << "Failed to delete temp dir " << temp_path.value();
    }
  }
}
void AddChannelValueUpdateWorkItems(
    const InstallationState& original_state,
    const InstallerState& installer_state,
    const ChannelInfo& channel_info,
    const std::vector<BrowserDistribution::Type>& dist_types,
    WorkItemList* update_list) {
  const bool system_level = installer_state.system_install();
  const HKEY reg_root = installer_state.root_key();
  for (size_t i = 0; i < dist_types.size(); ++i) {
    BrowserDistribution::Type dist_type = dist_types[i];
    const ProductState* product_state =
        original_state.GetProductState(system_level, dist_type);
    
    if (product_state != NULL &&
        product_state->is_multi_install() &&
        !product_state->channel().Equals(channel_info)) {
      BrowserDistribution* other_dist =
          BrowserDistribution::GetSpecificDistribution(dist_type);
      update_list->AddSetRegValueWorkItem(reg_root, other_dist->GetStateKey(),
          google_update::kRegApField, channel_info.value(), true);
    } else {
      LOG_IF(ERROR,
             product_state != NULL && product_state->is_multi_install())
          << "Channel value for "
          << BrowserDistribution::GetSpecificDistribution(
                 dist_type)->GetDisplayName()
          << " is somehow already set to the desired new value of "
          << channel_info.value();
    }
  }
}
void ProcessGoogleUpdateItems(const InstallationState& original_state,
                              const InstallerState& installer_state,
                              const Product& product) {
  DCHECK(installer_state.is_multi_install());
  const bool system_level = installer_state.system_install();
  BrowserDistribution* distribution = product.distribution();
  const ProductState* product_state =
      original_state.GetProductState(system_level, distribution->GetType());
  DCHECK(product_state != NULL);
  ChannelInfo channel_info;
  
  channel_info.set_value(product_state->channel().value());
  const bool modified = product.SetChannelFlags(false, &channel_info);
  
  if (modified) {
    scoped_ptr<WorkItemList>
        update_list(WorkItem::CreateNoRollbackWorkItemList());
    std::vector<BrowserDistribution::Type> dist_types;
    for (size_t i = 0; i < BrowserDistribution::NUM_TYPES; ++i) {
      BrowserDistribution::Type other_dist_type =
          static_cast<BrowserDistribution::Type>(i);
      if (distribution->GetType() != other_dist_type)
        dist_types.push_back(other_dist_type);
    }
    AddChannelValueUpdateWorkItems(original_state, installer_state,
                                   channel_info, dist_types,
                                   update_list.get());
    bool success = update_list->Do();
    LOG_IF(ERROR, !success) << "Failed updating channel values.";
  }
}
void ProcessOnOsUpgradeWorkItems(const InstallerState& installer_state,
                                 const Product& product) {
  scoped_ptr<WorkItemList> work_item_list(
      WorkItem::CreateNoRollbackWorkItemList());
  AddOsUpgradeWorkItems(installer_state, base::FilePath(), Version(), product,
                        work_item_list.get());
  if (!work_item_list->Do())
    LOG(ERROR) << "Failed to remove on-os-upgrade command.";
}
void ProcessIELowRightsPolicyWorkItems(const InstallerState& installer_state) {
  scoped_ptr<WorkItemList> work_items(WorkItem::CreateNoRollbackWorkItemList());
  AddDeleteOldIELowRightsPolicyWorkItems(installer_state, work_items.get());
  work_items->Do();
  RefreshElevationPolicy();
}
void ClearRlzProductState() {
  const rlz_lib::AccessPoint points[] = {rlz_lib::CHROME_OMNIBOX,
                                         rlz_lib::CHROME_HOME_PAGE,
                                         rlz_lib::CHROME_APP_LIST,
                                         rlz_lib::NO_ACCESS_POINT};
  rlz_lib::ClearProductState(rlz_lib::CHROME, points);
  
  base::string16 reactivation_brand_wide;
  if (GoogleUpdateSettings::GetReactivationBrand(&reactivation_brand_wide)) {
    std::string reactivation_brand(base::UTF16ToASCII(reactivation_brand_wide));
    rlz_lib::SupplementaryBranding branding(reactivation_brand.c_str());
    rlz_lib::ClearProductState(rlz_lib::CHROME, points);
  }
}
void CheckShouldRemoveSetupAndArchive(const InstallationState& original_state,
                                      const InstallerState& installer_state,
                                      bool* remove_setup,
                                      bool* remove_archive) {
  *remove_setup = true;
  *remove_archive = true;
  
  
  if (!installer_state.is_multi_install()) {
    VLOG(1) << "Removing all installer files for a non-multi installation.";
  } else {
    
    for (size_t i = 0; i < BrowserDistribution::NUM_TYPES; ++i) {
      BrowserDistribution::Type dist_type =
          static_cast<BrowserDistribution::Type>(i);
      const ProductState* product_state = original_state.GetProductState(
          installer_state.system_install(), dist_type);
      
      
      if (product_state && product_state->is_multi_install() &&
          !installer_state.FindProduct(dist_type)) {
        
        
        *remove_setup = false;
        
        
        if (dist_type != BrowserDistribution::CHROME_APP_HOST) {
          VLOG(1) << "Keeping all installer files due to a remaining "
                  << "multi-install product.";
          *remove_archive = false;
          return;
        }
        VLOG(1) << "Keeping setup.exe due to a remaining "
                << "app-host installation.";
      }
    }
    VLOG(1) << "Removing the installer archive.";
    if (remove_setup)
      VLOG(1) << "Removing setup.exe.";
  }
}
bool RemoveInstallerFiles(const base::FilePath& installer_directory,
                          bool remove_setup) {
  base::FileEnumerator file_enumerator(
      installer_directory,
      false,
      base::FileEnumerator::FILES | base::FileEnumerator::DIRECTORIES);
  bool success = true;
  base::FilePath setup_exe_base_name(installer::kSetupExe);
  for (base::FilePath to_delete = file_enumerator.Next(); !to_delete.empty();
       to_delete = file_enumerator.Next()) {
    if (!remove_setup && to_delete.BaseName() == setup_exe_base_name)
      continue;
    VLOG(1) << "Deleting installer path " << to_delete.value();
    if (!base::DeleteFile(to_delete, true)) {
      LOG(ERROR) << "Failed to delete path: " << to_delete.value();
      success = false;
    }
  }
  return success;
}
void CloseAllChromeProcesses() {
  base::CleanupProcesses(installer::kChromeExe, base::TimeDelta(),
                         content::RESULT_CODE_HUNG, NULL);
  base::CleanupProcesses(installer::kNaClExe, base::TimeDelta(),
                         content::RESULT_CODE_HUNG, NULL);
}
void CloseChromeFrameHelperProcess() {
  HWND window = FindWindow(installer::kChromeFrameHelperWndClass, NULL);
  if (!::IsWindow(window))
    return;
  const DWORD kWaitMs = 3000;
  DWORD pid = 0;
  ::GetWindowThreadProcessId(window, &pid);
  DCHECK_NE(pid, 0U);
  base::win::ScopedHandle process(::OpenProcess(SYNCHRONIZE, FALSE, pid));
  PLOG_IF(INFO, !process) << "Failed to open process: " << pid;
  bool kill = true;
  if (SendMessageTimeout(window, WM_CLOSE, 0, 0, SMTO_BLOCK, kWaitMs, NULL) &&
      process) {
    VLOG(1) << "Waiting for " << installer::kChromeFrameHelperExe;
    DWORD wait = ::WaitForSingleObject(process, kWaitMs);
    if (wait != WAIT_OBJECT_0) {
      LOG(WARNING) << "Wait for " << installer::kChromeFrameHelperExe
                   << " to exit failed or timed out.";
    } else {
      kill = false;
      VLOG(1) << installer::kChromeFrameHelperExe << " exited normally.";
    }
  }
  if (kill) {
    VLOG(1) << installer::kChromeFrameHelperExe << " hung.  Killing.";
    base::CleanupProcesses(installer::kChromeFrameHelperExe, base::TimeDelta(),
                           content::RESULT_CODE_HUNG, NULL);
  }
}
void RetargetUserShortcutsWithArgs(const InstallerState& installer_state,
                                   const Product& product,
                                   const base::FilePath& old_target_exe,
                                   const base::FilePath& new_target_exe) {
  if (installer_state.system_install()) {
    NOTREACHED();
    return;
  }
  BrowserDistribution* dist = product.distribution();
  ShellUtil::ShellChange install_level = ShellUtil::CURRENT_USER;
  
  
  VLOG(1) << "Retargeting shortcuts.";
  for (int location = ShellUtil::SHORTCUT_LOCATION_FIRST;
      location < ShellUtil::NUM_SHORTCUT_LOCATIONS; ++location) {
    if (!ShellUtil::RetargetShortcutsWithArgs(
            static_cast<ShellUtil::ShortcutLocation>(location), dist,
            install_level, old_target_exe, new_target_exe)) {
      LOG(WARNING) << "Failed to retarget shortcuts in ShortcutLocation: "
                   << location;
    }
  }
}
void DeleteShortcuts(const InstallerState& installer_state,
                     const Product& product,
                     const base::FilePath& target_exe) {
  BrowserDistribution* dist = product.distribution();
  
  
  ShellUtil::ShellChange install_level = installer_state.system_install() ?
      ShellUtil::SYSTEM_LEVEL : ShellUtil::CURRENT_USER;
  
  
  VLOG(1) << "Deleting shortcuts.";
  for (int location = ShellUtil::SHORTCUT_LOCATION_FIRST;
      location < ShellUtil::NUM_SHORTCUT_LOCATIONS; ++location) {
    if (!ShellUtil::RemoveShortcuts(
            static_cast<ShellUtil::ShortcutLocation>(location), dist,
            install_level, target_exe)) {
      LOG(WARNING) << "Failed to delete shortcuts in ShortcutLocation:"
                   << location;
    }
  }
}
bool ScheduleParentAndGrandparentForDeletion(const base::FilePath& path) {
  base::FilePath parent_dir = path.DirName();
  bool ret = ScheduleFileSystemEntityForDeletion(parent_dir);
  if (!ret) {
    LOG(ERROR) << "Failed to schedule parent dir for deletion: "
               << parent_dir.value();
  } else {
    base::FilePath grandparent_dir(parent_dir.DirName());
    ret = ScheduleFileSystemEntityForDeletion(grandparent_dir);
    if (!ret) {
      LOG(ERROR) << "Failed to schedule grandparent dir for deletion: "
                 << grandparent_dir.value();
    }
  }
  return ret;
}
DeleteResult DeleteEmptyDir(const base::FilePath& path) {
  if (!base::IsDirectoryEmpty(path))
    return DELETE_NOT_EMPTY;
  if (base::DeleteFile(path, true))
    return DELETE_SUCCEEDED;
  LOG(ERROR) << "Failed to delete folder: " << path.value();
  return DELETE_FAILED;
}
base::FilePath GetUserDataDir(const Product& product) {
  
  base::FilePath user_data_dir = product.GetUserDataPath();
  LOG_IF(ERROR, user_data_dir.empty())
      << "Could not retrieve user's profile directory.";
  return user_data_dir;
}
base::FilePath BackupLocalStateFile(const base::FilePath& user_data_dir) {
  base::FilePath backup;
  base::FilePath state_file(
      user_data_dir.Append(chrome::kLocalStateFilename));
  if (!base::CreateTemporaryFile(&backup))
    LOG(ERROR) << "Failed to create temporary file for Local State.";
  else
    base::CopyFile(state_file, backup);
  return backup;
}
DeleteResult DeleteUserDataDir(const base::FilePath& user_data_dir,
                               bool schedule_on_failure) {
  if (user_data_dir.empty())
    return DELETE_SUCCEEDED;
  DeleteResult result = DELETE_SUCCEEDED;
  VLOG(1) << "Deleting user profile " << user_data_dir.value();
  if (!base::DeleteFile(user_data_dir, true)) {
    LOG(ERROR) << "Failed to delete user profile dir: "
               << user_data_dir.value();
    if (schedule_on_failure) {
      ScheduleDirectoryForDeletion(user_data_dir);
      result = DELETE_REQUIRES_REBOOT;
    } else {
      result = DELETE_FAILED;
    }
  }
  if (result == DELETE_REQUIRES_REBOOT) {
    ScheduleParentAndGrandparentForDeletion(user_data_dir);
  } else {
    const base::FilePath user_data_dir(user_data_dir.DirName());
    if (!user_data_dir.empty() &&
        DeleteEmptyDir(user_data_dir) == DELETE_SUCCEEDED) {
      const base::FilePath product_dir(user_data_dir.DirName());
      if (!product_dir.empty())
        DeleteEmptyDir(product_dir);
    }
  }
  return result;
}
bool MoveSetupOutOfInstallFolder(const InstallerState& installer_state,
                                 const base::FilePath& setup_exe) {
  
  
  
  std::vector<base::FilePath> setup_files;
  setup_files.push_back(setup_exe);
#if defined(COMPONENT_BUILD)
  base::FileEnumerator file_enumerator(
      setup_exe.DirName(), false, base::FileEnumerator::FILES, L"*.dll");
  for (base::FilePath setup_dll = file_enumerator.Next(); !setup_dll.empty();
       setup_dll = file_enumerator.Next()) {
    setup_files.push_back(setup_dll);
  }
#endif  
  base::FilePath tmp_dir;
  base::FilePath temp_file;
  if (!PathService::Get(base::DIR_TEMP, &tmp_dir)) {
    NOTREACHED();
    return false;
  }
  
  
  VLOG(1) << "Changing current directory to: " << tmp_dir.value();
  if (!base::SetCurrentDirectory(tmp_dir))
    PLOG(ERROR) << "Failed to change the current directory.";
  for (std::vector<base::FilePath>::const_iterator it = setup_files.begin();
       it != setup_files.end(); ++it) {
    const base::FilePath& setup_file = *it;
    if (!base::CreateTemporaryFileInDir(tmp_dir, &temp_file)) {
      LOG(ERROR) << "Failed to create temporary file for "
                 << setup_file.BaseName().value();
      return false;
    }
    VLOG(1) << "Attempting to move " << setup_file.BaseName().value() << " to: "
            << temp_file.value();
    if (!base::Move(setup_file, temp_file)) {
      PLOG(ERROR) << "Failed to move " << setup_file.BaseName().value()
                  << " to " << temp_file.value();
      return false;
    }
    
    
    if (!base::DeleteFileAfterReboot(temp_file)) {
      const uint32 kDeleteAfterMs = 10 * 1000;
      installer::DeleteFileFromTempProcess(temp_file, kDeleteAfterMs);
    }
  }
  return true;
}
DeleteResult DeleteAppHostFilesAndFolders(const InstallerState& installer_state,
                                          const Version& installed_version) {
  const base::FilePath& target_path = installer_state.target_path();
  if (target_path.empty()) {
    LOG(ERROR) << "DeleteAppHostFilesAndFolders: no installation destination "
               << "path.";
    return DELETE_FAILED;  
  }
  DeleteInstallTempDir(target_path);
  DeleteResult result = DELETE_SUCCEEDED;
  base::FilePath app_host_exe(target_path.Append(installer::kChromeAppHostExe));
  if (!base::DeleteFile(app_host_exe, false)) {
    result = DELETE_FAILED;
    LOG(ERROR) << "Failed to delete path: " << app_host_exe.value();
  }
  return result;
}
DeleteResult DeleteChromeFilesAndFolders(const InstallerState& installer_state,
                                         const base::FilePath& setup_exe) {
  const base::FilePath& target_path = installer_state.target_path();
  if (target_path.empty()) {
    LOG(ERROR) << "DeleteChromeFilesAndFolders: no installation destination "
               << "path.";
    return DELETE_FAILED;  
  }
  DeleteInstallTempDir(target_path);
  DeleteResult result = DELETE_SUCCEEDED;
  base::FilePath installer_directory;
  if (target_path.IsParent(setup_exe))
    installer_directory = setup_exe.DirName();
  
  
  
  
  
  base::FileEnumerator file_enumerator(target_path, true,
      base::FileEnumerator::FILES | base::FileEnumerator::DIRECTORIES);
  for (base::FilePath to_delete = file_enumerator.Next(); !to_delete.empty();
       to_delete = file_enumerator.Next()) {
    if (to_delete.BaseName().value() == installer::kChromeAppHostExe)
      continue;
    if (!installer_directory.empty() &&
        (to_delete == installer_directory ||
         installer_directory.IsParent(to_delete) ||
         to_delete.IsParent(installer_directory))) {
      continue;
    }
    VLOG(1) << "Deleting install path " << to_delete.value();
    if (!base::DeleteFile(to_delete, true)) {
      LOG(ERROR) << "Failed to delete path (1st try): " << to_delete.value();
      if (installer_state.FindProduct(BrowserDistribution::CHROME_FRAME)) {
        
        
        
        base::FileEnumerator::FileInfo find_info = file_enumerator.GetInfo();
        if (find_info.IsDirectory())
          ScheduleDirectoryForDeletion(to_delete);
        else
          ScheduleFileSystemEntityForDeletion(to_delete);
        result = DELETE_REQUIRES_REBOOT;
      } else {
        
        
        CloseAllChromeProcesses();
        if (!base::DeleteFile(to_delete, true)) {
          LOG(ERROR) << "Failed to delete path (2nd try): "
                     << to_delete.value();
          result = DELETE_FAILED;
          break;
        }
      }
    }
  }
  return result;
}
InstallStatus IsChromeActiveOrUserCancelled(
    const InstallerState& installer_state,
    const Product& product) {
  int32 exit_code = content::RESULT_CODE_NORMAL_EXIT;
  CommandLine options(CommandLine::NO_PROGRAM);
  options.AppendSwitch(installer::switches::kUninstall);
  
  
  
  
  
  
  
  
  VLOG(1) << "Launching Chrome to do uninstall tasks.";
  if (product.LaunchChromeAndWait(installer_state.target_path(), options,
                                  &exit_code)) {
    VLOG(1) << "chrome.exe launched for uninstall confirmation returned: "
            << exit_code;
    if ((exit_code == chrome::RESULT_CODE_UNINSTALL_CHROME_ALIVE) ||
        (exit_code == chrome::RESULT_CODE_UNINSTALL_USER_CANCEL) ||
        (exit_code == content::RESULT_CODE_HUNG))
      return installer::UNINSTALL_CANCELLED;
    if (exit_code == chrome::RESULT_CODE_UNINSTALL_DELETE_PROFILE)
      return installer::UNINSTALL_DELETE_PROFILE;
  } else {
    PLOG(ERROR) << "Failed to launch chrome.exe for uninstall confirmation.";
  }
  return installer::UNINSTALL_CONFIRMED;
}
bool ShouldDeleteProfile(const InstallerState& installer_state,
                         const CommandLine& cmd_line, InstallStatus status,
                         const Product& product) {
  bool should_delete = false;
  
  
  
  
  if (product.is_chrome_frame() && !installer_state.is_msi()) {
    should_delete = true;
  } else {
    should_delete =
        status == installer::UNINSTALL_DELETE_PROFILE ||
        cmd_line.HasSwitch(installer::switches::kDeleteProfile);
  }
  return should_delete;
}
void RemoveFiletypeRegistration(const InstallerState& installer_state,
                                HKEY root,
                                const base::string16& browser_entry_suffix) {
  base::string16 classes_path(ShellUtil::kRegClasses);
  classes_path.push_back(base::FilePath::kSeparators[0]);
  BrowserDistribution* distribution = BrowserDistribution::GetDistribution();
  const base::string16 prog_id(
      distribution->GetBrowserProgIdPrefix() + browser_entry_suffix);
  
  
  
  
  std::vector<const wchar_t*> cleared_assocs;
  if (installer_state.system_install() ||
      !browser_entry_suffix.empty() ||
      !base::win::RegKey(HKEY_LOCAL_MACHINE, (classes_path + prog_id).c_str(),
                         KEY_QUERY_VALUE).Valid()) {
    InstallUtil::ValueEquals prog_id_pred(prog_id);
    for (const wchar_t* const* filetype =
         &ShellUtil::kPotentialFileAssociations[0]; *filetype != NULL;
         ++filetype) {
      if (InstallUtil::DeleteRegistryValueIf(
              root, (classes_path + *filetype).c_str(), NULL,
              prog_id_pred) == InstallUtil::DELETED) {
        cleared_assocs.push_back(*filetype);
      }
    }
  }
  
  
  
  
  if (root == HKEY_LOCAL_MACHINE) {
    base::string16 assoc;
    base::win::RegKey key;
    for (size_t i = 0; i < cleared_assocs.size(); ++i) {
      const wchar_t* replacement_prog_id = NULL;
      assoc.assign(cleared_assocs[i]);
      
      if (assoc == L".htm" || assoc == L".html")
        replacement_prog_id = L"htmlfile";
      else if (assoc == L".xht" || assoc == L".xhtml")
        replacement_prog_id = L"xhtmlfile";
      if (!replacement_prog_id) {
        LOG(WARNING) << "No known replacement ProgID for " << assoc
                     << " files.";
      } else if (key.Open(HKEY_LOCAL_MACHINE,
                          (classes_path + replacement_prog_id).c_str(),
                          KEY_QUERY_VALUE) == ERROR_SUCCESS &&
                 (key.Open(HKEY_LOCAL_MACHINE, (classes_path + assoc).c_str(),
                           KEY_SET_VALUE) != ERROR_SUCCESS ||
                  key.WriteValue(NULL, replacement_prog_id) != ERROR_SUCCESS)) {
        
        
        LOG(ERROR) << "Failed to restore system-level filetype association "
                   << assoc << " = " << replacement_prog_id;
      }
    }
  }
}
bool ProcessDelegateExecuteWorkItems(const InstallerState& installer_state,
                                     const Product& product) {
  scoped_ptr<WorkItemList> item_list(WorkItem::CreateNoRollbackWorkItemList());
  AddDelegateExecuteWorkItems(installer_state, base::FilePath(), Version(),
                              product, item_list.get());
  return item_list->Do();
}
void UninstallActiveSetupEntries(const InstallerState& installer_state,
                                 const Product& product) {
  VLOG(1) << "Uninstalling registry entries for ActiveSetup.";
  BrowserDistribution* distribution = product.distribution();
  if (!product.is_chrome() || !installer_state.system_install()) {
    const char* install_level =
        installer_state.system_install() ? "system" : "user";
    VLOG(1) << "No Active Setup processing to do for " << install_level
            << "-level " << distribution->GetDisplayName();
    return;
  }
  const base::string16 active_setup_path(
      InstallUtil::GetActiveSetupPath(distribution));
  InstallUtil::DeleteRegistryKey(HKEY_LOCAL_MACHINE, active_setup_path);
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  static const wchar_t kProfileList[] =
      L"Software\\Microsoft\\Windows NT\\CurrentVersion\\ProfileList\\";
  
  
  
  base::string16 alternate_active_setup_path(active_setup_path);
  alternate_active_setup_path.insert(arraysize("Software\\") - 1,
                                     L"Wow6432Node\\");
  
  ScopedTokenPrivilege se_restore_name_privilege(SE_RESTORE_NAME);
  ScopedTokenPrivilege se_backup_name_privilege(SE_BACKUP_NAME);
  if (!se_restore_name_privilege.is_enabled() ||
      !se_backup_name_privilege.is_enabled()) {
    
    
    
    LOG(WARNING) << "Failed to enable privileges required to load registry "
                    "hives.";
  }
  for (base::win::RegistryKeyIterator it(HKEY_LOCAL_MACHINE, kProfileList);
       it.Valid(); ++it) {
    const wchar_t* profile_sid = it.Name();
    
    
    base::win::RegKey user_reg_root_probe(
        HKEY_USERS, profile_sid, KEY_READ);
    bool loaded_hive = false;
    if (!user_reg_root_probe.Valid()) {
      VLOG(1) << "Attempting to load registry hive for " << profile_sid;
      base::string16 reg_profile_info_path(kProfileList);
      reg_profile_info_path.append(profile_sid);
      base::win::RegKey reg_profile_info_key(
          HKEY_LOCAL_MACHINE, reg_profile_info_path.c_str(), KEY_READ);
      base::string16 profile_path;
      LONG result = reg_profile_info_key.ReadValue(L"ProfileImagePath",
                                                   &profile_path);
      if (result != ERROR_SUCCESS) {
        LOG(ERROR) << "Error reading ProfileImagePath: " << result;
        continue;
      }
      base::FilePath registry_hive_file(profile_path);
      registry_hive_file = registry_hive_file.AppendASCII("NTUSER.DAT");
      result = RegLoadKey(HKEY_USERS, profile_sid,
                          registry_hive_file.value().c_str());
      if (result != ERROR_SUCCESS) {
        LOG(ERROR) << "Error loading registry hive: " << result;
        continue;
      }
      VLOG(1) << "Loaded registry hive for " << profile_sid;
      loaded_hive = true;
    }
    base::win::RegKey user_reg_root(
        HKEY_USERS, profile_sid, KEY_ALL_ACCESS);
    LONG result = user_reg_root.DeleteKey(active_setup_path.c_str());
    if (result != ERROR_SUCCESS) {
      result = user_reg_root.DeleteKey(alternate_active_setup_path.c_str());
      if (result != ERROR_SUCCESS && result != ERROR_FILE_NOT_FOUND) {
        LOG(ERROR) << "Failed to delete key at " << active_setup_path
                   << " and at " << alternate_active_setup_path
                   << ", result: " << result;
      }
    }
    if (loaded_hive) {
      user_reg_root.Close();
      if (RegUnLoadKey(HKEY_USERS, profile_sid) == ERROR_SUCCESS)
        VLOG(1) << "Unloaded registry hive for " << profile_sid;
      else
        LOG(ERROR) << "Error unloading registry hive for " << profile_sid;
    }
  }
}
}  
DeleteResult DeleteChromeDirectoriesIfEmpty(
    const base::FilePath& application_directory) {
  DeleteResult result(DeleteEmptyDir(application_directory));
  if (result == DELETE_SUCCEEDED) {
    
    
    const base::FilePath product_directory(application_directory.DirName());
    if (!product_directory.empty()) {
        result = DeleteEmptyDir(product_directory);
        if (result == DELETE_SUCCEEDED) {
          const base::FilePath vendor_directory(product_directory.DirName());
          if (!vendor_directory.empty())
            result = DeleteEmptyDir(vendor_directory);
        }
    }
  }
  if (result == DELETE_NOT_EMPTY)
    result = DELETE_SUCCEEDED;
  return result;
}
bool DeleteChromeRegistrationKeys(const InstallerState& installer_state,
                                  BrowserDistribution* dist,
                                  HKEY root,
                                  const base::string16& browser_entry_suffix,
                                  InstallStatus* exit_code) {
  DCHECK(exit_code);
  if (dist->GetDefaultBrowserControlPolicy() ==
      BrowserDistribution::DEFAULT_BROWSER_UNSUPPORTED) {
    
    return true;
  }
  base::FilePath chrome_exe(installer_state.target_path().Append(kChromeExe));
  
  const base::string16 prog_id(
      dist->GetBrowserProgIdPrefix() + browser_entry_suffix);
  base::string16 reg_prog_id(ShellUtil::kRegClasses);
  reg_prog_id.push_back(base::FilePath::kSeparators[0]);
  reg_prog_id.append(prog_id);
  InstallUtil::DeleteRegistryKey(root, reg_prog_id);
  
  base::string16 reg_app_id(ShellUtil::kRegClasses);
  reg_app_id.push_back(base::FilePath::kSeparators[0]);
  
  
  reg_app_id.append(dist->GetBaseAppId() + browser_entry_suffix);
  InstallUtil::DeleteRegistryKey(root, reg_app_id);
  
  {
    using base::win::RegistryKeyIterator;
    InstallUtil::ProgramCompare open_command_pred(chrome_exe);
    base::string16 client_name;
    base::string16 client_key;
    base::string16 open_key;
    for (RegistryKeyIterator iter(root, ShellUtil::kRegStartMenuInternet);
         iter.Valid(); ++iter) {
      client_name.assign(iter.Name());
      client_key.assign(ShellUtil::kRegStartMenuInternet)
          .append(1, L'\\')
          .append(client_name);
      open_key.assign(client_key).append(ShellUtil::kRegShellOpen);
      if (InstallUtil::DeleteRegistryKeyIf(root, client_key, open_key, NULL,
              open_command_pred) != InstallUtil::NOT_FOUND) {
        
        
        InstallUtil::DeleteRegistryValueIf(
            root, ShellUtil::kRegStartMenuInternet, NULL,
            InstallUtil::ValueEquals(client_name));
        
        
        if (root == HKEY_LOCAL_MACHINE) {
          InstallUtil::DeleteRegistryValueIf(
              HKEY_USERS,
              base::string16(L".DEFAULT\\").append(
                  ShellUtil::kRegStartMenuInternet).c_str(),
              NULL, InstallUtil::ValueEquals(client_name));
        }
      }
    }
  }
  
  InstallUtil::DeleteRegistryValue(
      root, ShellUtil::kRegRegisteredApplications,
      dist->GetBaseAppName() + browser_entry_suffix);
  
  
  base::string16 app_key(ShellUtil::kRegClasses);
  app_key.push_back(base::FilePath::kSeparators[0]);
  app_key.append(L"Applications");
  app_key.push_back(base::FilePath::kSeparators[0]);
  app_key.append(installer::kChromeExe);
  InstallUtil::DeleteRegistryKey(root, app_key);
  base::string16 app_path_key(ShellUtil::kAppPathsRegistryKey);
  app_path_key.push_back(base::FilePath::kSeparators[0]);
  app_path_key.append(installer::kChromeExe);
  InstallUtil::DeleteRegistryKey(root, app_path_key);
  
  
  base::string16 file_assoc_key;
  base::string16 open_with_list_key;
  base::string16 open_with_progids_key;
  for (int i = 0; ShellUtil::kPotentialFileAssociations[i] != NULL; ++i) {
    file_assoc_key.assign(ShellUtil::kRegClasses);
    file_assoc_key.push_back(base::FilePath::kSeparators[0]);
    file_assoc_key.append(ShellUtil::kPotentialFileAssociations[i]);
    file_assoc_key.push_back(base::FilePath::kSeparators[0]);
    open_with_list_key.assign(file_assoc_key);
    open_with_list_key.append(L"OpenWithList");
    open_with_list_key.push_back(base::FilePath::kSeparators[0]);
    open_with_list_key.append(installer::kChromeExe);
    InstallUtil::DeleteRegistryKey(root, open_with_list_key);
    open_with_progids_key.assign(file_assoc_key);
    open_with_progids_key.append(ShellUtil::kRegOpenWithProgids);
    InstallUtil::DeleteRegistryValue(root, open_with_progids_key, prog_id);
  }
  
  
  
  
  
  InstallUtil::DeleteRegistryValueIf(
      root, ShellUtil::kRegStartMenuInternet, NULL,
      InstallUtil::ValueEquals(dist->GetBaseAppName() + browser_entry_suffix));
  
  InstallUtil::ProgramCompare open_command_pred(chrome_exe);
  base::string16 parent_key(ShellUtil::kRegClasses);
  parent_key.push_back(base::FilePath::kSeparators[0]);
  const base::string16::size_type base_length = parent_key.size();
  base::string16 child_key;
  for (const wchar_t* const* proto =
           &ShellUtil::kPotentialProtocolAssociations[0];
       *proto != NULL;
       ++proto) {
    parent_key.resize(base_length);
    parent_key.append(*proto);
    child_key.assign(parent_key).append(ShellUtil::kRegShellOpen);
    InstallUtil::DeleteRegistryKeyIf(root, parent_key, child_key, NULL,
                                     open_command_pred);
  }
  RemoveFiletypeRegistration(installer_state, root, browser_entry_suffix);
  *exit_code = installer::UNINSTALL_SUCCESSFUL;
  return true;
}
void RemoveChromeLegacyRegistryKeys(BrowserDistribution* dist,
                                    const base::string16& chrome_exe) {
  
  
  
#if defined(GOOGLE_CHROME_BUILD)
const wchar_t kChromeExtProgId[] = L"ChromeExt";
#else
const wchar_t kChromeExtProgId[] = L"ChromiumExt";
#endif
  HKEY roots[] = { HKEY_LOCAL_MACHINE, HKEY_CURRENT_USER };
  for (size_t i = 0; i < arraysize(roots); ++i) {
    base::string16 suffix;
    if (roots[i] == HKEY_LOCAL_MACHINE)
      suffix = ShellUtil::GetCurrentInstallationSuffix(dist, chrome_exe);
    
    base::string16 ext_prog_id(ShellUtil::kRegClasses);
    ext_prog_id.push_back(base::FilePath::kSeparators[0]);
    ext_prog_id.append(kChromeExtProgId);
    ext_prog_id.append(suffix);
    InstallUtil::DeleteRegistryKey(roots[i], ext_prog_id);
    
    base::string16 ext_association(ShellUtil::kRegClasses);
    ext_association.append(L"\\");
    ext_association.append(extensions::kExtensionFileExtension);
    InstallUtil::DeleteRegistryKey(roots[i], ext_association);
  }
}
InstallStatus UninstallProduct(const InstallationState& original_state,
                               const InstallerState& installer_state,
                               const base::FilePath& setup_exe,
                               const Product& product,
                               bool remove_all,
                               bool force_uninstall,
                               const CommandLine& cmd_line) {
  InstallStatus status = installer::UNINSTALL_CONFIRMED;
  BrowserDistribution* browser_dist = product.distribution();
  const base::string16 chrome_exe(
      installer_state.target_path().Append(installer::kChromeExe).value());
  bool is_chrome = product.is_chrome();
  VLOG(1) << "UninstallProduct: " << browser_dist->GetDisplayName();
  if (force_uninstall) {
    
    
    
    if (is_chrome)
      CloseAllChromeProcesses();
  } else if (is_chrome) {
    
    status = IsChromeActiveOrUserCancelled(installer_state, product);
    if (status != installer::UNINSTALL_CONFIRMED &&
        status != installer::UNINSTALL_DELETE_PROFILE)
      return status;
    const base::string16 suffix(
        ShellUtil::GetCurrentInstallationSuffix(browser_dist, chrome_exe));
    
    
    
    
    
    
    if (remove_all &&
        ShellUtil::QuickIsChromeRegisteredInHKLM(
            browser_dist, chrome_exe, suffix) &&
        !::IsUserAnAdmin() &&
        base::win::GetVersion() >= base::win::VERSION_VISTA &&
        !cmd_line.HasSwitch(installer::switches::kRunAsAdmin)) {
      CommandLine new_cmd(CommandLine::NO_PROGRAM);
      new_cmd.AppendArguments(cmd_line, true);
      
      
      new_cmd.AppendSwitch(installer::switches::kRunAsAdmin);
      
      new_cmd.AppendSwitch(installer::switches::kRemoveChromeRegistration);
      if (!suffix.empty()) {
        new_cmd.AppendSwitchNative(
            installer::switches::kRegisterChromeBrowserSuffix, suffix);
      }
      DWORD exit_code = installer::UNKNOWN_STATUS;
      InstallUtil::ExecuteExeAsAdmin(new_cmd, &exit_code);
    }
  }
  if (is_chrome) {
    
    
    
    ClearRlzProductState();
    
    if (base::win::GetVersion() >= base::win::VERSION_WIN8) {
      InstallUtil::DeleteRegistryKey(HKEY_CURRENT_USER,
                                     chrome::kMetroRegistryPath);
    }
    auto_launch_util::DisableAllAutoStartFeatures(
        base::ASCIIToUTF16(chrome::kInitialProfile));
    
    
    
    if (cmd_line.HasSwitch(installer::switches::kSelfDestruct) &&
        !installer_state.system_install()) {
      const base::FilePath system_chrome_path(
          GetChromeInstallPath(true, browser_dist).
              Append(installer::kChromeExe));
      VLOG(1) << "Retargeting user-generated Chrome shortcuts.";
      if (base::PathExists(system_chrome_path)) {
        RetargetUserShortcutsWithArgs(installer_state, product,
                                      base::FilePath(chrome_exe),
                                      system_chrome_path);
      } else {
        LOG(ERROR) << "Retarget failed: system-level Chrome not found.";
      }
    }
    DeleteShortcuts(installer_state, product, base::FilePath(chrome_exe));
  }
  
  HKEY reg_root = installer_state.root_key();
  
  
  base::string16 distribution_data(browser_dist->GetDistributionData(reg_root));
  
  if (product.ShouldCreateUninstallEntry()) {
    InstallUtil::DeleteRegistryKey(reg_root,
                                   browser_dist->GetUninstallRegPath());
  }
  
  InstallUtil::DeleteRegistryKey(reg_root, browser_dist->GetVersionKey());
  
  
  
  
  product.SetMsiMarker(installer_state.system_install(), false);
  InstallStatus ret = installer::UNKNOWN_STATUS;
  if (is_chrome) {
    const base::string16 suffix(
        ShellUtil::GetCurrentInstallationSuffix(browser_dist, chrome_exe));
    
    
    
    DeleteChromeRegistrationKeys(installer_state, browser_dist,
                                 HKEY_CURRENT_USER, suffix, &ret);
    
    
    
    
    
    
    
    if (!suffix.empty()) {
      DeleteChromeRegistrationKeys(installer_state, browser_dist,
                                   HKEY_CURRENT_USER, base::string16(), &ret);
      
      
      
      base::string16 old_style_suffix;
      if (ShellUtil::GetOldUserSpecificRegistrySuffix(&old_style_suffix) &&
          suffix != old_style_suffix) {
        DeleteChromeRegistrationKeys(installer_state, browser_dist,
                                     HKEY_CURRENT_USER, old_style_suffix, &ret);
      }
    }
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    if (installer_state.system_install() ||
        (remove_all &&
         ShellUtil::QuickIsChromeRegisteredInHKLM(
             browser_dist, chrome_exe, suffix))) {
      DeleteChromeRegistrationKeys(installer_state, browser_dist,
                                   HKEY_LOCAL_MACHINE, suffix, &ret);
    }
    ProcessDelegateExecuteWorkItems(installer_state, product);
    ProcessOnOsUpgradeWorkItems(installer_state, product);
    UninstallActiveSetupEntries(installer_state, product);
    
    
    SHChangeNotify(SHCNE_ASSOCCHANGED, SHCNF_IDLIST, NULL, NULL);
    
    
    if (installer_state.is_multi_install()) {
      
      
      chrome_launcher_support::InstallationState level_to_check =
          installer_state.system_install() ?
              chrome_launcher_support::INSTALLED_AT_SYSTEM_LEVEL :
              chrome_launcher_support::INSTALLED_AT_USER_LEVEL;
      bool has_legacy_app_launcher = level_to_check ==
          chrome_launcher_support::GetAppLauncherInstallationState();
      if (!has_legacy_app_launcher) {
        BrowserDistribution* shadow_app_launcher_dist =
            BrowserDistribution::GetSpecificDistribution(
                BrowserDistribution::CHROME_APP_HOST);
        InstallUtil::DeleteRegistryKey(reg_root,
            shadow_app_launcher_dist->GetVersionKey());
      }
    }
  }
  if (installer_state.is_multi_install())
    ProcessGoogleUpdateItems(original_state, installer_state, product);
  
  const ProductState* product_state =
      original_state.GetProductState(installer_state.system_install(),
                                     browser_dist->GetType());
  
  
  if (remove_all) {
    if (!InstallUtil::IsChromeSxSProcess() && is_chrome) {
      
      
      
      base::string16 reg_path(installer::kMediaPlayerRegPath);
      reg_path.push_back(base::FilePath::kSeparators[0]);
      reg_path.append(installer::kChromeExe);
      InstallUtil::DeleteRegistryKey(HKEY_LOCAL_MACHINE, reg_path);
    }
    
    
    if (product_state != NULL) {
      std::vector<base::FilePath> com_dll_list;
      product.AddComDllList(&com_dll_list);
      base::FilePath dll_folder = installer_state.target_path().AppendASCII(
          product_state->version().GetString());
      scoped_ptr<WorkItemList> unreg_work_item_list(
          WorkItem::CreateWorkItemList());
      AddRegisterComDllWorkItems(dll_folder,
                                 com_dll_list,
                                 installer_state.system_install(),
                                 false,  
                                 true,   
                                 unreg_work_item_list.get());
      unreg_work_item_list->Do();
    }
    if (product.is_chrome_frame())
      ProcessIELowRightsPolicyWorkItems(installer_state);
  }
  
  if (product.is_chrome_frame()) {
    VLOG(1) << "Closing the Chrome Frame helper process";
    CloseChromeFrameHelperProcess();
  }
  if (product_state == NULL)
    return installer::UNINSTALL_SUCCESSFUL;
  
  
  bool delete_profile = ShouldDeleteProfile(installer_state, cmd_line, status,
                                            product);
  ret = installer::UNINSTALL_SUCCESSFUL;
  
  
  base::FilePath user_data_dir(GetUserDataDir(product));
  base::FilePath backup_state_file(BackupLocalStateFile(user_data_dir));
  if (product.is_chrome_app_host()) {
    DeleteAppHostFilesAndFolders(installer_state, product_state->version());
  } else if (!installer_state.is_multi_install() ||
             product.is_chrome_binaries()) {
    DeleteResult delete_result = DeleteChromeFilesAndFolders(
        installer_state, base::MakeAbsoluteFilePath(setup_exe));
    if (delete_result == DELETE_FAILED) {
      ret = installer::UNINSTALL_FAILED;
    } else if (delete_result == DELETE_REQUIRES_REBOOT) {
      ret = installer::UNINSTALL_REQUIRES_REBOOT;
    }
  }
  if (delete_profile)
    DeleteUserDataDir(user_data_dir, product.is_chrome_frame());
  if (!force_uninstall) {
    VLOG(1) << "Uninstallation complete. Launching post-uninstall operations.";
    browser_dist->DoPostUninstallOperations(product_state->version(),
        backup_state_file, distribution_data);
  }
  
  
  if (!backup_state_file.empty())
    base::DeleteFile(backup_state_file, false);
  return ret;
}
void CleanUpInstallationDirectoryAfterUninstall(
    const InstallationState& original_state,
    const InstallerState& installer_state,
    const base::FilePath& setup_exe,
    InstallStatus* uninstall_status) {
  if (*uninstall_status != UNINSTALL_SUCCESSFUL &&
      *uninstall_status != UNINSTALL_REQUIRES_REBOOT) {
    return;
  }
  const base::FilePath target_path(installer_state.target_path());
  if (target_path.empty()) {
    LOG(ERROR) << "No installation destination path.";
    *uninstall_status = UNINSTALL_FAILED;
    return;
  }
  if (!target_path.IsParent(base::MakeAbsoluteFilePath(setup_exe))) {
    VLOG(1) << "setup.exe is not in target path. Skipping installer cleanup.";
    return;
  }
  base::FilePath install_directory(setup_exe.DirName());
  bool remove_setup = true;
  bool remove_archive = true;
  CheckShouldRemoveSetupAndArchive(original_state, installer_state,
                                   &remove_setup, &remove_archive);
  if (!remove_archive)
    return;
  if (remove_setup) {
    
    
    
    MoveSetupOutOfInstallFolder(installer_state, setup_exe);
  }
  
  if (!RemoveInstallerFiles(install_directory, remove_setup)) {
    *uninstall_status = UNINSTALL_FAILED;
    return;
  }
  if (!remove_setup)
    return;
  
  
  if (DeleteEmptyDir(install_directory) != DELETE_SUCCEEDED) {
    *uninstall_status = UNINSTALL_FAILED;
    return;
  }
  
  DeleteResult delete_result = DeleteEmptyDir(install_directory.DirName());
  if (delete_result == DELETE_FAILED ||
      (delete_result == DELETE_NOT_EMPTY &&
       *uninstall_status != UNINSTALL_REQUIRES_REBOOT)) {
    *uninstall_status = UNINSTALL_FAILED;
    return;
  }
  if (*uninstall_status == UNINSTALL_REQUIRES_REBOOT) {
    
    ScheduleFileSystemEntityForDeletion(target_path);
    
    
    
    ScheduleParentAndGrandparentForDeletion(target_path);
  } else if (DeleteChromeDirectoriesIfEmpty(target_path) == DELETE_FAILED) {
    *uninstall_status = UNINSTALL_FAILED;
  }
}
}