// Copyright 2015 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <stdint.h>
#include "base/logging.h"
#include "base/metrics/field_trial.h"
#include "base/metrics/histogram_macros.h"
#include "base/strings/string_util.h"
#include "base/win/registry.h"
#include "build/branding_buildflags.h"
#include "chrome/browser/profile_resetter/triggered_profile_resetter.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/common/pref_names.h"
#include "components/prefs/pref_service.h"
#if BUILDFLAG(GOOGLE_CHROME_BRANDING)
#define PRODUCT_NAME L"Google\\Chrome"
#elif BUILDFLAG(CHROMIUM_BRANDING)
#define PRODUCT_NAME L"Chromium"
#else
#error Unknown branding
#endif
// The registry path where the TriggeredReset values get set. Note that this
// uses the same path for both SxS (Canary) and non-SxS Chrome. This is
// intended to allow third parties to use the API without needing to be
// aware of and maintain changes to Chrome's channel logic.
const wchar_t kTriggeredResetRegistryPath[] =
L"Software\\" PRODUCT_NAME L"\\TriggeredReset";
const wchar_t kTriggeredResetToolName[] = L"ToolName";
const wchar_t kTriggeredResetTimestamp[] = L"Timestamp";
namespace {
const char kTriggeredResetFieldTrialName[] = "TriggeredResetFieldTrial";
const char kTriggeredResetOffGroup[] = "Off";
bool IsDisabledByFieldTrial() {
return base::FieldTrialList::FindFullName(kTriggeredResetFieldTrialName) ==
kTriggeredResetOffGroup;
}
} // namespace
void TriggeredProfileResetter::Activate() {
activate_called_ = true;
// System profiles don't contain user settings and bail out if we're not in
// the field trial.
if (!profile_ || profile_->IsSystemProfile() || IsDisabledByFieldTrial()) {
UMA_HISTOGRAM_BOOLEAN("Profile.TriggeredReset", false);
return;
}
int64_t timestamp = 0;
base::win::RegKey reset_reg_key(HKEY_CURRENT_USER,
kTriggeredResetRegistryPath, KEY_QUERY_VALUE);
if (!reset_reg_key.Valid() ||
reset_reg_key.ReadInt64(kTriggeredResetTimestamp, ×tamp) !=
ERROR_SUCCESS) {
UMA_HISTOGRAM_BOOLEAN("Profile.TriggeredReset", false);
return;
}
// A reset trigger time was found. Compare it to the trigger time stored
// in this profile. If different, reset the profile and persist the new
// time.
PrefService* pref_service = profile_->GetPrefs();
const int64_t preference_timestamp =
pref_service->GetInt64(prefs::kLastProfileResetTimestamp);
if (profile_->IsNewProfile()) {
// New profiles should never be reset. Instead, persist the time stamp
// directly.
pref_service->SetInt64(prefs::kLastProfileResetTimestamp, timestamp);
} else if (timestamp != preference_timestamp) {
DVLOG(1) << "Profile reset detected.";
has_reset_trigger_ = true;
std::wstring tool_name;
if (reset_reg_key.ReadValue(kTriggeredResetToolName, &tool_name) !=
ERROR_SUCCESS) {
DVLOG(1) << "Failed to read triggered profile reset tool name.";
} else if (tool_name.length() > kMaxToolNameLength) {
tool_name.resize(kMaxToolNameLength);
}
tool_name_ = base::AsString16(tool_name);
pref_service->SetInt64(prefs::kLastProfileResetTimestamp, timestamp);
}
UMA_HISTOGRAM_BOOLEAN("Profile.TriggeredReset", has_reset_trigger_);
}