blob: e56f1c6bd1dc35bd11f02640297712fc7910cf5f [file] [log] [blame]
// Copyright (c) 2010 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/installer/util/google_update_settings.h"
#include <algorithm>
#include "base/command_line.h"
#include "base/registry.h"
#include "base/string_number_conversions.h"
#include "base/string_util.h"
#include "base/time.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/installer/util/browser_distribution.h"
#include "chrome/installer/util/google_update_constants.h"
#include "chrome/installer/util/install_util.h"
namespace {
bool ReadGoogleUpdateStrKey(const wchar_t* const name, std::wstring* value) {
BrowserDistribution* dist = BrowserDistribution::GetDistribution();
std::wstring reg_path = dist->GetStateKey();
RegKey key(HKEY_CURRENT_USER, reg_path.c_str(), KEY_READ);
if (!key.ReadValue(name, value)) {
RegKey hklm_key(HKEY_LOCAL_MACHINE, reg_path.c_str(), KEY_READ);
return hklm_key.ReadValue(name, value);
}
return true;
}
bool WriteGoogleUpdateStrKey(const wchar_t* const name,
const std::wstring& value) {
BrowserDistribution* dist = BrowserDistribution::GetDistribution();
std::wstring reg_path = dist->GetStateKey();
RegKey key(HKEY_CURRENT_USER, reg_path.c_str(), KEY_READ | KEY_WRITE);
return key.WriteValue(name, value.c_str());
}
bool ClearGoogleUpdateStrKey(const wchar_t* const name) {
BrowserDistribution* dist = BrowserDistribution::GetDistribution();
std::wstring reg_path = dist->GetStateKey();
RegKey key(HKEY_CURRENT_USER, reg_path.c_str(), KEY_READ | KEY_WRITE);
std::wstring value;
if (!key.ReadValue(name, &value))
return false;
return key.WriteValue(name, L"");
}
bool RemoveGoogleUpdateStrKey(const wchar_t* const name) {
BrowserDistribution* dist = BrowserDistribution::GetDistribution();
std::wstring reg_path = dist->GetStateKey();
RegKey key(HKEY_CURRENT_USER, reg_path.c_str(), KEY_READ | KEY_WRITE);
if (!key.ValueExists(name))
return true;
return key.DeleteValue(name);
}
} // namespace.
bool GoogleUpdateSettings::GetCollectStatsConsent() {
BrowserDistribution* dist = BrowserDistribution::GetDistribution();
std::wstring reg_path = dist->GetStateKey();
RegKey key(HKEY_CURRENT_USER, reg_path.c_str(), KEY_READ);
DWORD value;
if (!key.ReadValueDW(google_update::kRegUsageStatsField, &value)) {
RegKey hklm_key(HKEY_LOCAL_MACHINE, reg_path.c_str(), KEY_READ);
if (!hklm_key.ReadValueDW(google_update::kRegUsageStatsField, &value))
return false;
}
return (1 == value);
}
bool GoogleUpdateSettings::SetCollectStatsConsent(bool consented) {
DWORD value = consented? 1 : 0;
// Writing to HKLM is only a best effort deal.
BrowserDistribution* dist = BrowserDistribution::GetDistribution();
std::wstring reg_path = dist->GetStateMediumKey();
RegKey key_hklm(HKEY_LOCAL_MACHINE, reg_path.c_str(), KEY_READ | KEY_WRITE);
key_hklm.WriteValue(google_update::kRegUsageStatsField, value);
// Writing to HKCU is used both by chrome and by the crash reporter.
reg_path = dist->GetStateKey();
RegKey key_hkcu(HKEY_CURRENT_USER, reg_path.c_str(), KEY_READ | KEY_WRITE);
return key_hkcu.WriteValue(google_update::kRegUsageStatsField, value);
}
bool GoogleUpdateSettings::GetMetricsId(std::wstring* metrics_id) {
return ReadGoogleUpdateStrKey(google_update::kRegMetricsId, metrics_id);
}
bool GoogleUpdateSettings::SetMetricsId(const std::wstring& metrics_id) {
return WriteGoogleUpdateStrKey(google_update::kRegMetricsId, metrics_id);
}
bool GoogleUpdateSettings::SetEULAConsent(bool consented) {
BrowserDistribution* dist = BrowserDistribution::GetDistribution();
std::wstring reg_path = dist->GetStateMediumKey();
RegKey key(HKEY_LOCAL_MACHINE, reg_path.c_str(), KEY_READ | KEY_SET_VALUE);
return key.WriteValue(google_update::kRegEULAAceptedField, consented? 1 : 0);
}
int GoogleUpdateSettings::GetLastRunTime() {
std::wstring time_s;
if (!ReadGoogleUpdateStrKey(google_update::kRegLastRunTimeField, &time_s))
return -1;
int64 time_i;
if (!base::StringToInt64(time_s, &time_i))
return -1;
base::TimeDelta td =
base::Time::NowFromSystemTime() - base::Time::FromInternalValue(time_i);
return td.InDays();
}
bool GoogleUpdateSettings::SetLastRunTime() {
int64 time = base::Time::NowFromSystemTime().ToInternalValue();
return WriteGoogleUpdateStrKey(google_update::kRegLastRunTimeField,
base::Int64ToString16(time));
}
bool GoogleUpdateSettings::RemoveLastRunTime() {
return RemoveGoogleUpdateStrKey(google_update::kRegLastRunTimeField);
}
bool GoogleUpdateSettings::GetBrowser(std::wstring* browser) {
return ReadGoogleUpdateStrKey(google_update::kRegBrowserField, browser);
}
bool GoogleUpdateSettings::GetLanguage(std::wstring* language) {
return ReadGoogleUpdateStrKey(google_update::kRegLangField, language);
}
bool GoogleUpdateSettings::GetBrand(std::wstring* brand) {
return ReadGoogleUpdateStrKey(google_update::kRegRLZBrandField, brand);
}
bool GoogleUpdateSettings::GetClient(std::wstring* client) {
return ReadGoogleUpdateStrKey(google_update::kRegClientField, client);
}
bool GoogleUpdateSettings::SetClient(const std::wstring& client) {
return WriteGoogleUpdateStrKey(google_update::kRegClientField, client);
}
bool GoogleUpdateSettings::GetReferral(std::wstring* referral) {
return ReadGoogleUpdateStrKey(google_update::kRegReferralField, referral);
}
bool GoogleUpdateSettings::ClearReferral() {
return ClearGoogleUpdateStrKey(google_update::kRegReferralField);
}
bool GoogleUpdateSettings::GetChromeChannel(bool system_install,
std::wstring* channel) {
BrowserDistribution* dist = BrowserDistribution::GetDistribution();
if (dist->GetChromeChannel(channel))
return true;
HKEY root_key = system_install ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER;
std::wstring reg_path = dist->GetStateKey();
RegKey key(root_key, reg_path.c_str(), KEY_READ);
std::wstring update_branch;
if (!key.ReadValue(google_update::kRegApField, &update_branch)) {
*channel = L"unknown";
return false;
}
// Map to something pithy for human consumption. There are no rules as to
// what the ap string can contain, but generally it will contain a number
// followed by a dash followed by the branch name (and then some random
// suffix). We fall back on empty string in case we fail to parse.
// Only ever return "", "unknown", "dev" or "beta".
if (update_branch.find(L"-beta") != std::wstring::npos)
*channel = L"beta";
else if (update_branch.find(L"-dev") != std::wstring::npos)
*channel = L"dev";
else if (update_branch.empty())
*channel = L"";
else
*channel = L"unknown";
return true;
}
void GoogleUpdateSettings::UpdateDiffInstallStatus(bool system_install,
bool incremental_install, int install_return_code,
const std::wstring& product_guid) {
HKEY reg_root = (system_install) ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER;
RegKey key;
std::wstring ap_key_value;
std::wstring reg_key(google_update::kRegPathClientState);
reg_key.append(L"\\");
reg_key.append(product_guid);
if (!key.Open(reg_root, reg_key.c_str(), KEY_ALL_ACCESS) ||
!key.ReadValue(google_update::kRegApField, &ap_key_value)) {
LOG(INFO) << "Application key not found.";
if (!incremental_install || !install_return_code) {
LOG(INFO) << "Returning without changing application key.";
key.Close();
return;
} else if (!key.Valid()) {
reg_key.assign(google_update::kRegPathClientState);
if (!key.Open(reg_root, reg_key.c_str(), KEY_ALL_ACCESS) ||
!key.CreateKey(product_guid.c_str(), KEY_ALL_ACCESS)) {
LOG(ERROR) << "Failed to create application key.";
key.Close();
return;
}
}
}
std::wstring new_value = GetNewGoogleUpdateApKey(
incremental_install, install_return_code, ap_key_value);
if ((new_value.compare(ap_key_value) != 0) &&
!key.WriteValue(google_update::kRegApField, new_value.c_str())) {
LOG(ERROR) << "Failed to write value " << new_value
<< " to the registry field " << google_update::kRegApField;
}
key.Close();
}
std::wstring GoogleUpdateSettings::GetNewGoogleUpdateApKey(
bool diff_install, int install_return_code, const std::wstring& value) {
// Magic suffix that we need to add or remove to "ap" key value.
const std::wstring kMagicSuffix = L"-full";
bool has_magic_string = false;
if ((value.length() >= kMagicSuffix.length()) &&
(value.rfind(kMagicSuffix) == (value.length() - kMagicSuffix.length()))) {
LOG(INFO) << "Incremental installer failure key already set.";
has_magic_string = true;
}
std::wstring new_value(value);
if ((!diff_install || !install_return_code) && has_magic_string) {
LOG(INFO) << "Removing failure key from value " << value;
new_value = value.substr(0, value.length() - kMagicSuffix.length());
} else if ((diff_install && install_return_code) &&
!has_magic_string) {
LOG(INFO) << "Incremental installer failed, setting failure key.";
new_value.append(kMagicSuffix);
}
return new_value;
}
bool GoogleUpdateSettings::IsOrganic(const std::wstring& brand) {
const CommandLine& command_line = *CommandLine::ForCurrentProcess();
if (command_line.HasSwitch(switches::kOrganicInstall))
return true;
static const wchar_t* kBrands[] = {
L"CHFO", L"CHFT", L"CHHS", L"CHHM", L"CHMA", L"CHMB", L"CHME", L"CHMF",
L"CHMG", L"CHMH", L"CHMI", L"CHMQ", L"CHMV", L"CHNB", L"CHNC", L"CHNG",
L"CHNH", L"CHNI", L"CHOA", L"CHOB", L"CHOC", L"CHON", L"CHOO", L"CHOP",
L"CHOQ", L"CHOR", L"CHOS", L"CHOT", L"CHOU", L"CHOX", L"CHOY", L"CHOZ",
L"CHPD", L"CHPE", L"CHPF", L"CHPG", L"EUBB", L"EUBC", L"GGLA", L"GGLS"
};
const wchar_t** end = &kBrands[arraysize(kBrands)];
const wchar_t** found = std::find(&kBrands[0], end, brand);
if (found != end)
return true;
if (StartsWith(brand, L"EUB", true) || StartsWith(brand, L"EUC", true) ||
StartsWith(brand, L"GGR", true))
return true;
return false;
}