chromium/chrome/installer/setup/installer_state.cc

// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/installer/setup/installer_state.h"

#include <stddef.h>

#include <string>

#include "base/command_line.h"
#include "base/files/file_util.h"
#include "base/logging.h"
#include "base/win/registry.h"
#include "build/branding_buildflags.h"
#include "chrome/install_static/install_util.h"
#include "chrome/installer/setup/setup_util.h"
#include "chrome/installer/util/google_update_settings.h"
#include "chrome/installer/util/helper.h"
#include "chrome/installer/util/initial_preferences.h"
#include "chrome/installer/util/initial_preferences_constants.h"
#include "chrome/installer/util/install_util.h"
#include "chrome/installer/util/installation_state.h"
#include "chrome/installer/util/work_item.h"
#include "chrome/installer/util/work_item_list.h"

namespace installer {

namespace {

// Returns the boolean value of the distribution preference in |prefs| named
// |pref_name|, or |default_value| if not set.
bool GetMasterPreference(const InitialPreferences& prefs,
                         const char* pref_name,
                         bool default_value) {
  bool value;
  return prefs.GetBool(pref_name, &value) ? value : default_value;
}

}  // namespace

InstallerState::InstallerState()
    : operation_(UNINITIALIZED),
      level_(UNKNOWN_LEVEL),
      root_key_(nullptr),
      msi_(false),
      verbose_logging_(false) {}

InstallerState::InstallerState(Level level)
    : operation_(UNINITIALIZED),
      level_(UNKNOWN_LEVEL),
      root_key_(nullptr),
      msi_(false),
      verbose_logging_(false) {
  // Use set_level() so that root_key_ is updated properly.
  set_level(level);
}

InstallerState::~InstallerState() {}

void InstallerState::Initialize(const base::CommandLine& command_line,
                                const InitialPreferences& prefs,
                                const InstallationState& machine_state) {
  Clear();

  set_level(GetMasterPreference(prefs, initial_preferences::kSystemLevel, false)
                ? SYSTEM_LEVEL
                : USER_LEVEL);

  verbose_logging_ =
      GetMasterPreference(prefs, initial_preferences::kVerboseLogging, false);

  msi_ = GetMasterPreference(prefs, initial_preferences::kMsi, false);
  if (!msi_) {
    const ProductState* product_state =
        machine_state.GetProductState(system_install());
    if (product_state != nullptr)
      msi_ = product_state->is_msi();
  }

  const bool is_uninstall = command_line.HasSwitch(switches::kUninstall);

  target_path_ = GetChromeInstallPathWithPrefs(system_install(), prefs);

  state_key_ = install_static::GetClientStateKeyPath();

  VLOG(1) << (is_uninstall ? "Uninstall Chrome" : "Install Chrome");

  operation_ = is_uninstall ? UNINSTALL : SINGLE_INSTALL_OR_UPDATE;

  // Parse --critical-update-version=W.X.Y.Z
  std::string critical_version_value(
      command_line.GetSwitchValueASCII(switches::kCriticalUpdateVersion));
  critical_update_version_ = base::Version(critical_version_value);
}

void InstallerState::set_level(Level level) {
  level_ = level;
  switch (level) {
    case UNKNOWN_LEVEL:
      root_key_ = nullptr;
      return;
    case USER_LEVEL:
      root_key_ = HKEY_CURRENT_USER;
      return;
    case SYSTEM_LEVEL:
      root_key_ = HKEY_LOCAL_MACHINE;
      return;
  }
  NOTREACHED_IN_MIGRATION() << level;
}

bool InstallerState::system_install() const {
  DCHECK(level_ == USER_LEVEL || level_ == SYSTEM_LEVEL);
  return level_ == SYSTEM_LEVEL;
}

base::Version InstallerState::GetCurrentVersion(
    const InstallationState& machine_state) const {
  base::Version current_version;
  const ProductState* product_state =
      machine_state.GetProductState(level_ == SYSTEM_LEVEL);

  if (product_state) {
    // Be aware that there might be a pending "new_chrome.exe" already in the
    // installation path.  If so, we use old_version, which holds the version of
    // "chrome.exe" itself.
    if (base::PathExists(target_path().Append(kChromeNewExe)) &&
        product_state->old_version()) {
      current_version = *(product_state->old_version());
    } else {
      current_version = product_state->version();
    }
  }

  return current_version;
}

base::Version InstallerState::DetermineCriticalVersion(
    const base::Version& current_version,
    const base::Version& new_version) const {
  DCHECK(new_version.IsValid());
  if (critical_update_version_.IsValid() &&
      (!current_version.IsValid() ||
       (current_version.CompareTo(critical_update_version_) < 0)) &&
      new_version.CompareTo(critical_update_version_) >= 0) {
    return critical_update_version_;
  }
  return base::Version();
}

base::FilePath InstallerState::GetInstallerDirectory(
    const base::Version& version) const {
  return target_path().AppendASCII(version.GetString()).Append(kInstallerDir);
}

void InstallerState::Clear() {
  operation_ = UNINITIALIZED;
  target_path_.clear();
  state_key_.clear();
  critical_update_version_ = base::Version();
  level_ = UNKNOWN_LEVEL;
  root_key_ = nullptr;
  msi_ = false;
  verbose_logging_ = false;
}

void InstallerState::SetStage(InstallerStage stage) const {
  GoogleUpdateSettings::SetProgress(system_install(), state_key_,
                                    progress_calculator_.Calculate(stage));
}

void InstallerState::WriteInstallerResult(
    InstallStatus status,
    int string_resource_id,
    const std::wstring* const launch_cmd) const {
  // Use a no-rollback list since this is a best-effort deal.
  std::unique_ptr<WorkItemList> install_list(WorkItem::CreateWorkItemList());
  install_list->set_log_message("Write Installer Result");
  install_list->set_best_effort(true);
  install_list->set_rollback_enabled(false);
  const bool system_install = this->system_install();
  // Write the value for the product upon which we're operating.
  InstallUtil::AddInstallerResultItems(
      system_install, install_static::GetClientStateKeyPath(), status,
      string_resource_id, launch_cmd, install_list.get());
  install_list->Do();
}

bool InstallerState::RequiresActiveSetup() const {
  return system_install();
}

}  // namespace installer