Home | History | Annotate | Download | only in util
      1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "chrome/installer/util/installation_state.h"
      6 
      7 #include "base/logging.h"
      8 #include "base/strings/string_util.h"
      9 #include "base/strings/utf_string_conversions.h"
     10 #include "base/version.h"
     11 #include "base/win/registry.h"
     12 #include "chrome/installer/util/google_update_constants.h"
     13 #include "chrome/installer/util/install_util.h"
     14 
     15 namespace installer {
     16 
     17 ProductState::ProductState()
     18     : uninstall_command_(CommandLine::NO_PROGRAM),
     19       eula_accepted_(0),
     20       usagestats_(0),
     21       msi_(false),
     22       multi_install_(false),
     23       has_eula_accepted_(false),
     24       has_oem_install_(false),
     25       has_usagestats_(false) {
     26 }
     27 
     28 bool ProductState::Initialize(bool system_install,
     29                               BrowserDistribution::Type type) {
     30   return Initialize(system_install,
     31                     BrowserDistribution::GetSpecificDistribution(type));
     32 }
     33 
     34 // Initializes |commands| from the "Commands" subkey of |version_key|.
     35 // Returns false if there is no "Commands" subkey or on error.
     36 // static
     37 bool ProductState::InitializeCommands(const base::win::RegKey& version_key,
     38                                       AppCommands* commands) {
     39   static const DWORD kAccess =
     40       KEY_ENUMERATE_SUB_KEYS | KEY_QUERY_VALUE | KEY_WOW64_32KEY;
     41   base::win::RegKey commands_key;
     42 
     43   if (commands_key.Open(version_key.Handle(), google_update::kRegCommandsKey,
     44                         kAccess) == ERROR_SUCCESS)
     45     return commands->Initialize(commands_key);
     46   return false;
     47 }
     48 
     49 bool ProductState::Initialize(bool system_install,
     50                               BrowserDistribution* distribution) {
     51   static const DWORD kAccess = KEY_QUERY_VALUE | KEY_WOW64_32KEY;
     52   const std::wstring version_key(distribution->GetVersionKey());
     53   const std::wstring state_key(distribution->GetStateKey());
     54   const HKEY root_key = system_install ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER;
     55   base::win::RegKey key;
     56 
     57   // Clear the runway.
     58   Clear();
     59 
     60   // Read from the Clients key.
     61   if (key.Open(root_key, version_key.c_str(), kAccess) == ERROR_SUCCESS) {
     62     base::string16 version_str;
     63     if (key.ReadValue(google_update::kRegVersionField,
     64                       &version_str) == ERROR_SUCCESS) {
     65       version_.reset(new Version(base::UTF16ToASCII(version_str)));
     66       if (!version_->IsValid())
     67         version_.reset();
     68     }
     69 
     70     // Attempt to read the other values even if the "pv" version value was
     71     // absent. Note that ProductState instances containing these values will
     72     // only be accessible via InstallationState::GetNonVersionedProductState.
     73     if (key.ReadValue(google_update::kRegOldVersionField,
     74                       &version_str) == ERROR_SUCCESS) {
     75       old_version_.reset(new Version(base::UTF16ToASCII(version_str)));
     76       if (!old_version_->IsValid())
     77         old_version_.reset();
     78     }
     79 
     80     key.ReadValue(google_update::kRegRenameCmdField, &rename_cmd_);
     81     if (!InitializeCommands(key, &commands_))
     82       commands_.Clear();
     83   }
     84 
     85   // Read from the ClientState key.
     86   if (key.Open(root_key, state_key.c_str(), kAccess) == ERROR_SUCCESS) {
     87     std::wstring setup_path;
     88     std::wstring uninstall_arguments;
     89     // "ap" will be absent if not managed by Google Update.
     90     channel_.Initialize(key);
     91 
     92     // Read in the brand code, it may be absent
     93     key.ReadValue(google_update::kRegBrandField, &brand_);
     94 
     95     // "UninstallString" will be absent for the multi-installer package.
     96     key.ReadValue(kUninstallStringField, &setup_path);
     97     // "UninstallArguments" will be absent for the multi-installer package.
     98     key.ReadValue(kUninstallArgumentsField, &uninstall_arguments);
     99     InstallUtil::MakeUninstallCommand(setup_path, uninstall_arguments,
    100                                       &uninstall_command_);
    101 
    102     // "usagestats" may be absent, 0 (false), or 1 (true).  On the chance that
    103     // different values are permitted in the future, we'll simply hold whatever
    104     // we find.
    105     has_usagestats_ = (key.ReadValueDW(google_update::kRegUsageStatsField,
    106                                        &usagestats_) == ERROR_SUCCESS);
    107     // "oeminstall" may be present with any value or absent.
    108     has_oem_install_ = (key.ReadValue(google_update::kRegOemInstallField,
    109                                       &oem_install_) == ERROR_SUCCESS);
    110     // "eulaaccepted" may be absent, 0 or 1.
    111     has_eula_accepted_ = (key.ReadValueDW(google_update::kRegEULAAceptedField,
    112                                           &eula_accepted_) == ERROR_SUCCESS);
    113     // "msi" may be absent, 0 or 1
    114     DWORD dw_value = 0;
    115     msi_ = (key.ReadValueDW(google_update::kRegMSIField,
    116                             &dw_value) == ERROR_SUCCESS) && (dw_value != 0);
    117     // Multi-install is implied or is derived from the command-line.
    118     if (distribution->GetType() == BrowserDistribution::CHROME_BINARIES)
    119       multi_install_ = true;
    120     else
    121       multi_install_ = uninstall_command_.HasSwitch(switches::kMultiInstall);
    122   }
    123 
    124   // Read from the ClientStateMedium key.  Values here override those in
    125   // ClientState.
    126   if (system_install &&
    127       key.Open(root_key, distribution->GetStateMediumKey().c_str(), kAccess) ==
    128           ERROR_SUCCESS) {
    129     DWORD dword_value = 0;
    130 
    131     if (key.ReadValueDW(google_update::kRegUsageStatsField,
    132                         &dword_value) == ERROR_SUCCESS) {
    133       has_usagestats_ = true;
    134       usagestats_ = dword_value;
    135     }
    136 
    137     if (key.ReadValueDW(google_update::kRegEULAAceptedField,
    138                         &dword_value) == ERROR_SUCCESS) {
    139       has_eula_accepted_ = true;
    140       eula_accepted_ = dword_value;
    141     }
    142   }
    143 
    144   return version_.get() != NULL;
    145 }
    146 
    147 base::FilePath ProductState::GetSetupPath() const {
    148   return uninstall_command_.GetProgram();
    149 }
    150 
    151 const Version& ProductState::version() const {
    152   DCHECK(version_.get() != NULL);
    153   return *version_;
    154 }
    155 
    156 ProductState& ProductState::CopyFrom(const ProductState& other) {
    157   channel_.set_value(other.channel_.value());
    158   version_.reset(other.version_.get() ? new Version(*other.version_) : NULL);
    159   old_version_.reset(
    160       other.old_version_.get() ? new Version(*other.old_version_) : NULL);
    161   brand_ = other.brand_;
    162   rename_cmd_ = other.rename_cmd_;
    163   uninstall_command_ = other.uninstall_command_;
    164   oem_install_ = other.oem_install_;
    165   commands_.CopyFrom(other.commands_);
    166   eula_accepted_ = other.eula_accepted_;
    167   usagestats_ = other.usagestats_;
    168   msi_ = other.msi_;
    169   multi_install_ = other.multi_install_;
    170   has_eula_accepted_ = other.has_eula_accepted_;
    171   has_oem_install_ = other.has_oem_install_;
    172   has_usagestats_ = other.has_usagestats_;
    173 
    174   return *this;
    175 }
    176 
    177 void ProductState::Clear() {
    178   channel_.set_value(std::wstring());
    179   version_.reset();
    180   old_version_.reset();
    181   brand_.clear();
    182   rename_cmd_.clear();
    183   oem_install_.clear();
    184   uninstall_command_ = CommandLine(CommandLine::NO_PROGRAM);
    185   commands_.Clear();
    186   eula_accepted_ = 0;
    187   usagestats_ = 0;
    188   msi_ = false;
    189   multi_install_ = false;
    190   has_eula_accepted_ = false;
    191   has_oem_install_ = false;
    192   has_usagestats_ = false;
    193 }
    194 
    195 bool ProductState::GetEulaAccepted(DWORD* eula_accepted) const {
    196   DCHECK(eula_accepted);
    197   if (!has_eula_accepted_)
    198     return false;
    199   *eula_accepted = eula_accepted_;
    200   return true;
    201 }
    202 
    203 bool ProductState::GetOemInstall(std::wstring* oem_install) const {
    204   DCHECK(oem_install);
    205   if (!has_oem_install_)
    206     return false;
    207   *oem_install = oem_install_;
    208   return true;
    209 }
    210 
    211 bool ProductState::GetUsageStats(DWORD* usagestats) const {
    212   DCHECK(usagestats);
    213   if (!has_usagestats_)
    214     return false;
    215   *usagestats = usagestats_;
    216   return true;
    217 }
    218 
    219 InstallationState::InstallationState() {
    220 }
    221 
    222 // static
    223 int InstallationState::IndexFromDistType(BrowserDistribution::Type type) {
    224   COMPILE_ASSERT(BrowserDistribution::CHROME_BROWSER == CHROME_BROWSER_INDEX,
    225                  unexpected_chrome_browser_distribution_value_);
    226   COMPILE_ASSERT(BrowserDistribution::CHROME_FRAME == CHROME_FRAME_INDEX,
    227                  unexpected_chrome_frame_distribution_value_);
    228   COMPILE_ASSERT(BrowserDistribution::CHROME_BINARIES == CHROME_BINARIES_INDEX,
    229                  unexpected_chrome_frame_distribution_value_);
    230   COMPILE_ASSERT(BrowserDistribution::CHROME_APP_HOST == CHROME_APP_HOST_INDEX,
    231                  unexpected_chrome_frame_distribution_value_);
    232   DCHECK(type == BrowserDistribution::CHROME_BROWSER ||
    233          type == BrowserDistribution::CHROME_FRAME ||
    234          type == BrowserDistribution::CHROME_BINARIES ||
    235          type == BrowserDistribution::CHROME_APP_HOST);
    236   return type;
    237 }
    238 
    239 void InstallationState::Initialize() {
    240   BrowserDistribution* distribution;
    241 
    242   distribution = BrowserDistribution::GetSpecificDistribution(
    243       BrowserDistribution::CHROME_BROWSER);
    244   user_products_[CHROME_BROWSER_INDEX].Initialize(false, distribution);
    245   system_products_[CHROME_BROWSER_INDEX].Initialize(true, distribution);
    246 
    247   distribution = BrowserDistribution::GetSpecificDistribution(
    248       BrowserDistribution::CHROME_FRAME);
    249   user_products_[CHROME_FRAME_INDEX].Initialize(false, distribution);
    250   system_products_[CHROME_FRAME_INDEX].Initialize(true, distribution);
    251 
    252   distribution = BrowserDistribution::GetSpecificDistribution(
    253       BrowserDistribution::CHROME_BINARIES);
    254   user_products_[CHROME_BINARIES_INDEX].Initialize(false, distribution);
    255   system_products_[CHROME_BINARIES_INDEX].Initialize(true, distribution);
    256 
    257   distribution = BrowserDistribution::GetSpecificDistribution(
    258       BrowserDistribution::CHROME_APP_HOST);
    259   user_products_[CHROME_APP_HOST_INDEX].Initialize(false, distribution);
    260   system_products_[CHROME_APP_HOST_INDEX].Initialize(true, distribution);
    261 }
    262 
    263 const ProductState* InstallationState::GetNonVersionedProductState(
    264     bool system_install,
    265     BrowserDistribution::Type type) const {
    266   const ProductState& product_state = (system_install ? system_products_ :
    267       user_products_)[IndexFromDistType(type)];
    268   return &product_state;
    269 }
    270 
    271 const ProductState* InstallationState::GetProductState(
    272     bool system_install,
    273     BrowserDistribution::Type type) const {
    274   const ProductState* product_state =
    275       GetNonVersionedProductState(system_install, type);
    276   return product_state->version_.get() == NULL ? NULL : product_state;
    277 }
    278 }  // namespace installer
    279