[sql] Remove _HAS_EXCEPTIONS=0 from build info.
[chromium-blink-merge.git] / chrome / installer / util / google_update_settings.cc
blobd99f6e5845d3162b427526db1910803d0efaf964
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.
5 #include "chrome/installer/util/google_update_settings.h"
7 #include <algorithm>
8 #include <limits>
10 #include "base/command_line.h"
11 #include "base/files/file_path.h"
12 #include "base/logging.h"
13 #include "base/metrics/histogram.h"
14 #include "base/path_service.h"
15 #include "base/strings/string_number_conversions.h"
16 #include "base/strings/string_util.h"
17 #include "base/strings/utf_string_conversions.h"
18 #include "base/threading/thread_restrictions.h"
19 #include "base/time/time.h"
20 #include "base/win/registry.h"
21 #include "base/win/win_util.h"
22 #include "chrome/common/chrome_switches.h"
23 #include "chrome/installer/util/app_registration_data.h"
24 #include "chrome/installer/util/browser_distribution.h"
25 #include "chrome/installer/util/channel_info.h"
26 #include "chrome/installer/util/google_update_constants.h"
27 #include "chrome/installer/util/google_update_experiment_util.h"
28 #include "chrome/installer/util/install_util.h"
29 #include "chrome/installer/util/installation_state.h"
30 #include "chrome/installer/util/product.h"
32 using base::win::RegKey;
33 using installer::InstallationState;
35 const wchar_t GoogleUpdateSettings::kPoliciesKey[] =
36 L"SOFTWARE\\Policies\\Google\\Update";
37 const wchar_t GoogleUpdateSettings::kUpdatePolicyValue[] = L"UpdateDefault";
38 const wchar_t GoogleUpdateSettings::kUpdateOverrideValuePrefix[] = L"Update";
39 const wchar_t GoogleUpdateSettings::kCheckPeriodOverrideMinutes[] =
40 L"AutoUpdateCheckPeriodMinutes";
42 // Don't allow update periods longer than six weeks.
43 const int GoogleUpdateSettings::kCheckPeriodOverrideMinutesMax =
44 60 * 24 * 7 * 6;
46 const GoogleUpdateSettings::UpdatePolicy
47 GoogleUpdateSettings::kDefaultUpdatePolicy =
48 #if defined(GOOGLE_CHROME_BUILD)
49 GoogleUpdateSettings::AUTOMATIC_UPDATES;
50 #else
51 GoogleUpdateSettings::UPDATES_DISABLED;
52 #endif
54 namespace {
56 bool ReadGoogleUpdateStrKey(const wchar_t* const name, base::string16* value) {
57 BrowserDistribution* dist = BrowserDistribution::GetDistribution();
58 base::string16 reg_path = dist->GetStateKey();
59 RegKey key(HKEY_CURRENT_USER, reg_path.c_str(), KEY_READ | KEY_WOW64_32KEY);
60 if (key.ReadValue(name, value) != ERROR_SUCCESS) {
61 RegKey hklm_key(
62 HKEY_LOCAL_MACHINE, reg_path.c_str(), KEY_READ | KEY_WOW64_32KEY);
63 return (hklm_key.ReadValue(name, value) == ERROR_SUCCESS);
65 return true;
68 // Writes |value| into a user-specific value in the key |name| under
69 // |app_reg_data|'s ClientStateMedium key in HKLM along with the aggregation
70 // method |aggregate|. This function is solely for use by system-level installs.
71 bool WriteGoogleUpdateAggregateNumKeyInternal(
72 const AppRegistrationData& app_reg_data,
73 const wchar_t* const name,
74 size_t value,
75 const wchar_t* const aggregate) {
76 DCHECK(aggregate);
77 DCHECK(GoogleUpdateSettings::IsSystemInstall());
78 const REGSAM kAccess = KEY_SET_VALUE | KEY_WOW64_32KEY;
80 // Machine installs require each OS user to write a unique key under a
81 // named key in HKLM as well as an "aggregation" function that describes
82 // how the values of multiple users are to be combined.
83 base::string16 uniquename;
84 if (!base::win::GetUserSidString(&uniquename)) {
85 NOTREACHED();
86 return false;
89 base::string16 reg_path(app_reg_data.GetStateMediumKey());
90 reg_path.append(L"\\");
91 reg_path.append(name);
92 RegKey key(HKEY_LOCAL_MACHINE, reg_path.c_str(), kAccess);
93 key.WriteValue(google_update::kRegAggregateMethod, aggregate);
95 DWORD dword_value = (value > std::numeric_limits<DWORD>::max() ?
96 std::numeric_limits<DWORD>::max() :
97 static_cast<DWORD>(value));
98 return (key.WriteValue(uniquename.c_str(), dword_value) == ERROR_SUCCESS);
101 // Updates a registry key |name| to be |value| for the given |app_reg_data|.
102 bool WriteGoogleUpdateStrKeyInternal(const AppRegistrationData& app_reg_data,
103 const wchar_t* const name,
104 const base::string16& value) {
105 const REGSAM kAccess = KEY_SET_VALUE | KEY_WOW64_32KEY;
106 RegKey key(HKEY_CURRENT_USER, app_reg_data.GetStateKey().c_str(), kAccess);
107 return (key.WriteValue(name, value.c_str()) == ERROR_SUCCESS);
110 bool WriteGoogleUpdateStrKey(const wchar_t* const name,
111 const base::string16& value) {
112 BrowserDistribution* dist = BrowserDistribution::GetDistribution();
113 return WriteGoogleUpdateStrKeyInternal(
114 dist->GetAppRegistrationData(), name, value);
117 bool ClearGoogleUpdateStrKey(const wchar_t* const name) {
118 BrowserDistribution* dist = BrowserDistribution::GetDistribution();
119 base::string16 reg_path = dist->GetStateKey();
120 RegKey key(HKEY_CURRENT_USER,
121 reg_path.c_str(),
122 KEY_READ | KEY_WRITE | KEY_WOW64_32KEY);
123 base::string16 value;
124 if (key.ReadValue(name, &value) != ERROR_SUCCESS)
125 return false;
126 return (key.WriteValue(name, L"") == ERROR_SUCCESS);
129 bool RemoveGoogleUpdateStrKey(const wchar_t* const name) {
130 BrowserDistribution* dist = BrowserDistribution::GetDistribution();
131 base::string16 reg_path = dist->GetStateKey();
132 RegKey key(HKEY_CURRENT_USER,
133 reg_path.c_str(),
134 KEY_READ | KEY_WRITE | KEY_WOW64_32KEY);
135 if (!key.HasValue(name))
136 return true;
137 return (key.DeleteValue(name) == ERROR_SUCCESS);
140 bool GetChromeChannelInternal(bool system_install,
141 bool add_multi_modifier,
142 base::string16* channel) {
143 BrowserDistribution* dist = BrowserDistribution::GetDistribution();
145 // Shortcut in case this distribution knows what channel it is (canary).
146 if (dist->GetChromeChannel(channel))
147 return true;
149 // Determine whether or not chrome is multi-install. If so, updates are
150 // delivered under the binaries' app guid, so that's where the relevant
151 // channel is found.
152 installer::ProductState state;
153 installer::ChannelInfo channel_info;
154 ignore_result(state.Initialize(system_install, dist));
155 if (!state.is_multi_install()) {
156 // Use the channel info that was just read for this single-install chrome.
157 channel_info = state.channel();
158 } else {
159 // Read the channel info from the binaries' state key.
160 HKEY root_key = system_install ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER;
161 dist = BrowserDistribution::GetSpecificDistribution(
162 BrowserDistribution::CHROME_BINARIES);
163 RegKey key(root_key, dist->GetStateKey().c_str(),
164 KEY_READ | KEY_WOW64_32KEY);
166 if (!channel_info.Initialize(key)) {
167 channel->assign(installer::kChromeChannelUnknown);
168 return false;
172 if (!channel_info.GetChannelName(channel))
173 channel->assign(installer::kChromeChannelUnknown);
175 // Tag the channel name if this is a multi-install.
176 if (add_multi_modifier && state.is_multi_install()) {
177 if (!channel->empty())
178 channel->push_back(L'-');
179 channel->push_back(L'm');
182 return true;
185 #if defined(GOOGLE_CHROME_BUILD)
186 // Populates |update_policy| with the UpdatePolicy enum value corresponding to a
187 // DWORD read from the registry and returns true if |value| is within range.
188 // If |value| is out of range, returns false without modifying |update_policy|.
189 bool GetUpdatePolicyFromDword(
190 const DWORD value,
191 GoogleUpdateSettings::UpdatePolicy* update_policy) {
192 switch (value) {
193 case GoogleUpdateSettings::UPDATES_DISABLED:
194 case GoogleUpdateSettings::AUTOMATIC_UPDATES:
195 case GoogleUpdateSettings::MANUAL_UPDATES_ONLY:
196 case GoogleUpdateSettings::AUTO_UPDATES_ONLY:
197 *update_policy = static_cast<GoogleUpdateSettings::UpdatePolicy>(value);
198 return true;
199 default:
200 LOG(WARNING) << "Unexpected update policy override value: " << value;
202 return false;
204 #endif // defined(GOOGLE_CHROME_BUILD)
206 // Convenience routine: GoogleUpdateSettings::UpdateDidRunStateForApp()
207 // specialized for Chrome Binaries.
208 bool UpdateDidRunStateForBinaries(bool did_run) {
209 BrowserDistribution* dist = BrowserDistribution::GetSpecificDistribution(
210 BrowserDistribution::CHROME_BINARIES);
211 return GoogleUpdateSettings::UpdateDidRunStateForApp(
212 dist->GetAppRegistrationData(), did_run);
215 } // namespace
217 bool GoogleUpdateSettings::IsSystemInstall() {
218 bool system_install = false;
219 base::FilePath module_dir;
220 if (!PathService::Get(base::DIR_MODULE, &module_dir)) {
221 LOG(WARNING)
222 << "Failed to get directory of module; assuming per-user install.";
223 } else {
224 system_install = !InstallUtil::IsPerUserInstall(module_dir);
226 return system_install;
229 bool GoogleUpdateSettings::GetCollectStatsConsent() {
230 return GetCollectStatsConsentAtLevel(IsSystemInstall());
233 // Older versions of Chrome unconditionally read from HKCU\...\ClientState\...
234 // and then HKLM\...\ClientState\.... This means that system-level Chrome
235 // never checked ClientStateMedium (which has priority according to Google
236 // Update) and gave preference to a value in HKCU (which was never checked by
237 // Google Update). From now on, Chrome follows Google Update's policy.
238 bool GoogleUpdateSettings::GetCollectStatsConsentAtLevel(bool system_install) {
239 BrowserDistribution* dist = BrowserDistribution::GetDistribution();
241 // Consent applies to all products in a multi-install package.
242 if (InstallUtil::IsMultiInstall(dist, system_install)) {
243 dist = BrowserDistribution::GetSpecificDistribution(
244 BrowserDistribution::CHROME_BINARIES);
247 RegKey key;
248 DWORD value = 0;
249 bool have_value = false;
250 const REGSAM kAccess = KEY_QUERY_VALUE | KEY_WOW64_32KEY;
252 // For system-level installs, try ClientStateMedium first.
253 have_value =
254 system_install &&
255 key.Open(HKEY_LOCAL_MACHINE, dist->GetStateMediumKey().c_str(),
256 kAccess) == ERROR_SUCCESS &&
257 key.ReadValueDW(google_update::kRegUsageStatsField,
258 &value) == ERROR_SUCCESS;
260 // Otherwise, try ClientState.
261 if (!have_value) {
262 have_value =
263 key.Open(system_install ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER,
264 dist->GetStateKey().c_str(),
265 kAccess) == ERROR_SUCCESS &&
266 key.ReadValueDW(google_update::kRegUsageStatsField,
267 &value) == ERROR_SUCCESS;
270 // Google Update specifically checks that the value is 1, so we do the same.
271 return have_value && value == 1;
274 bool GoogleUpdateSettings::SetCollectStatsConsent(bool consented) {
275 return SetCollectStatsConsentAtLevel(IsSystemInstall(), consented);
278 bool GoogleUpdateSettings::SetCollectStatsConsentAtLevel(bool system_install,
279 bool consented) {
280 // Google Update writes and expects 1 for true, 0 for false.
281 DWORD value = consented ? 1 : 0;
283 BrowserDistribution* dist = BrowserDistribution::GetDistribution();
285 // Consent applies to all products in a multi-install package.
286 if (InstallUtil::IsMultiInstall(dist, system_install)) {
287 dist = BrowserDistribution::GetSpecificDistribution(
288 BrowserDistribution::CHROME_BINARIES);
291 // Write to ClientStateMedium for system-level; ClientState otherwise.
292 HKEY root_key = system_install ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER;
293 base::string16 reg_path =
294 system_install ? dist->GetStateMediumKey() : dist->GetStateKey();
295 RegKey key;
296 LONG result = key.Create(
297 root_key, reg_path.c_str(), KEY_SET_VALUE | KEY_WOW64_32KEY);
298 if (result != ERROR_SUCCESS) {
299 LOG(ERROR) << "Failed opening key " << reg_path << " to set "
300 << google_update::kRegUsageStatsField << "; result: " << result;
301 } else {
302 result = key.WriteValue(google_update::kRegUsageStatsField, value);
303 LOG_IF(ERROR, result != ERROR_SUCCESS) << "Failed setting "
304 << google_update::kRegUsageStatsField << " in key " << reg_path
305 << "; result: " << result;
307 return (result == ERROR_SUCCESS);
310 scoped_ptr<metrics::ClientInfo> GoogleUpdateSettings::LoadMetricsClientInfo() {
311 base::string16 client_id_16;
312 if (!ReadGoogleUpdateStrKey(google_update::kRegMetricsId, &client_id_16) ||
313 client_id_16.empty()) {
314 return scoped_ptr<metrics::ClientInfo>();
317 scoped_ptr<metrics::ClientInfo> client_info(new metrics::ClientInfo);
318 client_info->client_id = base::UTF16ToUTF8(client_id_16);
320 base::string16 installation_date_str;
321 if (ReadGoogleUpdateStrKey(google_update::kRegMetricsIdInstallDate,
322 &installation_date_str)) {
323 base::StringToInt64(installation_date_str, &client_info->installation_date);
326 base::string16 reporting_enbaled_date_date_str;
327 if (ReadGoogleUpdateStrKey(google_update::kRegMetricsIdEnabledDate,
328 &reporting_enbaled_date_date_str)) {
329 base::StringToInt64(reporting_enbaled_date_date_str,
330 &client_info->reporting_enabled_date);
333 return client_info.Pass();
336 void GoogleUpdateSettings::StoreMetricsClientInfo(
337 const metrics::ClientInfo& client_info) {
338 // Attempt a best-effort at backing |client_info| in the registry (but don't
339 // handle/report failures).
340 WriteGoogleUpdateStrKey(google_update::kRegMetricsId,
341 base::UTF8ToUTF16(client_info.client_id));
342 WriteGoogleUpdateStrKey(google_update::kRegMetricsIdInstallDate,
343 base::Int64ToString16(client_info.installation_date));
344 WriteGoogleUpdateStrKey(
345 google_update::kRegMetricsIdEnabledDate,
346 base::Int64ToString16(client_info.reporting_enabled_date));
349 // EULA consent is only relevant for system-level installs.
350 bool GoogleUpdateSettings::SetEULAConsent(
351 const InstallationState& machine_state,
352 BrowserDistribution* dist,
353 bool consented) {
354 DCHECK(dist);
355 const DWORD eula_accepted = consented ? 1 : 0;
356 const REGSAM kAccess = KEY_SET_VALUE | KEY_WOW64_32KEY;
357 base::string16 reg_path = dist->GetStateMediumKey();
358 bool succeeded = true;
359 RegKey key;
361 // Write the consent value into the product's ClientStateMedium key.
362 if (key.Create(HKEY_LOCAL_MACHINE, reg_path.c_str(),
363 kAccess) != ERROR_SUCCESS ||
364 key.WriteValue(google_update::kRegEULAAceptedField,
365 eula_accepted) != ERROR_SUCCESS) {
366 succeeded = false;
369 // If this is a multi-install, also write it into the binaries' key.
370 // --mutli-install is not provided on the command-line, so deduce it from
371 // the product's state.
372 const installer::ProductState* product_state =
373 machine_state.GetProductState(true, dist->GetType());
374 if (product_state != NULL && product_state->is_multi_install()) {
375 dist = BrowserDistribution::GetSpecificDistribution(
376 BrowserDistribution::CHROME_BINARIES);
377 reg_path = dist->GetStateMediumKey();
378 if (key.Create(HKEY_LOCAL_MACHINE, reg_path.c_str(),
379 kAccess) != ERROR_SUCCESS ||
380 key.WriteValue(google_update::kRegEULAAceptedField,
381 eula_accepted) != ERROR_SUCCESS) {
382 succeeded = false;
386 return succeeded;
389 int GoogleUpdateSettings::GetLastRunTime() {
390 base::string16 time_s;
391 if (!ReadGoogleUpdateStrKey(google_update::kRegLastRunTimeField, &time_s))
392 return -1;
393 int64 time_i;
394 if (!base::StringToInt64(time_s, &time_i))
395 return -1;
396 base::TimeDelta td =
397 base::Time::NowFromSystemTime() - base::Time::FromInternalValue(time_i);
398 return td.InDays();
401 bool GoogleUpdateSettings::SetLastRunTime() {
402 int64 time = base::Time::NowFromSystemTime().ToInternalValue();
403 return WriteGoogleUpdateStrKey(google_update::kRegLastRunTimeField,
404 base::Int64ToString16(time));
407 bool GoogleUpdateSettings::RemoveLastRunTime() {
408 return RemoveGoogleUpdateStrKey(google_update::kRegLastRunTimeField);
411 bool GoogleUpdateSettings::GetBrowser(base::string16* browser) {
412 return ReadGoogleUpdateStrKey(google_update::kRegBrowserField, browser);
415 bool GoogleUpdateSettings::GetLanguage(base::string16* language) {
416 return ReadGoogleUpdateStrKey(google_update::kRegLangField, language);
419 bool GoogleUpdateSettings::GetBrand(base::string16* brand) {
420 return ReadGoogleUpdateStrKey(google_update::kRegRLZBrandField, brand);
423 bool GoogleUpdateSettings::GetReactivationBrand(base::string16* brand) {
424 return ReadGoogleUpdateStrKey(google_update::kRegRLZReactivationBrandField,
425 brand);
428 bool GoogleUpdateSettings::GetClient(base::string16* client) {
429 return ReadGoogleUpdateStrKey(google_update::kRegClientField, client);
432 bool GoogleUpdateSettings::SetClient(const base::string16& client) {
433 return WriteGoogleUpdateStrKey(google_update::kRegClientField, client);
436 bool GoogleUpdateSettings::GetReferral(base::string16* referral) {
437 return ReadGoogleUpdateStrKey(google_update::kRegReferralField, referral);
440 bool GoogleUpdateSettings::ClearReferral() {
441 return ClearGoogleUpdateStrKey(google_update::kRegReferralField);
444 bool GoogleUpdateSettings::UpdateDidRunStateForApp(
445 const AppRegistrationData& app_reg_data,
446 bool did_run) {
447 return WriteGoogleUpdateStrKeyInternal(app_reg_data,
448 google_update::kRegDidRunField,
449 did_run ? L"1" : L"0");
452 bool GoogleUpdateSettings::UpdateDidRunState(bool did_run, bool system_level) {
453 BrowserDistribution* dist = BrowserDistribution::GetDistribution();
454 bool result = UpdateDidRunStateForApp(dist->GetAppRegistrationData(),
455 did_run);
456 // Update state for binaries, even if the previous call was unsuccessful.
457 if (InstallUtil::IsMultiInstall(dist, system_level))
458 result = UpdateDidRunStateForBinaries(did_run) && result;
459 return result;
462 base::string16 GoogleUpdateSettings::GetChromeChannel(bool system_install) {
463 base::string16 channel;
464 GetChromeChannelInternal(system_install, false, &channel);
465 return channel;
468 bool GoogleUpdateSettings::GetChromeChannelAndModifiers(
469 bool system_install,
470 base::string16* channel) {
471 return GetChromeChannelInternal(system_install, true, channel);
474 void GoogleUpdateSettings::UpdateInstallStatus(bool system_install,
475 installer::ArchiveType archive_type, int install_return_code,
476 const base::string16& product_guid) {
477 DCHECK(archive_type != installer::UNKNOWN_ARCHIVE_TYPE ||
478 install_return_code != 0);
479 HKEY reg_root = (system_install) ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER;
481 RegKey key;
482 installer::ChannelInfo channel_info;
483 base::string16 reg_key(google_update::kRegPathClientState);
484 reg_key.append(L"\\");
485 reg_key.append(product_guid);
486 LONG result = key.Open(reg_root,
487 reg_key.c_str(),
488 KEY_QUERY_VALUE | KEY_SET_VALUE | KEY_WOW64_32KEY);
489 if (result == ERROR_SUCCESS)
490 channel_info.Initialize(key);
491 else if (result != ERROR_FILE_NOT_FOUND)
492 LOG(ERROR) << "Failed to open " << reg_key << "; Error: " << result;
494 if (UpdateGoogleUpdateApKey(archive_type, install_return_code,
495 &channel_info)) {
496 // We have a modified channel_info value to write.
497 // Create the app's ClientState key if it doesn't already exist.
498 if (!key.Valid()) {
499 result = key.Open(reg_root,
500 google_update::kRegPathClientState,
501 KEY_CREATE_SUB_KEY | KEY_WOW64_32KEY);
502 if (result == ERROR_SUCCESS)
503 result = key.CreateKey(product_guid.c_str(),
504 KEY_SET_VALUE | KEY_WOW64_32KEY);
506 if (result != ERROR_SUCCESS) {
507 LOG(ERROR) << "Failed to create " << reg_key << "; Error: " << result;
508 return;
511 if (!channel_info.Write(&key)) {
512 LOG(ERROR) << "Failed to write to application's ClientState key "
513 << google_update::kRegApField << " = " << channel_info.value();
518 bool GoogleUpdateSettings::UpdateGoogleUpdateApKey(
519 installer::ArchiveType archive_type, int install_return_code,
520 installer::ChannelInfo* value) {
521 DCHECK(archive_type != installer::UNKNOWN_ARCHIVE_TYPE ||
522 install_return_code != 0);
523 bool modified = false;
525 if (archive_type == installer::FULL_ARCHIVE_TYPE || !install_return_code) {
526 if (value->SetFullSuffix(false)) {
527 VLOG(1) << "Removed incremental installer failure key; "
528 "switching to channel: "
529 << value->value();
530 modified = true;
532 } else if (archive_type == installer::INCREMENTAL_ARCHIVE_TYPE) {
533 if (value->SetFullSuffix(true)) {
534 VLOG(1) << "Incremental installer failed; switching to channel: "
535 << value->value();
536 modified = true;
537 } else {
538 VLOG(1) << "Incremental installer failure; already on channel: "
539 << value->value();
541 } else {
542 // It's okay if we don't know the archive type. In this case, leave the
543 // "-full" suffix as we found it.
544 DCHECK_EQ(installer::UNKNOWN_ARCHIVE_TYPE, archive_type);
547 if (value->SetMultiFailSuffix(false)) {
548 VLOG(1) << "Removed multi-install failure key; switching to channel: "
549 << value->value();
550 modified = true;
553 return modified;
556 void GoogleUpdateSettings::UpdateProfileCounts(size_t profiles_active,
557 size_t profiles_signedin) {
558 BrowserDistribution* dist = BrowserDistribution::GetDistribution();
559 // System-level installs must write into the ClientStateMedium key shared by
560 // all users. Special treatment is used to aggregate across those users.
561 if (IsSystemInstall()) {
562 // Write the counts as ints that get aggregated across all users via
563 // summation for system-level installs.
564 WriteGoogleUpdateAggregateNumKeyInternal(
565 dist->GetAppRegistrationData(),
566 google_update::kRegProfilesActive,
567 profiles_active,
568 L"sum()");
569 WriteGoogleUpdateAggregateNumKeyInternal(
570 dist->GetAppRegistrationData(),
571 google_update::kRegProfilesSignedIn,
572 profiles_signedin,
573 L"sum()");
574 } else {
575 // Write the counts as strings since no aggregation function is needed for
576 // user-level installs.
577 WriteGoogleUpdateStrKeyInternal(dist->GetAppRegistrationData(),
578 google_update::kRegProfilesActive,
579 base::SizeTToString16(profiles_active));
580 WriteGoogleUpdateStrKeyInternal(dist->GetAppRegistrationData(),
581 google_update::kRegProfilesSignedIn,
582 base::SizeTToString16(profiles_signedin));
586 int GoogleUpdateSettings::DuplicateGoogleUpdateSystemClientKey() {
587 BrowserDistribution* dist = BrowserDistribution::GetDistribution();
588 base::string16 reg_path = dist->GetStateKey();
590 // Minimum access needed is to be able to write to this key.
591 RegKey reg_key(
592 HKEY_LOCAL_MACHINE, reg_path.c_str(), KEY_SET_VALUE | KEY_WOW64_32KEY);
593 if (!reg_key.Valid())
594 return 0;
596 HANDLE target_handle = 0;
597 if (!DuplicateHandle(GetCurrentProcess(), reg_key.Handle(),
598 GetCurrentProcess(), &target_handle, KEY_SET_VALUE,
599 TRUE, DUPLICATE_SAME_ACCESS)) {
600 return 0;
602 return static_cast<int>(reinterpret_cast<uintptr_t>(target_handle));
605 bool GoogleUpdateSettings::WriteGoogleUpdateSystemClientKey(
606 int handle, const base::string16& key, const base::string16& value) {
607 HKEY reg_key = reinterpret_cast<HKEY>(
608 reinterpret_cast<void*>(static_cast<uintptr_t>(handle)));
609 DWORD size = static_cast<DWORD>(value.size()) * sizeof(wchar_t);
610 LSTATUS status = RegSetValueEx(reg_key, key.c_str(), 0, REG_SZ,
611 reinterpret_cast<const BYTE*>(value.c_str()), size);
612 return status == ERROR_SUCCESS;
615 GoogleUpdateSettings::UpdatePolicy GoogleUpdateSettings::GetAppUpdatePolicy(
616 const base::string16& app_guid,
617 bool* is_overridden) {
618 bool found_override = false;
619 UpdatePolicy update_policy = kDefaultUpdatePolicy;
621 #if defined(GOOGLE_CHROME_BUILD)
622 DCHECK(!app_guid.empty());
623 RegKey policy_key;
625 // Google Update Group Policy settings are always in HKLM.
626 // TODO(wfh): Check if policies should go into Wow6432Node or not.
627 if (policy_key.Open(HKEY_LOCAL_MACHINE, kPoliciesKey, KEY_QUERY_VALUE) ==
628 ERROR_SUCCESS) {
629 DWORD value = 0;
630 base::string16 app_update_override(kUpdateOverrideValuePrefix);
631 app_update_override.append(app_guid);
632 // First try to read and comprehend the app-specific override.
633 found_override = (policy_key.ReadValueDW(app_update_override.c_str(),
634 &value) == ERROR_SUCCESS &&
635 GetUpdatePolicyFromDword(value, &update_policy));
637 // Failing that, try to read and comprehend the default override.
638 if (!found_override &&
639 policy_key.ReadValueDW(kUpdatePolicyValue, &value) == ERROR_SUCCESS) {
640 GetUpdatePolicyFromDword(value, &update_policy);
643 #endif // defined(GOOGLE_CHROME_BUILD)
645 if (is_overridden != NULL)
646 *is_overridden = found_override;
648 return update_policy;
651 // static
652 bool GoogleUpdateSettings::AreAutoupdatesEnabled() {
653 #if defined(GOOGLE_CHROME_BUILD)
654 // Check the auto-update check period override. If it is 0 or exceeds the
655 // maximum timeout, then for all intents and purposes auto updates are
656 // disabled.
657 RegKey policy_key;
658 DWORD value = 0;
659 if (policy_key.Open(HKEY_LOCAL_MACHINE, kPoliciesKey,
660 KEY_QUERY_VALUE) == ERROR_SUCCESS &&
661 policy_key.ReadValueDW(kCheckPeriodOverrideMinutes,
662 &value) == ERROR_SUCCESS &&
663 (value == 0 || value > kCheckPeriodOverrideMinutesMax)) {
664 return false;
667 // Auto updates are subtly broken when Chrome and the binaries have different
668 // overrides in place. If this Chrome cannot possibly be multi-install by
669 // virtue of being a side-by-side installation, simply check Chrome's policy.
670 BrowserDistribution* dist = BrowserDistribution::GetDistribution();
671 UpdatePolicy app_policy = GetAppUpdatePolicy(dist->GetAppGuid(), nullptr);
672 if (InstallUtil::IsChromeSxSProcess())
673 return app_policy == AUTOMATIC_UPDATES || app_policy == AUTO_UPDATES_ONLY;
675 // Otherwise, check for consistency between Chrome and the binaries regardless
676 // of whether or not this Chrome is multi-install since the next update likely
677 // will attempt to migrate it to such.
678 BrowserDistribution* binaries = BrowserDistribution::GetSpecificDistribution(
679 BrowserDistribution::CHROME_BINARIES);
680 return (GetAppUpdatePolicy(binaries->GetAppGuid(), nullptr) == app_policy &&
681 (app_policy == AUTOMATIC_UPDATES || app_policy == AUTO_UPDATES_ONLY));
682 #else // defined(GOOGLE_CHROME_BUILD)
683 // Chromium does not auto update.
684 return false;
685 #endif // !defined(GOOGLE_CHROME_BUILD)
688 // static
689 bool GoogleUpdateSettings::ReenableAutoupdates() {
690 #if defined(GOOGLE_CHROME_BUILD)
691 int needs_reset_count = 0;
692 int did_reset_count = 0;
694 // Reset overrides for Chrome and for the binaries if this Chrome supports
695 // multi-install.
696 std::vector<base::string16> app_guids;
697 app_guids.push_back(BrowserDistribution::GetDistribution()->GetAppGuid());
698 if (!InstallUtil::IsChromeSxSProcess()) {
699 app_guids.push_back(BrowserDistribution::GetSpecificDistribution(
700 BrowserDistribution::CHROME_BINARIES)->GetAppGuid());
703 UpdatePolicy update_policy = kDefaultUpdatePolicy;
704 RegKey policy_key;
705 if (policy_key.Open(HKEY_LOCAL_MACHINE, kPoliciesKey,
706 KEY_SET_VALUE | KEY_QUERY_VALUE) == ERROR_SUCCESS) {
707 // Set to true while app-specific overrides are present that allow automatic
708 // updates. When this is the case, the defaults are irrelevant and don't
709 // need to be checked or reset.
710 bool automatic_updates_allowed_by_overrides = true;
711 DWORD value = 0;
712 for (const base::string16& app_guid : app_guids) {
713 // First check the app-specific override value and reset that if needed.
714 // Note that this intentionally sets the override to AUTOMATIC_UPDATES
715 // even if it was previously AUTO_UPDATES_ONLY. The thinking is that
716 // AUTOMATIC_UPDATES is marginally more likely to let a user update and
717 // this code is only called when a stuck user asks for updates.
718 base::string16 app_update_override(kUpdateOverrideValuePrefix);
719 app_update_override.append(app_guid);
720 if (policy_key.ReadValueDW(app_update_override.c_str(),
721 &value) != ERROR_SUCCESS) {
722 automatic_updates_allowed_by_overrides = false;
723 } else if (!GetUpdatePolicyFromDword(value, &update_policy) ||
724 update_policy != GoogleUpdateSettings::AUTOMATIC_UPDATES) {
725 automatic_updates_allowed_by_overrides = false;
726 ++needs_reset_count;
727 if (policy_key.WriteValue(
728 app_update_override.c_str(),
729 static_cast<DWORD>(GoogleUpdateSettings::AUTOMATIC_UPDATES)) ==
730 ERROR_SUCCESS) {
731 ++did_reset_count;
736 // If there were no app-specific override policies, see if there's a global
737 // policy preventing updates and delete it if so.
738 if (!automatic_updates_allowed_by_overrides &&
739 policy_key.ReadValueDW(kUpdatePolicyValue, &value) == ERROR_SUCCESS &&
740 (!GetUpdatePolicyFromDword(value, &update_policy) ||
741 update_policy != GoogleUpdateSettings::AUTOMATIC_UPDATES)) {
742 ++needs_reset_count;
743 if (policy_key.DeleteValue(kUpdatePolicyValue) == ERROR_SUCCESS)
744 ++did_reset_count;
747 // Check the auto-update check period override. If it is 0 or exceeds
748 // the maximum timeout, delete the override value.
749 if (policy_key.ReadValueDW(kCheckPeriodOverrideMinutes,
750 &value) == ERROR_SUCCESS &&
751 (value == 0 || value > kCheckPeriodOverrideMinutesMax)) {
752 ++needs_reset_count;
753 if (policy_key.DeleteValue(kCheckPeriodOverrideMinutes) == ERROR_SUCCESS)
754 ++did_reset_count;
757 // Return whether the number of successful resets is the same as the
758 // number of things that appeared to need resetting.
759 return (needs_reset_count == did_reset_count);
760 } else {
761 // For some reason we couldn't open the policy key with the desired
762 // permissions to make changes (the most likely reason is that there is no
763 // policy set). Simply return whether or not we think updates are enabled.
764 return AreAutoupdatesEnabled();
767 #endif
768 // Non Google Chrome isn't going to autoupdate.
769 return true;
772 void GoogleUpdateSettings::RecordChromeUpdatePolicyHistograms() {
773 const bool is_multi_install = InstallUtil::IsMultiInstall(
774 BrowserDistribution::GetDistribution(), IsSystemInstall());
775 const base::string16 app_guid =
776 BrowserDistribution::GetSpecificDistribution(
777 is_multi_install ? BrowserDistribution::CHROME_BINARIES :
778 BrowserDistribution::CHROME_BROWSER)->GetAppGuid();
780 bool is_overridden = false;
781 const UpdatePolicy update_policy = GetAppUpdatePolicy(app_guid,
782 &is_overridden);
783 UMA_HISTOGRAM_BOOLEAN("GoogleUpdate.UpdatePolicyIsOverridden", is_overridden);
784 UMA_HISTOGRAM_ENUMERATION("GoogleUpdate.EffectivePolicy", update_policy,
785 UPDATE_POLICIES_COUNT);
788 base::string16 GoogleUpdateSettings::GetUninstallCommandLine(
789 bool system_install) {
790 const HKEY root_key = system_install ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER;
791 base::string16 cmd_line;
792 RegKey update_key;
794 if (update_key.Open(root_key, google_update::kRegPathGoogleUpdate,
795 KEY_QUERY_VALUE | KEY_WOW64_32KEY) == ERROR_SUCCESS) {
796 update_key.ReadValue(google_update::kRegUninstallCmdLine, &cmd_line);
799 return cmd_line;
802 Version GoogleUpdateSettings::GetGoogleUpdateVersion(bool system_install) {
803 const HKEY root_key = system_install ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER;
804 base::string16 version;
805 RegKey key;
807 if (key.Open(root_key,
808 google_update::kRegPathGoogleUpdate,
809 KEY_QUERY_VALUE | KEY_WOW64_32KEY) == ERROR_SUCCESS &&
810 key.ReadValue(google_update::kRegGoogleUpdateVersion, &version) ==
811 ERROR_SUCCESS) {
812 return Version(base::UTF16ToUTF8(version));
815 return Version();
818 base::Time GoogleUpdateSettings::GetGoogleUpdateLastStartedAU(
819 bool system_install) {
820 const HKEY root_key = system_install ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER;
821 RegKey update_key;
823 if (update_key.Open(root_key,
824 google_update::kRegPathGoogleUpdate,
825 KEY_QUERY_VALUE | KEY_WOW64_32KEY) == ERROR_SUCCESS) {
826 DWORD last_start;
827 if (update_key.ReadValueDW(google_update::kRegLastStartedAUField,
828 &last_start) == ERROR_SUCCESS) {
829 return base::Time::FromTimeT(last_start);
833 return base::Time();
836 base::Time GoogleUpdateSettings::GetGoogleUpdateLastChecked(
837 bool system_install) {
838 const HKEY root_key = system_install ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER;
839 RegKey update_key;
841 if (update_key.Open(root_key,
842 google_update::kRegPathGoogleUpdate,
843 KEY_QUERY_VALUE | KEY_WOW64_32KEY) == ERROR_SUCCESS) {
844 DWORD last_check;
845 if (update_key.ReadValueDW(google_update::kRegLastCheckedField,
846 &last_check) == ERROR_SUCCESS) {
847 return base::Time::FromTimeT(last_check);
851 return base::Time();
854 bool GoogleUpdateSettings::GetUpdateDetailForApp(bool system_install,
855 const wchar_t* app_guid,
856 ProductData* data) {
857 DCHECK(app_guid);
858 DCHECK(data);
860 bool product_found = false;
862 const HKEY root_key = system_install ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER;
863 base::string16 clientstate_reg_path(google_update::kRegPathClientState);
864 clientstate_reg_path.append(L"\\");
865 clientstate_reg_path.append(app_guid);
867 RegKey clientstate;
868 if (clientstate.Open(root_key,
869 clientstate_reg_path.c_str(),
870 KEY_QUERY_VALUE | KEY_WOW64_32KEY) == ERROR_SUCCESS) {
871 base::string16 version;
872 DWORD dword_value;
873 if ((clientstate.ReadValueDW(google_update::kRegLastCheckSuccessField,
874 &dword_value) == ERROR_SUCCESS) &&
875 (clientstate.ReadValue(google_update::kRegVersionField,
876 &version) == ERROR_SUCCESS)) {
877 product_found = true;
878 data->version = base::UTF16ToASCII(version);
879 data->last_success = base::Time::FromTimeT(dword_value);
880 data->last_result = 0;
881 data->last_error_code = 0;
882 data->last_extra_code = 0;
884 if (clientstate.ReadValueDW(google_update::kRegLastInstallerResultField,
885 &dword_value) == ERROR_SUCCESS) {
886 // Google Update convention is that if an installer writes an result
887 // code that is invalid, it is clamped to an exit code result.
888 const DWORD kMaxValidInstallResult = 4; // INSTALLER_RESULT_EXIT_CODE
889 data->last_result = std::min(dword_value, kMaxValidInstallResult);
891 if (clientstate.ReadValueDW(google_update::kRegLastInstallerErrorField,
892 &dword_value) == ERROR_SUCCESS) {
893 data->last_error_code = dword_value;
895 if (clientstate.ReadValueDW(google_update::kRegLastInstallerExtraField,
896 &dword_value) == ERROR_SUCCESS) {
897 data->last_extra_code = dword_value;
902 return product_found;
905 bool GoogleUpdateSettings::GetUpdateDetailForGoogleUpdate(bool system_install,
906 ProductData* data) {
907 return GetUpdateDetailForApp(system_install,
908 google_update::kGoogleUpdateUpgradeCode,
909 data);
912 bool GoogleUpdateSettings::GetUpdateDetail(bool system_install,
913 ProductData* data) {
914 BrowserDistribution* dist = BrowserDistribution::GetDistribution();
915 return GetUpdateDetailForApp(system_install,
916 dist->GetAppGuid().c_str(),
917 data);
920 bool GoogleUpdateSettings::SetExperimentLabels(
921 bool system_install,
922 const base::string16& experiment_labels) {
923 HKEY reg_root = system_install ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER;
925 // Use the browser distribution and install level to write to the correct
926 // client state/app guid key.
927 bool success = false;
928 BrowserDistribution* dist = BrowserDistribution::GetDistribution();
929 if (dist->ShouldSetExperimentLabels()) {
930 base::string16 client_state_path(
931 system_install ? dist->GetStateMediumKey() : dist->GetStateKey());
932 RegKey client_state(
933 reg_root, client_state_path.c_str(), KEY_SET_VALUE | KEY_WOW64_32KEY);
934 // It is possible that the registry keys do not yet exist or have not yet
935 // been ACLed by Google Update to be user writable.
936 if (!client_state.Valid())
937 return false;
938 if (experiment_labels.empty()) {
939 success = client_state.DeleteValue(google_update::kExperimentLabels)
940 == ERROR_SUCCESS;
941 } else {
942 success = client_state.WriteValue(google_update::kExperimentLabels,
943 experiment_labels.c_str()) == ERROR_SUCCESS;
947 return success;
950 bool GoogleUpdateSettings::ReadExperimentLabels(
951 bool system_install,
952 base::string16* experiment_labels) {
953 HKEY reg_root = system_install ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER;
955 // If this distribution does not set the experiment labels, don't bother
956 // reading.
957 BrowserDistribution* dist = BrowserDistribution::GetDistribution();
958 if (!dist->ShouldSetExperimentLabels())
959 return false;
961 base::string16 client_state_path(
962 system_install ? dist->GetStateMediumKey() : dist->GetStateKey());
964 RegKey client_state;
965 LONG result = client_state.Open(
966 reg_root, client_state_path.c_str(), KEY_QUERY_VALUE | KEY_WOW64_32KEY);
967 if (result == ERROR_SUCCESS) {
968 result = client_state.ReadValue(google_update::kExperimentLabels,
969 experiment_labels);
972 // If the key or value was not present, return the empty string.
973 if (result == ERROR_FILE_NOT_FOUND || result == ERROR_PATH_NOT_FOUND) {
974 experiment_labels->clear();
975 return true;
978 return result == ERROR_SUCCESS;