Commit 37970334 authored by Weilun Shi's avatar Weilun Shi Committed by Commit Bot

Record low entropy source values for every metrics log

Create entropy_state_provider to record low_entropy_source and
old_low_entropy_source values to system profile for every metrics logs
as well as the local persistent file.

Bug: 1013707
Change-Id: Ie7fe38b023ada65e92e113aafaa49705b4931c48
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1994098
Commit-Queue: Weilun Shi <sweilun@chromium.org>
Auto-Submit: Weilun Shi <sweilun@chromium.org>
Reviewed-by: default avatarRichard Coles <torne@chromium.org>
Reviewed-by: default avatarSteven Holte <holte@chromium.org>
Reviewed-by: default avatarScott Violet <sky@chromium.org>
Reviewed-by: default avatarAlexei Svitkine <asvitkine@chromium.org>
Cr-Commit-Position: refs/heads/master@{#732637}
parent 54ab7217
......@@ -28,6 +28,7 @@
#include "components/metrics/cpu_metrics_provider.h"
#include "components/metrics/drive_metrics_provider.h"
#include "components/metrics/enabled_state_provider.h"
#include "components/metrics/entropy_state_provider.h"
#include "components/metrics/gpu/gpu_metrics_provider.h"
#include "components/metrics/metrics_log_uploader.h"
#include "components/metrics/metrics_pref_names.h"
......@@ -130,6 +131,8 @@ std::unique_ptr<metrics::MetricsService> CreateMetricsService(
std::make_unique<metrics::AndroidMetricsProvider>());
service->RegisterMetricsProvider(
std::make_unique<metrics::CPUMetricsProvider>());
service->RegisterMetricsProvider(
std::make_unique<metrics::EntropyStateProvider>(prefs));
service->RegisterMetricsProvider(
std::make_unique<metrics::GPUMetricsProvider>());
service->RegisterMetricsProvider(
......
......@@ -68,6 +68,7 @@
#include "components/metrics/cpu_metrics_provider.h"
#include "components/metrics/demographic_metrics_provider.h"
#include "components/metrics/drive_metrics_provider.h"
#include "components/metrics/entropy_state_provider.h"
#include "components/metrics/field_trials_provider.h"
#include "components/metrics/gpu/gpu_metrics_provider.h"
#include "components/metrics/metrics_log_uploader.h"
......@@ -654,6 +655,9 @@ void ChromeMetricsServiceClient::RegisterMetricsServiceProviders() {
metrics_service_->RegisterMetricsProvider(
std::make_unique<metrics::CPUMetricsProvider>());
metrics_service_->RegisterMetricsProvider(
std::make_unique<metrics::EntropyStateProvider>(local_state));
metrics_service_->RegisterMetricsProvider(
std::make_unique<metrics::ScreenInfoMetricsProvider>());
......
......@@ -150,7 +150,7 @@ TEST_F(ChromeMetricsServiceClientTest, TestRegisterMetricsServiceProviders) {
size_t expected_providers = 3;
// This is the number of metrics providers that are outside any #if macros.
expected_providers += 19;
expected_providers += 20;
#if BUILDFLAG(ENABLE_EXTENSIONS)
expected_providers++; // ExtensionsMetricsProvider.
......
......@@ -8,6 +8,8 @@
#include "chrome/browser/metrics/chrome_feature_list_creator.h"
#include "chrome/browser/prefs/profile_pref_store_manager.h"
#include "chrome/common/channel_info.h"
#include "components/metrics/delegating_provider.h"
#include "components/metrics/entropy_state_provider.h"
#include "components/metrics/field_trials_provider.h"
#include "components/metrics/metrics_log.h"
#include "components/metrics/persistent_system_profile.h"
......@@ -73,11 +75,20 @@ void StartupData::RecordCoreSystemProfile() {
chrome_feature_list_creator_->actual_locale(),
metrics::GetAppPackageName(), &system_profile);
metrics::DelegatingProvider delegating_provider;
// TODO(hanxi): Create SyntheticTrialRegistry and pass it to
// |field_trial_provider|.
variations::FieldTrialsProvider field_trial_provider(nullptr,
base::StringPiece());
field_trial_provider.ProvideSystemProfileMetricsWithLogCreationTime(
delegating_provider.RegisterMetricsProvider(
std::make_unique<variations::FieldTrialsProvider>(nullptr,
base::StringPiece()));
// Persists low entropy source values.
delegating_provider.RegisterMetricsProvider(
std::make_unique<metrics::EntropyStateProvider>(
chrome_feature_list_creator_->local_state()));
delegating_provider.ProvideSystemProfileMetricsWithLogCreationTime(
base::TimeTicks(), &system_profile);
// TODO(crbug.com/965482): Records information from other providers.
......
......@@ -15,9 +15,7 @@ static_library("demographic_metrics_provider") {
"demographic_metrics_provider.h",
]
public_deps = [
"//third_party/metrics_proto",
]
public_deps = [ "//third_party/metrics_proto" ]
deps = [
":metrics",
......@@ -56,6 +54,10 @@ jumbo_static_library("metrics") {
"drive_metrics_provider_win.cc",
"enabled_state_provider.cc",
"enabled_state_provider.h",
"entropy_state.cc",
"entropy_state.h",
"entropy_state_provider.cc",
"entropy_state_provider.h",
"environment_recorder.cc",
"environment_recorder.h",
"expired_histogram_util.cc",
......@@ -177,9 +179,7 @@ if (is_android) {
java_cpp_strings("java_switches_srcjar") {
# External code should depend on ":metrics_java" instead.
visibility = [ ":*" ]
sources = [
"//components/metrics/metrics_switches.cc",
]
sources = [ "//components/metrics/metrics_switches.cc" ]
template =
"//components/metrics/android/java_templates/MetricsSwitches.java.tmpl"
}
......@@ -200,9 +200,7 @@ static_library("component_metrics") {
"component_metrics_provider.h",
]
public_deps = [
"//third_party/metrics_proto",
]
public_deps = [ "//third_party/metrics_proto" ]
deps = [
":metrics",
......@@ -218,9 +216,7 @@ if (!is_ios) {
"gpu/gpu_metrics_provider.h",
]
public_deps = [
":metrics",
]
public_deps = [ ":metrics" ]
deps = [
"//base",
"//content/public/browser",
......@@ -241,9 +237,7 @@ jumbo_static_library("net") {
"net/wifi_access_point_info_provider.h",
]
public_deps = [
":metrics",
]
public_deps = [ ":metrics" ]
allow_circular_includes_from = [ ":metrics" ]
deps = [
......@@ -273,9 +267,7 @@ static_library("ui") {
"ui/screen_info_metrics_provider.h",
]
public_deps = [
":metrics",
]
public_deps = [ ":metrics" ]
deps = [
"//base",
"//ui/display",
......@@ -308,9 +300,7 @@ source_set("call_stack_profile_params") {
"call_stack_profile_encoding.h",
"call_stack_profile_params.h",
]
sources = [
"call_stack_profile_encoding.cc",
]
sources = [ "call_stack_profile_encoding.cc" ]
deps = [
"//base:base",
......@@ -330,9 +320,7 @@ source_set("child_call_stack_profile_builder") {
"call_stack_profile_metadata.cc",
"child_call_stack_profile_collector.cc",
]
public_deps = [
":call_stack_profile_params",
]
public_deps = [ ":call_stack_profile_params" ]
deps = [
"//base",
"//components/metrics/public/mojom:call_stack_mojo_bindings",
......@@ -346,12 +334,8 @@ source_set("child_call_stack_profile_builder") {
# Dependency for browser process use of the CallStackProfileBuilder.
source_set("call_stack_profile_builder") {
deps = [
":metrics",
]
public_deps = [
":child_call_stack_profile_builder",
]
deps = [ ":metrics" ]
public_deps = [ ":child_call_stack_profile_builder" ]
}
# The browser process mojo service for collecting profiles from child
......@@ -381,12 +365,8 @@ jumbo_static_library("test_support") {
"test_metrics_service_client.h",
]
public_deps = [
":metrics",
]
deps = [
"//base",
]
public_deps = [ ":metrics" ]
deps = [ "//base" ]
}
if (is_linux) {
......@@ -397,9 +377,7 @@ if (is_linux) {
"serialization/serialization_utils.cc",
"serialization/serialization_utils.h",
]
deps = [
"//base",
]
deps = [ "//base" ]
}
}
......@@ -417,6 +395,8 @@ source_set("unit_tests") {
"data_use_tracker_unittest.cc",
"demographic_metrics_provider_unittest.cc",
"drive_metrics_provider_unittest.cc",
"entropy_state_provider_unittest.cc",
"entropy_state_unittest.cc",
"environment_recorder_unittest.cc",
"expired_histograms_checker_unittest.cc",
"field_trials_provider_unittest.cc",
......@@ -497,9 +477,7 @@ source_set("unit_tests") {
# Convenience testing target
test("metrics_unittests") {
sources = [
"//components/test/run_all_unittests.cc",
]
sources = [ "//components/test/run_all_unittests.cc" ]
deps = [
":unit_tests",
"//components/test:test_support",
......
// Copyright 2020 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 "components/metrics/entropy_state.h"
#include "base/command_line.h"
#include "base/metrics/histogram_functions.h"
#include "base/no_destructor.h"
#include "base/rand_util.h"
#include "base/strings/string_number_conversions.h"
#include "components/metrics/metrics_pref_names.h"
#include "components/metrics/metrics_switches.h"
#include "components/prefs/pref_service.h"
namespace metrics {
namespace {
// The argument used to generate a non-identifying entropy source. We want no
// more than 13 bits of entropy, so use this max to return a number in the range
// [0, 7999] as the entropy source (12.97 bits of entropy).
const int kMaxLowEntropySize = 8000;
// Generates a new non-identifying entropy source used to seed persistent
// activities. Using a NoDestructor so that the new low entropy source value
// will only be generated on first access. And thus, even though we may write
// the new low entropy source value to prefs multiple times, it stays the same
// value.
int GenerateLowEntropySource() {
static const base::NoDestructor<int> low_entropy_source(
[] { return base::RandInt(0, kMaxLowEntropySize - 1); }());
return *low_entropy_source;
}
} // namespace
EntropyState::EntropyState(PrefService* local_state)
: local_state_(local_state) {}
// static
constexpr int EntropyState::kLowEntropySourceNotSet;
void EntropyState::ClearPrefs() {
DCHECK_EQ(kLowEntropySourceNotSet, low_entropy_source_);
local_state_->ClearPref(prefs::kMetricsLowEntropySource);
local_state_->ClearPref(prefs::kMetricsOldLowEntropySource);
}
// static
void EntropyState::RegisterPrefs(PrefRegistrySimple* registry) {
registry->RegisterIntegerPref(prefs::kMetricsLowEntropySource,
kLowEntropySourceNotSet);
registry->RegisterIntegerPref(prefs::kMetricsOldLowEntropySource,
kLowEntropySourceNotSet);
}
std::string EntropyState::GetHighEntropySource(
const std::string& client_id,
const std::string& provisional_client_id) {
// For metrics reporting-enabled users, we combine the client ID and low
// entropy source to get the final entropy source.
// This has two useful properties:
// 1) It makes the entropy source less identifiable for parties that do not
// know the low entropy source.
// 2) It makes the final entropy source resettable.
// If this install has an old low entropy source, continue using it, to avoid
// changing the group assignments of studies using high entropy. New installs
// only have the new low entropy source. If the number of installs with old
// sources ever becomes small enough (see UMA.LowEntropySourceValue), we could
// remove it, and just use the new source here.
int low_entropy_source = GetOldLowEntropySource();
if (low_entropy_source == kLowEntropySourceNotSet)
low_entropy_source = GetLowEntropySource();
const std::string& client_id_to_use =
(client_id.empty() ? provisional_client_id : client_id);
return client_id_to_use + base::NumberToString(low_entropy_source);
}
int EntropyState::GetLowEntropySource() {
UpdateLowEntropySources();
return low_entropy_source_;
}
int EntropyState::GetOldLowEntropySource() {
UpdateLowEntropySources();
return old_low_entropy_source_;
}
void EntropyState::UpdateLowEntropySources() {
// The default value for |low_entropy_source_| and the default pref value are
// both |kLowEntropySourceNotSet|, which indicates the value has not been set.
if (low_entropy_source_ != kLowEntropySourceNotSet)
return;
const base::CommandLine* command_line(base::CommandLine::ForCurrentProcess());
// Only try to load the value from prefs if the user did not request a reset.
// Otherwise, skip to generating a new value. We would have already returned
// if |low_entropy_source_| were set, ensuring we only do this reset on the
// first call to UpdateLowEntropySources().
if (!command_line->HasSwitch(switches::kResetVariationState)) {
int new_pref = local_state_->GetInteger(prefs::kMetricsLowEntropySource);
if (IsValidLowEntropySource(new_pref))
low_entropy_source_ = new_pref;
int old_pref = local_state_->GetInteger(prefs::kMetricsOldLowEntropySource);
if (IsValidLowEntropySource(old_pref))
old_low_entropy_source_ = old_pref;
}
// If the new source is missing or corrupt (or requested to be reset), then
// (re)create it. Don't bother recreating the old source if it's corrupt,
// because we only keep the old source around for consistency, and we can't
// maintain a consistent value if we recreate it.
if (low_entropy_source_ == kLowEntropySourceNotSet) {
low_entropy_source_ = GenerateLowEntropySource();
DCHECK(IsValidLowEntropySource(low_entropy_source_));
local_state_->SetInteger(prefs::kMetricsLowEntropySource,
low_entropy_source_);
}
// If the old source was present but corrupt (or requested to be reset), then
// we'll never use it again, so delete it.
if (old_low_entropy_source_ == kLowEntropySourceNotSet &&
local_state_->HasPrefPath(prefs::kMetricsOldLowEntropySource)) {
local_state_->ClearPref(prefs::kMetricsOldLowEntropySource);
}
DCHECK_NE(low_entropy_source_, kLowEntropySourceNotSet);
// TODO(crbug/1041710): Currently, these metrics might be recorded multiple
// times but that shouldn't matter because we can workaround it by using count
// unique user mode. Also, once we verify that we can persist
// low_entropy_source to our system profile proto, These two metrics are
// longer needed and should be removed.
base::UmaHistogramSparse("UMA.LowEntropySource3Value", low_entropy_source_);
if (old_low_entropy_source_ != kLowEntropySourceNotSet) {
base::UmaHistogramSparse("UMA.LowEntropySourceValue",
old_low_entropy_source_);
}
}
// static
bool EntropyState::IsValidLowEntropySource(int value) {
return value >= 0 && value < kMaxLowEntropySize;
}
} // namespace metrics
// Copyright 2020 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.
#ifndef COMPONENTS_METRICS_ENTROPY_STATE_H_
#define COMPONENTS_METRICS_ENTROPY_STATE_H_
#include <string>
#include "base/gtest_prod_util.h"
#include "components/prefs/pref_registry_simple.h"
class PrefService;
namespace metrics {
// A class to get entropy source values from the PrefService.
class EntropyState final {
public:
// Creates the EntropyState with the given |local_state| to get
// the entropy source value from this helper class.
explicit EntropyState(PrefService* local_state);
EntropyState(const EntropyState&) = delete;
EntropyState& operator=(const EntropyState&) = delete;
// Clears low_entropy_source and old_low_entropy_source in the prefs.
void ClearPrefs();
// Registers low_entropy_source and old_low_entropy_source in the prefs.
static void RegisterPrefs(PrefRegistrySimple* registry);
// Returns the high entropy source for this client, which is composed of a
// client ID and the low entropy source. This is intended to be unique for
// each install. UMA must be enabled (and |client_id_| must be set) or
// |provisional_client_id_| must be set before calling this.
std::string GetHighEntropySource(const std::string& client_id,
const std::string& provisional_client_id);
// Returns the low entropy source for this client. Generates a new value if
// there is none. See the |low_entropy_source_| comment for more info.
int GetLowEntropySource();
// Returns the old low entropy source for this client. Does not generate a new
// value, but instead returns |kLowEntropySourceNotSet|, if there is none. See
// the |old_low_entropy_source_| comment for more info.
int GetOldLowEntropySource();
private:
FRIEND_TEST_ALL_PREFIXES(EntropyStateTest, LowEntropySource0NotReset);
FRIEND_TEST_ALL_PREFIXES(EntropyStateTest, HaveNoLowEntropySource);
FRIEND_TEST_ALL_PREFIXES(EntropyStateTest, HaveOnlyNewLowEntropySource);
FRIEND_TEST_ALL_PREFIXES(EntropyStateTest, HaveOnlyOldLowEntropySource);
FRIEND_TEST_ALL_PREFIXES(EntropyStateTest, CorruptNewLowEntropySources);
FRIEND_TEST_ALL_PREFIXES(EntropyStateTest, CorruptOldLowEntropySources);
// Default value for prefs::kMetricsLowEntropySource.
static constexpr int kLowEntropySourceNotSet = -1;
// Loads the low entropy source values from prefs. Creates the new source
// value if it doesn't exist, but doesn't create the old source value. After
// this function finishes, |low_entropy_source_| will be set, but
// |old_low_entropy_source_| may still be |kLowEntropySourceNotSet|.
void UpdateLowEntropySources();
// Checks whether a value is on the range of allowed low entropy source
// values.
static bool IsValidLowEntropySource(int value);
// The local state prefs store.
PrefService* const local_state_;
// The non-identifying low entropy source values. These values seed the
// pseudorandom generators which pick experimental groups. The "old" value is
// thought to be biased in the wild, and is no longer used for experiments
// requiring low entropy. Clients which already have an "old" value continue
// incorporating it into the high entropy source, to avoid changing those
// group assignments. New clients only have the new source.
int low_entropy_source_ = kLowEntropySourceNotSet;
int old_low_entropy_source_ = kLowEntropySourceNotSet;
};
} // namespace metrics
#endif // COMPONENTS_METRICS_ENTROPY_STATE_H_
// Copyright 2020 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 "components/metrics/entropy_state_provider.h"
#include "third_party/metrics_proto/system_profile.pb.h"
namespace metrics {
EntropyStateProvider::EntropyStateProvider(PrefService* local_state)
: entropy_state_(local_state) {}
EntropyStateProvider::~EntropyStateProvider() = default;
void EntropyStateProvider::ProvideSystemProfileMetrics(
SystemProfileProto* system_profile) {
system_profile->set_low_entropy_source(entropy_state_.GetLowEntropySource());
system_profile->set_old_low_entropy_source(
entropy_state_.GetOldLowEntropySource());
}
} // namespace metrics
// Copyright 2020 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.
#ifndef COMPONENTS_METRICS_ENTROPY_STATE_PROVIDER_H_
#define COMPONENTS_METRICS_ENTROPY_STATE_PROVIDER_H_
#include "components/metrics/entropy_state.h"
#include "components/metrics/metrics_provider.h"
class PrefService;
namespace metrics {
// EntropyStateProvider adds information about low entropy sources in the system
// profile. This includes |low_entropy_source| and |old_low_entropy_source|.
class EntropyStateProvider : public MetricsProvider {
public:
explicit EntropyStateProvider(PrefService* local_state);
~EntropyStateProvider() override;
EntropyStateProvider(const EntropyStateProvider&) = delete;
EntropyStateProvider& operator=(const EntropyStateProvider&) = delete;
void ProvideSystemProfileMetrics(
SystemProfileProto* system_profile_proto) override;
private:
EntropyState entropy_state_;
};
} // namespace metrics
#endif // COMPONENTS_METRICS_ENTROPY_STATE_PROVIDER_H_
// Copyright 2020 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 "components/metrics/entropy_state_provider.h"
#include "components/metrics/metrics_pref_names.h"
#include "components/metrics/metrics_service.h"
#include "components/prefs/testing_pref_service.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/metrics_proto/system_profile.pb.h"
namespace metrics {
class EntropyStateProviderTest : public testing::Test {
public:
EntropyStateProviderTest() {
MetricsService::RegisterPrefs(prefs_.registry());
}
EntropyStateProviderTest(const EntropyStateProviderTest&) = delete;
EntropyStateProviderTest& operator=(const EntropyStateProviderTest&) = delete;
protected:
TestingPrefServiceSimple prefs_;
};
TEST_F(EntropyStateProviderTest, PopulateBothLowEntropySource) {
const int new_low_source = 1234;
const int old_low_source = 5678;
prefs_.SetInteger(prefs::kMetricsLowEntropySource, new_low_source);
prefs_.SetInteger(prefs::kMetricsOldLowEntropySource, old_low_source);
EntropyStateProvider provider(&prefs_);
SystemProfileProto system_profile;
provider.ProvideSystemProfileMetrics(&system_profile);
EXPECT_EQ(new_low_source, system_profile.low_entropy_source());
EXPECT_EQ(old_low_source, system_profile.old_low_entropy_source());
}
} // namespace metrics
// Copyright 2020 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 "components/metrics/entropy_state.h"
#include <string>
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_util.h"
#include "components/metrics/metrics_pref_names.h"
#include "components/metrics/metrics_service.h"
#include "components/prefs/testing_pref_service.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace metrics {
class EntropyStateTest : public testing::Test {
public:
EntropyStateTest() { MetricsService::RegisterPrefs(prefs_.registry()); }
EntropyStateTest(const EntropyStateTest&) = delete;
EntropyStateTest& operator=(const EntropyStateTest&) = delete;
protected:
TestingPrefServiceSimple prefs_;
};
TEST_F(EntropyStateTest, LowEntropySource0NotReset) {
EntropyState entropy_state(&prefs_);
// Get the low entropy source once, to initialize it.
entropy_state.GetLowEntropySource();
// Now, set it to 0 and ensure it doesn't get reset.
entropy_state.low_entropy_source_ = 0;
EXPECT_EQ(0, entropy_state.GetLowEntropySource());
// Call it another time, just to make sure.
EXPECT_EQ(0, entropy_state.GetLowEntropySource());
}
TEST_F(EntropyStateTest, HaveNoLowEntropySource) {
EntropyState entropy_state(&prefs_);
// If we have neither the new nor old low entropy sources in prefs, then the
// new source should be created...
int new_low_source = entropy_state.GetLowEntropySource();
EXPECT_TRUE(EntropyState::IsValidLowEntropySource(new_low_source))
<< new_low_source;
// ...but the old source should not...
EXPECT_EQ(EntropyState::kLowEntropySourceNotSet,
entropy_state.GetOldLowEntropySource());
// ...and the high entropy source should include the *new* low entropy source.
std::string high_source = entropy_state.GetHighEntropySource(
"AAAAAAAA-BBBB-CCCC-DDDD-EEEEEEEEEEEF", "");
EXPECT_TRUE(base::EndsWith(high_source, base::NumberToString(new_low_source),
base::CompareCase::SENSITIVE))
<< high_source;
}
TEST_F(EntropyStateTest, HaveOnlyNewLowEntropySource) {
// If we have the new low entropy sources in prefs, but not the old one...
const int new_low_source = 1234;
prefs_.SetInteger(prefs::kMetricsLowEntropySource, new_low_source);
EntropyState entropy_state(&prefs_);
// ...then the new source should be loaded...
EXPECT_EQ(new_low_source, entropy_state.GetLowEntropySource());
// ...but the old source should not be created...
EXPECT_EQ(EntropyState::kLowEntropySourceNotSet,
entropy_state.GetOldLowEntropySource());
// ...and the high entropy source should include the *new* low entropy source.
std::string high_source = entropy_state.GetHighEntropySource(
"AAAAAAAA-BBBB-CCCC-DDDD-EEEEEEEEEEEF", "");
EXPECT_TRUE(base::EndsWith(high_source, base::NumberToString(new_low_source),
base::CompareCase::SENSITIVE))
<< high_source;
}
TEST_F(EntropyStateTest, HaveOnlyOldLowEntropySource) {
// If we have the old low entropy sources in prefs, but not the new one...
const int old_low_source = 5678;
prefs_.SetInteger(prefs::kMetricsOldLowEntropySource, old_low_source);
// ...then the new source should be created...
EntropyState entropy_state(&prefs_);
int new_low_source = entropy_state.GetLowEntropySource();
EXPECT_TRUE(EntropyState::IsValidLowEntropySource(new_low_source))
<< new_low_source;
// ...and the old source should be loaded...
EXPECT_EQ(old_low_source, entropy_state.GetOldLowEntropySource());
// ...and the high entropy source should include the *old* low entropy source.
std::string high_source = entropy_state.GetHighEntropySource(
"AAAAAAAA-BBBB-CCCC-DDDD-EEEEEEEEEEEF", "");
EXPECT_TRUE(base::EndsWith(high_source, base::NumberToString(old_low_source),
base::CompareCase::SENSITIVE))
<< high_source;
}
TEST_F(EntropyStateTest, HaveBothLowEntropySources) {
// If we have the new and old low entropy sources in prefs...
const int new_low_source = 1234;
const int old_low_source = 5678;
prefs_.SetInteger(prefs::kMetricsLowEntropySource, new_low_source);
prefs_.SetInteger(prefs::kMetricsOldLowEntropySource, old_low_source);
// ...then both should be loaded...
EntropyState entropy_state(&prefs_);
EXPECT_EQ(new_low_source, entropy_state.GetLowEntropySource());
EXPECT_EQ(old_low_source, entropy_state.GetOldLowEntropySource());
// ...and the high entropy source should include the *old* low entropy source.
std::string high_source = entropy_state.GetHighEntropySource(
"AAAAAAAA-BBBB-CCCC-DDDD-EEEEEEEEEEEF", "");
EXPECT_TRUE(base::EndsWith(high_source, base::NumberToString(old_low_source),
base::CompareCase::SENSITIVE))
<< high_source;
}
TEST_F(EntropyStateTest, CorruptNewLowEntropySources) {
EntropyState entropy_state(&prefs_);
const int corrupt_sources[] = {-12345, -1, 8000, 12345};
for (int corrupt_source : corrupt_sources) {
// If the new low entropy source has been corrupted...
EXPECT_FALSE(EntropyState::IsValidLowEntropySource(corrupt_source))
<< corrupt_source;
prefs_.SetInteger(prefs::kMetricsLowEntropySource, corrupt_source);
// ...then a new source should be created.
int loaded_source = entropy_state.GetLowEntropySource();
EXPECT_TRUE(EntropyState::IsValidLowEntropySource(loaded_source))
<< loaded_source;
}
}
TEST_F(EntropyStateTest, CorruptOldLowEntropySources) {
EntropyState entropy_state(&prefs_);
const int corrupt_sources[] = {-12345, -1, 8000, 12345};
for (int corrupt_source : corrupt_sources) {
// If the old low entropy source has been corrupted...
EXPECT_FALSE(EntropyState::IsValidLowEntropySource(corrupt_source))
<< corrupt_source;
prefs_.SetInteger(prefs::kMetricsOldLowEntropySource, corrupt_source);
// ...then it should be ignored.
EXPECT_EQ(EntropyState::kLowEntropySourceNotSet,
entropy_state.GetOldLowEntropySource());
}
}
} // namespace metrics
......@@ -30,7 +30,6 @@ class HistogramSnapshotManager;
namespace metrics {
class MetricsProvider;
class MetricsServiceClient;
class DelegatingProvider;
namespace internal {
......
......@@ -10,7 +10,6 @@
#include <memory>
#include <utility>
#include "base/command_line.h"
#include "base/guid.h"
#include "base/metrics/histogram_functions.h"
#include "base/metrics/histogram_macros.h"
......@@ -22,6 +21,7 @@
#include "build/build_config.h"
#include "components/metrics/cloned_install_detector.h"
#include "components/metrics/enabled_state_provider.h"
#include "components/metrics/entropy_state.h"
#include "components/metrics/machine_id_provider.h"
#include "components/metrics/metrics_log.h"
#include "components/metrics/metrics_pref_names.h"
......@@ -43,12 +43,6 @@ namespace {
// [0, 7999] as the entropy source (12.97 bits of entropy).
const int kMaxLowEntropySize = 8000;
// Generates a new non-identifying entropy source used to seed persistent
// activities.
int GenerateLowEntropySource() {
return base::RandInt(0, kMaxLowEntropySize - 1);
}
int64_t ReadEnabledDate(PrefService* local_state) {
return local_state->GetInt64(prefs::kMetricsReportingEnabledTimestamp);
}
......@@ -134,8 +128,7 @@ MetricsStateManager::MetricsStateManager(
store_client_info_(store_client_info),
load_client_info_(retrieve_client_info),
clean_exit_beacon_(backup_registry_key, local_state),
low_entropy_source_(kLowEntropySourceNotSet),
old_low_entropy_source_(kLowEntropySourceNotSet),
entropy_state_(local_state),
entropy_source_returned_(ENTROPY_SOURCE_NONE),
metrics_ids_were_reset_(false) {
ResetMetricsIDsIfNecessary();
......@@ -324,18 +317,12 @@ void MetricsStateManager::RegisterPrefs(PrefRegistrySimple* registry) {
registry->RegisterBooleanPref(prefs::kMetricsResetIds, false);
registry->RegisterStringPref(prefs::kMetricsClientID, std::string());
registry->RegisterInt64Pref(prefs::kMetricsReportingEnabledTimestamp, 0);
registry->RegisterIntegerPref(prefs::kMetricsLowEntropySource,
kLowEntropySourceNotSet);
registry->RegisterIntegerPref(prefs::kMetricsOldLowEntropySource,
kLowEntropySourceNotSet);
registry->RegisterInt64Pref(prefs::kInstallDate, 0);
EntropyState::RegisterPrefs(registry);
ClonedInstallDetector::RegisterPrefs(registry);
}
// static
constexpr int MetricsStateManager::kLowEntropySourceNotSet;
void MetricsStateManager::BackUpCurrentClientInfo() {
ClientInfo client_info;
client_info.client_id = client_id_;
......@@ -363,82 +350,16 @@ std::string MetricsStateManager::GetHighEntropySource() {
// constructor and calling this, because field trial setup happens at Chrome
// initialization. Only one of these is expected to hold a value.
DCHECK(client_id_.empty() != provisional_client_id_.empty());
// For metrics reporting-enabled users, we combine the client ID and low
// entropy source to get the final entropy source.
// This has two useful properties:
// 1) It makes the entropy source less identifiable for parties that do not
// know the low entropy source.
// 2) It makes the final entropy source resettable.
// If this install has an old low entropy source, continue using it, to avoid
// changing the group assignments of studies using high entropy. New installs
// only have the new low entropy source. If the number of installs with old
// sources ever becomes small enough (see UMA.LowEntropySourceValue), we could
// remove it, and just use the new source here.
int low_entropy_source = GetOldLowEntropySource();
if (low_entropy_source == kLowEntropySourceNotSet)
low_entropy_source = GetLowEntropySource();
const std::string& client_id_to_use =
(client_id_.empty() ? provisional_client_id_ : client_id_);
return client_id_to_use + base::NumberToString(low_entropy_source);
return entropy_state_.GetHighEntropySource(client_id_,
provisional_client_id_);
}
int MetricsStateManager::GetLowEntropySource() {
UpdateLowEntropySources();
return low_entropy_source_;
return entropy_state_.GetLowEntropySource();
}
int MetricsStateManager::GetOldLowEntropySource() {
UpdateLowEntropySources();
return old_low_entropy_source_;
}
void MetricsStateManager::UpdateLowEntropySources() {
// The default value for |low_entropy_source_| and the default pref value are
// both |kLowEntropySourceNotSet|, which indicates the value has not been set.
if (low_entropy_source_ != kLowEntropySourceNotSet)
return;
const base::CommandLine* command_line(base::CommandLine::ForCurrentProcess());
// Only try to load the value from prefs if the user did not request a reset.
// Otherwise, skip to generating a new value. We would have already returned
// if |low_entropy_source_| were set, ensuring we only do this reset on the
// first call to UpdateLowEntropySources().
if (!command_line->HasSwitch(switches::kResetVariationState)) {
int new_pref = local_state_->GetInteger(prefs::kMetricsLowEntropySource);
if (IsValidLowEntropySource(new_pref))
low_entropy_source_ = new_pref;
int old_pref = local_state_->GetInteger(prefs::kMetricsOldLowEntropySource);
if (IsValidLowEntropySource(old_pref))
old_low_entropy_source_ = old_pref;
}
// If the new source is missing or corrupt (or requested to be reset), then
// (re)create it. Don't bother recreating the old source if it's corrupt,
// because we only keep the old source around for consistency, and we can't
// maintain a consistent value if we recreate it.
if (low_entropy_source_ == kLowEntropySourceNotSet) {
low_entropy_source_ = GenerateLowEntropySource();
DCHECK(IsValidLowEntropySource(low_entropy_source_));
local_state_->SetInteger(prefs::kMetricsLowEntropySource,
low_entropy_source_);
}
// If the old source was present but corrupt (or requested to be reset), then
// we'll never use it again, so delete it.
if (old_low_entropy_source_ == kLowEntropySourceNotSet &&
local_state_->HasPrefPath(prefs::kMetricsOldLowEntropySource)) {
local_state_->ClearPref(prefs::kMetricsOldLowEntropySource);
}
DCHECK_NE(low_entropy_source_, kLowEntropySourceNotSet);
base::UmaHistogramSparse("UMA.LowEntropySource3Value", low_entropy_source_);
if (old_low_entropy_source_ != kLowEntropySourceNotSet) {
base::UmaHistogramSparse("UMA.LowEntropySourceValue",
old_low_entropy_source_);
}
return entropy_state_.GetOldLowEntropySource();
}
void MetricsStateManager::UpdateEntropySourceReturnedValue(
......@@ -460,20 +381,13 @@ void MetricsStateManager::ResetMetricsIDsIfNecessary() {
UMA_HISTOGRAM_BOOLEAN("UMA.MetricsIDsReset", true);
DCHECK(client_id_.empty());
DCHECK_EQ(kLowEntropySourceNotSet, low_entropy_source_);
local_state_->ClearPref(prefs::kMetricsClientID);
local_state_->ClearPref(prefs::kMetricsLowEntropySource);
local_state_->ClearPref(prefs::kMetricsOldLowEntropySource);
local_state_->ClearPref(prefs::kMetricsResetIds);
entropy_state_.ClearPrefs();
// Also clear the backed up client info.
store_client_info_.Run(ClientInfo());
}
// static
bool MetricsStateManager::IsValidLowEntropySource(int value) {
return value >= 0 && value < kMaxLowEntropySize;
}
} // namespace metrics
......@@ -15,6 +15,7 @@
#include "base/strings/string16.h"
#include "components/metrics/clean_exit_beacon.h"
#include "components/metrics/client_info.h"
#include "components/metrics/entropy_state.h"
class PrefService;
class PrefRegistrySimple;
......@@ -108,17 +109,6 @@ class MetricsStateManager final {
FRIEND_TEST_ALL_PREFIXES(MetricsStateManagerTest, CheckProviderResetIds);
FRIEND_TEST_ALL_PREFIXES(MetricsStateManagerTest, EntropySourceUsed_Low);
FRIEND_TEST_ALL_PREFIXES(MetricsStateManagerTest, EntropySourceUsed_High);
FRIEND_TEST_ALL_PREFIXES(MetricsStateManagerTest, LowEntropySource0NotReset);
FRIEND_TEST_ALL_PREFIXES(MetricsStateManagerTest, HaveNoLowEntropySource);
FRIEND_TEST_ALL_PREFIXES(MetricsStateManagerTest,
HaveOnlyNewLowEntropySource);
FRIEND_TEST_ALL_PREFIXES(MetricsStateManagerTest,
HaveOnlyOldLowEntropySource);
FRIEND_TEST_ALL_PREFIXES(MetricsStateManagerTest, HaveBothLowEntropySources);
FRIEND_TEST_ALL_PREFIXES(MetricsStateManagerTest,
CorruptNewLowEntropySources);
FRIEND_TEST_ALL_PREFIXES(MetricsStateManagerTest,
CorruptOldLowEntropySources);
FRIEND_TEST_ALL_PREFIXES(MetricsStateManagerTest,
ProvisionalClientId_PromotedToClientId);
FRIEND_TEST_ALL_PREFIXES(MetricsStateManagerTest,
......@@ -136,9 +126,6 @@ class MetricsStateManager final {
ENTROPY_SOURCE_ENUM_SIZE,
};
// Default value for prefs::kMetricsLowEntropySource.
static constexpr int kLowEntropySourceNotSet = -1;
// Creates the MetricsStateManager with the given |local_state|. Uses
// |enabled_state_provider| to query whether there is consent for metrics
// reporting, and if it is enabled. Clients should instead use Create(), which
......@@ -163,21 +150,12 @@ class MetricsStateManager final {
// |provisional_client_id_| must be set before calling this.
std::string GetHighEntropySource();
// Returns the low entropy source for this client. Generates a new value if
// there is none. See the |low_entropy_source_| comment for more info.
// Returns the low entropy source for this client.
int GetLowEntropySource();
// Returns the old low entropy source for this client. Does not generate a new
// value, but instead returns |kLowEntropySourceNotSet|, if there is none. See
// the |old_low_entropy_source_| comment for more info.
// Returns the old low entropy source for this client.
int GetOldLowEntropySource();
// Loads the low entropy source values from prefs. Creates the new source
// value if it doesn't exist, but doesn't create the old source value. After
// this function finishes, |low_entropy_source_| will be set, but
// |old_low_entropy_source_| may still be |kLowEntropySourceNotSet|.
void UpdateLowEntropySources();
// Updates |entropy_source_returned_| with |type| iff the current value is
// ENTROPY_SOURCE_NONE and logs the new value in a histogram.
void UpdateEntropySourceReturnedValue(EntropySourceType type);
......@@ -193,10 +171,6 @@ class MetricsStateManager final {
// pref is true.
void ResetMetricsIDsIfNecessary();
// Checks whether a value is on the range of allowed low entropy source
// values.
static bool IsValidLowEntropySource(int value);
// Whether an instance of this class exists. Used to enforce that there aren't
// multiple instances of this class at a given time.
static bool instance_exists_;
......@@ -231,14 +205,8 @@ class MetricsStateManager final {
// trials don't toggle state between first and second run.
std::string provisional_client_id_;
// The non-identifying low entropy source values. These values seed the
// pseudorandom generators which pick experimental groups. The "old" value is
// thought to be biased in the wild, and is no longer used for experiments
// requiring low entropy. Clients which already have an "old" value continue
// incorporating it into the high entropy source, to avoid changing those
// group assignments. New clients only have the new source.
int low_entropy_source_;
int old_low_entropy_source_;
// An instance of EntropyState for getting the entropy source values.
EntropyState entropy_state_;
// The last entropy source returned by this service, used for testing.
EntropySourceType entropy_source_returned_;
......
......@@ -175,129 +175,6 @@ TEST_F(MetricsStateManagerTest, EntropySourceUsed_High) {
state_manager->entropy_source_returned());
}
TEST_F(MetricsStateManagerTest, LowEntropySource0NotReset) {
std::unique_ptr<MetricsStateManager> state_manager(CreateStateManager());
// Get the low entropy source once, to initialize it.
state_manager->GetLowEntropySource();
// Now, set it to 0 and ensure it doesn't get reset.
state_manager->low_entropy_source_ = 0;
EXPECT_EQ(0, state_manager->GetLowEntropySource());
// Call it another time, just to make sure.
EXPECT_EQ(0, state_manager->GetLowEntropySource());
}
TEST_F(MetricsStateManagerTest, HaveNoLowEntropySource) {
prefs_.SetString(prefs::kMetricsClientID,
"AAAAAAAA-BBBB-CCCC-DDDD-EEEEEEEEEEEF");
EnableMetricsReporting();
std::unique_ptr<MetricsStateManager> state_manager(CreateStateManager());
// If we have neither the new nor old low entropy sources in prefs, then the
// new source should be created...
int new_low_source = state_manager->GetLowEntropySource();
EXPECT_TRUE(MetricsStateManager::IsValidLowEntropySource(new_low_source))
<< new_low_source;
// ...but the old source should not...
EXPECT_EQ(MetricsStateManager::kLowEntropySourceNotSet,
state_manager->GetOldLowEntropySource());
// ...and the high entropy source should include the *new* low entropy source.
std::string high_source = state_manager->GetHighEntropySource();
EXPECT_TRUE(base::EndsWith(high_source, base::NumberToString(new_low_source),
base::CompareCase::SENSITIVE))
<< high_source;
}
TEST_F(MetricsStateManagerTest, HaveOnlyNewLowEntropySource) {
// If we have the new low entropy sources in prefs, but not the old one...
const int new_low_source = 1234;
prefs_.SetInteger(prefs::kMetricsLowEntropySource, new_low_source);
prefs_.SetString(prefs::kMetricsClientID,
"AAAAAAAA-BBBB-CCCC-DDDD-EEEEEEEEEEEF");
EnableMetricsReporting();
std::unique_ptr<MetricsStateManager> state_manager(CreateStateManager());
// ...then the new source should be loaded...
EXPECT_EQ(new_low_source, state_manager->GetLowEntropySource());
// ...but the old source should not be created...
EXPECT_EQ(MetricsStateManager::kLowEntropySourceNotSet,
state_manager->GetOldLowEntropySource());
// ...and the high entropy source should include the *new* low entropy source.
std::string high_source = state_manager->GetHighEntropySource();
EXPECT_TRUE(base::EndsWith(high_source, base::NumberToString(new_low_source),
base::CompareCase::SENSITIVE))
<< high_source;
}
TEST_F(MetricsStateManagerTest, HaveOnlyOldLowEntropySource) {
// If we have the old low entropy sources in prefs, but not the new one...
const int old_low_source = 5678;
prefs_.SetInteger(prefs::kMetricsOldLowEntropySource, old_low_source);
prefs_.SetString(prefs::kMetricsClientID,
"AAAAAAAA-BBBB-CCCC-DDDD-EEEEEEEEEEEF");
EnableMetricsReporting();
// ...then the new source should be created...
std::unique_ptr<MetricsStateManager> state_manager(CreateStateManager());
int new_low_source = state_manager->GetLowEntropySource();
EXPECT_TRUE(MetricsStateManager::IsValidLowEntropySource(new_low_source))
<< new_low_source;
// ...and the old source should be loaded...
EXPECT_EQ(old_low_source, state_manager->GetOldLowEntropySource());
// ...and the high entropy source should include the *old* low entropy source.
std::string high_source = state_manager->GetHighEntropySource();
EXPECT_TRUE(base::EndsWith(high_source, base::NumberToString(old_low_source),
base::CompareCase::SENSITIVE))
<< high_source;
}
TEST_F(MetricsStateManagerTest, HaveBothLowEntropySources) {
// If we have the new and old low entropy sources in prefs...
const int new_low_source = 1234;
const int old_low_source = 5678;
prefs_.SetInteger(prefs::kMetricsLowEntropySource, new_low_source);
prefs_.SetInteger(prefs::kMetricsOldLowEntropySource, old_low_source);
prefs_.SetString(prefs::kMetricsClientID,
"AAAAAAAA-BBBB-CCCC-DDDD-EEEEEEEEEEEF");
EnableMetricsReporting();
// ...then both should be loaded...
std::unique_ptr<MetricsStateManager> state_manager(CreateStateManager());
EXPECT_EQ(new_low_source, state_manager->GetLowEntropySource());
EXPECT_EQ(old_low_source, state_manager->GetOldLowEntropySource());
// ...and the high entropy source should include the *old* low entropy source.
std::string high_source = state_manager->GetHighEntropySource();
EXPECT_TRUE(base::EndsWith(high_source, base::NumberToString(old_low_source),
base::CompareCase::SENSITIVE))
<< high_source;
}
TEST_F(MetricsStateManagerTest, CorruptNewLowEntropySources) {
std::unique_ptr<MetricsStateManager> state_manager(CreateStateManager());
const int corrupt_sources[] = {-12345, -1, 8000, 12345};
for (int corrupt_source : corrupt_sources) {
// If the new low entropy source has been corrupted...
EXPECT_FALSE(MetricsStateManager::IsValidLowEntropySource(corrupt_source))
<< corrupt_source;
prefs_.SetInteger(prefs::kMetricsLowEntropySource, corrupt_source);
// ...then a new source should be created.
int loaded_source = state_manager->GetLowEntropySource();
EXPECT_TRUE(MetricsStateManager::IsValidLowEntropySource(loaded_source))
<< loaded_source;
}
}
TEST_F(MetricsStateManagerTest, CorruptOldLowEntropySources) {
std::unique_ptr<MetricsStateManager> state_manager(CreateStateManager());
const int corrupt_sources[] = {-12345, -1, 8000, 12345};
for (int corrupt_source : corrupt_sources) {
// If the old low entropy source has been corrupted...
EXPECT_FALSE(MetricsStateManager::IsValidLowEntropySource(corrupt_source))
<< corrupt_source;
prefs_.SetInteger(prefs::kMetricsOldLowEntropySource, corrupt_source);
// ...then it should be ignored.
EXPECT_EQ(MetricsStateManager::kLowEntropySourceNotSet,
state_manager->GetOldLowEntropySource());
}
}
// Check that setting the kMetricsResetIds pref to true causes the client id to
// be reset. We do not check that the low entropy source is reset because we
// cannot ensure that metrics state manager won't generate the same id again.
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment