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