Enable MSVC warning for unused locals.
[chromium-blink-merge.git] / chrome / installer / util / google_update_settings.cc
blob3c4cba6662885c745cbf166ca1fa6813dc6b0e6d
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>
9 #include "base/command_line.h"
10 #include "base/files/file_path.h"
11 #include "base/logging.h"
12 #include "base/metrics/histogram.h"
13 #include "base/path_service.h"
14 #include "base/strings/string_number_conversions.h"
15 #include "base/strings/string_util.h"
16 #include "base/strings/utf_string_conversions.h"
17 #include "base/threading/thread_restrictions.h"
18 #include "base/time/time.h"
19 #include "base/win/registry.h"
20 #include "base/win/win_util.h"
21 #include "chrome/common/chrome_switches.h"
22 #include "chrome/installer/util/app_registration_data.h"
23 #include "chrome/installer/util/browser_distribution.h"
24 #include "chrome/installer/util/channel_info.h"
25 #include "chrome/installer/util/google_update_constants.h"
26 #include "chrome/installer/util/google_update_experiment_util.h"
27 #include "chrome/installer/util/install_util.h"
28 #include "chrome/installer/util/installation_state.h"
29 #include "chrome/installer/util/product.h"
31 using base::win::RegKey;
32 using installer::InstallationState;
34 const wchar_t GoogleUpdateSettings::kPoliciesKey[] =
35 L"SOFTWARE\\Policies\\Google\\Update";
36 const wchar_t GoogleUpdateSettings::kUpdatePolicyValue[] = L"UpdateDefault";
37 const wchar_t GoogleUpdateSettings::kUpdateOverrideValuePrefix[] = L"Update";
38 const wchar_t GoogleUpdateSettings::kCheckPeriodOverrideMinutes[] =
39 L"AutoUpdateCheckPeriodMinutes";
41 // Don't allow update periods longer than six weeks.
42 const int GoogleUpdateSettings::kCheckPeriodOverrideMinutesMax =
43 60 * 24 * 7 * 6;
45 const GoogleUpdateSettings::UpdatePolicy
46 GoogleUpdateSettings::kDefaultUpdatePolicy =
47 #if defined(GOOGLE_CHROME_BUILD)
48 GoogleUpdateSettings::AUTOMATIC_UPDATES;
49 #else
50 GoogleUpdateSettings::UPDATES_DISABLED;
51 #endif
53 namespace {
55 bool ReadGoogleUpdateStrKey(const wchar_t* const name, base::string16* value) {
56 BrowserDistribution* dist = BrowserDistribution::GetDistribution();
57 base::string16 reg_path = dist->GetStateKey();
58 RegKey key(HKEY_CURRENT_USER, reg_path.c_str(), KEY_READ | KEY_WOW64_32KEY);
59 if (key.ReadValue(name, value) != ERROR_SUCCESS) {
60 RegKey hklm_key(
61 HKEY_LOCAL_MACHINE, reg_path.c_str(), KEY_READ | KEY_WOW64_32KEY);
62 return (hklm_key.ReadValue(name, value) == ERROR_SUCCESS);
64 return true;
67 // Updates a registry key |name| to be |value| for the given |app_reg_data|.
68 // If this is a |system_install|, then update the value under HKLM (istead of
69 // HKCU for user-installs) using a group of keys (one for each OS user) and also
70 // include the method to |aggregate| these values when reporting.
71 bool WriteGoogleUpdateStrKeyInternal(const AppRegistrationData& app_reg_data,
72 bool system_install,
73 const wchar_t* const name,
74 const base::string16& value,
75 const wchar_t* const aggregate) {
76 const REGSAM kAccess = KEY_SET_VALUE | KEY_WOW64_32KEY;
77 if (system_install) {
78 DCHECK(aggregate);
79 // Machine installs require each OS user to write a unique key under a
80 // named key in HKLM as well as an "aggregation" function that describes
81 // how the values of multiple users are to be combined.
82 base::string16 uniquename;
83 if (!base::win::GetUserSidString(&uniquename)) {
84 NOTREACHED();
85 return false;
88 base::string16 reg_path(app_reg_data.GetStateMediumKey());
89 reg_path.append(L"\\");
90 reg_path.append(name);
91 RegKey key(HKEY_LOCAL_MACHINE, reg_path.c_str(), kAccess);
92 key.WriteValue(google_update::kRegAggregateMethod, aggregate);
93 return (key.WriteValue(uniquename.c_str(), value.c_str()) == ERROR_SUCCESS);
94 } else {
95 // User installs are easy: just write the values to HKCU tree.
96 RegKey key(HKEY_CURRENT_USER, app_reg_data.GetStateKey().c_str(), kAccess);
97 return (key.WriteValue(name, value.c_str()) == ERROR_SUCCESS);
101 bool WriteGoogleUpdateStrKey(const wchar_t* const name,
102 const base::string16& value) {
103 BrowserDistribution* dist = BrowserDistribution::GetDistribution();
104 return WriteGoogleUpdateStrKeyInternal(
105 dist->GetAppRegistrationData(), false, name, value, NULL);
108 bool ClearGoogleUpdateStrKey(const wchar_t* const name) {
109 BrowserDistribution* dist = BrowserDistribution::GetDistribution();
110 base::string16 reg_path = dist->GetStateKey();
111 RegKey key(HKEY_CURRENT_USER,
112 reg_path.c_str(),
113 KEY_READ | KEY_WRITE | KEY_WOW64_32KEY);
114 base::string16 value;
115 if (key.ReadValue(name, &value) != ERROR_SUCCESS)
116 return false;
117 return (key.WriteValue(name, L"") == ERROR_SUCCESS);
120 bool RemoveGoogleUpdateStrKey(const wchar_t* const name) {
121 BrowserDistribution* dist = BrowserDistribution::GetDistribution();
122 base::string16 reg_path = dist->GetStateKey();
123 RegKey key(HKEY_CURRENT_USER,
124 reg_path.c_str(),
125 KEY_READ | KEY_WRITE | KEY_WOW64_32KEY);
126 if (!key.HasValue(name))
127 return true;
128 return (key.DeleteValue(name) == ERROR_SUCCESS);
131 bool GetChromeChannelInternal(bool system_install,
132 bool add_multi_modifier,
133 base::string16* channel) {
134 BrowserDistribution* dist = BrowserDistribution::GetDistribution();
136 // Shortcut in case this distribution knows what channel it is (canary).
137 if (dist->GetChromeChannel(channel))
138 return true;
140 // Determine whether or not chrome is multi-install. If so, updates are
141 // delivered under the binaries' app guid, so that's where the relevant
142 // channel is found.
143 installer::ProductState state;
144 installer::ChannelInfo channel_info;
145 ignore_result(state.Initialize(system_install, dist));
146 if (!state.is_multi_install()) {
147 // Use the channel info that was just read for this single-install chrome.
148 channel_info = state.channel();
149 } else {
150 // Read the channel info from the binaries' state key.
151 HKEY root_key = system_install ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER;
152 dist = BrowserDistribution::GetSpecificDistribution(
153 BrowserDistribution::CHROME_BINARIES);
154 RegKey key(root_key, dist->GetStateKey().c_str(),
155 KEY_READ | KEY_WOW64_32KEY);
157 if (!channel_info.Initialize(key)) {
158 channel->assign(installer::kChromeChannelUnknown);
159 return false;
163 if (!channel_info.GetChannelName(channel))
164 channel->assign(installer::kChromeChannelUnknown);
166 // Tag the channel name if this is a multi-install.
167 if (add_multi_modifier && state.is_multi_install()) {
168 if (!channel->empty())
169 channel->push_back(L'-');
170 channel->push_back(L'm');
173 return true;
176 // Populates |update_policy| with the UpdatePolicy enum value corresponding to a
177 // DWORD read from the registry and returns true if |value| is within range.
178 // If |value| is out of range, returns false without modifying |update_policy|.
179 bool GetUpdatePolicyFromDword(
180 const DWORD value,
181 GoogleUpdateSettings::UpdatePolicy* update_policy) {
182 switch (value) {
183 case GoogleUpdateSettings::UPDATES_DISABLED:
184 case GoogleUpdateSettings::AUTOMATIC_UPDATES:
185 case GoogleUpdateSettings::MANUAL_UPDATES_ONLY:
186 case GoogleUpdateSettings::AUTO_UPDATES_ONLY:
187 *update_policy = static_cast<GoogleUpdateSettings::UpdatePolicy>(value);
188 return true;
189 default:
190 LOG(WARNING) << "Unexpected update policy override value: " << value;
192 return false;
195 // Convenience routine: GoogleUpdateSettings::UpdateDidRunStateForApp()
196 // specialized for Chrome Binaries.
197 bool UpdateDidRunStateForBinaries(bool did_run) {
198 BrowserDistribution* dist = BrowserDistribution::GetSpecificDistribution(
199 BrowserDistribution::CHROME_BINARIES);
200 return GoogleUpdateSettings::UpdateDidRunStateForApp(
201 dist->GetAppRegistrationData(), did_run);
204 } // namespace
206 bool GoogleUpdateSettings::IsSystemInstall() {
207 bool system_install = false;
208 base::FilePath module_dir;
209 if (!PathService::Get(base::DIR_MODULE, &module_dir)) {
210 LOG(WARNING)
211 << "Failed to get directory of module; assuming per-user install.";
212 } else {
213 system_install = !InstallUtil::IsPerUserInstall(module_dir.value().c_str());
215 return system_install;
218 bool GoogleUpdateSettings::GetCollectStatsConsent() {
219 return GetCollectStatsConsentAtLevel(IsSystemInstall());
222 // Older versions of Chrome unconditionally read from HKCU\...\ClientState\...
223 // and then HKLM\...\ClientState\.... This means that system-level Chrome
224 // never checked ClientStateMedium (which has priority according to Google
225 // Update) and gave preference to a value in HKCU (which was never checked by
226 // Google Update). From now on, Chrome follows Google Update's policy.
227 bool GoogleUpdateSettings::GetCollectStatsConsentAtLevel(bool system_install) {
228 BrowserDistribution* dist = BrowserDistribution::GetDistribution();
230 // Consent applies to all products in a multi-install package.
231 if (InstallUtil::IsMultiInstall(dist, system_install)) {
232 dist = BrowserDistribution::GetSpecificDistribution(
233 BrowserDistribution::CHROME_BINARIES);
236 RegKey key;
237 DWORD value = 0;
238 bool have_value = false;
239 const REGSAM kAccess = KEY_QUERY_VALUE | KEY_WOW64_32KEY;
241 // For system-level installs, try ClientStateMedium first.
242 have_value =
243 system_install &&
244 key.Open(HKEY_LOCAL_MACHINE, dist->GetStateMediumKey().c_str(),
245 kAccess) == ERROR_SUCCESS &&
246 key.ReadValueDW(google_update::kRegUsageStatsField,
247 &value) == ERROR_SUCCESS;
249 // Otherwise, try ClientState.
250 if (!have_value) {
251 have_value =
252 key.Open(system_install ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER,
253 dist->GetStateKey().c_str(),
254 kAccess) == ERROR_SUCCESS &&
255 key.ReadValueDW(google_update::kRegUsageStatsField,
256 &value) == ERROR_SUCCESS;
259 // Google Update specifically checks that the value is 1, so we do the same.
260 return have_value && value == 1;
263 bool GoogleUpdateSettings::SetCollectStatsConsent(bool consented) {
264 return SetCollectStatsConsentAtLevel(IsSystemInstall(), consented);
267 bool GoogleUpdateSettings::SetCollectStatsConsentAtLevel(bool system_install,
268 bool consented) {
269 // Google Update writes and expects 1 for true, 0 for false.
270 DWORD value = consented ? 1 : 0;
272 BrowserDistribution* dist = BrowserDistribution::GetDistribution();
274 // Consent applies to all products in a multi-install package.
275 if (InstallUtil::IsMultiInstall(dist, system_install)) {
276 dist = BrowserDistribution::GetSpecificDistribution(
277 BrowserDistribution::CHROME_BINARIES);
280 // Write to ClientStateMedium for system-level; ClientState otherwise.
281 HKEY root_key = system_install ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER;
282 base::string16 reg_path =
283 system_install ? dist->GetStateMediumKey() : dist->GetStateKey();
284 RegKey key;
285 LONG result = key.Create(
286 root_key, reg_path.c_str(), KEY_SET_VALUE | KEY_WOW64_32KEY);
287 if (result != ERROR_SUCCESS) {
288 LOG(ERROR) << "Failed opening key " << reg_path << " to set "
289 << google_update::kRegUsageStatsField << "; result: " << result;
290 } else {
291 result = key.WriteValue(google_update::kRegUsageStatsField, value);
292 LOG_IF(ERROR, result != ERROR_SUCCESS) << "Failed setting "
293 << google_update::kRegUsageStatsField << " in key " << reg_path
294 << "; result: " << result;
296 return (result == ERROR_SUCCESS);
299 scoped_ptr<metrics::ClientInfo> GoogleUpdateSettings::LoadMetricsClientInfo() {
300 base::string16 client_id_16;
301 if (!ReadGoogleUpdateStrKey(google_update::kRegMetricsId, &client_id_16) ||
302 client_id_16.empty()) {
303 return scoped_ptr<metrics::ClientInfo>();
306 scoped_ptr<metrics::ClientInfo> client_info(new metrics::ClientInfo);
307 client_info->client_id = base::UTF16ToUTF8(client_id_16);
309 base::string16 installation_date_str;
310 if (ReadGoogleUpdateStrKey(google_update::kRegMetricsIdInstallDate,
311 &installation_date_str)) {
312 base::StringToInt64(installation_date_str, &client_info->installation_date);
315 base::string16 reporting_enbaled_date_date_str;
316 if (ReadGoogleUpdateStrKey(google_update::kRegMetricsIdEnabledDate,
317 &reporting_enbaled_date_date_str)) {
318 base::StringToInt64(reporting_enbaled_date_date_str,
319 &client_info->reporting_enabled_date);
322 return client_info.Pass();
325 void GoogleUpdateSettings::StoreMetricsClientInfo(
326 const metrics::ClientInfo& client_info) {
327 // Attempt a best-effort at backing |client_info| in the registry (but don't
328 // handle/report failures).
329 WriteGoogleUpdateStrKey(google_update::kRegMetricsId,
330 base::UTF8ToUTF16(client_info.client_id));
331 WriteGoogleUpdateStrKey(google_update::kRegMetricsIdInstallDate,
332 base::Int64ToString16(client_info.installation_date));
333 WriteGoogleUpdateStrKey(
334 google_update::kRegMetricsIdEnabledDate,
335 base::Int64ToString16(client_info.reporting_enabled_date));
338 // EULA consent is only relevant for system-level installs.
339 bool GoogleUpdateSettings::SetEULAConsent(
340 const InstallationState& machine_state,
341 BrowserDistribution* dist,
342 bool consented) {
343 DCHECK(dist);
344 const DWORD eula_accepted = consented ? 1 : 0;
345 const REGSAM kAccess = KEY_SET_VALUE | KEY_WOW64_32KEY;
346 base::string16 reg_path = dist->GetStateMediumKey();
347 bool succeeded = true;
348 RegKey key;
350 // Write the consent value into the product's ClientStateMedium key.
351 if (key.Create(HKEY_LOCAL_MACHINE, reg_path.c_str(),
352 kAccess) != ERROR_SUCCESS ||
353 key.WriteValue(google_update::kRegEULAAceptedField,
354 eula_accepted) != ERROR_SUCCESS) {
355 succeeded = false;
358 // If this is a multi-install, also write it into the binaries' key.
359 // --mutli-install is not provided on the command-line, so deduce it from
360 // the product's state.
361 const installer::ProductState* product_state =
362 machine_state.GetProductState(true, dist->GetType());
363 if (product_state != NULL && product_state->is_multi_install()) {
364 dist = BrowserDistribution::GetSpecificDistribution(
365 BrowserDistribution::CHROME_BINARIES);
366 reg_path = dist->GetStateMediumKey();
367 if (key.Create(HKEY_LOCAL_MACHINE, reg_path.c_str(),
368 kAccess) != ERROR_SUCCESS ||
369 key.WriteValue(google_update::kRegEULAAceptedField,
370 eula_accepted) != ERROR_SUCCESS) {
371 succeeded = false;
375 return succeeded;
378 int GoogleUpdateSettings::GetLastRunTime() {
379 base::string16 time_s;
380 if (!ReadGoogleUpdateStrKey(google_update::kRegLastRunTimeField, &time_s))
381 return -1;
382 int64 time_i;
383 if (!base::StringToInt64(time_s, &time_i))
384 return -1;
385 base::TimeDelta td =
386 base::Time::NowFromSystemTime() - base::Time::FromInternalValue(time_i);
387 return td.InDays();
390 bool GoogleUpdateSettings::SetLastRunTime() {
391 int64 time = base::Time::NowFromSystemTime().ToInternalValue();
392 return WriteGoogleUpdateStrKey(google_update::kRegLastRunTimeField,
393 base::Int64ToString16(time));
396 bool GoogleUpdateSettings::RemoveLastRunTime() {
397 return RemoveGoogleUpdateStrKey(google_update::kRegLastRunTimeField);
400 bool GoogleUpdateSettings::GetBrowser(base::string16* browser) {
401 return ReadGoogleUpdateStrKey(google_update::kRegBrowserField, browser);
404 bool GoogleUpdateSettings::GetLanguage(base::string16* language) {
405 return ReadGoogleUpdateStrKey(google_update::kRegLangField, language);
408 bool GoogleUpdateSettings::GetBrand(base::string16* brand) {
409 return ReadGoogleUpdateStrKey(google_update::kRegRLZBrandField, brand);
412 bool GoogleUpdateSettings::GetReactivationBrand(base::string16* brand) {
413 return ReadGoogleUpdateStrKey(google_update::kRegRLZReactivationBrandField,
414 brand);
417 bool GoogleUpdateSettings::GetClient(base::string16* client) {
418 return ReadGoogleUpdateStrKey(google_update::kRegClientField, client);
421 bool GoogleUpdateSettings::SetClient(const base::string16& client) {
422 return WriteGoogleUpdateStrKey(google_update::kRegClientField, client);
425 bool GoogleUpdateSettings::GetReferral(base::string16* referral) {
426 return ReadGoogleUpdateStrKey(google_update::kRegReferralField, referral);
429 bool GoogleUpdateSettings::ClearReferral() {
430 return ClearGoogleUpdateStrKey(google_update::kRegReferralField);
433 bool GoogleUpdateSettings::UpdateDidRunStateForApp(
434 const AppRegistrationData& app_reg_data,
435 bool did_run) {
436 return WriteGoogleUpdateStrKeyInternal(app_reg_data,
437 false, // user level.
438 google_update::kRegDidRunField,
439 did_run ? L"1" : L"0",
440 NULL);
443 bool GoogleUpdateSettings::UpdateDidRunState(bool did_run, bool system_level) {
444 BrowserDistribution* dist = BrowserDistribution::GetDistribution();
445 bool result = UpdateDidRunStateForApp(dist->GetAppRegistrationData(),
446 did_run);
447 // Update state for binaries, even if the previous call was unsuccessful.
448 if (InstallUtil::IsMultiInstall(dist, system_level))
449 result = UpdateDidRunStateForBinaries(did_run) && result;
450 return result;
453 base::string16 GoogleUpdateSettings::GetChromeChannel(bool system_install) {
454 base::string16 channel;
455 GetChromeChannelInternal(system_install, false, &channel);
456 return channel;
459 bool GoogleUpdateSettings::GetChromeChannelAndModifiers(
460 bool system_install,
461 base::string16* channel) {
462 return GetChromeChannelInternal(system_install, true, channel);
465 void GoogleUpdateSettings::UpdateInstallStatus(bool system_install,
466 installer::ArchiveType archive_type, int install_return_code,
467 const base::string16& product_guid) {
468 DCHECK(archive_type != installer::UNKNOWN_ARCHIVE_TYPE ||
469 install_return_code != 0);
470 HKEY reg_root = (system_install) ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER;
472 RegKey key;
473 installer::ChannelInfo channel_info;
474 base::string16 reg_key(google_update::kRegPathClientState);
475 reg_key.append(L"\\");
476 reg_key.append(product_guid);
477 LONG result = key.Open(reg_root,
478 reg_key.c_str(),
479 KEY_QUERY_VALUE | KEY_SET_VALUE | KEY_WOW64_32KEY);
480 if (result == ERROR_SUCCESS)
481 channel_info.Initialize(key);
482 else if (result != ERROR_FILE_NOT_FOUND)
483 LOG(ERROR) << "Failed to open " << reg_key << "; Error: " << result;
485 if (UpdateGoogleUpdateApKey(archive_type, install_return_code,
486 &channel_info)) {
487 // We have a modified channel_info value to write.
488 // Create the app's ClientState key if it doesn't already exist.
489 if (!key.Valid()) {
490 result = key.Open(reg_root,
491 google_update::kRegPathClientState,
492 KEY_CREATE_SUB_KEY | KEY_WOW64_32KEY);
493 if (result == ERROR_SUCCESS)
494 result = key.CreateKey(product_guid.c_str(),
495 KEY_SET_VALUE | KEY_WOW64_32KEY);
497 if (result != ERROR_SUCCESS) {
498 LOG(ERROR) << "Failed to create " << reg_key << "; Error: " << result;
499 return;
502 if (!channel_info.Write(&key)) {
503 LOG(ERROR) << "Failed to write to application's ClientState key "
504 << google_update::kRegApField << " = " << channel_info.value();
509 bool GoogleUpdateSettings::UpdateGoogleUpdateApKey(
510 installer::ArchiveType archive_type, int install_return_code,
511 installer::ChannelInfo* value) {
512 DCHECK(archive_type != installer::UNKNOWN_ARCHIVE_TYPE ||
513 install_return_code != 0);
514 bool modified = false;
516 if (archive_type == installer::FULL_ARCHIVE_TYPE || !install_return_code) {
517 if (value->SetFullSuffix(false)) {
518 VLOG(1) << "Removed incremental installer failure key; "
519 "switching to channel: "
520 << value->value();
521 modified = true;
523 } else if (archive_type == installer::INCREMENTAL_ARCHIVE_TYPE) {
524 if (value->SetFullSuffix(true)) {
525 VLOG(1) << "Incremental installer failed; switching to channel: "
526 << value->value();
527 modified = true;
528 } else {
529 VLOG(1) << "Incremental installer failure; already on channel: "
530 << value->value();
532 } else {
533 // It's okay if we don't know the archive type. In this case, leave the
534 // "-full" suffix as we found it.
535 DCHECK_EQ(installer::UNKNOWN_ARCHIVE_TYPE, archive_type);
538 if (value->SetMultiFailSuffix(false)) {
539 VLOG(1) << "Removed multi-install failure key; switching to channel: "
540 << value->value();
541 modified = true;
544 return modified;
547 void GoogleUpdateSettings::UpdateProfileCounts(int profiles_active,
548 int profiles_signedin) {
549 BrowserDistribution* dist = BrowserDistribution::GetDistribution();
550 bool system_install = IsSystemInstall();
551 WriteGoogleUpdateStrKeyInternal(dist->GetAppRegistrationData(),
552 system_install,
553 google_update::kRegProfilesActive,
554 base::Int64ToString16(profiles_active),
555 L"sum()");
556 WriteGoogleUpdateStrKeyInternal(dist->GetAppRegistrationData(),
557 system_install,
558 google_update::kRegProfilesSignedIn,
559 base::Int64ToString16(profiles_signedin),
560 L"sum()");
563 int GoogleUpdateSettings::DuplicateGoogleUpdateSystemClientKey() {
564 BrowserDistribution* dist = BrowserDistribution::GetDistribution();
565 base::string16 reg_path = dist->GetStateKey();
567 // Minimum access needed is to be able to write to this key.
568 RegKey reg_key(
569 HKEY_LOCAL_MACHINE, reg_path.c_str(), KEY_SET_VALUE | KEY_WOW64_32KEY);
570 if (!reg_key.Valid())
571 return 0;
573 HANDLE target_handle = 0;
574 if (!DuplicateHandle(GetCurrentProcess(), reg_key.Handle(),
575 GetCurrentProcess(), &target_handle, KEY_SET_VALUE,
576 TRUE, DUPLICATE_SAME_ACCESS)) {
577 return 0;
579 return reinterpret_cast<int>(target_handle);
582 bool GoogleUpdateSettings::WriteGoogleUpdateSystemClientKey(
583 int handle, const base::string16& key, const base::string16& value) {
584 HKEY reg_key = reinterpret_cast<HKEY>(reinterpret_cast<void*>(handle));
585 DWORD size = static_cast<DWORD>(value.size()) * sizeof(wchar_t);
586 LSTATUS status = RegSetValueEx(reg_key, key.c_str(), 0, REG_SZ,
587 reinterpret_cast<const BYTE*>(value.c_str()), size);
588 return status == ERROR_SUCCESS;
591 GoogleUpdateSettings::UpdatePolicy GoogleUpdateSettings::GetAppUpdatePolicy(
592 const base::string16& app_guid,
593 bool* is_overridden) {
594 bool found_override = false;
595 UpdatePolicy update_policy = kDefaultUpdatePolicy;
597 #if defined(GOOGLE_CHROME_BUILD)
598 DCHECK(!app_guid.empty());
599 RegKey policy_key;
601 // Google Update Group Policy settings are always in HKLM.
602 // TODO(wfh): Check if policies should go into Wow6432Node or not.
603 if (policy_key.Open(HKEY_LOCAL_MACHINE, kPoliciesKey, KEY_QUERY_VALUE) ==
604 ERROR_SUCCESS) {
605 DWORD value = 0;
606 base::string16 app_update_override(kUpdateOverrideValuePrefix);
607 app_update_override.append(app_guid);
608 // First try to read and comprehend the app-specific override.
609 found_override = (policy_key.ReadValueDW(app_update_override.c_str(),
610 &value) == ERROR_SUCCESS &&
611 GetUpdatePolicyFromDword(value, &update_policy));
613 // Failing that, try to read and comprehend the default override.
614 if (!found_override &&
615 policy_key.ReadValueDW(kUpdatePolicyValue, &value) == ERROR_SUCCESS) {
616 GetUpdatePolicyFromDword(value, &update_policy);
619 #endif // defined(GOOGLE_CHROME_BUILD)
621 if (is_overridden != NULL)
622 *is_overridden = found_override;
624 return update_policy;
627 // static
628 bool GoogleUpdateSettings::AreAutoupdatesEnabled(
629 const base::string16& app_guid) {
630 // Check the auto-update check period override. If it is 0 or exceeds the
631 // maximum timeout, then for all intents and purposes auto updates are
632 // disabled.
633 RegKey policy_key;
634 DWORD value = 0;
635 if (policy_key.Open(HKEY_LOCAL_MACHINE, kPoliciesKey,
636 KEY_QUERY_VALUE) == ERROR_SUCCESS &&
637 policy_key.ReadValueDW(kCheckPeriodOverrideMinutes,
638 &value) == ERROR_SUCCESS &&
639 (value == 0 || value > kCheckPeriodOverrideMinutesMax)) {
640 return false;
643 UpdatePolicy policy = GetAppUpdatePolicy(app_guid, NULL);
644 return (policy == AUTOMATIC_UPDATES || policy == AUTO_UPDATES_ONLY);
647 // static
648 bool GoogleUpdateSettings::ReenableAutoupdatesForApp(
649 const base::string16& app_guid) {
650 #if defined(GOOGLE_CHROME_BUILD)
651 int needs_reset_count = 0;
652 int did_reset_count = 0;
654 UpdatePolicy update_policy = kDefaultUpdatePolicy;
655 RegKey policy_key;
656 if (policy_key.Open(HKEY_LOCAL_MACHINE, kPoliciesKey,
657 KEY_SET_VALUE | KEY_QUERY_VALUE) == ERROR_SUCCESS) {
658 // First check the app-specific override value and reset that if needed.
659 // Note that this intentionally sets the override to AUTOMATIC_UPDATES
660 // even if it was previously AUTO_UPDATES_ONLY. The thinking is that
661 // AUTOMATIC_UPDATES is marginally more likely to let a user update and this
662 // code is only called when a stuck user asks for updates.
663 base::string16 app_update_override(kUpdateOverrideValuePrefix);
664 app_update_override.append(app_guid);
665 DWORD value = 0;
666 bool has_app_update_override =
667 policy_key.ReadValueDW(app_update_override.c_str(),
668 &value) == ERROR_SUCCESS;
669 if (has_app_update_override &&
670 (!GetUpdatePolicyFromDword(value, &update_policy) ||
671 update_policy != GoogleUpdateSettings::AUTOMATIC_UPDATES)) {
672 ++needs_reset_count;
673 if (policy_key.WriteValue(
674 app_update_override.c_str(),
675 static_cast<DWORD>(GoogleUpdateSettings::AUTOMATIC_UPDATES)) ==
676 ERROR_SUCCESS) {
677 ++did_reset_count;
681 // If there was no app-specific override policy see if there's a global
682 // policy preventing updates and delete it if so.
683 if (!has_app_update_override &&
684 policy_key.ReadValueDW(kUpdatePolicyValue, &value) == ERROR_SUCCESS &&
685 (!GetUpdatePolicyFromDword(value, &update_policy) ||
686 update_policy != GoogleUpdateSettings::AUTOMATIC_UPDATES)) {
687 ++needs_reset_count;
688 if (policy_key.DeleteValue(kUpdatePolicyValue) == ERROR_SUCCESS)
689 ++did_reset_count;
692 // Check the auto-update check period override. If it is 0 or exceeds
693 // the maximum timeout, delete the override value.
694 if (policy_key.ReadValueDW(kCheckPeriodOverrideMinutes,
695 &value) == ERROR_SUCCESS &&
696 (value == 0 || value > kCheckPeriodOverrideMinutesMax)) {
697 ++needs_reset_count;
698 if (policy_key.DeleteValue(kCheckPeriodOverrideMinutes) == ERROR_SUCCESS)
699 ++did_reset_count;
702 // Return whether the number of successful resets is the same as the
703 // number of things that appeared to need resetting.
704 return (needs_reset_count == did_reset_count);
705 } else {
706 // For some reason we couldn't open the policy key with the desired
707 // permissions to make changes (the most likely reason is that there is no
708 // policy set). Simply return whether or not we think updates are enabled.
709 return AreAutoupdatesEnabled(app_guid);
712 #endif
713 // Non Google Chrome isn't going to autoupdate.
714 return true;
717 void GoogleUpdateSettings::RecordChromeUpdatePolicyHistograms() {
718 const bool is_multi_install = InstallUtil::IsMultiInstall(
719 BrowserDistribution::GetDistribution(), IsSystemInstall());
720 const base::string16 app_guid =
721 BrowserDistribution::GetSpecificDistribution(
722 is_multi_install ? BrowserDistribution::CHROME_BINARIES :
723 BrowserDistribution::CHROME_BROWSER)->GetAppGuid();
725 bool is_overridden = false;
726 const UpdatePolicy update_policy = GetAppUpdatePolicy(app_guid,
727 &is_overridden);
728 UMA_HISTOGRAM_BOOLEAN("GoogleUpdate.UpdatePolicyIsOverridden", is_overridden);
729 UMA_HISTOGRAM_ENUMERATION("GoogleUpdate.EffectivePolicy", update_policy,
730 UPDATE_POLICIES_COUNT);
733 base::string16 GoogleUpdateSettings::GetUninstallCommandLine(
734 bool system_install) {
735 const HKEY root_key = system_install ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER;
736 base::string16 cmd_line;
737 RegKey update_key;
739 if (update_key.Open(root_key, google_update::kRegPathGoogleUpdate,
740 KEY_QUERY_VALUE | KEY_WOW64_32KEY) == ERROR_SUCCESS) {
741 update_key.ReadValue(google_update::kRegUninstallCmdLine, &cmd_line);
744 return cmd_line;
747 Version GoogleUpdateSettings::GetGoogleUpdateVersion(bool system_install) {
748 const HKEY root_key = system_install ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER;
749 base::string16 version;
750 RegKey key;
752 if (key.Open(root_key,
753 google_update::kRegPathGoogleUpdate,
754 KEY_QUERY_VALUE | KEY_WOW64_32KEY) == ERROR_SUCCESS &&
755 key.ReadValue(google_update::kRegGoogleUpdateVersion, &version) ==
756 ERROR_SUCCESS) {
757 return Version(base::UTF16ToUTF8(version));
760 return Version();
763 base::Time GoogleUpdateSettings::GetGoogleUpdateLastStartedAU(
764 bool system_install) {
765 const HKEY root_key = system_install ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER;
766 RegKey update_key;
768 if (update_key.Open(root_key,
769 google_update::kRegPathGoogleUpdate,
770 KEY_QUERY_VALUE | KEY_WOW64_32KEY) == ERROR_SUCCESS) {
771 DWORD last_start;
772 if (update_key.ReadValueDW(google_update::kRegLastStartedAUField,
773 &last_start) == ERROR_SUCCESS) {
774 return base::Time::FromTimeT(last_start);
778 return base::Time();
781 base::Time GoogleUpdateSettings::GetGoogleUpdateLastChecked(
782 bool system_install) {
783 const HKEY root_key = system_install ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER;
784 RegKey update_key;
786 if (update_key.Open(root_key,
787 google_update::kRegPathGoogleUpdate,
788 KEY_QUERY_VALUE | KEY_WOW64_32KEY) == ERROR_SUCCESS) {
789 DWORD last_check;
790 if (update_key.ReadValueDW(google_update::kRegLastCheckedField,
791 &last_check) == ERROR_SUCCESS) {
792 return base::Time::FromTimeT(last_check);
796 return base::Time();
799 bool GoogleUpdateSettings::GetUpdateDetailForApp(bool system_install,
800 const wchar_t* app_guid,
801 ProductData* data) {
802 DCHECK(app_guid);
803 DCHECK(data);
805 bool product_found = false;
807 const HKEY root_key = system_install ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER;
808 base::string16 clientstate_reg_path(google_update::kRegPathClientState);
809 clientstate_reg_path.append(L"\\");
810 clientstate_reg_path.append(app_guid);
812 RegKey clientstate;
813 if (clientstate.Open(root_key,
814 clientstate_reg_path.c_str(),
815 KEY_QUERY_VALUE | KEY_WOW64_32KEY) == ERROR_SUCCESS) {
816 base::string16 version;
817 DWORD dword_value;
818 if ((clientstate.ReadValueDW(google_update::kRegLastCheckSuccessField,
819 &dword_value) == ERROR_SUCCESS) &&
820 (clientstate.ReadValue(google_update::kRegVersionField,
821 &version) == ERROR_SUCCESS)) {
822 product_found = true;
823 data->version = base::UTF16ToASCII(version);
824 data->last_success = base::Time::FromTimeT(dword_value);
825 data->last_result = 0;
826 data->last_error_code = 0;
827 data->last_extra_code = 0;
829 if (clientstate.ReadValueDW(google_update::kRegLastInstallerResultField,
830 &dword_value) == ERROR_SUCCESS) {
831 // Google Update convention is that if an installer writes an result
832 // code that is invalid, it is clamped to an exit code result.
833 const DWORD kMaxValidInstallResult = 4; // INSTALLER_RESULT_EXIT_CODE
834 data->last_result = std::min(dword_value, kMaxValidInstallResult);
836 if (clientstate.ReadValueDW(google_update::kRegLastInstallerErrorField,
837 &dword_value) == ERROR_SUCCESS) {
838 data->last_error_code = dword_value;
840 if (clientstate.ReadValueDW(google_update::kRegLastInstallerExtraField,
841 &dword_value) == ERROR_SUCCESS) {
842 data->last_extra_code = dword_value;
847 return product_found;
850 bool GoogleUpdateSettings::GetUpdateDetailForGoogleUpdate(bool system_install,
851 ProductData* data) {
852 return GetUpdateDetailForApp(system_install,
853 google_update::kGoogleUpdateUpgradeCode,
854 data);
857 bool GoogleUpdateSettings::GetUpdateDetail(bool system_install,
858 ProductData* data) {
859 BrowserDistribution* dist = BrowserDistribution::GetDistribution();
860 return GetUpdateDetailForApp(system_install,
861 dist->GetAppGuid().c_str(),
862 data);
865 bool GoogleUpdateSettings::SetExperimentLabels(
866 bool system_install,
867 const base::string16& experiment_labels) {
868 HKEY reg_root = system_install ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER;
870 // Use the browser distribution and install level to write to the correct
871 // client state/app guid key.
872 bool success = false;
873 BrowserDistribution* dist = BrowserDistribution::GetDistribution();
874 if (dist->ShouldSetExperimentLabels()) {
875 base::string16 client_state_path(
876 system_install ? dist->GetStateMediumKey() : dist->GetStateKey());
877 RegKey client_state(
878 reg_root, client_state_path.c_str(), KEY_SET_VALUE | KEY_WOW64_32KEY);
879 if (experiment_labels.empty()) {
880 success = client_state.DeleteValue(google_update::kExperimentLabels)
881 == ERROR_SUCCESS;
882 } else {
883 success = client_state.WriteValue(google_update::kExperimentLabels,
884 experiment_labels.c_str()) == ERROR_SUCCESS;
888 return success;
891 bool GoogleUpdateSettings::ReadExperimentLabels(
892 bool system_install,
893 base::string16* experiment_labels) {
894 HKEY reg_root = system_install ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER;
896 // If this distribution does not set the experiment labels, don't bother
897 // reading.
898 BrowserDistribution* dist = BrowserDistribution::GetDistribution();
899 if (!dist->ShouldSetExperimentLabels())
900 return false;
902 base::string16 client_state_path(
903 system_install ? dist->GetStateMediumKey() : dist->GetStateKey());
905 RegKey client_state;
906 LONG result = client_state.Open(
907 reg_root, client_state_path.c_str(), KEY_QUERY_VALUE | KEY_WOW64_32KEY);
908 if (result == ERROR_SUCCESS) {
909 result = client_state.ReadValue(google_update::kExperimentLabels,
910 experiment_labels);
913 // If the key or value was not present, return the empty string.
914 if (result == ERROR_FILE_NOT_FOUND || result == ERROR_PATH_NOT_FOUND) {
915 experiment_labels->clear();
916 return true;
919 return result == ERROR_SUCCESS;