1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "chrome/installer/util/google_update_settings.h"
6
7 #include <algorithm>
8 #include <string>
9
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"
31
32 using base::win::RegKey;
33 using installer::InstallationState;
34
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";
41
42 // Don't allow update periods longer than six weeks.
43 const int GoogleUpdateSettings::kCheckPeriodOverrideMinutesMax =
44 60 * 24 * 7 * 6;
45
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
53
54 namespace {
55
ReadGoogleUpdateStrKey(const wchar_t * const name,std::wstring * value)56 bool ReadGoogleUpdateStrKey(const wchar_t* const name, std::wstring* value) {
57 BrowserDistribution* dist = BrowserDistribution::GetDistribution();
58 std::wstring 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);
64 }
65 return true;
66 }
67
68 // Updates a registry key |name| to be |value| for the given |app_reg_data|.
69 // If this is a |system_install|, then update the value under HKLM (istead of
70 // HKCU for user-installs) using a group of keys (one for each OS user) and also
71 // include the method to |aggregate| these values when reporting.
WriteGoogleUpdateStrKeyInternal(const AppRegistrationData & app_reg_data,bool system_install,const wchar_t * const name,const std::wstring & value,const wchar_t * const aggregate)72 bool WriteGoogleUpdateStrKeyInternal(const AppRegistrationData& app_reg_data,
73 bool system_install,
74 const wchar_t* const name,
75 // presubmit: allow wstring
76 const std::wstring& value,
77 const wchar_t* const aggregate) {
78 const REGSAM kAccess = KEY_SET_VALUE | KEY_WOW64_32KEY;
79 if (system_install) {
80 DCHECK(aggregate);
81 // Machine installs require each OS user to write a unique key under a
82 // named key in HKLM as well as an "aggregation" function that describes
83 // how the values of multiple users are to be combined.
84 std::wstring uniquename; // presubmit: allow wstring
85 if (!base::win::GetUserSidString(&uniquename)) {
86 NOTREACHED();
87 return false;
88 }
89
90 base::string16 reg_path(app_reg_data.GetStateMediumKey());
91 reg_path.append(L"\\");
92 reg_path.append(name);
93 RegKey key(HKEY_LOCAL_MACHINE, reg_path.c_str(), kAccess);
94 key.WriteValue(google_update::kRegAggregateMethod, aggregate);
95 return (key.WriteValue(uniquename.c_str(), value.c_str()) == ERROR_SUCCESS);
96 } else {
97 // User installs are easy: just write the values to HKCU tree.
98 RegKey key(HKEY_CURRENT_USER, app_reg_data.GetStateKey().c_str(), kAccess);
99 return (key.WriteValue(name, value.c_str()) == ERROR_SUCCESS);
100 }
101 }
102
WriteGoogleUpdateStrKey(const wchar_t * const name,const std::wstring & value)103 bool WriteGoogleUpdateStrKey(const wchar_t* const name,
104 const std::wstring& value) {
105 BrowserDistribution* dist = BrowserDistribution::GetDistribution();
106 return WriteGoogleUpdateStrKeyInternal(
107 dist->GetAppRegistrationData(), false, name, value, NULL);
108 }
109
ClearGoogleUpdateStrKey(const wchar_t * const name)110 bool ClearGoogleUpdateStrKey(const wchar_t* const name) {
111 BrowserDistribution* dist = BrowserDistribution::GetDistribution();
112 std::wstring reg_path = dist->GetStateKey();
113 RegKey key(HKEY_CURRENT_USER,
114 reg_path.c_str(),
115 KEY_READ | KEY_WRITE | KEY_WOW64_32KEY);
116 std::wstring value;
117 if (key.ReadValue(name, &value) != ERROR_SUCCESS)
118 return false;
119 return (key.WriteValue(name, L"") == ERROR_SUCCESS);
120 }
121
RemoveGoogleUpdateStrKey(const wchar_t * const name)122 bool RemoveGoogleUpdateStrKey(const wchar_t* const name) {
123 BrowserDistribution* dist = BrowserDistribution::GetDistribution();
124 std::wstring reg_path = dist->GetStateKey();
125 RegKey key(HKEY_CURRENT_USER,
126 reg_path.c_str(),
127 KEY_READ | KEY_WRITE | KEY_WOW64_32KEY);
128 if (!key.HasValue(name))
129 return true;
130 return (key.DeleteValue(name) == ERROR_SUCCESS);
131 }
132
GetChromeChannelInternal(bool system_install,bool add_multi_modifier,base::string16 * channel)133 bool GetChromeChannelInternal(bool system_install,
134 bool add_multi_modifier,
135 base::string16* channel) {
136 BrowserDistribution* dist = BrowserDistribution::GetDistribution();
137
138 // Shortcut in case this distribution knows what channel it is (canary).
139 if (dist->GetChromeChannel(channel))
140 return true;
141
142 // Determine whether or not chrome is multi-install. If so, updates are
143 // delivered under the binaries' app guid, so that's where the relevant
144 // channel is found.
145 installer::ProductState state;
146 installer::ChannelInfo channel_info;
147 ignore_result(state.Initialize(system_install, dist));
148 if (!state.is_multi_install()) {
149 // Use the channel info that was just read for this single-install chrome.
150 channel_info = state.channel();
151 } else {
152 // Read the channel info from the binaries' state key.
153 HKEY root_key = system_install ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER;
154 dist = BrowserDistribution::GetSpecificDistribution(
155 BrowserDistribution::CHROME_BINARIES);
156 RegKey key(root_key, dist->GetStateKey().c_str(),
157 KEY_READ | KEY_WOW64_32KEY);
158
159 if (!channel_info.Initialize(key)) {
160 channel->assign(installer::kChromeChannelUnknown);
161 return false;
162 }
163 }
164
165 if (!channel_info.GetChannelName(channel))
166 channel->assign(installer::kChromeChannelUnknown);
167
168 // Tag the channel name if this is a multi-install.
169 if (add_multi_modifier && state.is_multi_install()) {
170 if (!channel->empty())
171 channel->push_back(L'-');
172 channel->push_back(L'm');
173 }
174
175 return true;
176 }
177
178 // Populates |update_policy| with the UpdatePolicy enum value corresponding to a
179 // DWORD read from the registry and returns true if |value| is within range.
180 // If |value| is out of range, returns false without modifying |update_policy|.
GetUpdatePolicyFromDword(const DWORD value,GoogleUpdateSettings::UpdatePolicy * update_policy)181 bool GetUpdatePolicyFromDword(
182 const DWORD value,
183 GoogleUpdateSettings::UpdatePolicy* update_policy) {
184 switch (value) {
185 case GoogleUpdateSettings::UPDATES_DISABLED:
186 case GoogleUpdateSettings::AUTOMATIC_UPDATES:
187 case GoogleUpdateSettings::MANUAL_UPDATES_ONLY:
188 case GoogleUpdateSettings::AUTO_UPDATES_ONLY:
189 *update_policy = static_cast<GoogleUpdateSettings::UpdatePolicy>(value);
190 return true;
191 default:
192 LOG(WARNING) << "Unexpected update policy override value: " << value;
193 }
194 return false;
195 }
196
197 // Convenience routine: GoogleUpdateSettings::UpdateDidRunStateForApp()
198 // specialized for Chrome Binaries.
UpdateDidRunStateForBinaries(bool did_run)199 bool UpdateDidRunStateForBinaries(bool did_run) {
200 BrowserDistribution* dist = BrowserDistribution::GetSpecificDistribution(
201 BrowserDistribution::CHROME_BINARIES);
202 return GoogleUpdateSettings::UpdateDidRunStateForApp(
203 dist->GetAppRegistrationData(), did_run);
204 }
205
206 } // namespace
207
IsSystemInstall()208 bool GoogleUpdateSettings::IsSystemInstall() {
209 bool system_install = false;
210 base::FilePath module_dir;
211 if (!PathService::Get(base::DIR_MODULE, &module_dir)) {
212 LOG(WARNING)
213 << "Failed to get directory of module; assuming per-user install.";
214 } else {
215 system_install = !InstallUtil::IsPerUserInstall(module_dir.value().c_str());
216 }
217 return system_install;
218 }
219
GetCollectStatsConsent()220 bool GoogleUpdateSettings::GetCollectStatsConsent() {
221 return GetCollectStatsConsentAtLevel(IsSystemInstall());
222 }
223
224 // Older versions of Chrome unconditionally read from HKCU\...\ClientState\...
225 // and then HKLM\...\ClientState\.... This means that system-level Chrome
226 // never checked ClientStateMedium (which has priority according to Google
227 // Update) and gave preference to a value in HKCU (which was never checked by
228 // Google Update). From now on, Chrome follows Google Update's policy.
GetCollectStatsConsentAtLevel(bool system_install)229 bool GoogleUpdateSettings::GetCollectStatsConsentAtLevel(bool system_install) {
230 BrowserDistribution* dist = BrowserDistribution::GetDistribution();
231
232 // Consent applies to all products in a multi-install package.
233 if (InstallUtil::IsMultiInstall(dist, system_install)) {
234 dist = BrowserDistribution::GetSpecificDistribution(
235 BrowserDistribution::CHROME_BINARIES);
236 }
237
238 RegKey key;
239 DWORD value = 0;
240 bool have_value = false;
241 const REGSAM kAccess = KEY_QUERY_VALUE | KEY_WOW64_32KEY;
242
243 // For system-level installs, try ClientStateMedium first.
244 have_value =
245 system_install &&
246 key.Open(HKEY_LOCAL_MACHINE, dist->GetStateMediumKey().c_str(),
247 kAccess) == ERROR_SUCCESS &&
248 key.ReadValueDW(google_update::kRegUsageStatsField,
249 &value) == ERROR_SUCCESS;
250
251 // Otherwise, try ClientState.
252 if (!have_value) {
253 have_value =
254 key.Open(system_install ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER,
255 dist->GetStateKey().c_str(),
256 kAccess) == ERROR_SUCCESS &&
257 key.ReadValueDW(google_update::kRegUsageStatsField,
258 &value) == ERROR_SUCCESS;
259 }
260
261 // Google Update specifically checks that the value is 1, so we do the same.
262 return have_value && value == 1;
263 }
264
SetCollectStatsConsent(bool consented)265 bool GoogleUpdateSettings::SetCollectStatsConsent(bool consented) {
266 return SetCollectStatsConsentAtLevel(IsSystemInstall(), consented);
267 }
268
SetCollectStatsConsentAtLevel(bool system_install,bool consented)269 bool GoogleUpdateSettings::SetCollectStatsConsentAtLevel(bool system_install,
270 bool consented) {
271 // Google Update writes and expects 1 for true, 0 for false.
272 DWORD value = consented ? 1 : 0;
273
274 BrowserDistribution* dist = BrowserDistribution::GetDistribution();
275
276 // Consent applies to all products in a multi-install package.
277 if (InstallUtil::IsMultiInstall(dist, system_install)) {
278 dist = BrowserDistribution::GetSpecificDistribution(
279 BrowserDistribution::CHROME_BINARIES);
280 }
281
282 // Write to ClientStateMedium for system-level; ClientState otherwise.
283 HKEY root_key = system_install ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER;
284 std::wstring reg_path =
285 system_install ? dist->GetStateMediumKey() : dist->GetStateKey();
286 RegKey key;
287 LONG result = key.Create(
288 root_key, reg_path.c_str(), KEY_SET_VALUE | KEY_WOW64_32KEY);
289 if (result != ERROR_SUCCESS) {
290 LOG(ERROR) << "Failed opening key " << reg_path << " to set "
291 << google_update::kRegUsageStatsField << "; result: " << result;
292 } else {
293 result = key.WriteValue(google_update::kRegUsageStatsField, value);
294 LOG_IF(ERROR, result != ERROR_SUCCESS) << "Failed setting "
295 << google_update::kRegUsageStatsField << " in key " << reg_path
296 << "; result: " << result;
297 }
298 return (result == ERROR_SUCCESS);
299 }
300
GetMetricsId(std::string * metrics_id)301 bool GoogleUpdateSettings::GetMetricsId(std::string* metrics_id) {
302 std::wstring metrics_id_w;
303 bool rv = ReadGoogleUpdateStrKey(google_update::kRegMetricsId, &metrics_id_w);
304 *metrics_id = base::WideToUTF8(metrics_id_w);
305 return rv;
306 }
307
SetMetricsId(const std::string & metrics_id)308 bool GoogleUpdateSettings::SetMetricsId(const std::string& metrics_id) {
309 std::wstring metrics_id_w = base::UTF8ToWide(metrics_id);
310 return WriteGoogleUpdateStrKey(google_update::kRegMetricsId, metrics_id_w);
311 }
312
313 // EULA consent is only relevant for system-level installs.
SetEULAConsent(const InstallationState & machine_state,BrowserDistribution * dist,bool consented)314 bool GoogleUpdateSettings::SetEULAConsent(
315 const InstallationState& machine_state,
316 BrowserDistribution* dist,
317 bool consented) {
318 DCHECK(dist);
319 const DWORD eula_accepted = consented ? 1 : 0;
320 const REGSAM kAccess = KEY_SET_VALUE | KEY_WOW64_32KEY;
321 std::wstring reg_path = dist->GetStateMediumKey();
322 bool succeeded = true;
323 RegKey key;
324
325 // Write the consent value into the product's ClientStateMedium key.
326 if (key.Create(HKEY_LOCAL_MACHINE, reg_path.c_str(),
327 kAccess) != ERROR_SUCCESS ||
328 key.WriteValue(google_update::kRegEULAAceptedField,
329 eula_accepted) != ERROR_SUCCESS) {
330 succeeded = false;
331 }
332
333 // If this is a multi-install, also write it into the binaries' key.
334 // --mutli-install is not provided on the command-line, so deduce it from
335 // the product's state.
336 const installer::ProductState* product_state =
337 machine_state.GetProductState(true, dist->GetType());
338 if (product_state != NULL && product_state->is_multi_install()) {
339 dist = BrowserDistribution::GetSpecificDistribution(
340 BrowserDistribution::CHROME_BINARIES);
341 reg_path = dist->GetStateMediumKey();
342 if (key.Create(HKEY_LOCAL_MACHINE, reg_path.c_str(),
343 kAccess) != ERROR_SUCCESS ||
344 key.WriteValue(google_update::kRegEULAAceptedField,
345 eula_accepted) != ERROR_SUCCESS) {
346 succeeded = false;
347 }
348 }
349
350 return succeeded;
351 }
352
GetLastRunTime()353 int GoogleUpdateSettings::GetLastRunTime() {
354 std::wstring time_s;
355 if (!ReadGoogleUpdateStrKey(google_update::kRegLastRunTimeField, &time_s))
356 return -1;
357 int64 time_i;
358 if (!base::StringToInt64(time_s, &time_i))
359 return -1;
360 base::TimeDelta td =
361 base::Time::NowFromSystemTime() - base::Time::FromInternalValue(time_i);
362 return td.InDays();
363 }
364
SetLastRunTime()365 bool GoogleUpdateSettings::SetLastRunTime() {
366 int64 time = base::Time::NowFromSystemTime().ToInternalValue();
367 return WriteGoogleUpdateStrKey(google_update::kRegLastRunTimeField,
368 base::Int64ToString16(time));
369 }
370
RemoveLastRunTime()371 bool GoogleUpdateSettings::RemoveLastRunTime() {
372 return RemoveGoogleUpdateStrKey(google_update::kRegLastRunTimeField);
373 }
374
GetBrowser(std::wstring * browser)375 bool GoogleUpdateSettings::GetBrowser(std::wstring* browser) {
376 return ReadGoogleUpdateStrKey(google_update::kRegBrowserField, browser);
377 }
378
GetLanguage(std::wstring * language)379 bool GoogleUpdateSettings::GetLanguage(std::wstring* language) {
380 return ReadGoogleUpdateStrKey(google_update::kRegLangField, language);
381 }
382
GetBrand(std::wstring * brand)383 bool GoogleUpdateSettings::GetBrand(std::wstring* brand) {
384 return ReadGoogleUpdateStrKey(google_update::kRegRLZBrandField, brand);
385 }
386
GetReactivationBrand(std::wstring * brand)387 bool GoogleUpdateSettings::GetReactivationBrand(std::wstring* brand) {
388 return ReadGoogleUpdateStrKey(google_update::kRegRLZReactivationBrandField,
389 brand);
390 }
391
GetClient(std::wstring * client)392 bool GoogleUpdateSettings::GetClient(std::wstring* client) {
393 return ReadGoogleUpdateStrKey(google_update::kRegClientField, client);
394 }
395
SetClient(const std::wstring & client)396 bool GoogleUpdateSettings::SetClient(const std::wstring& client) {
397 return WriteGoogleUpdateStrKey(google_update::kRegClientField, client);
398 }
399
GetReferral(std::wstring * referral)400 bool GoogleUpdateSettings::GetReferral(std::wstring* referral) {
401 return ReadGoogleUpdateStrKey(google_update::kRegReferralField, referral);
402 }
403
ClearReferral()404 bool GoogleUpdateSettings::ClearReferral() {
405 return ClearGoogleUpdateStrKey(google_update::kRegReferralField);
406 }
407
UpdateDidRunStateForApp(const AppRegistrationData & app_reg_data,bool did_run)408 bool GoogleUpdateSettings::UpdateDidRunStateForApp(
409 const AppRegistrationData& app_reg_data,
410 bool did_run) {
411 return WriteGoogleUpdateStrKeyInternal(app_reg_data,
412 false, // user level.
413 google_update::kRegDidRunField,
414 did_run ? L"1" : L"0",
415 NULL);
416 }
417
UpdateDidRunState(bool did_run,bool system_level)418 bool GoogleUpdateSettings::UpdateDidRunState(bool did_run, bool system_level) {
419 BrowserDistribution* dist = BrowserDistribution::GetDistribution();
420 bool result = UpdateDidRunStateForApp(dist->GetAppRegistrationData(),
421 did_run);
422 // Update state for binaries, even if the previous call was unsuccessful.
423 if (InstallUtil::IsMultiInstall(dist, system_level))
424 result = UpdateDidRunStateForBinaries(did_run) && result;
425 return result;
426 }
427
GetChromeChannel(bool system_install)428 base::string16 GoogleUpdateSettings::GetChromeChannel(bool system_install) {
429 base::string16 channel;
430 GetChromeChannelInternal(system_install, false, &channel);
431 return channel;
432 }
433
GetChromeChannelAndModifiers(bool system_install,base::string16 * channel)434 bool GoogleUpdateSettings::GetChromeChannelAndModifiers(
435 bool system_install,
436 base::string16* channel) {
437 return GetChromeChannelInternal(system_install, true, channel);
438 }
439
UpdateInstallStatus(bool system_install,installer::ArchiveType archive_type,int install_return_code,const std::wstring & product_guid)440 void GoogleUpdateSettings::UpdateInstallStatus(bool system_install,
441 installer::ArchiveType archive_type, int install_return_code,
442 const std::wstring& product_guid) {
443 DCHECK(archive_type != installer::UNKNOWN_ARCHIVE_TYPE ||
444 install_return_code != 0);
445 HKEY reg_root = (system_install) ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER;
446
447 RegKey key;
448 installer::ChannelInfo channel_info;
449 std::wstring reg_key(google_update::kRegPathClientState);
450 reg_key.append(L"\\");
451 reg_key.append(product_guid);
452 LONG result = key.Open(reg_root,
453 reg_key.c_str(),
454 KEY_QUERY_VALUE | KEY_SET_VALUE | KEY_WOW64_32KEY);
455 if (result == ERROR_SUCCESS)
456 channel_info.Initialize(key);
457 else if (result != ERROR_FILE_NOT_FOUND)
458 LOG(ERROR) << "Failed to open " << reg_key << "; Error: " << result;
459
460 if (UpdateGoogleUpdateApKey(archive_type, install_return_code,
461 &channel_info)) {
462 // We have a modified channel_info value to write.
463 // Create the app's ClientState key if it doesn't already exist.
464 if (!key.Valid()) {
465 result = key.Open(reg_root,
466 google_update::kRegPathClientState,
467 KEY_CREATE_SUB_KEY | KEY_WOW64_32KEY);
468 if (result == ERROR_SUCCESS)
469 result = key.CreateKey(product_guid.c_str(),
470 KEY_SET_VALUE | KEY_WOW64_32KEY);
471
472 if (result != ERROR_SUCCESS) {
473 LOG(ERROR) << "Failed to create " << reg_key << "; Error: " << result;
474 return;
475 }
476 }
477 if (!channel_info.Write(&key)) {
478 LOG(ERROR) << "Failed to write to application's ClientState key "
479 << google_update::kRegApField << " = " << channel_info.value();
480 }
481 }
482 }
483
UpdateGoogleUpdateApKey(installer::ArchiveType archive_type,int install_return_code,installer::ChannelInfo * value)484 bool GoogleUpdateSettings::UpdateGoogleUpdateApKey(
485 installer::ArchiveType archive_type, int install_return_code,
486 installer::ChannelInfo* value) {
487 DCHECK(archive_type != installer::UNKNOWN_ARCHIVE_TYPE ||
488 install_return_code != 0);
489 bool modified = false;
490
491 if (archive_type == installer::FULL_ARCHIVE_TYPE || !install_return_code) {
492 if (value->SetFullSuffix(false)) {
493 VLOG(1) << "Removed incremental installer failure key; "
494 "switching to channel: "
495 << value->value();
496 modified = true;
497 }
498 } else if (archive_type == installer::INCREMENTAL_ARCHIVE_TYPE) {
499 if (value->SetFullSuffix(true)) {
500 VLOG(1) << "Incremental installer failed; switching to channel: "
501 << value->value();
502 modified = true;
503 } else {
504 VLOG(1) << "Incremental installer failure; already on channel: "
505 << value->value();
506 }
507 } else {
508 // It's okay if we don't know the archive type. In this case, leave the
509 // "-full" suffix as we found it.
510 DCHECK_EQ(installer::UNKNOWN_ARCHIVE_TYPE, archive_type);
511 }
512
513 if (value->SetMultiFailSuffix(false)) {
514 VLOG(1) << "Removed multi-install failure key; switching to channel: "
515 << value->value();
516 modified = true;
517 }
518
519 return modified;
520 }
521
UpdateProfileCounts(int profiles_active,int profiles_signedin)522 void GoogleUpdateSettings::UpdateProfileCounts(int profiles_active,
523 int profiles_signedin) {
524 BrowserDistribution* dist = BrowserDistribution::GetDistribution();
525 bool system_install = IsSystemInstall();
526 WriteGoogleUpdateStrKeyInternal(dist->GetAppRegistrationData(),
527 system_install,
528 google_update::kRegProfilesActive,
529 base::Int64ToString16(profiles_active),
530 L"sum()");
531 WriteGoogleUpdateStrKeyInternal(dist->GetAppRegistrationData(),
532 system_install,
533 google_update::kRegProfilesSignedIn,
534 base::Int64ToString16(profiles_signedin),
535 L"sum()");
536 }
537
DuplicateGoogleUpdateSystemClientKey()538 int GoogleUpdateSettings::DuplicateGoogleUpdateSystemClientKey() {
539 BrowserDistribution* dist = BrowserDistribution::GetDistribution();
540 std::wstring reg_path = dist->GetStateKey();
541
542 // Minimum access needed is to be able to write to this key.
543 RegKey reg_key(
544 HKEY_LOCAL_MACHINE, reg_path.c_str(), KEY_SET_VALUE | KEY_WOW64_32KEY);
545 if (!reg_key.Valid())
546 return 0;
547
548 HANDLE target_handle = 0;
549 if (!DuplicateHandle(GetCurrentProcess(), reg_key.Handle(),
550 GetCurrentProcess(), &target_handle, KEY_SET_VALUE,
551 TRUE, DUPLICATE_SAME_ACCESS)) {
552 return 0;
553 }
554 return reinterpret_cast<int>(target_handle);
555 }
556
WriteGoogleUpdateSystemClientKey(int handle,const std::wstring & key,const std::wstring & value)557 bool GoogleUpdateSettings::WriteGoogleUpdateSystemClientKey(
558 int handle, const std::wstring& key, const std::wstring& value) {
559 HKEY reg_key = reinterpret_cast<HKEY>(reinterpret_cast<void*>(handle));
560 DWORD size = static_cast<DWORD>(value.size()) * sizeof(wchar_t);
561 LSTATUS status = RegSetValueEx(reg_key, key.c_str(), 0, REG_SZ,
562 reinterpret_cast<const BYTE*>(value.c_str()), size);
563 return status == ERROR_SUCCESS;
564 }
565
GetAppUpdatePolicy(const std::wstring & app_guid,bool * is_overridden)566 GoogleUpdateSettings::UpdatePolicy GoogleUpdateSettings::GetAppUpdatePolicy(
567 const std::wstring& app_guid,
568 bool* is_overridden) {
569 bool found_override = false;
570 UpdatePolicy update_policy = kDefaultUpdatePolicy;
571
572 #if defined(GOOGLE_CHROME_BUILD)
573 DCHECK(!app_guid.empty());
574 RegKey policy_key;
575
576 // Google Update Group Policy settings are always in HKLM.
577 // TODO(wfh): Check if policies should go into Wow6432Node or not.
578 if (policy_key.Open(HKEY_LOCAL_MACHINE, kPoliciesKey, KEY_QUERY_VALUE) ==
579 ERROR_SUCCESS) {
580 DWORD value = 0;
581 base::string16 app_update_override(kUpdateOverrideValuePrefix);
582 app_update_override.append(app_guid);
583 // First try to read and comprehend the app-specific override.
584 found_override = (policy_key.ReadValueDW(app_update_override.c_str(),
585 &value) == ERROR_SUCCESS &&
586 GetUpdatePolicyFromDword(value, &update_policy));
587
588 // Failing that, try to read and comprehend the default override.
589 if (!found_override &&
590 policy_key.ReadValueDW(kUpdatePolicyValue, &value) == ERROR_SUCCESS) {
591 GetUpdatePolicyFromDword(value, &update_policy);
592 }
593 }
594 #endif // defined(GOOGLE_CHROME_BUILD)
595
596 if (is_overridden != NULL)
597 *is_overridden = found_override;
598
599 return update_policy;
600 }
601
602 // static
AreAutoupdatesEnabled(const base::string16 & app_guid)603 bool GoogleUpdateSettings::AreAutoupdatesEnabled(
604 const base::string16& app_guid) {
605 // Check the auto-update check period override. If it is 0 or exceeds the
606 // maximum timeout, then for all intents and purposes auto updates are
607 // disabled.
608 RegKey policy_key;
609 DWORD value = 0;
610 if (policy_key.Open(HKEY_LOCAL_MACHINE, kPoliciesKey,
611 KEY_QUERY_VALUE) == ERROR_SUCCESS &&
612 policy_key.ReadValueDW(kCheckPeriodOverrideMinutes,
613 &value) == ERROR_SUCCESS &&
614 (value == 0 || value > kCheckPeriodOverrideMinutesMax)) {
615 return false;
616 }
617
618 UpdatePolicy policy = GetAppUpdatePolicy(app_guid, NULL);
619 return (policy == AUTOMATIC_UPDATES || policy == AUTO_UPDATES_ONLY);
620 }
621
622 // static
ReenableAutoupdatesForApp(const base::string16 & app_guid)623 bool GoogleUpdateSettings::ReenableAutoupdatesForApp(
624 const base::string16& app_guid) {
625 #if defined(GOOGLE_CHROME_BUILD)
626 int needs_reset_count = 0;
627 int did_reset_count = 0;
628
629 UpdatePolicy update_policy = kDefaultUpdatePolicy;
630 RegKey policy_key;
631 if (policy_key.Open(HKEY_LOCAL_MACHINE, kPoliciesKey,
632 KEY_SET_VALUE | KEY_QUERY_VALUE) == ERROR_SUCCESS) {
633 // First check the app-specific override value and reset that if needed.
634 // Note that this intentionally sets the override to AUTOMATIC_UPDATES
635 // even if it was previously AUTO_UPDATES_ONLY. The thinking is that
636 // AUTOMATIC_UPDATES is marginally more likely to let a user update and this
637 // code is only called when a stuck user asks for updates.
638 base::string16 app_update_override(kUpdateOverrideValuePrefix);
639 app_update_override.append(app_guid);
640 DWORD value = 0;
641 bool has_app_update_override =
642 policy_key.ReadValueDW(app_update_override.c_str(),
643 &value) == ERROR_SUCCESS;
644 if (has_app_update_override &&
645 (!GetUpdatePolicyFromDword(value, &update_policy) ||
646 update_policy != GoogleUpdateSettings::AUTOMATIC_UPDATES)) {
647 ++needs_reset_count;
648 if (policy_key.WriteValue(
649 app_update_override.c_str(),
650 static_cast<DWORD>(GoogleUpdateSettings::AUTOMATIC_UPDATES)) ==
651 ERROR_SUCCESS) {
652 ++did_reset_count;
653 }
654 }
655
656 // If there was no app-specific override policy see if there's a global
657 // policy preventing updates and delete it if so.
658 if (!has_app_update_override &&
659 policy_key.ReadValueDW(kUpdatePolicyValue, &value) == ERROR_SUCCESS &&
660 (!GetUpdatePolicyFromDword(value, &update_policy) ||
661 update_policy != GoogleUpdateSettings::AUTOMATIC_UPDATES)) {
662 ++needs_reset_count;
663 if (policy_key.DeleteValue(kUpdatePolicyValue) == ERROR_SUCCESS)
664 ++did_reset_count;
665 }
666
667 // Check the auto-update check period override. If it is 0 or exceeds
668 // the maximum timeout, delete the override value.
669 if (policy_key.ReadValueDW(kCheckPeriodOverrideMinutes,
670 &value) == ERROR_SUCCESS &&
671 (value == 0 || value > kCheckPeriodOverrideMinutesMax)) {
672 ++needs_reset_count;
673 if (policy_key.DeleteValue(kCheckPeriodOverrideMinutes) == ERROR_SUCCESS)
674 ++did_reset_count;
675 }
676
677 // Return whether the number of successful resets is the same as the
678 // number of things that appeared to need resetting.
679 return (needs_reset_count == did_reset_count);
680 } else {
681 // For some reason we couldn't open the policy key with the desired
682 // permissions to make changes (the most likely reason is that there is no
683 // policy set). Simply return whether or not we think updates are enabled.
684 return AreAutoupdatesEnabled(app_guid);
685 }
686
687 #endif
688 // Non Google Chrome isn't going to autoupdate.
689 return true;
690 }
691
RecordChromeUpdatePolicyHistograms()692 void GoogleUpdateSettings::RecordChromeUpdatePolicyHistograms() {
693 const bool is_multi_install = InstallUtil::IsMultiInstall(
694 BrowserDistribution::GetDistribution(), IsSystemInstall());
695 const base::string16 app_guid =
696 BrowserDistribution::GetSpecificDistribution(
697 is_multi_install ? BrowserDistribution::CHROME_BINARIES :
698 BrowserDistribution::CHROME_BROWSER)->GetAppGuid();
699
700 bool is_overridden = false;
701 const UpdatePolicy update_policy = GetAppUpdatePolicy(app_guid,
702 &is_overridden);
703 UMA_HISTOGRAM_BOOLEAN("GoogleUpdate.UpdatePolicyIsOverridden", is_overridden);
704 UMA_HISTOGRAM_ENUMERATION("GoogleUpdate.EffectivePolicy", update_policy,
705 UPDATE_POLICIES_COUNT);
706 }
707
GetUninstallCommandLine(bool system_install)708 base::string16 GoogleUpdateSettings::GetUninstallCommandLine(
709 bool system_install) {
710 const HKEY root_key = system_install ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER;
711 base::string16 cmd_line;
712 RegKey update_key;
713
714 if (update_key.Open(root_key, google_update::kRegPathGoogleUpdate,
715 KEY_QUERY_VALUE | KEY_WOW64_32KEY) == ERROR_SUCCESS) {
716 update_key.ReadValue(google_update::kRegUninstallCmdLine, &cmd_line);
717 }
718
719 return cmd_line;
720 }
721
GetGoogleUpdateVersion(bool system_install)722 Version GoogleUpdateSettings::GetGoogleUpdateVersion(bool system_install) {
723 const HKEY root_key = system_install ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER;
724 base::string16 version;
725 RegKey key;
726
727 if (key.Open(root_key,
728 google_update::kRegPathGoogleUpdate,
729 KEY_QUERY_VALUE | KEY_WOW64_32KEY) == ERROR_SUCCESS &&
730 key.ReadValue(google_update::kRegGoogleUpdateVersion, &version) ==
731 ERROR_SUCCESS) {
732 return Version(base::UTF16ToUTF8(version));
733 }
734
735 return Version();
736 }
737
GetGoogleUpdateLastStartedAU(bool system_install)738 base::Time GoogleUpdateSettings::GetGoogleUpdateLastStartedAU(
739 bool system_install) {
740 const HKEY root_key = system_install ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER;
741 RegKey update_key;
742
743 if (update_key.Open(root_key,
744 google_update::kRegPathGoogleUpdate,
745 KEY_QUERY_VALUE | KEY_WOW64_32KEY) == ERROR_SUCCESS) {
746 DWORD last_start;
747 if (update_key.ReadValueDW(google_update::kRegLastStartedAUField,
748 &last_start) == ERROR_SUCCESS) {
749 return base::Time::FromTimeT(last_start);
750 }
751 }
752
753 return base::Time();
754 }
755
GetGoogleUpdateLastChecked(bool system_install)756 base::Time GoogleUpdateSettings::GetGoogleUpdateLastChecked(
757 bool system_install) {
758 const HKEY root_key = system_install ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER;
759 RegKey update_key;
760
761 if (update_key.Open(root_key,
762 google_update::kRegPathGoogleUpdate,
763 KEY_QUERY_VALUE | KEY_WOW64_32KEY) == ERROR_SUCCESS) {
764 DWORD last_check;
765 if (update_key.ReadValueDW(google_update::kRegLastCheckedField,
766 &last_check) == ERROR_SUCCESS) {
767 return base::Time::FromTimeT(last_check);
768 }
769 }
770
771 return base::Time();
772 }
773
GetUpdateDetailForApp(bool system_install,const wchar_t * app_guid,ProductData * data)774 bool GoogleUpdateSettings::GetUpdateDetailForApp(bool system_install,
775 const wchar_t* app_guid,
776 ProductData* data) {
777 DCHECK(app_guid);
778 DCHECK(data);
779
780 bool product_found = false;
781
782 const HKEY root_key = system_install ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER;
783 base::string16 clientstate_reg_path(google_update::kRegPathClientState);
784 clientstate_reg_path.append(L"\\");
785 clientstate_reg_path.append(app_guid);
786
787 RegKey clientstate;
788 if (clientstate.Open(root_key,
789 clientstate_reg_path.c_str(),
790 KEY_QUERY_VALUE | KEY_WOW64_32KEY) == ERROR_SUCCESS) {
791 base::string16 version;
792 DWORD dword_value;
793 if ((clientstate.ReadValueDW(google_update::kRegLastCheckSuccessField,
794 &dword_value) == ERROR_SUCCESS) &&
795 (clientstate.ReadValue(google_update::kRegVersionField,
796 &version) == ERROR_SUCCESS)) {
797 product_found = true;
798 data->version = base::UTF16ToASCII(version);
799 data->last_success = base::Time::FromTimeT(dword_value);
800 data->last_result = 0;
801 data->last_error_code = 0;
802 data->last_extra_code = 0;
803
804 if (clientstate.ReadValueDW(google_update::kRegLastInstallerResultField,
805 &dword_value) == ERROR_SUCCESS) {
806 // Google Update convention is that if an installer writes an result
807 // code that is invalid, it is clamped to an exit code result.
808 const DWORD kMaxValidInstallResult = 4; // INSTALLER_RESULT_EXIT_CODE
809 data->last_result = std::min(dword_value, kMaxValidInstallResult);
810 }
811 if (clientstate.ReadValueDW(google_update::kRegLastInstallerErrorField,
812 &dword_value) == ERROR_SUCCESS) {
813 data->last_error_code = dword_value;
814 }
815 if (clientstate.ReadValueDW(google_update::kRegLastInstallerExtraField,
816 &dword_value) == ERROR_SUCCESS) {
817 data->last_extra_code = dword_value;
818 }
819 }
820 }
821
822 return product_found;
823 }
824
GetUpdateDetailForGoogleUpdate(bool system_install,ProductData * data)825 bool GoogleUpdateSettings::GetUpdateDetailForGoogleUpdate(bool system_install,
826 ProductData* data) {
827 return GetUpdateDetailForApp(system_install,
828 google_update::kGoogleUpdateUpgradeCode,
829 data);
830 }
831
GetUpdateDetail(bool system_install,ProductData * data)832 bool GoogleUpdateSettings::GetUpdateDetail(bool system_install,
833 ProductData* data) {
834 BrowserDistribution* dist = BrowserDistribution::GetDistribution();
835 return GetUpdateDetailForApp(system_install,
836 dist->GetAppGuid().c_str(),
837 data);
838 }
839
SetExperimentLabels(bool system_install,const base::string16 & experiment_labels)840 bool GoogleUpdateSettings::SetExperimentLabels(
841 bool system_install,
842 const base::string16& experiment_labels) {
843 HKEY reg_root = system_install ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER;
844
845 // Use the browser distribution and install level to write to the correct
846 // client state/app guid key.
847 bool success = false;
848 BrowserDistribution* dist = BrowserDistribution::GetDistribution();
849 if (dist->ShouldSetExperimentLabels()) {
850 base::string16 client_state_path(
851 system_install ? dist->GetStateMediumKey() : dist->GetStateKey());
852 RegKey client_state(
853 reg_root, client_state_path.c_str(), KEY_SET_VALUE | KEY_WOW64_32KEY);
854 if (experiment_labels.empty()) {
855 success = client_state.DeleteValue(google_update::kExperimentLabels)
856 == ERROR_SUCCESS;
857 } else {
858 success = client_state.WriteValue(google_update::kExperimentLabels,
859 experiment_labels.c_str()) == ERROR_SUCCESS;
860 }
861 }
862
863 return success;
864 }
865
ReadExperimentLabels(bool system_install,base::string16 * experiment_labels)866 bool GoogleUpdateSettings::ReadExperimentLabels(
867 bool system_install,
868 base::string16* experiment_labels) {
869 HKEY reg_root = system_install ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER;
870
871 // If this distribution does not set the experiment labels, don't bother
872 // reading.
873 BrowserDistribution* dist = BrowserDistribution::GetDistribution();
874 if (!dist->ShouldSetExperimentLabels())
875 return false;
876
877 base::string16 client_state_path(
878 system_install ? dist->GetStateMediumKey() : dist->GetStateKey());
879
880 RegKey client_state;
881 LONG result = client_state.Open(
882 reg_root, client_state_path.c_str(), KEY_QUERY_VALUE | KEY_WOW64_32KEY);
883 if (result == ERROR_SUCCESS) {
884 result = client_state.ReadValue(google_update::kExperimentLabels,
885 experiment_labels);
886 }
887
888 // If the key or value was not present, return the empty string.
889 if (result == ERROR_FILE_NOT_FOUND || result == ERROR_PATH_NOT_FOUND) {
890 experiment_labels->clear();
891 return true;
892 }
893
894 return result == ERROR_SUCCESS;
895 }
896