google_update_settings.cc revision 5d1f7b1de12d16ceb2c938c56701a3e8bfa558f7
10d8019e55c0f465bafc11b04aed691de95b9131dTed Kremenek// Copyright (c) 2012 The Chromium Authors. All rights reserved. 20d8019e55c0f465bafc11b04aed691de95b9131dTed Kremenek// Use of this source code is governed by a BSD-style license that can be 30d8019e55c0f465bafc11b04aed691de95b9131dTed Kremenek// found in the LICENSE file. 40d8019e55c0f465bafc11b04aed691de95b9131dTed Kremenek 50d8019e55c0f465bafc11b04aed691de95b9131dTed Kremenek#include "chrome/installer/util/google_update_settings.h" 60d8019e55c0f465bafc11b04aed691de95b9131dTed Kremenek 70d8019e55c0f465bafc11b04aed691de95b9131dTed Kremenek#include <algorithm> 80d8019e55c0f465bafc11b04aed691de95b9131dTed Kremenek#include <string> 90d8019e55c0f465bafc11b04aed691de95b9131dTed Kremenek 100d8019e55c0f465bafc11b04aed691de95b9131dTed Kremenek#include "base/command_line.h" 110d8019e55c0f465bafc11b04aed691de95b9131dTed Kremenek#include "base/path_service.h" 120d8019e55c0f465bafc11b04aed691de95b9131dTed Kremenek#include "base/strings/string_number_conversions.h" 130d8019e55c0f465bafc11b04aed691de95b9131dTed Kremenek#include "base/strings/string_util.h" 140d8019e55c0f465bafc11b04aed691de95b9131dTed Kremenek#include "base/strings/utf_string_conversions.h" 150d8019e55c0f465bafc11b04aed691de95b9131dTed Kremenek#include "base/threading/thread_restrictions.h" 167dd445ec20e704846cfbdb132e56539280d71311Argyrios Kyrtzidis#include "base/time/time.h" 1755fc873017f10f6f566b182b70f6fc22aefa3464Chandler Carruth#include "base/win/registry.h" 180d8019e55c0f465bafc11b04aed691de95b9131dTed Kremenek#include "base/win/win_util.h" 190d8019e55c0f465bafc11b04aed691de95b9131dTed Kremenek#include "chrome/common/chrome_switches.h" 2055fc873017f10f6f566b182b70f6fc22aefa3464Chandler Carruth#include "chrome/installer/util/browser_distribution.h" 2155fc873017f10f6f566b182b70f6fc22aefa3464Chandler Carruth#include "chrome/installer/util/channel_info.h" 2255fc873017f10f6f566b182b70f6fc22aefa3464Chandler Carruth#include "chrome/installer/util/google_update_constants.h" 230d8019e55c0f465bafc11b04aed691de95b9131dTed Kremenek#include "chrome/installer/util/google_update_experiment_util.h" 2413493ea1583f39d62a66e2b2a0802f08d8ec32caTed Kremenek#include "chrome/installer/util/install_util.h" 250d8019e55c0f465bafc11b04aed691de95b9131dTed Kremenek#include "chrome/installer/util/installation_state.h" 260d8019e55c0f465bafc11b04aed691de95b9131dTed Kremenek#include "chrome/installer/util/product.h" 279ef6537a894c33003359b1f9b9676e9178e028b7Ted Kremenek 280d8019e55c0f465bafc11b04aed691de95b9131dTed Kremenekusing base::win::RegKey; 290d8019e55c0f465bafc11b04aed691de95b9131dTed Kremenekusing installer::InstallationState; 309c378f705405d37f49795d5e915989de774fe11fTed Kremenek 310d8019e55c0f465bafc11b04aed691de95b9131dTed Kremeneknamespace { 320d8019e55c0f465bafc11b04aed691de95b9131dTed Kremenek 330d8019e55c0f465bafc11b04aed691de95b9131dTed Kremenekconst wchar_t kGoogleUpdatePoliciesKey[] = 3458f9f2c884af6b72d036b746a016d8031d31cb7aSteve Naroff L"SOFTWARE\\Policies\\Google\\Update"; 350d8019e55c0f465bafc11b04aed691de95b9131dTed Kremenekconst wchar_t kGoogleUpdateUpdatePolicyValue[] = L"UpdateDefault"; 360d8019e55c0f465bafc11b04aed691de95b9131dTed Kremenekconst wchar_t kGoogleUpdateUpdateOverrideValuePrefix[] = L"Update"; 370d8019e55c0f465bafc11b04aed691de95b9131dTed Kremenekconst GoogleUpdateSettings::UpdatePolicy kGoogleUpdateDefaultUpdatePolicy = 380d8019e55c0f465bafc11b04aed691de95b9131dTed Kremenek#if defined(GOOGLE_CHROME_BUILD) 390d8019e55c0f465bafc11b04aed691de95b9131dTed Kremenek GoogleUpdateSettings::AUTOMATIC_UPDATES; 402376002038c8b904acd20be754aedd1a7471be71Ted Kremenek#else 412376002038c8b904acd20be754aedd1a7471be71Ted Kremenek GoogleUpdateSettings::UPDATES_DISABLED; 422376002038c8b904acd20be754aedd1a7471be71Ted Kremenek#endif 43651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines 44651f13cea278ec967336033dd032faef0e9fc2ecStephen Hinesbool ReadGoogleUpdateStrKey(const wchar_t* const name, std::wstring* value) { 451eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump BrowserDistribution* dist = BrowserDistribution::GetDistribution(); 46651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines std::wstring reg_path = dist->GetStateKey(); 47651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines RegKey key(HKEY_CURRENT_USER, reg_path.c_str(), KEY_READ); 481eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump if (key.ReadValue(name, value) != ERROR_SUCCESS) { 490d8019e55c0f465bafc11b04aed691de95b9131dTed Kremenek RegKey hklm_key(HKEY_LOCAL_MACHINE, reg_path.c_str(), KEY_READ); 5013493ea1583f39d62a66e2b2a0802f08d8ec32caTed Kremenek return (hklm_key.ReadValue(name, value) == ERROR_SUCCESS); 5113493ea1583f39d62a66e2b2a0802f08d8ec32caTed Kremenek } 521eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump return true; 530d8019e55c0f465bafc11b04aed691de95b9131dTed Kremenek} 54b8989f27f116ff2400e92a52c067a69846119eb5Benjamin Kramer 550d8019e55c0f465bafc11b04aed691de95b9131dTed Kremenek// Update a state registry key |name| to be |value| for the given browser 56b8989f27f116ff2400e92a52c067a69846119eb5Benjamin Kramer// |dist|. If this is a |system_install|, then update the value under 57651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines// HKLM (istead of HKCU for user-installs) using a group of keys (one 58651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines// for each OS user) and also include the method to |aggregate| these 59651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines// values when reporting. 600d8019e55c0f465bafc11b04aed691de95b9131dTed Kremenekbool WriteGoogleUpdateStrKeyInternal(BrowserDistribution* dist, 61e4773eb6398acb03ad692050cb84b53ca1750b5bTed Kremenek bool system_install, 62e4773eb6398acb03ad692050cb84b53ca1750b5bTed Kremenek const wchar_t* const name, 63b8989f27f116ff2400e92a52c067a69846119eb5Benjamin Kramer // presubmit: allow wstring 64e4773eb6398acb03ad692050cb84b53ca1750b5bTed Kremenek const std::wstring& value, 650d8019e55c0f465bafc11b04aed691de95b9131dTed Kremenek const wchar_t* const aggregate) { 660d8019e55c0f465bafc11b04aed691de95b9131dTed Kremenek DCHECK(dist); 670d8019e55c0f465bafc11b04aed691de95b9131dTed Kremenek 681eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump if (system_install) { 69590dd8e0959d8df5621827768987c4792b74fc06Anna Zaks DCHECK(aggregate); 70590dd8e0959d8df5621827768987c4792b74fc06Anna Zaks // Machine installs require each OS user to write a unique key under a 71590dd8e0959d8df5621827768987c4792b74fc06Anna Zaks // named key in HKLM as well as an "aggregation" function that describes 72590dd8e0959d8df5621827768987c4792b74fc06Anna Zaks // how the values of multiple users are to be combined. 73651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines std::wstring uniquename; // presubmit: allow wstring 74651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines if (!base::win::GetUserSidString(&uniquename)) { 75651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines NOTREACHED(); 760d8019e55c0f465bafc11b04aed691de95b9131dTed Kremenek return false; 770d8019e55c0f465bafc11b04aed691de95b9131dTed Kremenek } 780d8019e55c0f465bafc11b04aed691de95b9131dTed Kremenek 799c378f705405d37f49795d5e915989de774fe11fTed Kremenek // presubmit: allow wstring 80651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines std::wstring reg_path(dist->GetStateMediumKey()); 81651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines reg_path.append(L"\\"); 821eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump reg_path.append(name); 839c378f705405d37f49795d5e915989de774fe11fTed Kremenek RegKey key(HKEY_LOCAL_MACHINE, reg_path.c_str(), KEY_SET_VALUE); 849c378f705405d37f49795d5e915989de774fe11fTed Kremenek key.WriteValue(google_update::kRegAggregateMethod, aggregate); 850d8019e55c0f465bafc11b04aed691de95b9131dTed Kremenek return (key.WriteValue(uniquename.c_str(), value.c_str()) == ERROR_SUCCESS); 860d8019e55c0f465bafc11b04aed691de95b9131dTed Kremenek } else { 870d8019e55c0f465bafc11b04aed691de95b9131dTed Kremenek // User installs are easy: just write the values to HKCU tree. 881eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump RegKey key(HKEY_CURRENT_USER, dist->GetStateKey().c_str(), KEY_SET_VALUE); 899c378f705405d37f49795d5e915989de774fe11fTed Kremenek return (key.WriteValue(name, value.c_str()) == ERROR_SUCCESS); 901eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump } 910d8019e55c0f465bafc11b04aed691de95b9131dTed Kremenek} 920d8019e55c0f465bafc11b04aed691de95b9131dTed Kremenek 930d8019e55c0f465bafc11b04aed691de95b9131dTed Kremenekbool WriteGoogleUpdateStrKey(const wchar_t* const name, 940d8019e55c0f465bafc11b04aed691de95b9131dTed Kremenek const std::wstring& value) { 951eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump BrowserDistribution* dist = BrowserDistribution::GetDistribution(); 96651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines return WriteGoogleUpdateStrKeyInternal(dist, false, name, value, NULL); 970d8019e55c0f465bafc11b04aed691de95b9131dTed Kremenek} 980d8019e55c0f465bafc11b04aed691de95b9131dTed Kremenek 990d8019e55c0f465bafc11b04aed691de95b9131dTed Kremenekbool WriteGoogleUpdateStrKeyMultiInstall(BrowserDistribution* dist, 1000d8019e55c0f465bafc11b04aed691de95b9131dTed Kremenek const wchar_t* const name, 1010d8019e55c0f465bafc11b04aed691de95b9131dTed Kremenek const std::wstring& value, 1020d8019e55c0f465bafc11b04aed691de95b9131dTed Kremenek bool system_level) { 1030d8019e55c0f465bafc11b04aed691de95b9131dTed Kremenek bool result = WriteGoogleUpdateStrKeyInternal(dist, false, name, value, NULL); 104651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines if (!InstallUtil::IsMultiInstall(dist, system_level)) 1050d8019e55c0f465bafc11b04aed691de95b9131dTed Kremenek return result; 1061eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump // It is a multi-install distro. Must write the reg value again. 1070d8019e55c0f465bafc11b04aed691de95b9131dTed Kremenek BrowserDistribution* multi_dist = 1080d8019e55c0f465bafc11b04aed691de95b9131dTed Kremenek BrowserDistribution::GetSpecificDistribution( 1096bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines BrowserDistribution::CHROME_BINARIES); 1100d8019e55c0f465bafc11b04aed691de95b9131dTed Kremenek return 1111eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump WriteGoogleUpdateStrKeyInternal(multi_dist, false, name, value, NULL) && 1120d8019e55c0f465bafc11b04aed691de95b9131dTed Kremenek result; 1139c378f705405d37f49795d5e915989de774fe11fTed Kremenek} 1146bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines 1151eb4433ac451dc16f4133a88af2d002ac26c58efMike Stumpbool ClearGoogleUpdateStrKey(const wchar_t* const name) { 116651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines BrowserDistribution* dist = BrowserDistribution::GetDistribution(); 1170d8019e55c0f465bafc11b04aed691de95b9131dTed Kremenek std::wstring reg_path = dist->GetStateKey(); 1181eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump RegKey key(HKEY_CURRENT_USER, reg_path.c_str(), KEY_READ | KEY_WRITE); 1190d8019e55c0f465bafc11b04aed691de95b9131dTed Kremenek std::wstring value; 1200d8019e55c0f465bafc11b04aed691de95b9131dTed Kremenek if (key.ReadValue(name, &value) != ERROR_SUCCESS) 1210d8019e55c0f465bafc11b04aed691de95b9131dTed Kremenek return false; 1227dd445ec20e704846cfbdb132e56539280d71311Argyrios Kyrtzidis return (key.WriteValue(name, L"") == ERROR_SUCCESS); 1237dd445ec20e704846cfbdb132e56539280d71311Argyrios Kyrtzidis} 1247dd445ec20e704846cfbdb132e56539280d71311Argyrios Kyrtzidis 1257dd445ec20e704846cfbdb132e56539280d71311Argyrios Kyrtzidisbool RemoveGoogleUpdateStrKey(const wchar_t* const name) { 1267dd445ec20e704846cfbdb132e56539280d71311Argyrios Kyrtzidis BrowserDistribution* dist = BrowserDistribution::GetDistribution(); 1277dd445ec20e704846cfbdb132e56539280d71311Argyrios Kyrtzidis std::wstring reg_path = dist->GetStateKey(); 128ec8605f1d7ec846dbf51047bfd5c56d32d1ff91cArgyrios Kyrtzidis RegKey key(HKEY_CURRENT_USER, reg_path.c_str(), KEY_READ | KEY_WRITE); 1297dd445ec20e704846cfbdb132e56539280d71311Argyrios Kyrtzidis if (!key.HasValue(name)) 1307dd445ec20e704846cfbdb132e56539280d71311Argyrios Kyrtzidis return true; 1317dd445ec20e704846cfbdb132e56539280d71311Argyrios Kyrtzidis return (key.DeleteValue(name) == ERROR_SUCCESS); 1327dd445ec20e704846cfbdb132e56539280d71311Argyrios Kyrtzidis} 133651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines 1347dd445ec20e704846cfbdb132e56539280d71311Argyrios Kyrtzidisbool GetChromeChannelInternal(bool system_install, 1357dd445ec20e704846cfbdb132e56539280d71311Argyrios Kyrtzidis bool add_multi_modifier, 1367dd445ec20e704846cfbdb132e56539280d71311Argyrios Kyrtzidis base::string16* channel) { 1377dd445ec20e704846cfbdb132e56539280d71311Argyrios Kyrtzidis BrowserDistribution* dist = BrowserDistribution::GetDistribution(); 1387dd445ec20e704846cfbdb132e56539280d71311Argyrios Kyrtzidis if (dist->GetChromeChannel(channel)) { 1397dd445ec20e704846cfbdb132e56539280d71311Argyrios Kyrtzidis return true; 1407dd445ec20e704846cfbdb132e56539280d71311Argyrios Kyrtzidis } 141 142 HKEY root_key = system_install ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER; 143 base::string16 reg_path = dist->GetStateKey(); 144 RegKey key(root_key, reg_path.c_str(), KEY_READ); 145 146 installer::ChannelInfo channel_info; 147 if (!channel_info.Initialize(key)) { 148 channel->assign(installer::kChromeChannelUnknown); 149 return false; 150 } 151 152 if (!channel_info.GetChannelName(channel)) { 153 channel->assign(installer::kChromeChannelUnknown); 154 } 155 156 // Tag the channel name if this is a multi-install. 157 if (add_multi_modifier && channel_info.IsMultiInstall()) { 158 if (!channel->empty()) { 159 channel->append(1, L'-'); 160 } 161 channel->append(1, L'm'); 162 } 163 164 return true; 165} 166 167// Populates |update_policy| with the UpdatePolicy enum value corresponding to a 168// DWORD read from the registry and returns true if |value| is within range. 169// If |value| is out of range, returns false without modifying |update_policy|. 170bool GetUpdatePolicyFromDword( 171 const DWORD value, 172 GoogleUpdateSettings::UpdatePolicy* update_policy) { 173 switch (value) { 174 case GoogleUpdateSettings::UPDATES_DISABLED: 175 case GoogleUpdateSettings::AUTOMATIC_UPDATES: 176 case GoogleUpdateSettings::MANUAL_UPDATES_ONLY: 177 case GoogleUpdateSettings::AUTO_UPDATES_ONLY: 178 *update_policy = static_cast<GoogleUpdateSettings::UpdatePolicy>(value); 179 return true; 180 default: 181 LOG(WARNING) << "Unexpected update policy override value: " << value; 182 } 183 return false; 184} 185 186} // namespace 187 188bool GoogleUpdateSettings::IsSystemInstall() { 189 bool system_install = false; 190 base::FilePath module_dir; 191 if (!PathService::Get(base::DIR_MODULE, &module_dir)) { 192 LOG(WARNING) 193 << "Failed to get directory of module; assuming per-user install."; 194 } else { 195 system_install = !InstallUtil::IsPerUserInstall(module_dir.value().c_str()); 196 } 197 return system_install; 198} 199 200bool GoogleUpdateSettings::GetCollectStatsConsent() { 201 return GetCollectStatsConsentAtLevel(IsSystemInstall()); 202} 203 204// Older versions of Chrome unconditionally read from HKCU\...\ClientState\... 205// and then HKLM\...\ClientState\.... This means that system-level Chrome 206// never checked ClientStateMedium (which has priority according to Google 207// Update) and gave preference to a value in HKCU (which was never checked by 208// Google Update). From now on, Chrome follows Google Update's policy. 209bool GoogleUpdateSettings::GetCollectStatsConsentAtLevel(bool system_install) { 210 BrowserDistribution* dist = BrowserDistribution::GetDistribution(); 211 212 // Consent applies to all products in a multi-install package. 213 if (InstallUtil::IsMultiInstall(dist, system_install)) { 214 dist = BrowserDistribution::GetSpecificDistribution( 215 BrowserDistribution::CHROME_BINARIES); 216 } 217 218 RegKey key; 219 DWORD value = 0; 220 bool have_value = false; 221 222 // For system-level installs, try ClientStateMedium first. 223 have_value = 224 system_install && 225 key.Open(HKEY_LOCAL_MACHINE, dist->GetStateMediumKey().c_str(), 226 KEY_QUERY_VALUE) == ERROR_SUCCESS && 227 key.ReadValueDW(google_update::kRegUsageStatsField, 228 &value) == ERROR_SUCCESS; 229 230 // Otherwise, try ClientState. 231 if (!have_value) { 232 have_value = 233 key.Open(system_install ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER, 234 dist->GetStateKey().c_str(), 235 KEY_QUERY_VALUE) == ERROR_SUCCESS && 236 key.ReadValueDW(google_update::kRegUsageStatsField, 237 &value) == ERROR_SUCCESS; 238 } 239 240 // Google Update specifically checks that the value is 1, so we do the same. 241 return have_value && value == 1; 242} 243 244bool GoogleUpdateSettings::SetCollectStatsConsent(bool consented) { 245 return SetCollectStatsConsentAtLevel(IsSystemInstall(), consented); 246} 247 248bool GoogleUpdateSettings::SetCollectStatsConsentAtLevel(bool system_install, 249 bool consented) { 250 // Google Update writes and expects 1 for true, 0 for false. 251 DWORD value = consented ? 1 : 0; 252 253 BrowserDistribution* dist = BrowserDistribution::GetDistribution(); 254 255 // Consent applies to all products in a multi-install package. 256 if (InstallUtil::IsMultiInstall(dist, system_install)) { 257 dist = BrowserDistribution::GetSpecificDistribution( 258 BrowserDistribution::CHROME_BINARIES); 259 } 260 261 // Write to ClientStateMedium for system-level; ClientState otherwise. 262 HKEY root_key = system_install ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER; 263 std::wstring reg_path = 264 system_install ? dist->GetStateMediumKey() : dist->GetStateKey(); 265 RegKey key; 266 LONG result = key.Create(root_key, reg_path.c_str(), KEY_SET_VALUE); 267 if (result != ERROR_SUCCESS) { 268 LOG(ERROR) << "Failed opening key " << reg_path << " to set " 269 << google_update::kRegUsageStatsField << "; result: " << result; 270 } else { 271 result = key.WriteValue(google_update::kRegUsageStatsField, value); 272 LOG_IF(ERROR, result != ERROR_SUCCESS) << "Failed setting " 273 << google_update::kRegUsageStatsField << " in key " << reg_path 274 << "; result: " << result; 275 } 276 return (result == ERROR_SUCCESS); 277} 278 279bool GoogleUpdateSettings::GetMetricsId(std::string* metrics_id) { 280 std::wstring metrics_id_w; 281 bool rv = ReadGoogleUpdateStrKey(google_update::kRegMetricsId, &metrics_id_w); 282 *metrics_id = base::WideToUTF8(metrics_id_w); 283 return rv; 284} 285 286bool GoogleUpdateSettings::SetMetricsId(const std::string& metrics_id) { 287 std::wstring metrics_id_w = base::UTF8ToWide(metrics_id); 288 return WriteGoogleUpdateStrKey(google_update::kRegMetricsId, metrics_id_w); 289} 290 291// EULA consent is only relevant for system-level installs. 292bool GoogleUpdateSettings::SetEULAConsent( 293 const InstallationState& machine_state, 294 BrowserDistribution* dist, 295 bool consented) { 296 DCHECK(dist); 297 const DWORD eula_accepted = consented ? 1 : 0; 298 std::wstring reg_path = dist->GetStateMediumKey(); 299 bool succeeded = true; 300 RegKey key; 301 302 // Write the consent value into the product's ClientStateMedium key. 303 if (key.Create(HKEY_LOCAL_MACHINE, reg_path.c_str(), 304 KEY_SET_VALUE) != ERROR_SUCCESS || 305 key.WriteValue(google_update::kRegEULAAceptedField, 306 eula_accepted) != ERROR_SUCCESS) { 307 succeeded = false; 308 } 309 310 // If this is a multi-install, also write it into the binaries' key. 311 // --mutli-install is not provided on the command-line, so deduce it from 312 // the product's state. 313 const installer::ProductState* product_state = 314 machine_state.GetProductState(true, dist->GetType()); 315 if (product_state != NULL && product_state->is_multi_install()) { 316 dist = BrowserDistribution::GetSpecificDistribution( 317 BrowserDistribution::CHROME_BINARIES); 318 reg_path = dist->GetStateMediumKey(); 319 if (key.Create(HKEY_LOCAL_MACHINE, reg_path.c_str(), 320 KEY_SET_VALUE) != ERROR_SUCCESS || 321 key.WriteValue(google_update::kRegEULAAceptedField, 322 eula_accepted) != ERROR_SUCCESS) { 323 succeeded = false; 324 } 325 } 326 327 return succeeded; 328} 329 330int GoogleUpdateSettings::GetLastRunTime() { 331 std::wstring time_s; 332 if (!ReadGoogleUpdateStrKey(google_update::kRegLastRunTimeField, &time_s)) 333 return -1; 334 int64 time_i; 335 if (!base::StringToInt64(time_s, &time_i)) 336 return -1; 337 base::TimeDelta td = 338 base::Time::NowFromSystemTime() - base::Time::FromInternalValue(time_i); 339 return td.InDays(); 340} 341 342bool GoogleUpdateSettings::SetLastRunTime() { 343 int64 time = base::Time::NowFromSystemTime().ToInternalValue(); 344 return WriteGoogleUpdateStrKey(google_update::kRegLastRunTimeField, 345 base::Int64ToString16(time)); 346} 347 348bool GoogleUpdateSettings::RemoveLastRunTime() { 349 return RemoveGoogleUpdateStrKey(google_update::kRegLastRunTimeField); 350} 351 352bool GoogleUpdateSettings::GetBrowser(std::wstring* browser) { 353 return ReadGoogleUpdateStrKey(google_update::kRegBrowserField, browser); 354} 355 356bool GoogleUpdateSettings::GetLanguage(std::wstring* language) { 357 return ReadGoogleUpdateStrKey(google_update::kRegLangField, language); 358} 359 360bool GoogleUpdateSettings::GetBrand(std::wstring* brand) { 361 return ReadGoogleUpdateStrKey(google_update::kRegRLZBrandField, brand); 362} 363 364bool GoogleUpdateSettings::GetReactivationBrand(std::wstring* brand) { 365 return ReadGoogleUpdateStrKey(google_update::kRegRLZReactivationBrandField, 366 brand); 367} 368 369bool GoogleUpdateSettings::GetClient(std::wstring* client) { 370 return ReadGoogleUpdateStrKey(google_update::kRegClientField, client); 371} 372 373bool GoogleUpdateSettings::SetClient(const std::wstring& client) { 374 return WriteGoogleUpdateStrKey(google_update::kRegClientField, client); 375} 376 377bool GoogleUpdateSettings::GetReferral(std::wstring* referral) { 378 return ReadGoogleUpdateStrKey(google_update::kRegReferralField, referral); 379} 380 381bool GoogleUpdateSettings::ClearReferral() { 382 return ClearGoogleUpdateStrKey(google_update::kRegReferralField); 383} 384 385bool GoogleUpdateSettings::UpdateDidRunState(bool did_run, 386 bool system_level) { 387 BrowserDistribution* dist = BrowserDistribution::GetDistribution(); 388 return UpdateDidRunStateForDistribution(dist, did_run, system_level); 389} 390 391bool GoogleUpdateSettings::UpdateDidRunStateForDistribution( 392 BrowserDistribution* dist, 393 bool did_run, 394 bool system_level) { 395 return WriteGoogleUpdateStrKeyMultiInstall(dist, 396 google_update::kRegDidRunField, 397 did_run ? L"1" : L"0", 398 system_level); 399} 400 401std::wstring GoogleUpdateSettings::GetChromeChannel(bool system_install) { 402 std::wstring channel; 403 GetChromeChannelInternal(system_install, false, &channel); 404 return channel; 405} 406 407bool GoogleUpdateSettings::GetChromeChannelAndModifiers( 408 bool system_install, 409 base::string16* channel) { 410 return GetChromeChannelInternal(system_install, true, channel); 411} 412 413void GoogleUpdateSettings::UpdateInstallStatus(bool system_install, 414 installer::ArchiveType archive_type, int install_return_code, 415 const std::wstring& product_guid) { 416 DCHECK(archive_type != installer::UNKNOWN_ARCHIVE_TYPE || 417 install_return_code != 0); 418 HKEY reg_root = (system_install) ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER; 419 420 RegKey key; 421 installer::ChannelInfo channel_info; 422 std::wstring reg_key(google_update::kRegPathClientState); 423 reg_key.append(L"\\"); 424 reg_key.append(product_guid); 425 LONG result = key.Open(reg_root, reg_key.c_str(), 426 KEY_QUERY_VALUE | KEY_SET_VALUE); 427 if (result == ERROR_SUCCESS) 428 channel_info.Initialize(key); 429 else if (result != ERROR_FILE_NOT_FOUND) 430 LOG(ERROR) << "Failed to open " << reg_key << "; Error: " << result; 431 432 if (UpdateGoogleUpdateApKey(archive_type, install_return_code, 433 &channel_info)) { 434 // We have a modified channel_info value to write. 435 // Create the app's ClientState key if it doesn't already exist. 436 if (!key.Valid()) { 437 result = key.Open(reg_root, google_update::kRegPathClientState, 438 KEY_CREATE_SUB_KEY); 439 if (result == ERROR_SUCCESS) 440 result = key.CreateKey(product_guid.c_str(), KEY_SET_VALUE); 441 442 if (result != ERROR_SUCCESS) { 443 LOG(ERROR) << "Failed to create " << reg_key << "; Error: " << result; 444 return; 445 } 446 } 447 if (!channel_info.Write(&key)) { 448 LOG(ERROR) << "Failed to write to application's ClientState key " 449 << google_update::kRegApField << " = " << channel_info.value(); 450 } 451 } 452} 453 454bool GoogleUpdateSettings::UpdateGoogleUpdateApKey( 455 installer::ArchiveType archive_type, int install_return_code, 456 installer::ChannelInfo* value) { 457 DCHECK(archive_type != installer::UNKNOWN_ARCHIVE_TYPE || 458 install_return_code != 0); 459 bool modified = false; 460 461 if (archive_type == installer::FULL_ARCHIVE_TYPE || !install_return_code) { 462 if (value->SetFullSuffix(false)) { 463 VLOG(1) << "Removed incremental installer failure key; " 464 "switching to channel: " 465 << value->value(); 466 modified = true; 467 } 468 } else if (archive_type == installer::INCREMENTAL_ARCHIVE_TYPE) { 469 if (value->SetFullSuffix(true)) { 470 VLOG(1) << "Incremental installer failed; switching to channel: " 471 << value->value(); 472 modified = true; 473 } else { 474 VLOG(1) << "Incremental installer failure; already on channel: " 475 << value->value(); 476 } 477 } else { 478 // It's okay if we don't know the archive type. In this case, leave the 479 // "-full" suffix as we found it. 480 DCHECK_EQ(installer::UNKNOWN_ARCHIVE_TYPE, archive_type); 481 } 482 483 if (value->SetMultiFailSuffix(false)) { 484 VLOG(1) << "Removed multi-install failure key; switching to channel: " 485 << value->value(); 486 modified = true; 487 } 488 489 return modified; 490} 491 492void GoogleUpdateSettings::UpdateProfileCounts(int profiles_active, 493 int profiles_signedin) { 494 BrowserDistribution* dist = BrowserDistribution::GetDistribution(); 495 bool system_install = IsSystemInstall(); 496 WriteGoogleUpdateStrKeyInternal(dist, system_install, 497 google_update::kRegProfilesActive, 498 base::Int64ToString16(profiles_active), 499 L"sum()"); 500 WriteGoogleUpdateStrKeyInternal(dist, system_install, 501 google_update::kRegProfilesSignedIn, 502 base::Int64ToString16(profiles_signedin), 503 L"sum()"); 504} 505 506int GoogleUpdateSettings::DuplicateGoogleUpdateSystemClientKey() { 507 BrowserDistribution* dist = BrowserDistribution::GetDistribution(); 508 std::wstring reg_path = dist->GetStateKey(); 509 510 // Minimum access needed is to be able to write to this key. 511 RegKey reg_key(HKEY_LOCAL_MACHINE, reg_path.c_str(), KEY_SET_VALUE); 512 if (!reg_key.Valid()) 513 return 0; 514 515 HANDLE target_handle = 0; 516 if (!DuplicateHandle(GetCurrentProcess(), reg_key.Handle(), 517 GetCurrentProcess(), &target_handle, KEY_SET_VALUE, 518 TRUE, DUPLICATE_SAME_ACCESS)) { 519 return 0; 520 } 521 return reinterpret_cast<int>(target_handle); 522} 523 524bool GoogleUpdateSettings::WriteGoogleUpdateSystemClientKey( 525 int handle, const std::wstring& key, const std::wstring& value) { 526 HKEY reg_key = reinterpret_cast<HKEY>(reinterpret_cast<void*>(handle)); 527 DWORD size = static_cast<DWORD>(value.size()) * sizeof(wchar_t); 528 LSTATUS status = RegSetValueEx(reg_key, key.c_str(), 0, REG_SZ, 529 reinterpret_cast<const BYTE*>(value.c_str()), size); 530 return status == ERROR_SUCCESS; 531} 532 533GoogleUpdateSettings::UpdatePolicy GoogleUpdateSettings::GetAppUpdatePolicy( 534 const std::wstring& app_guid, 535 bool* is_overridden) { 536 bool found_override = false; 537 UpdatePolicy update_policy = kGoogleUpdateDefaultUpdatePolicy; 538 539#if defined(GOOGLE_CHROME_BUILD) 540 DCHECK(!app_guid.empty()); 541 RegKey policy_key; 542 543 // Google Update Group Policy settings are always in HKLM. 544 if (policy_key.Open(HKEY_LOCAL_MACHINE, kGoogleUpdatePoliciesKey, 545 KEY_QUERY_VALUE) == ERROR_SUCCESS) { 546 static const size_t kPrefixLen = 547 arraysize(kGoogleUpdateUpdateOverrideValuePrefix) - 1; 548 DWORD value; 549 std::wstring app_update_override; 550 app_update_override.reserve(kPrefixLen + app_guid.size()); 551 app_update_override.append(kGoogleUpdateUpdateOverrideValuePrefix, 552 kPrefixLen); 553 app_update_override.append(app_guid); 554 // First try to read and comprehend the app-specific override. 555 found_override = (policy_key.ReadValueDW(app_update_override.c_str(), 556 &value) == ERROR_SUCCESS && 557 GetUpdatePolicyFromDword(value, &update_policy)); 558 559 // Failing that, try to read and comprehend the default override. 560 if (!found_override && 561 policy_key.ReadValueDW(kGoogleUpdateUpdatePolicyValue, 562 &value) == ERROR_SUCCESS) { 563 GetUpdatePolicyFromDword(value, &update_policy); 564 } 565 } 566#endif // defined(GOOGLE_CHROME_BUILD) 567 568 if (is_overridden != NULL) 569 *is_overridden = found_override; 570 571 return update_policy; 572} 573 574base::string16 GoogleUpdateSettings::GetUninstallCommandLine( 575 bool system_install) { 576 const HKEY root_key = system_install ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER; 577 base::string16 cmd_line; 578 RegKey update_key; 579 580 if (update_key.Open(root_key, google_update::kRegPathGoogleUpdate, 581 KEY_QUERY_VALUE) == ERROR_SUCCESS) { 582 update_key.ReadValue(google_update::kRegUninstallCmdLine, &cmd_line); 583 } 584 585 return cmd_line; 586} 587 588Version GoogleUpdateSettings::GetGoogleUpdateVersion(bool system_install) { 589 const HKEY root_key = system_install ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER; 590 base::string16 version; 591 RegKey key; 592 593 if (key.Open(root_key, 594 google_update::kRegPathGoogleUpdate, 595 KEY_QUERY_VALUE) == ERROR_SUCCESS && 596 key.ReadValue(google_update::kRegGoogleUpdateVersion, 597 &version) == ERROR_SUCCESS) { 598 return Version(base::UTF16ToUTF8(version)); 599 } 600 601 return Version(); 602} 603 604base::Time GoogleUpdateSettings::GetGoogleUpdateLastStartedAU( 605 bool system_install) { 606 const HKEY root_key = system_install ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER; 607 RegKey update_key; 608 609 if (update_key.Open(root_key, google_update::kRegPathGoogleUpdate, 610 KEY_QUERY_VALUE) == ERROR_SUCCESS) { 611 DWORD last_start; 612 if (update_key.ReadValueDW(google_update::kRegLastStartedAUField, 613 &last_start) == ERROR_SUCCESS) { 614 return base::Time::FromTimeT(last_start); 615 } 616 } 617 618 return base::Time(); 619} 620 621base::Time GoogleUpdateSettings::GetGoogleUpdateLastChecked( 622 bool system_install) { 623 const HKEY root_key = system_install ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER; 624 RegKey update_key; 625 626 if (update_key.Open(root_key, google_update::kRegPathGoogleUpdate, 627 KEY_QUERY_VALUE) == ERROR_SUCCESS) { 628 DWORD last_check; 629 if (update_key.ReadValueDW(google_update::kRegLastCheckedField, 630 &last_check) == ERROR_SUCCESS) { 631 return base::Time::FromTimeT(last_check); 632 } 633 } 634 635 return base::Time(); 636} 637 638bool GoogleUpdateSettings::GetUpdateDetailForApp(bool system_install, 639 const wchar_t* app_guid, 640 ProductData* data) { 641 DCHECK(app_guid); 642 DCHECK(data); 643 644 bool product_found = false; 645 646 const HKEY root_key = system_install ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER; 647 base::string16 clientstate_reg_path(google_update::kRegPathClientState); 648 clientstate_reg_path.append(L"\\"); 649 clientstate_reg_path.append(app_guid); 650 651 RegKey clientstate; 652 if (clientstate.Open(root_key, clientstate_reg_path.c_str(), 653 KEY_QUERY_VALUE) == ERROR_SUCCESS) { 654 base::string16 version; 655 DWORD dword_value; 656 if ((clientstate.ReadValueDW(google_update::kRegLastCheckSuccessField, 657 &dword_value) == ERROR_SUCCESS) && 658 (clientstate.ReadValue(google_update::kRegVersionField, 659 &version) == ERROR_SUCCESS)) { 660 product_found = true; 661 data->version = WideToASCII(version); 662 data->last_success = base::Time::FromTimeT(dword_value); 663 data->last_result = 0; 664 data->last_error_code = 0; 665 data->last_extra_code = 0; 666 667 if (clientstate.ReadValueDW(google_update::kRegLastInstallerResultField, 668 &dword_value) == ERROR_SUCCESS) { 669 // Google Update convention is that if an installer writes an result 670 // code that is invalid, it is clamped to an exit code result. 671 const DWORD kMaxValidInstallResult = 4; // INSTALLER_RESULT_EXIT_CODE 672 data->last_result = std::min(dword_value, kMaxValidInstallResult); 673 } 674 if (clientstate.ReadValueDW(google_update::kRegLastInstallerErrorField, 675 &dword_value) == ERROR_SUCCESS) { 676 data->last_error_code = dword_value; 677 } 678 if (clientstate.ReadValueDW(google_update::kRegLastInstallerExtraField, 679 &dword_value) == ERROR_SUCCESS) { 680 data->last_extra_code = dword_value; 681 } 682 } 683 } 684 685 return product_found; 686} 687 688bool GoogleUpdateSettings::GetUpdateDetailForGoogleUpdate(bool system_install, 689 ProductData* data) { 690 return GetUpdateDetailForApp(system_install, 691 google_update::kGoogleUpdateUpgradeCode, 692 data); 693} 694 695bool GoogleUpdateSettings::GetUpdateDetail(bool system_install, 696 ProductData* data) { 697 BrowserDistribution* dist = BrowserDistribution::GetDistribution(); 698 return GetUpdateDetailForApp(system_install, 699 dist->GetAppGuid().c_str(), 700 data); 701} 702 703bool GoogleUpdateSettings::SetExperimentLabels( 704 bool system_install, 705 const base::string16& experiment_labels) { 706 HKEY reg_root = system_install ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER; 707 708 // Use the browser distribution and install level to write to the correct 709 // client state/app guid key. 710 bool success = false; 711 BrowserDistribution* dist = BrowserDistribution::GetDistribution(); 712 if (dist->ShouldSetExperimentLabels()) { 713 base::string16 client_state_path( 714 system_install ? dist->GetStateMediumKey() : dist->GetStateKey()); 715 RegKey client_state( 716 reg_root, client_state_path.c_str(), KEY_SET_VALUE); 717 if (experiment_labels.empty()) { 718 success = client_state.DeleteValue(google_update::kExperimentLabels) 719 == ERROR_SUCCESS; 720 } else { 721 success = client_state.WriteValue(google_update::kExperimentLabels, 722 experiment_labels.c_str()) == ERROR_SUCCESS; 723 } 724 } 725 726 return success; 727} 728 729bool GoogleUpdateSettings::ReadExperimentLabels( 730 bool system_install, 731 base::string16* experiment_labels) { 732 HKEY reg_root = system_install ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER; 733 734 // If this distribution does not set the experiment labels, don't bother 735 // reading. 736 BrowserDistribution* dist = BrowserDistribution::GetDistribution(); 737 if (!dist->ShouldSetExperimentLabels()) 738 return false; 739 740 base::string16 client_state_path( 741 system_install ? dist->GetStateMediumKey() : dist->GetStateKey()); 742 743 RegKey client_state; 744 LONG result = 745 client_state.Open(reg_root, client_state_path.c_str(), KEY_QUERY_VALUE); 746 if (result == ERROR_SUCCESS) { 747 result = client_state.ReadValue(google_update::kExperimentLabels, 748 experiment_labels); 749 } 750 751 // If the key or value was not present, return the empty string. 752 if (result == ERROR_FILE_NOT_FOUND || result == ERROR_PATH_NOT_FOUND) { 753 experiment_labels->clear(); 754 return true; 755 } 756 757 return result == ERROR_SUCCESS; 758} 759