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