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