root/chrome/installer/util/installation_state.cc

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. has_usagestats_
  2. Initialize
  3. InitializeCommands
  4. Initialize
  5. GetSetupPath
  6. version
  7. CopyFrom
  8. Clear
  9. GetEulaAccepted
  10. GetOemInstall
  11. GetUsageStats
  12. IndexFromDistType
  13. Initialize
  14. GetNonVersionedProductState
  15. GetProductState

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

#include "chrome/installer/util/installation_state.h"

#include "base/logging.h"
#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
#include "base/version.h"
#include "base/win/registry.h"
#include "chrome/installer/util/google_update_constants.h"
#include "chrome/installer/util/install_util.h"

namespace installer {

ProductState::ProductState()
    : uninstall_command_(CommandLine::NO_PROGRAM),
      eula_accepted_(0),
      usagestats_(0),
      msi_(false),
      multi_install_(false),
      has_eula_accepted_(false),
      has_oem_install_(false),
      has_usagestats_(false) {
}

bool ProductState::Initialize(bool system_install,
                              BrowserDistribution::Type type) {
  return Initialize(system_install,
                    BrowserDistribution::GetSpecificDistribution(type));
}

// Initializes |commands| from the "Commands" subkey of |version_key|.
// Returns false if there is no "Commands" subkey or on error.
// static
bool ProductState::InitializeCommands(const base::win::RegKey& version_key,
                                      AppCommands* commands) {
  static const DWORD kAccess = KEY_ENUMERATE_SUB_KEYS | KEY_QUERY_VALUE;
  base::win::RegKey commands_key;

  if (commands_key.Open(version_key.Handle(), google_update::kRegCommandsKey,
                        kAccess) == ERROR_SUCCESS)
    return commands->Initialize(commands_key);
  return false;
}

bool ProductState::Initialize(bool system_install,
                              BrowserDistribution* distribution) {
  const std::wstring version_key(distribution->GetVersionKey());
  const std::wstring state_key(distribution->GetStateKey());
  const HKEY root_key = system_install ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER;
  base::win::RegKey key;

  // Clear the runway.
  Clear();

  // Read from the Clients key.
  if (key.Open(root_key, version_key.c_str(),
               KEY_QUERY_VALUE) == ERROR_SUCCESS) {
    base::string16 version_str;
    if (key.ReadValue(google_update::kRegVersionField,
                      &version_str) == ERROR_SUCCESS) {
      version_.reset(new Version(base::UTF16ToASCII(version_str)));
      if (!version_->IsValid())
        version_.reset();
    }

    // Attempt to read the other values even if the "pv" version value was
    // absent. Note that ProductState instances containing these values will
    // only be accessible via InstallationState::GetNonVersionedProductState.
    if (key.ReadValue(google_update::kRegOldVersionField,
                      &version_str) == ERROR_SUCCESS) {
      old_version_.reset(new Version(base::UTF16ToASCII(version_str)));
      if (!old_version_->IsValid())
        old_version_.reset();
    }

    key.ReadValue(google_update::kRegRenameCmdField, &rename_cmd_);
    if (!InitializeCommands(key, &commands_))
      commands_.Clear();
  }

  // Read from the ClientState key.
  if (key.Open(root_key, state_key.c_str(),
               KEY_QUERY_VALUE) == ERROR_SUCCESS) {
    std::wstring setup_path;
    std::wstring uninstall_arguments;
    // "ap" will be absent if not managed by Google Update.
    channel_.Initialize(key);

    // Read in the brand code, it may be absent
    key.ReadValue(google_update::kRegBrandField, &brand_);

    // "UninstallString" will be absent for the multi-installer package.
    key.ReadValue(kUninstallStringField, &setup_path);
    // "UninstallArguments" will be absent for the multi-installer package.
    key.ReadValue(kUninstallArgumentsField, &uninstall_arguments);
    InstallUtil::MakeUninstallCommand(setup_path, uninstall_arguments,
                                      &uninstall_command_);

    // "usagestats" may be absent, 0 (false), or 1 (true).  On the chance that
    // different values are permitted in the future, we'll simply hold whatever
    // we find.
    has_usagestats_ = (key.ReadValueDW(google_update::kRegUsageStatsField,
                                       &usagestats_) == ERROR_SUCCESS);
    // "oeminstall" may be present with any value or absent.
    has_oem_install_ = (key.ReadValue(google_update::kRegOemInstallField,
                                      &oem_install_) == ERROR_SUCCESS);
    // "eulaaccepted" may be absent, 0 or 1.
    has_eula_accepted_ = (key.ReadValueDW(google_update::kRegEULAAceptedField,
                                          &eula_accepted_) == ERROR_SUCCESS);
    // "msi" may be absent, 0 or 1
    DWORD dw_value = 0;
    msi_ = (key.ReadValueDW(google_update::kRegMSIField,
                            &dw_value) == ERROR_SUCCESS) && (dw_value != 0);
    // Multi-install is implied or is derived from the command-line.
    if (distribution->GetType() == BrowserDistribution::CHROME_BINARIES)
      multi_install_ = true;
    else
      multi_install_ = uninstall_command_.HasSwitch(switches::kMultiInstall);
  }

  // Read from the ClientStateMedium key.  Values here override those in
  // ClientState.
  if (system_install &&
      key.Open(root_key, distribution->GetStateMediumKey().c_str(),
               KEY_QUERY_VALUE) == ERROR_SUCCESS) {
    DWORD dword_value = 0;

    if (key.ReadValueDW(google_update::kRegUsageStatsField,
                        &dword_value) == ERROR_SUCCESS) {
      has_usagestats_ = true;
      usagestats_ = dword_value;
    }

    if (key.ReadValueDW(google_update::kRegEULAAceptedField,
                        &dword_value) == ERROR_SUCCESS) {
      has_eula_accepted_ = true;
      eula_accepted_ = dword_value;
    }
  }

  return version_.get() != NULL;
}

base::FilePath ProductState::GetSetupPath() const {
  return uninstall_command_.GetProgram();
}

const Version& ProductState::version() const {
  DCHECK(version_.get() != NULL);
  return *version_;
}

ProductState& ProductState::CopyFrom(const ProductState& other) {
  channel_.set_value(other.channel_.value());
  version_.reset(other.version_.get() ? new Version(*other.version_) : NULL);
  old_version_.reset(
      other.old_version_.get() ? new Version(*other.old_version_) : NULL);
  brand_ = other.brand_;
  rename_cmd_ = other.rename_cmd_;
  uninstall_command_ = other.uninstall_command_;
  oem_install_ = other.oem_install_;
  commands_.CopyFrom(other.commands_);
  eula_accepted_ = other.eula_accepted_;
  usagestats_ = other.usagestats_;
  msi_ = other.msi_;
  multi_install_ = other.multi_install_;
  has_eula_accepted_ = other.has_eula_accepted_;
  has_oem_install_ = other.has_oem_install_;
  has_usagestats_ = other.has_usagestats_;

  return *this;
}

void ProductState::Clear() {
  channel_.set_value(std::wstring());
  version_.reset();
  old_version_.reset();
  brand_.clear();
  rename_cmd_.clear();
  oem_install_.clear();
  uninstall_command_ = CommandLine(CommandLine::NO_PROGRAM);
  commands_.Clear();
  eula_accepted_ = 0;
  usagestats_ = 0;
  msi_ = false;
  multi_install_ = false;
  has_eula_accepted_ = false;
  has_oem_install_ = false;
  has_usagestats_ = false;
}

bool ProductState::GetEulaAccepted(DWORD* eula_accepted) const {
  DCHECK(eula_accepted);
  if (!has_eula_accepted_)
    return false;
  *eula_accepted = eula_accepted_;
  return true;
}

bool ProductState::GetOemInstall(std::wstring* oem_install) const {
  DCHECK(oem_install);
  if (!has_oem_install_)
    return false;
  *oem_install = oem_install_;
  return true;
}

bool ProductState::GetUsageStats(DWORD* usagestats) const {
  DCHECK(usagestats);
  if (!has_usagestats_)
    return false;
  *usagestats = usagestats_;
  return true;
}

InstallationState::InstallationState() {
}

// static
int InstallationState::IndexFromDistType(BrowserDistribution::Type type) {
  COMPILE_ASSERT(BrowserDistribution::CHROME_BROWSER == CHROME_BROWSER_INDEX,
                 unexpected_chrome_browser_distribution_value_);
  COMPILE_ASSERT(BrowserDistribution::CHROME_FRAME == CHROME_FRAME_INDEX,
                 unexpected_chrome_frame_distribution_value_);
  COMPILE_ASSERT(BrowserDistribution::CHROME_BINARIES == CHROME_BINARIES_INDEX,
                 unexpected_chrome_frame_distribution_value_);
  COMPILE_ASSERT(BrowserDistribution::CHROME_APP_HOST == CHROME_APP_HOST_INDEX,
                 unexpected_chrome_frame_distribution_value_);
  DCHECK(type == BrowserDistribution::CHROME_BROWSER ||
         type == BrowserDistribution::CHROME_FRAME ||
         type == BrowserDistribution::CHROME_BINARIES ||
         type == BrowserDistribution::CHROME_APP_HOST);
  return type;
}

void InstallationState::Initialize() {
  BrowserDistribution* distribution;

  distribution = BrowserDistribution::GetSpecificDistribution(
      BrowserDistribution::CHROME_BROWSER);
  user_products_[CHROME_BROWSER_INDEX].Initialize(false, distribution);
  system_products_[CHROME_BROWSER_INDEX].Initialize(true, distribution);

  distribution = BrowserDistribution::GetSpecificDistribution(
      BrowserDistribution::CHROME_FRAME);
  user_products_[CHROME_FRAME_INDEX].Initialize(false, distribution);
  system_products_[CHROME_FRAME_INDEX].Initialize(true, distribution);

  distribution = BrowserDistribution::GetSpecificDistribution(
      BrowserDistribution::CHROME_BINARIES);
  user_products_[CHROME_BINARIES_INDEX].Initialize(false, distribution);
  system_products_[CHROME_BINARIES_INDEX].Initialize(true, distribution);

  distribution = BrowserDistribution::GetSpecificDistribution(
      BrowserDistribution::CHROME_APP_HOST);
  user_products_[CHROME_APP_HOST_INDEX].Initialize(false, distribution);
  system_products_[CHROME_APP_HOST_INDEX].Initialize(true, distribution);
}

const ProductState* InstallationState::GetNonVersionedProductState(
    bool system_install,
    BrowserDistribution::Type type) const {
  const ProductState& product_state = (system_install ? system_products_ :
      user_products_)[IndexFromDistType(type)];
  return &product_state;
}

const ProductState* InstallationState::GetProductState(
    bool system_install,
    BrowserDistribution::Type type) const {
  const ProductState* product_state =
      GetNonVersionedProductState(system_install, type);
  return product_state->version_.get() == NULL ? NULL : product_state;
}
}  // namespace installer

/* [<][>][^][v][top][bottom][index][help] */