diff options
author | Allan Sandfeld Jensen <allan.jensen@qt.io> | 2022-02-04 17:20:24 +0100 |
---|---|---|
committer | Allan Sandfeld Jensen <allan.jensen@qt.io> | 2022-02-12 08:15:25 +0000 |
commit | 8fa0776f1f79e91fc9c0b9c1ba11a0a29c05196b (patch) | |
tree | 788d8d7549712682703a0310ca4a0f0860d4802b /chromium/components/variations | |
parent | 606d85f2a5386472314d39923da28c70c60dc8e7 (diff) | |
download | qtwebengine-chromium-8fa0776f1f79e91fc9c0b9c1ba11a0a29c05196b.tar.gz |
BASELINE: Update Chromium to 98.0.4758.90
Change-Id: Ib7c41539bf8a8e0376bd639f27d68294de90f3c8
Reviewed-by: Allan Sandfeld Jensen <allan.jensen@qt.io>
Diffstat (limited to 'chromium/components/variations')
51 files changed, 820 insertions, 802 deletions
diff --git a/chromium/components/variations/BUILD.gn b/chromium/components/variations/BUILD.gn index e289f6b3a03..406e48daceb 100644 --- a/chromium/components/variations/BUILD.gn +++ b/chromium/components/variations/BUILD.gn @@ -128,6 +128,7 @@ component("variations") { "//build:chromeos_buildflags", "//components/crash/core/common:crash_key", "//components/prefs", + "//components/version_info", "//crypto", "//third_party/protobuf:protobuf_lite", "//third_party/zlib/google:compression_utils", diff --git a/chromium/components/variations/DEPS b/chromium/components/variations/DEPS index 6cbcd541878..aacb6bfa9f9 100644 --- a/chromium/components/variations/DEPS +++ b/chromium/components/variations/DEPS @@ -8,6 +8,7 @@ include_rules = [ "+components/metrics", "+components/prefs", "+components/variations", + "+components/version_info", "+crypto", "-net", "+third_party/protobuf", diff --git a/chromium/components/variations/child_process_field_trial_syncer.h b/chromium/components/variations/child_process_field_trial_syncer.h index d3cd5e41090..d01575a1f94 100644 --- a/chromium/components/variations/child_process_field_trial_syncer.h +++ b/chromium/components/variations/child_process_field_trial_syncer.h @@ -10,7 +10,6 @@ #include "base/callback.h" #include "base/component_export.h" -#include "base/macros.h" #include "base/metrics/field_trial.h" #include "base/threading/thread_local.h" diff --git a/chromium/components/variations/child_process_field_trial_syncer_unittest.cc b/chromium/components/variations/child_process_field_trial_syncer_unittest.cc index bab525295c6..7f8c3a4621b 100644 --- a/chromium/components/variations/child_process_field_trial_syncer_unittest.cc +++ b/chromium/components/variations/child_process_field_trial_syncer_unittest.cc @@ -22,7 +22,7 @@ TEST(ChildProcessFieldTrialSyncerTest, FieldTrialState) { // We don't use the descriptor here anyways so it's ok to pass -1. base::FieldTrialList::CreateTrialsFromCommandLine( - *base::CommandLine::ForCurrentProcess(), "field_trial_handle_switch", -1); + *base::CommandLine::ForCurrentProcess(), -1); base::FieldTrial* trial1 = base::FieldTrialList::CreateFieldTrial("A", "G1"); base::FieldTrial* trial2 = base::FieldTrialList::CreateFieldTrial("B", "G2"); diff --git a/chromium/components/variations/client_filterable_state.h b/chromium/components/variations/client_filterable_state.h index 800c9371ffe..10da00095b1 100644 --- a/chromium/components/variations/client_filterable_state.h +++ b/chromium/components/variations/client_filterable_state.h @@ -9,7 +9,6 @@ #include "base/callback.h" #include "base/component_export.h" -#include "base/macros.h" #include "base/time/time.h" #include "base/version.h" #include "components/variations/proto/study.pb.h" diff --git a/chromium/components/variations/entropy_provider.h b/chromium/components/variations/entropy_provider.h index 23273fe0e19..1195036cf25 100644 --- a/chromium/components/variations/entropy_provider.h +++ b/chromium/components/variations/entropy_provider.h @@ -14,7 +14,6 @@ #include "base/compiler_specific.h" #include "base/component_export.h" -#include "base/macros.h" #include "base/metrics/field_trial.h" namespace variations { diff --git a/chromium/components/variations/entropy_provider_unittest.cc b/chromium/components/variations/entropy_provider_unittest.cc index add104fc13d..56d202c2e32 100644 --- a/chromium/components/variations/entropy_provider_unittest.cc +++ b/chromium/components/variations/entropy_provider_unittest.cc @@ -14,7 +14,6 @@ #include "base/cxx17_backports.h" #include "base/guid.h" -#include "base/macros.h" #include "base/rand_util.h" #include "base/strings/string_number_conversions.h" #include "base/test/scoped_field_trial_list_resetter.h" diff --git a/chromium/components/variations/field_trial_config/field_trial_util_unittest.cc b/chromium/components/variations/field_trial_config/field_trial_util_unittest.cc index 667d4452dee..22902f6ddc3 100644 --- a/chromium/components/variations/field_trial_config/field_trial_util_unittest.cc +++ b/chromium/components/variations/field_trial_config/field_trial_util_unittest.cc @@ -10,7 +10,6 @@ #include "base/command_line.h" #include "base/cxx17_backports.h" -#include "base/macros.h" #include "base/metrics/field_trial.h" #include "base/metrics/field_trial_params.h" #include "base/strings/utf_string_conversions.h" diff --git a/chromium/components/variations/hashing_unittest.cc b/chromium/components/variations/hashing_unittest.cc index 125581aa279..1c5e7add116 100644 --- a/chromium/components/variations/hashing_unittest.cc +++ b/chromium/components/variations/hashing_unittest.cc @@ -8,7 +8,6 @@ #include <stdint.h> #include "base/cxx17_backports.h" -#include "base/macros.h" #include "testing/gtest/include/gtest/gtest.h" namespace variations { diff --git a/chromium/components/variations/metrics.cc b/chromium/components/variations/metrics.cc index b876460632e..3f57768060e 100644 --- a/chromium/components/variations/metrics.cc +++ b/chromium/components/variations/metrics.cc @@ -26,28 +26,27 @@ void RecordLoadSafeSeedResult(LoadSeedResult state) { } void RecordStoreSeedResult(StoreSeedResult result) { - UMA_HISTOGRAM_ENUMERATION("Variations.SeedStoreResult", result, - StoreSeedResult::ENUM_SIZE); + base::UmaHistogramEnumeration("Variations.SeedStoreResult", result); } void ReportUnsupportedSeedFormatError() { - RecordStoreSeedResult(StoreSeedResult::FAILED_UNSUPPORTED_SEED_FORMAT); + RecordStoreSeedResult(StoreSeedResult::kFailedUnsupportedSeedFormat); } void RecordStoreSafeSeedResult(StoreSeedResult result) { - UMA_HISTOGRAM_ENUMERATION("Variations.SafeMode.StoreSafeSeed.Result", result, - StoreSeedResult::ENUM_SIZE); + base::UmaHistogramEnumeration("Variations.SafeMode.StoreSafeSeed.Result", + result); } void RecordSeedInstanceManipulations(const InstanceManipulations& im) { if (im.delta_compressed && im.gzip_compressed) { - RecordStoreSeedResult(StoreSeedResult::GZIP_DELTA_COUNT); + RecordStoreSeedResult(StoreSeedResult::kGzipDeltaCount); } else if (im.delta_compressed) { - RecordStoreSeedResult(StoreSeedResult::NON_GZIP_DELTA_COUNT); + RecordStoreSeedResult(StoreSeedResult::kNonGzipDeltaCount); } else if (im.gzip_compressed) { - RecordStoreSeedResult(StoreSeedResult::GZIP_FULL_COUNT); + RecordStoreSeedResult(StoreSeedResult::kGzipFullCount); } else { - RecordStoreSeedResult(StoreSeedResult::NON_GZIP_FULL_COUNT); + RecordStoreSeedResult(StoreSeedResult::kNonGzipFullCount); } } diff --git a/chromium/components/variations/metrics.h b/chromium/components/variations/metrics.h index ebf5be97d6e..0bae191fc94 100644 --- a/chromium/components/variations/metrics.h +++ b/chromium/components/variations/metrics.h @@ -44,29 +44,31 @@ enum class LoadSeedResult { }; // The result of attempting to store a variations seed received from the server. -// Note: UMA histogram enum - don't re-order or remove entries. +// +// These values are persisted to logs. Entries should not be renumbered and +// numeric values should never be reused. enum class StoreSeedResult { - SUCCESS, - FAILED_EMPTY, - FAILED_PARSE, - FAILED_SIGNATURE, - FAILED_GZIP, - DELTA_COUNT_OBSOLETE, - FAILED_DELTA_READ_SEED, - FAILED_DELTA_APPLY, - FAILED_DELTA_STORE, - FAILED_UNGZIP, - FAILED_EMPTY_GZIP_CONTENTS, - FAILED_UNSUPPORTED_SEED_FORMAT, + kSuccess = 0, + // kFailedEmpty = 1, // Deprecated. + kFailedParse = 2, + kFailedSignature = 3, + kFailedGzip = 4, + // kDeltaCount = 5, // Deprecated. + kFailedDeltaReadSeed = 6, + kFailedDeltaApply = 7, + kFailedDeltaStore = 8, + kFailedUngzip = 9, + kFailedEmptyGzipContents = 10, + kFailedUnsupportedSeedFormat = 11, // The following are not so much a result of the seed store, but rather // counting the types of seeds the SeedStore() function saw. Kept in the same // histogram for efficiency and convenience of comparing against the other // values. - GZIP_DELTA_COUNT, - NON_GZIP_DELTA_COUNT, - GZIP_FULL_COUNT, - NON_GZIP_FULL_COUNT, - ENUM_SIZE + kGzipDeltaCount = 12, + kNonGzipDeltaCount = 13, + kGzipFullCount = 14, + kNonGzipFullCount = 15, + kMaxValue = kNonGzipFullCount, }; // The result of updating the date associated with an existing stored variations diff --git a/chromium/components/variations/net/variations_command_line_unittest.cc b/chromium/components/variations/net/variations_command_line_unittest.cc index 2ca4a019a86..c2fce5cc413 100644 --- a/chromium/components/variations/net/variations_command_line_unittest.cc +++ b/chromium/components/variations/net/variations_command_line_unittest.cc @@ -6,7 +6,6 @@ #include <stddef.h> -#include "base/macros.h" #include "base/metrics/field_trial.h" #include "base/metrics/field_trial_params.h" #include "base/test/scoped_feature_list.h" diff --git a/chromium/components/variations/net/variations_http_headers.cc b/chromium/components/variations/net/variations_http_headers.cc index 8f463333d4b..a93f5076f93 100644 --- a/chromium/components/variations/net/variations_http_headers.cc +++ b/chromium/components/variations/net/variations_http_headers.cc @@ -8,7 +8,7 @@ #include "base/bind.h" #include "base/feature_list.h" -#include "base/macros.h" +#include "base/memory/raw_ptr.h" #include "base/metrics/histogram_functions.h" #include "base/metrics/histogram_macros.h" #include "base/strings/string_util.h" @@ -256,8 +256,9 @@ class VariationsHeaderHelper { if (variations_header_.empty()) return false; - // Set the variations header to cors_exempt_headers rather than headers - // to be exempted from CORS checks. + // Set the variations header to cors_exempt_headers rather than headers to + // be exempted from CORS checks, and to avoid exposing the header to service + // workers. resource_request_->cors_exempt_headers.SetHeaderIfMissing( kClientDataHeader, variations_header_); return true; @@ -285,7 +286,7 @@ class VariationsHeaderHelper { GetVisibilityKey(owner, resource_request)); } - network::ResourceRequest* resource_request_; + raw_ptr<network::ResourceRequest> resource_request_; std::string variations_header_; }; @@ -358,11 +359,6 @@ CreateSimpleURLLoaderWithVariationsHeaderUnknownSignedIn( std::move(request), incognito, SignedIn::kNo, annotation_tag); } -bool IsVariationsHeader(const std::string& header_name) { - return header_name == kClientDataHeader || - header_name == kOmniboxOnDeviceSuggestionsHeader; -} - bool HasVariationsHeader(const network::ResourceRequest& request) { // Note: kOmniboxOnDeviceSuggestionsHeader is not listed because this function // is only used for testing. diff --git a/chromium/components/variations/net/variations_http_headers.h b/chromium/components/variations/net/variations_http_headers.h index 9b526a8ee93..33240c68305 100644 --- a/chromium/components/variations/net/variations_http_headers.h +++ b/chromium/components/variations/net/variations_http_headers.h @@ -116,9 +116,6 @@ CreateSimpleURLLoaderWithVariationsHeaderUnknownSignedIn( InIncognito incognito, const net::NetworkTrafficAnnotationTag& annotation_tag); -// Checks if |header_name| is one for the variations header. -bool IsVariationsHeader(const std::string& header_name); - // Checks if |request| contains the variations header. bool HasVariationsHeader(const network::ResourceRequest& request); diff --git a/chromium/components/variations/net/variations_http_headers_unittest.cc b/chromium/components/variations/net/variations_http_headers_unittest.cc index 33808793da4..dc073e0b3d8 100644 --- a/chromium/components/variations/net/variations_http_headers_unittest.cc +++ b/chromium/components/variations/net/variations_http_headers_unittest.cc @@ -8,7 +8,6 @@ #include "base/containers/flat_map.h" #include "base/cxx17_backports.h" -#include "base/macros.h" #include "base/test/metrics/histogram_tester.h" #include "base/test/task_environment.h" #include "components/variations/variations.mojom.h" diff --git a/chromium/components/variations/platform_field_trials.h b/chromium/components/variations/platform_field_trials.h index ac96dc6e59c..a07eedb4e47 100644 --- a/chromium/components/variations/platform_field_trials.h +++ b/chromium/components/variations/platform_field_trials.h @@ -22,7 +22,7 @@ class COMPONENT_EXPORT(VARIATIONS) PlatformFieldTrials { virtual ~PlatformFieldTrials() = default; // Set up field trials for a specific platform. - virtual void SetupFieldTrials() = 0; + virtual void SetUpFieldTrials() = 0; // Create field trials that will control feature list features. This should be // called during the same timing window as @@ -32,7 +32,7 @@ class COMPONENT_EXPORT(VARIATIONS) PlatformFieldTrials { // controlled by the variations seed. |low_entropy_provider| can be used as a // parameter to creating a FieldTrial that should be visible to Google web // properties. - virtual void SetupFeatureControllingFieldTrials( + virtual void SetUpFeatureControllingFieldTrials( bool has_seed, const base::FieldTrial::EntropyProvider* low_entropy_provider, base::FeatureList* feature_list) = 0; diff --git a/chromium/components/variations/pref_names.cc b/chromium/components/variations/pref_names.cc index 03783fa316b..201e59bff65 100644 --- a/chromium/components/variations/pref_names.cc +++ b/chromium/components/variations/pref_names.cc @@ -34,6 +34,9 @@ const char kVariationsFailedToFetchSeedStreak[] = // Variations server responds with 200 or 304). This is a client timestamp. const char kVariationsLastFetchTime[] = "variations_last_fetch_time"; +// The milestone, e.g. 96, with which the regular seed was fetched. +const char kVariationsSeedMilestone[] = "variations_seed_milestone"; + // Pair of <Chrome version string, country code string> representing the country // used for filtering permanent consistency studies until the next time Chrome // is updated. @@ -84,6 +87,9 @@ const char kVariationsSafeSeedFetchTime[] = "variations_safe_seed_fetch_time"; // last known "safe" seed. const char kVariationsSafeSeedLocale[] = "variations_safe_seed_locale"; +// The milestone with which the "safe" seed was fetched. +const char kVariationsSafeSeedMilestone[] = "variations_safe_seed_milestone"; + // A saved copy of |kVariationsPermanentConsistencyCountry|. The saved value is // the most recent value that was successfully used by the VariationsService for // evaluating permanent consistency studies. diff --git a/chromium/components/variations/pref_names.h b/chromium/components/variations/pref_names.h index a7ef1d34f1e..3d6ad20b06c 100644 --- a/chromium/components/variations/pref_names.h +++ b/chromium/components/variations/pref_names.h @@ -21,6 +21,7 @@ COMPONENT_EXPORT(VARIATIONS) extern const char kVariationsCrashStreak[]; COMPONENT_EXPORT(VARIATIONS) extern const char kVariationsFailedToFetchSeedStreak[]; COMPONENT_EXPORT(VARIATIONS) extern const char kVariationsLastFetchTime[]; +COMPONENT_EXPORT(VARIATIONS) extern const char kVariationsSeedMilestone[]; COMPONENT_EXPORT(VARIATIONS) extern const char kVariationsPermanentConsistencyCountry[]; COMPONENT_EXPORT(VARIATIONS) @@ -32,6 +33,7 @@ COMPONENT_EXPORT(VARIATIONS) extern const char kVariationsSafeCompressedSeed[]; COMPONENT_EXPORT(VARIATIONS) extern const char kVariationsSafeSeedDate[]; COMPONENT_EXPORT(VARIATIONS) extern const char kVariationsSafeSeedFetchTime[]; COMPONENT_EXPORT(VARIATIONS) extern const char kVariationsSafeSeedLocale[]; +COMPONENT_EXPORT(VARIATIONS) extern const char kVariationsSafeSeedMilestone[]; COMPONENT_EXPORT(VARIATIONS) extern const char kVariationsSafeSeedPermanentConsistencyCountry[]; COMPONENT_EXPORT(VARIATIONS) diff --git a/chromium/components/variations/processed_study.h b/chromium/components/variations/processed_study.h index 095bf2da0fd..1b60a113351 100644 --- a/chromium/components/variations/processed_study.h +++ b/chromium/components/variations/processed_study.h @@ -9,6 +9,7 @@ #include <vector> #include "base/component_export.h" +#include "base/memory/raw_ptr.h" #include "base/metrics/field_trial.h" namespace variations { @@ -55,7 +56,7 @@ class COMPONENT_EXPORT(VARIATIONS) ProcessedStudy { private: // Corresponding Study object. Weak reference. - const Study* study_ = nullptr; + raw_ptr<const Study> study_ = nullptr; // Computed total group probability for the study. base::FieldTrial::Probability total_probability_ = 0; diff --git a/chromium/components/variations/service/safe_seed_manager.cc b/chromium/components/variations/service/safe_seed_manager.cc index 641db31aff7..113a7bf1604 100644 --- a/chromium/components/variations/service/safe_seed_manager.cc +++ b/chromium/components/variations/service/safe_seed_manager.cc @@ -88,14 +88,15 @@ bool SafeSeedManager::ShouldRunInSafeMode() const { void SafeSeedManager::SetActiveSeedState( const std::string& seed_data, const std::string& base64_seed_signature, + int seed_milestone, std::unique_ptr<ClientFilterableState> client_filterable_state, base::Time seed_fetch_time) { DCHECK(!has_set_active_seed_state_); has_set_active_seed_state_ = true; active_seed_state_ = std::make_unique<ActiveSeedState>( - seed_data, base64_seed_signature, std::move(client_filterable_state), - seed_fetch_time); + seed_data, base64_seed_signature, seed_milestone, + std::move(client_filterable_state), seed_fetch_time); } void SafeSeedManager::RecordFetchStarted() { @@ -117,6 +118,7 @@ void SafeSeedManager::RecordSuccessfulFetch(VariationsSeedStore* seed_store) { if (active_seed_state_) { seed_store->StoreSafeSeed(active_seed_state_->seed_data, active_seed_state_->base64_seed_signature, + active_seed_state_->seed_milestone, *active_seed_state_->client_filterable_state, active_seed_state_->seed_fetch_time); @@ -136,10 +138,12 @@ void SafeSeedManager::RecordSuccessfulFetch(VariationsSeedStore* seed_store) { SafeSeedManager::ActiveSeedState::ActiveSeedState( const std::string& seed_data, const std::string& base64_seed_signature, + int seed_milestone, std::unique_ptr<ClientFilterableState> client_filterable_state, base::Time seed_fetch_time) : seed_data(seed_data), base64_seed_signature(base64_seed_signature), + seed_milestone(seed_milestone), client_filterable_state(std::move(client_filterable_state)), seed_fetch_time(seed_fetch_time) {} diff --git a/chromium/components/variations/service/safe_seed_manager.h b/chromium/components/variations/service/safe_seed_manager.h index 95173c17789..5c3bd660bd9 100644 --- a/chromium/components/variations/service/safe_seed_manager.h +++ b/chromium/components/variations/service/safe_seed_manager.h @@ -8,7 +8,7 @@ #include <memory> #include <string> -#include "base/macros.h" +#include "base/memory/raw_ptr.h" #include "base/time/time.h" class PrefRegistrySimple; @@ -57,12 +57,13 @@ class SafeSeedManager { virtual bool ShouldRunInSafeMode() const; // Stores the combined server and client state that control the active - // variations state. Must be called at most once per launch of the Chrome app. - // As an optimization, should not be called when running in safe mode. + // variations state. May be called at most once per Chrome app launch. As an + // optimization, should not be called when running in safe mode. // Virtual for testing. virtual void SetActiveSeedState( const std::string& seed_data, const std::string& base64_seed_signature, + int seed_milestone, std::unique_ptr<ClientFilterableState> client_filterable_state, base::Time seed_fetch_time); @@ -82,6 +83,7 @@ class SafeSeedManager { ActiveSeedState( const std::string& seed_data, const std::string& base64_seed_signature, + int seed_milestone, std::unique_ptr<ClientFilterableState> client_filterable_state, base::Time seed_fetch_time); ~ActiveSeedState(); @@ -92,6 +94,9 @@ class SafeSeedManager { // The base64-encoded signature for the seed data. const std::string base64_seed_signature; + // The milestone with which the active seed was fetched. + const int seed_milestone; + // The client state which is used for filtering studies. const std::unique_ptr<ClientFilterableState> client_filterable_state; @@ -106,7 +111,7 @@ class SafeSeedManager { // The pref service used to persist the variations seed. Weak reference; must // outlive |this| instance. - PrefService* local_state_; + raw_ptr<PrefService> local_state_; }; } // namespace variations diff --git a/chromium/components/variations/service/safe_seed_manager_unittest.cc b/chromium/components/variations/service/safe_seed_manager_unittest.cc index 94ecf9a419f..1aa1c327306 100644 --- a/chromium/components/variations/service/safe_seed_manager_unittest.cc +++ b/chromium/components/variations/service/safe_seed_manager_unittest.cc @@ -9,7 +9,6 @@ #include "base/base_switches.h" #include "base/command_line.h" -#include "base/macros.h" #include "base/test/metrics/histogram_tester.h" #include "base/time/time.h" #include "components/metrics/clean_exit_beacon.h" @@ -25,6 +24,7 @@ namespace { const char kTestSeed[] = "compressed, base-64 encoded serialized seed data"; const char kTestSignature[] = "a completely unforged signature, I promise!"; +const int kTestSeedMilestone = 92; const char kTestLocale[] = "en-US"; const char kTestPermanentConsistencyCountry[] = "US"; const char kTestSessionConsistencyCountry[] = "CA"; @@ -36,8 +36,10 @@ base::Time GetTestFetchTime() { // A simple fake data store. class FakeSeedStore : public VariationsSeedStore { public: - explicit FakeSeedStore(PrefService* local_state) - : VariationsSeedStore(local_state) {} + explicit FakeSeedStore(TestingPrefServiceSimple* local_state) + : VariationsSeedStore(local_state) { + VariationsSeedStore::RegisterPrefs(local_state->registry()); + } FakeSeedStore(const FakeSeedStore&) = delete; FakeSeedStore& operator=(const FakeSeedStore&) = delete; @@ -46,10 +48,12 @@ class FakeSeedStore : public VariationsSeedStore { bool StoreSafeSeed(const std::string& seed_data, const std::string& base64_seed_signature, + int seed_milestone, const ClientFilterableState& client_state, base::Time seed_fetch_time) override { seed_data_ = seed_data; signature_ = base64_seed_signature; + seed_milestone_ = seed_milestone; date_ = client_state.reference_date; locale_ = client_state.locale; permanent_consistency_country_ = client_state.permanent_consistency_country; @@ -60,6 +64,7 @@ class FakeSeedStore : public VariationsSeedStore { const std::string& seed_data() const { return seed_data_; } const std::string& signature() const { return signature_; } + int seed_milestone() const { return seed_milestone_; } const base::Time& date() const { return date_; } const std::string& locale() const { return locale_; } const std::string& permanent_consistency_country() const { @@ -74,6 +79,7 @@ class FakeSeedStore : public VariationsSeedStore { // The stored data. std::string seed_data_; std::string signature_; + int seed_milestone_ = 0; base::Time date_; std::string locale_; std::string permanent_consistency_country_; @@ -81,9 +87,10 @@ class FakeSeedStore : public VariationsSeedStore { base::Time fetch_time_; }; -// Passes the default test values as the active state into the -// |safe_seed_manager|. -void SetDefaultActiveState(SafeSeedManager* safe_seed_manager) { +// Passes the default test values as the active state into |safe_seed_manager| +// and |local_state|. +void SetDefaultActiveState(SafeSeedManager* safe_seed_manager, + PrefService* local_state) { std::unique_ptr<ClientFilterableState> client_state = std::make_unique<ClientFilterableState>( base::BindOnce([] { return false; })); @@ -93,14 +100,18 @@ void SetDefaultActiveState(SafeSeedManager* safe_seed_manager) { client_state->session_consistency_country = kTestSessionConsistencyCountry; client_state->reference_date = base::Time::UnixEpoch(); + local_state->SetInteger(prefs::kVariationsSeedMilestone, kTestSeedMilestone); + safe_seed_manager->SetActiveSeedState( - kTestSeed, kTestSignature, std::move(client_state), GetTestFetchTime()); + kTestSeed, kTestSignature, kTestSeedMilestone, std::move(client_state), + GetTestFetchTime()); } // Verifies that the default test values were written to the seed store. void ExpectDefaultActiveState(const FakeSeedStore& seed_store) { EXPECT_EQ(kTestSeed, seed_store.seed_data()); EXPECT_EQ(kTestSignature, seed_store.signature()); + EXPECT_EQ(kTestSeedMilestone, seed_store.seed_milestone()); EXPECT_EQ(kTestLocale, seed_store.locale()); EXPECT_EQ(kTestPermanentConsistencyCountry, seed_store.permanent_consistency_country()); @@ -126,36 +137,34 @@ class SafeSeedManagerTest : public testing::Test { TEST_F(SafeSeedManagerTest, RecordSuccessfulFetch_FirstCallSavesSafeSeed) { SafeSeedManager safe_seed_manager(&prefs_); - SetDefaultActiveState(&safe_seed_manager); - FakeSeedStore seed_store(&prefs_); - safe_seed_manager.RecordSuccessfulFetch(&seed_store); + SetDefaultActiveState(&safe_seed_manager, &prefs_); + safe_seed_manager.RecordSuccessfulFetch(&seed_store); ExpectDefaultActiveState(seed_store); } TEST_F(SafeSeedManagerTest, RecordSuccessfulFetch_RepeatedCallsRetainSafeSeed) { SafeSeedManager safe_seed_manager(&prefs_); - SetDefaultActiveState(&safe_seed_manager); - FakeSeedStore seed_store(&prefs_); + SetDefaultActiveState(&safe_seed_manager, &prefs_); + safe_seed_manager.RecordSuccessfulFetch(&seed_store); safe_seed_manager.RecordSuccessfulFetch(&seed_store); safe_seed_manager.RecordSuccessfulFetch(&seed_store); - ExpectDefaultActiveState(seed_store); } TEST_F(SafeSeedManagerTest, RecordSuccessfulFetch_NoActiveState_DoesntSaveSafeSeed) { SafeSeedManager safe_seed_manager(&prefs_); + FakeSeedStore seed_store(&prefs_); // Omit setting any active state. - FakeSeedStore seed_store(&prefs_); safe_seed_manager.RecordSuccessfulFetch(&seed_store); - EXPECT_EQ(std::string(), seed_store.seed_data()); EXPECT_EQ(std::string(), seed_store.signature()); + EXPECT_EQ(0, seed_store.seed_milestone()); EXPECT_EQ(std::string(), seed_store.locale()); EXPECT_EQ(std::string(), seed_store.permanent_consistency_country()); EXPECT_EQ(std::string(), seed_store.session_consistency_country()); diff --git a/chromium/components/variations/service/ui_string_overrider.h b/chromium/components/variations/service/ui_string_overrider.h index c02cc59c405..a1cda9c7471 100644 --- a/chromium/components/variations/service/ui_string_overrider.h +++ b/chromium/components/variations/service/ui_string_overrider.h @@ -8,8 +8,6 @@ #include <stddef.h> #include <stdint.h> -#include "base/macros.h" - namespace variations { // Provides a mapping from hashes of generated resource names to their IDs. The diff --git a/chromium/components/variations/service/ui_string_overrider_unittest.cc b/chromium/components/variations/service/ui_string_overrider_unittest.cc index 1ea2539a077..f8b6bc437c6 100644 --- a/chromium/components/variations/service/ui_string_overrider_unittest.cc +++ b/chromium/components/variations/service/ui_string_overrider_unittest.cc @@ -7,7 +7,6 @@ #include <stddef.h> #include <stdint.h> -#include "base/macros.h" #include "testing/gtest/include/gtest/gtest.h" namespace variations { diff --git a/chromium/components/variations/service/variations_field_trial_creator.cc b/chromium/components/variations/service/variations_field_trial_creator.cc index 30d8b8a0d9b..86461fd574c 100644 --- a/chromium/components/variations/service/variations_field_trial_creator.cc +++ b/chromium/components/variations/service/variations_field_trial_creator.cc @@ -41,6 +41,7 @@ #include "components/variations/variations_seed_processor.h" #include "components/variations/variations_switches.h" #include "components/version_info/channel.h" +#include "components/version_info/version_info.h" #include "ui/base/device_form_factor.h" #include "ui/base/l10n/l10n_util.h" #include "ui/base/resource/resource_bundle.h" @@ -173,7 +174,7 @@ std::string VariationsFieldTrialCreator::GetLatestCountry() const { : local_state()->GetString(prefs::kVariationsCountry); } -bool VariationsFieldTrialCreator::SetupFieldTrials( +bool VariationsFieldTrialCreator::SetUpFieldTrials( const std::vector<std::string>& variation_ids, const std::vector<base::FeatureList::FeatureOverrideInfo>& extra_overrides, std::unique_ptr<const base::FieldTrial::EntropyProvider> @@ -189,36 +190,6 @@ bool VariationsFieldTrialCreator::SetupFieldTrials( DCHECK(platform_field_trials); DCHECK(safe_seed_manager); - const base::CommandLine* command_line = - base::CommandLine::ForCurrentProcess(); - if (command_line->HasSwitch(switches::kForceFieldTrialParams)) { - bool result = AssociateParamsFromString( - command_line->GetSwitchValueASCII(switches::kForceFieldTrialParams)); - if (!result) { - // Some field trial params implement things like csv or json with a - // particular param. If some control characters are not %-encoded, it can - // lead to confusing error messages, so add a hint here. - ExitWithMessage(base::StringPrintf( - "Invalid --%s list specified. Make sure you %%-" - "encode the following characters in param values: %%:/.,", - switches::kForceFieldTrialParams)); - } - } - - // Ensure any field trials specified on the command line are initialized. - if (command_line->HasSwitch(::switches::kForceFieldTrials)) { - // Create field trials without activating them, so that this behaves in a - // consistent manner with field trials created from the server. - bool result = base::FieldTrialList::CreateTrialsFromString( - command_line->GetSwitchValueASCII(::switches::kForceFieldTrials)); - if (!result) { - ExitWithMessage(base::StringPrintf("Invalid --%s list specified.", - ::switches::kForceFieldTrials)); - } - } - -#if !defined(OS_ANDROID) - // TODO(crbug/1248239): Enable Extended Variations Safe Mode on Android. if (extend_variations_safe_mode && !metrics_state_manager->is_background_session()) { // If the session is expected to be a background session, then do not extend @@ -228,11 +199,15 @@ bool VariationsFieldTrialCreator::SetupFieldTrials( // crashes. MaybeExtendVariationsSafeMode(metrics_state_manager); } -#endif + // TODO(crbug/1257204): Some FieldTrial-setup-related code is here and some is + // in MetricsStateManager::InstantiateFieldTrialList(). It's not ideal that + // it's in two places. VariationsIdsProvider* http_header_provider = VariationsIdsProvider::GetInstance(); http_header_provider->SetLowEntropySourceValue(low_entropy_source_value); + const base::CommandLine* command_line = + base::CommandLine::ForCurrentProcess(); // Force the variation ids selected in chrome://flags and/or specified using // the command-line flag. auto result = http_header_provider->ForceVariationIds( @@ -291,7 +266,7 @@ bool VariationsFieldTrialCreator::SetupFieldTrials( feature_list.get(), safe_seed_manager); } - platform_field_trials->SetupFeatureControllingFieldTrials( + platform_field_trials->SetUpFeatureControllingFieldTrials( used_seed, low_entropy_provider.get(), feature_list.get()); base::FeatureList::SetInstance(std::move(feature_list)); @@ -305,7 +280,7 @@ bool VariationsFieldTrialCreator::SetupFieldTrials( } // This must be called after |local_state_| is initialized. - platform_field_trials->SetupFieldTrials(); + platform_field_trials->SetUpFieldTrials(); return used_seed; } @@ -370,24 +345,25 @@ std::string VariationsFieldTrialCreator::LoadPermanentConsistencyCountry( const base::ListValue* list_value = local_state()->GetList(prefs::kVariationsPermanentConsistencyCountry); - std::string stored_version_string; - std::string stored_country; + const std::string* stored_version_string = nullptr; + const std::string* stored_country = nullptr; // Determine if the saved pref value is present and valid. const bool is_pref_empty = list_value->GetList().empty(); - const bool is_pref_valid = list_value->GetList().size() == 2 && - list_value->GetString(0, &stored_version_string) && - list_value->GetString(1, &stored_country) && - base::Version(stored_version_string).IsValid(); + const bool is_pref_valid = + list_value->GetList().size() == 2 && + (stored_version_string = list_value->GetList()[0].GetIfString()) && + (stored_country = list_value->GetList()[1].GetIfString()) && + base::Version(*stored_version_string).IsValid(); // Determine if the version from the saved pref matches |version|. const bool does_version_match = - is_pref_valid && version == base::Version(stored_version_string); + is_pref_valid && version == base::Version(*stored_version_string); // Determine if the country in the saved pref matches the country in // |latest_country|. const bool does_country_match = is_pref_valid && !latest_country.empty() && - stored_country == latest_country; + *stored_country == latest_country; // Record a histogram for how the saved pref value compares to the current // version and the country code in the variations seed. @@ -414,7 +390,7 @@ std::string VariationsFieldTrialCreator::LoadPermanentConsistencyCountry( // Use the stored country if one is available and was fetched since the last // time Chrome was updated. if (does_version_match) - return stored_country; + return *stored_country; if (latest_country.empty()) { if (!is_pref_valid) @@ -469,6 +445,27 @@ bool VariationsFieldTrialCreator::IsOverrideResourceMapEmpty() { return overridden_strings_map_.empty(); } +void VariationsFieldTrialCreator::MaybeExtendVariationsSafeMode( + metrics::MetricsStateManager* metrics_state_manager) { + const std::string group_name = + base::FieldTrialList::FindFullName(kExtendedSafeModeTrial); + if (group_name.empty() || group_name == kDefaultGroup) + return; + + if (group_name == kControlGroup) { + // Populate the histogram for the control group to more easily compare it + // with the groups that introduce new behavior. + SCOPED_UMA_HISTOGRAM_TIMER_MICROS( + "Variations.ExtendedSafeMode.WritePrefsTime"); + return; + } + + DCHECK_EQ(group_name, kSignalAndWriteViaFileUtilGroup); + metrics_state_manager->LogHasSessionShutdownCleanly( + /*has_session_shutdown_cleanly=*/false, + /*write_synchronously=*/true); +} + bool VariationsFieldTrialCreator::HasSeedExpired(bool is_safe_seed) { const base::Time fetch_time = is_safe_seed ? GetSeedStore()->GetSafeSeedFetchTime() @@ -499,6 +496,21 @@ bool VariationsFieldTrialCreator::HasSeedExpired(bool is_safe_seed) { return has_seed_expired; } +bool VariationsFieldTrialCreator::IsSeedForFutureMilestone(bool is_safe_seed) { + const std::string milestone_pref = is_safe_seed + ? prefs::kVariationsSafeSeedMilestone + : prefs::kVariationsSeedMilestone; + + // The regular and safe seed milestone prefs were added in M97, so the prefs + // are not populated for seeds stored before then. + int seed_milestone = local_state()->GetInteger(milestone_pref); + if (!seed_milestone) + return false; + + int client_milestone = version_info::GetMajorVersionNumberAsInt(); + return seed_milestone > client_milestone; +} + bool VariationsFieldTrialCreator::CreateTrialsFromSeed( const base::FieldTrial::EntropyProvider* low_entropy_provider, base::FeatureList* feature_list, @@ -528,10 +540,17 @@ bool VariationsFieldTrialCreator::CreateTrialsFromSeed( LoadSeedResult result = GetSeedStore()->LoadSafeSeed(&seed, client_filterable_state.get()); if (result == LoadSeedResult::kSuccess) { + // TODO(crbug/1261685): The expiry and milestone checks are repeated below + // for regular seeds. Refactor this. if (HasSeedExpired(/*is_safe_seed=*/true)) { RecordVariationsSeedUsage(SeedUsage::kExpiredSafeSeedNotUsed); return false; } + if (IsSeedForFutureMilestone(/*is_safe_seed=*/true)) { + RecordVariationsSeedUsage( + SeedUsage::kSafeSeedForFutureMilestoneNotUsed); + return false; + } RecordVariationsSeedUsage(SeedUsage::kSafeSeedUsed); run_in_safe_mode = true; // This line is a no-op. Added for clarity. } else if (result == LoadSeedResult::kEmpty) { @@ -559,6 +578,11 @@ bool VariationsFieldTrialCreator::CreateTrialsFromSeed( RecordVariationsSeedUsage(seed_usage); return false; } + if (IsSeedForFutureMilestone(/*is_safe_seed=*/false)) { + RecordVariationsSeedUsage( + SeedUsage::kRegularSeedForFutureMilestoneNotUsed); + return false; + } seed_usage = should_run_in_safe_mode ? SeedUsage::kRegularSeedUsedAfterEmptySafeSeedLoaded : SeedUsage::kRegularSeedUsed; @@ -589,13 +613,15 @@ bool VariationsFieldTrialCreator::CreateTrialsFromSeed( // running in safe mode – once running in safe mode, there can never be a need // to save the active state to the safe seed prefs. if (!run_in_safe_mode) { - safe_seed_manager->SetActiveSeedState(seed_data, base64_seed_signature, - std::move(client_filterable_state), - seed_store_->GetLastFetchTime()); + safe_seed_manager->SetActiveSeedState( + seed_data, base64_seed_signature, + local_state()->GetInteger(prefs::kVariationsSeedMilestone), + std::move(client_filterable_state), seed_store_->GetLastFetchTime()); } - UMA_HISTOGRAM_TIMES("Variations.SeedProcessingTime", - base::TimeTicks::Now() - start_time); + base::UmaHistogramCounts1M("Variations.AppliedSeed.Size", seed_data.size()); + base::UmaHistogramTimes("Variations.SeedProcessingTime", + base::TimeTicks::Now() - start_time); return true; } @@ -630,43 +656,4 @@ Study::Platform VariationsFieldTrialCreator::GetPlatform() { return ClientFilterableState::GetCurrentPlatform(); } -#if !defined(OS_ANDROID) -void VariationsFieldTrialCreator::MaybeExtendVariationsSafeMode( - metrics::MetricsStateManager* metrics_state_manager) const { - version_info::Channel channel = client_->GetChannelForVariations(); - if (channel != version_info::Channel::UNKNOWN && - channel != version_info::Channel::CANARY && - channel != version_info::Channel::DEV) { - return; - } - - int default_group; - scoped_refptr<base::FieldTrial> trial( - base::FieldTrialList::FactoryGetFieldTrial( - kExtendedSafeModeTrial, 100, kDefaultGroup, - base::FieldTrial::ONE_TIME_RANDOMIZED, &default_group)); - - const int control_group = trial->AppendGroup(kControlGroup, 25); - const int write_only_group = - trial->AppendGroup(kWriteSynchronouslyViaPrefServiceGroup, 25); - trial->AppendGroup(kSignalAndWriteSynchronouslyViaPrefServiceGroup, 25); - trial->AppendGroup(kSignalAndWriteViaFileUtilGroup, 25); - const int assigned_group = trial->group(); - - if (assigned_group == control_group) - return; - - // For clients in the SignalAndWrite* groups, the beacon is updated and a - // synchronous write is performed. Conversely, for clients in - // |write_only_group|, i.e. the WriteSynchronouslyViaPrefService group, prefs - // are written synchronously without updating the beacon, i.e. without - // signaling that Chrome should start watching for crashes. - bool update_beacon = assigned_group != write_only_group; - - metrics_state_manager->LogHasSessionShutdownCleanly( - /*has_session_shutdown_cleanly=*/false, /*write_synchronously=*/true, - update_beacon); -} -#endif // !defined(OS_ANDROID) - } // namespace variations diff --git a/chromium/components/variations/service/variations_field_trial_creator.h b/chromium/components/variations/service/variations_field_trial_creator.h index 463fac1acaf..8baf0c6500b 100644 --- a/chromium/components/variations/service/variations_field_trial_creator.h +++ b/chromium/components/variations/service/variations_field_trial_creator.h @@ -11,7 +11,7 @@ #include <vector> #include "base/compiler_specific.h" -#include "base/macros.h" +#include "base/memory/raw_ptr.h" #include "base/metrics/field_trial.h" #include "base/time/time.h" #include "build/build_config.h" @@ -44,7 +44,9 @@ enum class SeedUsage { kRegularSeedUsedAfterEmptySafeSeedLoaded = 6, kExpiredRegularSeedNotUsedAfterEmptySafeSeedLoaded = 7, kCorruptedRegularSeedNotUsedAfterEmptySafeSeedLoaded = 8, - kMaxValue = kCorruptedRegularSeedNotUsedAfterEmptySafeSeedLoaded, + kRegularSeedForFutureMilestoneNotUsed = 9, + kSafeSeedForFutureMilestoneNotUsed = 10, + kMaxValue = kSafeSeedForFutureMilestoneNotUsed, }; // Denotes a variations seed's expiry state. Exposed for testing. @@ -77,7 +79,7 @@ class PlatformFieldTrials; class SafeSeedManager; class VariationsServiceClient; -// Used to setup field trials based on stored variations seed data. +// Used to set up field trials based on stored variations seed data. class VariationsFieldTrialCreator { public: // Caller is responsible for ensuring that objects passed to the constructor @@ -128,7 +130,7 @@ class VariationsFieldTrialCreator { // explicit --disable-features and --enable-features from the command line // take precedence over |extra_overrides|, which takes precedence over the // field trials. - bool SetupFieldTrials( + bool SetUpFieldTrials( const std::vector<std::string>& variation_ids, const std::vector<base::FeatureList::FeatureOverrideInfo>& extra_overrides, @@ -176,6 +178,14 @@ class VariationsFieldTrialCreator { // Returns the locale that was used for evaluating trials. const std::string& application_locale() const { return application_locale_; } + protected: + // If the client is in an Extended Variations Safe Mode experiment group, + // applies group-specific behavior. Does nothing if the client is not in the + // experiment. See CleanExitBeacon::Initialize() for group assignment details. + // Protected and virtual for testing. + virtual void MaybeExtendVariationsSafeMode( + metrics::MetricsStateManager* metrics_state_manager); + private: // Returns true if the loaded VariationsSeed has expired. An expired seed is // one that (a) was fetched over |kMaxVariationsSeedAgeDays| ago and (b) is @@ -184,6 +194,12 @@ class VariationsFieldTrialCreator { // Also, records a couple VariationsSeed-related metrics. bool HasSeedExpired(bool is_safe_seed); + // Returns true if the loaded VariationsSeed is for a future milestone (e.g. + // if the client is on M92 and the seed was fetched with M93). A seed for a + // future milestone is invalid as it may be missing studies filtered out by + // the server. + bool IsSeedForFutureMilestone(bool is_safe_seed); + // Creates field trials based on the variations seed loaded from local state. // If there is a problem loading the seed data, all trials specified by the // seed may not be created. Some field trials are configured to override or @@ -209,18 +225,10 @@ class VariationsFieldTrialCreator { // Get the platform we're running on, respecting OverrideVariationsPlatform(). Study::Platform GetPlatform(); -#if !defined(OS_ANDROID) - // On channels that support the ExtendedVariationsSafeMode experiment, (a) - // assigns the client to an experiment group and (b) applies group-specific - // behavior. Does nothing if the channel does not support the experiment. - void MaybeExtendVariationsSafeMode( - metrics::MetricsStateManager* metrics_state_manager) const; -#endif - PrefService* local_state() { return seed_store_->local_state(); } const PrefService* local_state() const { return seed_store_->local_state(); } - VariationsServiceClient* client_; + raw_ptr<VariationsServiceClient> client_; UIStringOverrider ui_string_overrider_; diff --git a/chromium/components/variations/service/variations_field_trial_creator_unittest.cc b/chromium/components/variations/service/variations_field_trial_creator_unittest.cc index 6c73d8563c0..4daa6a05659 100644 --- a/chromium/components/variations/service/variations_field_trial_creator_unittest.cc +++ b/chromium/components/variations/service/variations_field_trial_creator_unittest.cc @@ -5,17 +5,17 @@ #include "components/variations/service/variations_field_trial_creator.h" #include <stddef.h> +#include <cstring> #include <memory> #include <utility> #include "base/callback.h" #include "base/callback_helpers.h" -#include "base/containers/contains.h" #include "base/feature_list.h" #include "base/files/file_path.h" #include "base/files/file_util.h" #include "base/files/scoped_temp_dir.h" -#include "base/macros.h" +#include "base/memory/raw_ptr.h" #include "base/test/metrics/histogram_tester.h" #include "base/test/mock_entropy_provider.h" #include "base/test/scoped_field_trial_list_resetter.h" @@ -23,7 +23,6 @@ #include "base/time/time.h" #include "base/version.h" #include "build/build_config.h" -#include "components/metrics/clean_exit_beacon.h" #include "components/metrics/client_info.h" #include "components/metrics/metrics_service.h" #include "components/metrics/metrics_state_manager.h" @@ -40,7 +39,6 @@ #include "components/variations/service/variations_service.h" #include "components/variations/service/variations_service_client.h" #include "components/variations/variations_seed_store.h" -#include "components/variations/variations_switches.h" #include "components/variations/variations_test_utils.h" #include "components/version_info/channel.h" #include "components/version_info/version_info.h" @@ -50,7 +48,7 @@ #if defined(OS_ANDROID) #include "components/variations/seed_response.h" -#endif // OS_ANDROID +#endif namespace variations { namespace { @@ -70,11 +68,10 @@ const char kTestSeedSerialNumber[] = "123"; // Constants used to mock the serialized seed state. const char kTestSeedSerializedData[] = "a serialized seed, 100% realistic"; const char kTestSeedSignature[] = "a totally valid signature, I swear!"; +const int kTestSeedMilestone = 90; -#if !defined(OS_ANDROID) // The content of an empty prefs file. const char kEmptyPrefsFile[] = "{}"; -#endif // !defined(OS_ANDROID) // Used for similar tests. struct TestParams { @@ -83,8 +80,8 @@ struct TestParams { const base::Time binary_build_time; }; -// Populates |seed| with simple test data. The resulting seed will contain one -// study called "test", which contains one experiment called "abc" with +// Returns a seed with simple test data. The seed has a single study, +// "UMA-Uniformity-Trial-10-Percent", which has a single experiment, "abc", with // probability weight 100. VariationsSeed CreateTestSeed() { VariationsSeed seed; @@ -98,11 +95,12 @@ VariationsSeed CreateTestSeed() { return seed; } -// Returns a seed containing simple test data. The resulting seed will contain -// one study called "test", which contains one experiment called "abc.safe" with -// probability weight 100. This is intended to be used whenever a "safe" seed is -// called for, so that test expectations can distinguish between a "safe" seed -// and a "latest" seed. +// Returns a seed with simple test data. The seed has a single study, +// "UMA-Uniformity-Trial-10-Percent", which has a single experiment, +// "abc.safe", with probability weight 100. +// +// Intended to be used when a "safe" seed is needed so that test expectations +// can distinguish between a regular and safe seeds. VariationsSeed CreateTestSafeSeed() { VariationsSeed seed = CreateTestSeed(); Study* study = seed.mutable_study(0); @@ -133,7 +131,7 @@ std::string SerializeSeed(const VariationsSeed& seed) { seed.SerializeToString(&serialized_seed); return serialized_seed; } -#endif // OS_ANDROID +#endif // defined(OS_ANDROID) class TestPlatformFieldTrials : public PlatformFieldTrials { public: @@ -145,8 +143,8 @@ class TestPlatformFieldTrials : public PlatformFieldTrials { ~TestPlatformFieldTrials() override = default; // PlatformFieldTrials: - void SetupFieldTrials() override {} - void SetupFeatureControllingFieldTrials( + void SetUpFieldTrials() override {} + void SetUpFeatureControllingFieldTrials( bool has_seed, const base::FieldTrial::EntropyProvider* low_entropy_provider, base::FeatureList* feature_list) override {} @@ -163,18 +161,20 @@ class MockSafeSeedManager : public SafeSeedManager { ~MockSafeSeedManager() override = default; MOCK_CONST_METHOD0(ShouldRunInSafeMode, bool()); - MOCK_METHOD4(DoSetActiveSeedState, + MOCK_METHOD5(DoSetActiveSeedState, void(const std::string& seed_data, const std::string& base64_seed_signature, + int seed_milestone, ClientFilterableState* client_filterable_state, base::Time seed_fetch_time)); void SetActiveSeedState( const std::string& seed_data, const std::string& base64_seed_signature, + int seed_milestone, std::unique_ptr<ClientFilterableState> client_filterable_state, base::Time seed_fetch_time) override { - DoSetActiveSeedState(seed_data, base64_seed_signature, + DoSetActiveSeedState(seed_data, base64_seed_signature, seed_milestone, client_filterable_state.get(), seed_fetch_time); } }; @@ -210,10 +210,7 @@ class TestVariationsServiceClient : public VariationsServiceClient { private: // VariationsServiceClient: version_info::Channel GetChannel() override { - // Set to stable to skip logic related to the Extended Variations Safe Mode - // experiment. - // TODO(crbug/1241702): Clean this up once the experiment is done. - return version_info::Channel::STABLE; + return version_info::Channel::UNKNOWN; } std::string restrict_parameter_; @@ -277,6 +274,7 @@ class TestVariationsFieldTrialCreator : public VariationsFieldTrialCreator { PrefService* local_state, TestVariationsServiceClient* client, SafeSeedManager* safe_seed_manager, + version_info::Channel channel = version_info::Channel::UNKNOWN, const base::FilePath user_data_dir = base::FilePath(), metrics::StartupVisibility startup_visibility = metrics::StartupVisibility::kUnknown) @@ -290,7 +288,7 @@ class TestVariationsFieldTrialCreator : public VariationsFieldTrialCreator { build_time_(base::Time::Now()) { metrics_state_manager_ = metrics::MetricsStateManager::Create( local_state, &enabled_state_provider_, std::wstring(), user_data_dir, - startup_visibility); + startup_visibility, channel); metrics_state_manager_->InstantiateFieldTrialList(); } @@ -301,11 +299,11 @@ class TestVariationsFieldTrialCreator : public VariationsFieldTrialCreator { ~TestVariationsFieldTrialCreator() override = default; - // A convenience wrapper around SetupFieldTrials() which passes default values + // A convenience wrapper around SetUpFieldTrials() which passes default values // for uninteresting params. - bool SetupFieldTrials(bool extend_variations_safe_mode = true) { + bool SetUpFieldTrials(bool extend_variations_safe_mode = true) { TestPlatformFieldTrials platform_field_trials; - return VariationsFieldTrialCreator::SetupFieldTrials( + return VariationsFieldTrialCreator::SetUpFieldTrials( /*variation_ids=*/std::vector<std::string>(), std::vector<base::FeatureList::FeatureOverrideInfo>(), /*low_entropy_provider=*/nullptr, std::make_unique<base::FeatureList>(), @@ -316,6 +314,17 @@ class TestVariationsFieldTrialCreator : public VariationsFieldTrialCreator { TestVariationsSeedStore* seed_store() { return &seed_store_; } void SetBuildTime(const base::Time& time) { build_time_ = time; } + bool was_maybe_extend_variations_safe_mode_called() { + return was_maybe_extend_variations_safe_mode_called_; + } + + protected: + void MaybeExtendVariationsSafeMode( + metrics::MetricsStateManager* metrics_state_manager) override { + was_maybe_extend_variations_safe_mode_called_ = true; + VariationsFieldTrialCreator::MaybeExtendVariationsSafeMode( + metrics_state_manager); + } private: VariationsSeedStore* GetSeedStore() override { return &seed_store_; } @@ -323,9 +332,10 @@ class TestVariationsFieldTrialCreator : public VariationsFieldTrialCreator { metrics::TestEnabledStateProvider enabled_state_provider_; TestVariationsSeedStore seed_store_; - SafeSeedManager* const safe_seed_manager_; + const raw_ptr<SafeSeedManager> safe_seed_manager_; base::Time build_time_; std::unique_ptr<metrics::MetricsStateManager> metrics_state_manager_; + bool was_maybe_extend_variations_safe_mode_called_ = false; }; } // namespace @@ -366,8 +376,6 @@ class FieldTrialCreatorTest : public ::testing::Test { std::unique_ptr<base::FeatureList> global_feature_list_; }; -#if !defined(OS_ANDROID) -// TODO(crbug/1248239): Enable Extended Variations Safe Mode on Android. class FieldTrialCreatorSafeModeExperimentTest : public FieldTrialCreatorTest { public: FieldTrialCreatorSafeModeExperimentTest() @@ -399,26 +407,6 @@ class FieldTrialCreatorSafeModeExperimentTest : public FieldTrialCreatorTest { return pref_service_factory.Create(pref_registry); } - // Sets up the extended safe mode experiment such that |group_name| is the - // active group. Returns the numeric value that denotes the active group. - int SetUpExtendedSafeModeExperiment(const std::string& group_name) { - int default_group; - scoped_refptr<base::FieldTrial> trial( - base::FieldTrialList::FactoryGetFieldTrial( - kExtendedSafeModeTrial, 100, kDefaultGroup, - base::FieldTrial::ONE_TIME_RANDOMIZED, &default_group)); - - int active_group; - if (group_name == kDefaultGroup) { - active_group = default_group; - } else { - active_group = trial->AppendGroup(group_name, 100); - } - - trial->SetForced(); - return active_group; - } - const base::FilePath prefs_file() const { return prefs_file_; } const base::FilePath user_data_dir_path() const { return temp_dir_.GetPath(); @@ -435,16 +423,15 @@ class FieldTrialCreatorSafeModeExperimentTest : public FieldTrialCreatorTest { struct StartupVisibilityTestParams { const std::string test_name; metrics::StartupVisibility startup_visibility; - bool is_trial_active; + bool extend_safe_mode; }; class FieldTrialCreatorTestWithStartupVisibility : public FieldTrialCreatorSafeModeExperimentTest, public ::testing::WithParamInterface<StartupVisibilityTestParams> {}; -#endif // !defined(OS_ANDROID) // Verify that unexpired seeds are used. -TEST_F(FieldTrialCreatorTest, SetupFieldTrials_ValidSeed_NotExpired) { +TEST_F(FieldTrialCreatorTest, SetUpFieldTrials_ValidSeed_NotExpired) { DisableTestingConfig(); const base::Time now = base::Time::Now(); @@ -463,9 +450,10 @@ TEST_F(FieldTrialCreatorTest, SetupFieldTrials_ValidSeed_NotExpired) { NiceMock<MockSafeSeedManager> safe_seed_manager(&prefs_); ON_CALL(safe_seed_manager, ShouldRunInSafeMode()) .WillByDefault(Return(false)); - EXPECT_CALL(safe_seed_manager, - DoSetActiveSeedState(kTestSeedSerializedData, - kTestSeedSignature, _, seed_fetch_time)) + EXPECT_CALL( + safe_seed_manager, + DoSetActiveSeedState(kTestSeedSerializedData, kTestSeedSignature, + kTestSeedMilestone, _, seed_fetch_time)) .Times(1); TestVariationsServiceClient variations_service_client; @@ -476,11 +464,14 @@ TEST_F(FieldTrialCreatorTest, SetupFieldTrials_ValidSeed_NotExpired) { // Simulate the seed being stored. prefs_.SetTime(prefs::kVariationsLastFetchTime, seed_fetch_time); + // Simulate a seed from an earlier (i.e. valid) milestone. + prefs_.SetInteger(prefs::kVariationsSeedMilestone, kTestSeedMilestone); + // Check that field trials are created from the seed. Since the test study // has only one experiment with 100% probability weight, we must be part of // it. base::HistogramTester histogram_tester; - EXPECT_TRUE(field_trial_creator.SetupFieldTrials()); + EXPECT_TRUE(field_trial_creator.SetUpFieldTrials()); EXPECT_EQ(kTestSeedExperimentName, base::FieldTrialList::FindFullName(kTestSeedStudyName)); @@ -492,12 +483,14 @@ TEST_F(FieldTrialCreatorTest, SetupFieldTrials_ValidSeed_NotExpired) { freshness_in_minutes, 1); histogram_tester.ExpectUniqueSample("Variations.SeedUsage", SeedUsage::kRegularSeedUsed, 1); + histogram_tester.ExpectUniqueSample("Variations.AppliedSeed.Size", + strlen(kTestSeedSerializedData), 1); ResetFeatureList(); } } -TEST_F(FieldTrialCreatorTest, SetupFieldTrials_ValidSeed_NoLastFetchTime) { +TEST_F(FieldTrialCreatorTest, SetUpFieldTrials_ValidSeed_NoLastFetchTime) { DisableTestingConfig(); // With a valid seed on first run, the safe seed manager should be informed of @@ -509,7 +502,7 @@ TEST_F(FieldTrialCreatorTest, SetupFieldTrials_ValidSeed_NoLastFetchTime) { const base::Time start_time = base::Time::Now(); EXPECT_CALL(safe_seed_manager, DoSetActiveSeedState(kTestSeedSerializedData, kTestSeedSignature, - _, Ge(start_time))) + _, _, Ge(start_time))) .Times(1); TestVariationsServiceClient variations_service_client; @@ -522,7 +515,7 @@ TEST_F(FieldTrialCreatorTest, SetupFieldTrials_ValidSeed_NoLastFetchTime) { // Check that field trials are created from the seed. Since the test study has // only one experiment with 100% probability weight, we must be part of it. base::HistogramTester histogram_tester; - EXPECT_TRUE(field_trial_creator.SetupFieldTrials()); + EXPECT_TRUE(field_trial_creator.SetUpFieldTrials()); EXPECT_EQ(base::FieldTrialList::FindFullName(kTestSeedStudyName), kTestSeedExperimentName); @@ -536,7 +529,51 @@ TEST_F(FieldTrialCreatorTest, SetupFieldTrials_ValidSeed_NoLastFetchTime) { SeedUsage::kRegularSeedUsed, 1); } -TEST_F(FieldTrialCreatorTest, SetupFieldTrials_ExpiredSeed) { +// Verify that a regular seed can be used when the milestone with which the seed +// was fetched is unknown. This can happen if the seed was fetched before the +// milestone pref was added. +TEST_F(FieldTrialCreatorTest, SetUpFieldTrials_ValidSeed_NoMilestone) { + DisableTestingConfig(); + + // The regular seed should be used, so the safe seed manager should be + // informed of the active seed state. + NiceMock<MockSafeSeedManager> safe_seed_manager(&prefs_); + ON_CALL(safe_seed_manager, ShouldRunInSafeMode()) + .WillByDefault(Return(false)); + const int minutes = 45; + const base::Time seed_fetch_time = base::Time::Now() - base::Minutes(minutes); + EXPECT_CALL(safe_seed_manager, + DoSetActiveSeedState(kTestSeedSerializedData, kTestSeedSignature, + 0, _, seed_fetch_time)) + .Times(1); + + TestVariationsServiceClient variations_service_client; + TestVariationsFieldTrialCreator field_trial_creator( + &prefs_, &variations_service_client, &safe_seed_manager); + + // Simulate the seed being stored. + prefs_.SetTime(prefs::kVariationsLastFetchTime, seed_fetch_time); + + // Simulate the absence of a milestone by leaving + // |prefs::kVariationsSeedMilestone| empty. + EXPECT_EQ(0, prefs_.GetInteger(prefs::kVariationsSeedMilestone)); + + // Check that field trials are created from the seed. Since the test study has + // only one experiment with 100% probability weight, we must be part of it. + base::HistogramTester histogram_tester; + EXPECT_TRUE(field_trial_creator.SetUpFieldTrials()); + EXPECT_EQ(base::FieldTrialList::FindFullName(kTestSeedStudyName), + kTestSeedExperimentName); + + // Verify metrics. + histogram_tester.ExpectUniqueSample("Variations.CreateTrials.SeedExpiry", + VariationsSeedExpiry::kNotExpired, 1); + histogram_tester.ExpectUniqueSample("Variations.SeedFreshness", minutes, 1); + histogram_tester.ExpectUniqueSample("Variations.SeedUsage", + SeedUsage::kRegularSeedUsed, 1); +} + +TEST_F(FieldTrialCreatorTest, SetUpFieldTrials_ExpiredSeed) { DisableTestingConfig(); // When the seed is older than 30 days and older than the binary, no field @@ -545,7 +582,7 @@ TEST_F(FieldTrialCreatorTest, SetupFieldTrials_ExpiredSeed) { NiceMock<MockSafeSeedManager> safe_seed_manager(&prefs_); ON_CALL(safe_seed_manager, ShouldRunInSafeMode()) .WillByDefault(Return(false)); - EXPECT_CALL(safe_seed_manager, DoSetActiveSeedState(_, _, _, _)).Times(0); + EXPECT_CALL(safe_seed_manager, DoSetActiveSeedState(_, _, _, _, _)).Times(0); TestVariationsServiceClient variations_service_client; TestVariationsFieldTrialCreator field_trial_creator( @@ -560,7 +597,7 @@ TEST_F(FieldTrialCreatorTest, SetupFieldTrials_ExpiredSeed) { // Check that field trials are not created from the expired seed. base::HistogramTester histogram_tester; - EXPECT_FALSE(field_trial_creator.SetupFieldTrials()); + EXPECT_FALSE(field_trial_creator.SetUpFieldTrials()); EXPECT_FALSE(base::FieldTrialList::TrialExists(kTestSeedStudyName)); // Verify metrics. The seed freshness metric should not be recorded for an @@ -572,9 +609,43 @@ TEST_F(FieldTrialCreatorTest, SetupFieldTrials_ExpiredSeed) { SeedUsage::kExpiredRegularSeedNotUsed, 1); } +// Verify that a regular seed is not used when the milestone with which it was +// fetched is greater than the client's milestone. +TEST_F(FieldTrialCreatorTest, SetUpFieldTrials_FutureMilestone) { + DisableTestingConfig(); + const int future_seed_milestone = 7890; + + // When the seed is associated with a future milestone (relative to the + // client's milestone), no field trials should be created from the seed. + // Hence, no active state should be passed to the safe seed manager. + NiceMock<MockSafeSeedManager> safe_seed_manager(&prefs_); + ON_CALL(safe_seed_manager, ShouldRunInSafeMode()) + .WillByDefault(Return(false)); + EXPECT_CALL(safe_seed_manager, DoSetActiveSeedState(_, _, _, _, _)).Times(0); + + TestVariationsServiceClient variations_service_client; + TestVariationsFieldTrialCreator field_trial_creator( + &prefs_, &variations_service_client, &safe_seed_manager); + const base::Time now = base::Time::Now(); + field_trial_creator.SetBuildTime(now); + + // Simulate a seed from a future milestone. + prefs_.SetInteger(prefs::kVariationsSeedMilestone, future_seed_milestone); + + // Check that field trials are not created from the seed. + base::HistogramTester histogram_tester; + EXPECT_FALSE(field_trial_creator.SetUpFieldTrials()); + EXPECT_FALSE(base::FieldTrialList::TrialExists(kTestSeedStudyName)); + + // Verify metrics. + histogram_tester.ExpectUniqueSample( + "Variations.SeedUsage", SeedUsage::kRegularSeedForFutureMilestoneNotUsed, + 1); +} + // Verify that unexpired safe seeds are used. TEST_F(FieldTrialCreatorTest, - SetupFieldTrials_ValidSafeSeed_NewBinaryUsesSeed) { + SetUpFieldTrials_ValidSafeSeed_NewBinaryUsesSeed) { DisableTestingConfig(); const base::Time now = base::Time::Now(); @@ -595,7 +666,8 @@ TEST_F(FieldTrialCreatorTest, NiceMock<MockSafeSeedManager> safe_seed_manager(&prefs_); ON_CALL(safe_seed_manager, ShouldRunInSafeMode()) .WillByDefault(Return(true)); - EXPECT_CALL(safe_seed_manager, DoSetActiveSeedState(_, _, _, _)).Times(0); + EXPECT_CALL(safe_seed_manager, DoSetActiveSeedState(_, _, _, _, _)) + .Times(0); TestVariationsServiceClient variations_service_client; TestVariationsFieldTrialCreator field_trial_creator( @@ -610,7 +682,7 @@ TEST_F(FieldTrialCreatorTest, // study has only one experiment with 100% probability weight, we must be // part of it. base::HistogramTester histogram_tester; - EXPECT_TRUE(field_trial_creator.SetupFieldTrials()); + EXPECT_TRUE(field_trial_creator.SetUpFieldTrials()); EXPECT_EQ(kTestSafeSeedExperimentName, base::FieldTrialList::FindFullName(kTestSeedStudyName)); @@ -630,7 +702,7 @@ TEST_F(FieldTrialCreatorTest, // Verify that Chrome applies the regular variations seed when Chrome should run // in variations safe mode but the safe seed is empty. -TEST_F(FieldTrialCreatorTest, SetupFieldTrials_EmptySafeSeed_UsesRegularSeed) { +TEST_F(FieldTrialCreatorTest, SetUpFieldTrials_EmptySafeSeed_UsesRegularSeed) { DisableTestingConfig(); NiceMock<MockSafeSeedManager> safe_seed_manager(&prefs_); @@ -642,7 +714,7 @@ TEST_F(FieldTrialCreatorTest, SetupFieldTrials_EmptySafeSeed_UsesRegularSeed) { // the active seed state. EXPECT_CALL(safe_seed_manager, DoSetActiveSeedState(kTestSeedSerializedData, kTestSeedSignature, - _, recent_time)) + _, _, recent_time)) .Times(1); TestVariationsServiceClient variations_service_client; @@ -654,7 +726,7 @@ TEST_F(FieldTrialCreatorTest, SetupFieldTrials_EmptySafeSeed_UsesRegularSeed) { // study has only one experiment with 100% probability weight, we must be part // of it. base::HistogramTester histogram_tester; - EXPECT_TRUE(field_trial_creator.SetupFieldTrials()); + EXPECT_TRUE(field_trial_creator.SetUpFieldTrials()); EXPECT_EQ(kTestSeedExperimentName, base::FieldTrialList::FindFullName(kTestSeedStudyName)); @@ -670,7 +742,7 @@ TEST_F(FieldTrialCreatorTest, SetupFieldTrials_EmptySafeSeed_UsesRegularSeed) { // Verify that Chrome does not apply a variations seed when Chrome should run in // variations safe mode and a safe seed cannot be loaded. TEST_F(FieldTrialCreatorTest, - SetupFieldTrials_CorruptedSafeSeed_DoesNotUseSeed) { + SetUpFieldTrials_CorruptedSafeSeed_DoesNotUseSeed) { DisableTestingConfig(); NiceMock<MockSafeSeedManager> safe_seed_manager(&prefs_); @@ -678,7 +750,7 @@ TEST_F(FieldTrialCreatorTest, // When falling back to client-side defaults, the safe seed manager should not // be informed of the active seed state. - EXPECT_CALL(safe_seed_manager, DoSetActiveSeedState(_, _, _, _)).Times(0); + EXPECT_CALL(safe_seed_manager, DoSetActiveSeedState(_, _, _, _, _)).Times(0); TestVariationsServiceClient variations_service_client; TestVariationsFieldTrialCreator field_trial_creator( @@ -688,7 +760,7 @@ TEST_F(FieldTrialCreatorTest, base::HistogramTester histogram_tester; // Verify that field trials were not set up. - EXPECT_FALSE(field_trial_creator.SetupFieldTrials()); + EXPECT_FALSE(field_trial_creator.SetUpFieldTrials()); EXPECT_FALSE(base::FieldTrialList::TrialExists(kTestSeedStudyName)); // Verify that Chrome did not apply the safe seed. @@ -697,7 +769,7 @@ TEST_F(FieldTrialCreatorTest, } // Verify that valid safe seeds with missing download times are applied. -TEST_F(FieldTrialCreatorTest, SetupFieldTrials_ValidSafeSeed_NoLastFetchTime) { +TEST_F(FieldTrialCreatorTest, SetUpFieldTrials_ValidSafeSeed_NoLastFetchTime) { DisableTestingConfig(); // With a valid safe seed, the safe seed manager should not be informed of the @@ -705,7 +777,7 @@ TEST_F(FieldTrialCreatorTest, SetupFieldTrials_ValidSafeSeed_NoLastFetchTime) { // already running in safe mode. NiceMock<MockSafeSeedManager> safe_seed_manager(&prefs_); ON_CALL(safe_seed_manager, ShouldRunInSafeMode()).WillByDefault(Return(true)); - EXPECT_CALL(safe_seed_manager, DoSetActiveSeedState(_, _, _, _)).Times(0); + EXPECT_CALL(safe_seed_manager, DoSetActiveSeedState(_, _, _, _, _)).Times(0); TestVariationsServiceClient variations_service_client; TestVariationsFieldTrialCreator field_trial_creator( @@ -718,7 +790,7 @@ TEST_F(FieldTrialCreatorTest, SetupFieldTrials_ValidSafeSeed_NoLastFetchTime) { // study has only one experiment with 100% probability weight, we must be part // of it. base::HistogramTester histogram_tester; - EXPECT_TRUE(field_trial_creator.SetupFieldTrials()); + EXPECT_TRUE(field_trial_creator.SetUpFieldTrials()); EXPECT_EQ(kTestSafeSeedExperimentName, base::FieldTrialList::FindFullName(kTestSeedStudyName)); @@ -734,15 +806,13 @@ TEST_F(FieldTrialCreatorTest, SetupFieldTrials_ValidSafeSeed_NoLastFetchTime) { // Verify that no seed is applied when (i) safe mode is triggered and (ii) the // loaded safe seed has expired. -TEST_F(FieldTrialCreatorTest, SetupFieldTrials_ExpiredSafeSeed) { +TEST_F(FieldTrialCreatorTest, SetUpFieldTrials_ExpiredSafeSeed) { DisableTestingConfig(); - // With a valid safe seed, the safe seed manager should not be informed of the - // active seed state. This is an optimization to avoid saving a safe seed when - // already running in safe mode. + // The safe seed manager should not be informed of the active seed state. NiceMock<MockSafeSeedManager> safe_seed_manager(&prefs_); ON_CALL(safe_seed_manager, ShouldRunInSafeMode()).WillByDefault(Return(true)); - EXPECT_CALL(safe_seed_manager, DoSetActiveSeedState(_, _, _, _)).Times(0); + EXPECT_CALL(safe_seed_manager, DoSetActiveSeedState(_, _, _, _, _)).Times(0); TestVariationsServiceClient variations_service_client; TestVariationsFieldTrialCreator field_trial_creator( @@ -757,7 +827,7 @@ TEST_F(FieldTrialCreatorTest, SetupFieldTrials_ExpiredSafeSeed) { // Check that field trials are not created from the expired seed. base::HistogramTester histogram_tester; - EXPECT_FALSE(field_trial_creator.SetupFieldTrials()); + EXPECT_FALSE(field_trial_creator.SetUpFieldTrials()); EXPECT_FALSE(base::FieldTrialList::TrialExists(kTestSeedStudyName)); // Verify metrics. The seed freshness metric should not be recorded for an @@ -770,9 +840,37 @@ TEST_F(FieldTrialCreatorTest, SetupFieldTrials_ExpiredSafeSeed) { SeedUsage::kExpiredSafeSeedNotUsed, 1); } +// Verify that no seed is applied when (i) safe mode is triggered and (ii) the +// loaded safe seed was fetched with a future milestone. +TEST_F(FieldTrialCreatorTest, SetUpFieldTrials_SafeSeedForFutureMilestone) { + DisableTestingConfig(); + const int future_seed_milestone = 7890; + + // The safe seed manager should not be informed of the active seed state. + NiceMock<MockSafeSeedManager> safe_seed_manager(&prefs_); + ON_CALL(safe_seed_manager, ShouldRunInSafeMode()).WillByDefault(Return(true)); + EXPECT_CALL(safe_seed_manager, DoSetActiveSeedState(_, _, _, _, _)).Times(0); + + TestVariationsServiceClient variations_service_client; + TestVariationsFieldTrialCreator field_trial_creator( + &prefs_, &variations_service_client, &safe_seed_manager); + + // Simulate a safe seed that was fetched with a future milestone. + prefs_.SetInteger(prefs::kVariationsSafeSeedMilestone, future_seed_milestone); + + // Check that field trials are not created from the safe seed. + base::HistogramTester histogram_tester; + EXPECT_FALSE(field_trial_creator.SetUpFieldTrials()); + EXPECT_FALSE(base::FieldTrialList::TrialExists(kTestSeedStudyName)); + + // Verify metrics. + histogram_tester.ExpectUniqueSample( + "Variations.SeedUsage", SeedUsage::kSafeSeedForFutureMilestoneNotUsed, 1); +} + #if defined(OS_ANDROID) -// This is a regression test for https://crbug.com/829527 -TEST_F(FieldTrialCreatorTest, SetupFieldTrials_LoadsCountryOnFirstRun) { +// This is a regression test for crbug/829527. +TEST_F(FieldTrialCreatorTest, SetUpFieldTrials_LoadsCountryOnFirstRun) { DisableTestingConfig(); // Simulate having received a seed in Java during First Run. @@ -807,7 +905,7 @@ TEST_F(FieldTrialCreatorTest, SetupFieldTrials_LoadsCountryOnFirstRun) { // single study with an experiment targeting 100% of users in India. Since // |initial_seed| included the country code for India, this study should be // active. - EXPECT_TRUE(field_trial_creator.SetupFieldTrials( + EXPECT_TRUE(field_trial_creator.SetUpFieldTrials( /*variation_ids=*/std::vector<std::string>(), std::vector<base::FeatureList::FeatureOverrideInfo>(), /*low_entropy_provider=*/nullptr, std::make_unique<base::FeatureList>(), @@ -835,10 +933,8 @@ TEST_F(FieldTrialCreatorTest, ClientFilterableState_HardwareClass) { field_trial_creator.GetClientFilterableStateForVersion(current_version); EXPECT_NE(client_filterable_state->hardware_class, std::string()); } -#endif // OS_ANDROID +#endif // defined(OS_ANDROID) -#if !defined(OS_ANDROID) -// TODO(crbug/1248239): Enable Extended Variations Safe Mode on Android. TEST_F(FieldTrialCreatorSafeModeExperimentTest, OptOutOfExperiment) { std::unique_ptr<PrefService> pref_service(CreatePrefService()); @@ -847,15 +943,17 @@ TEST_F(FieldTrialCreatorSafeModeExperimentTest, OptOutOfExperiment) { ON_CALL(safe_seed_manager, ShouldRunInSafeMode()) .WillByDefault(Return(false)); + version_info::Channel channel = version_info::Channel::DEV; NiceMock<MockVariationsServiceClient> variations_service_client; ON_CALL(variations_service_client, GetChannel()) - .WillByDefault(Return(version_info::Channel::DEV)); + .WillByDefault(Return(channel)); TestVariationsFieldTrialCreator field_trial_creator( - pref_service.get(), &variations_service_client, &safe_seed_manager); + pref_service.get(), &variations_service_client, &safe_seed_manager, + channel); base::HistogramTester histogram_tester; - ASSERT_TRUE(field_trial_creator.SetupFieldTrials( + ASSERT_TRUE(field_trial_creator.SetUpFieldTrials( /*extend_variations_safe_mode=*/false)); // Verify that the experiment is not active and that the WritePrefsTime metric @@ -874,15 +972,15 @@ INSTANTIATE_TEST_SUITE_P( StartupVisibilityTestParams{ .test_name = "UnknownVisibility", .startup_visibility = metrics::StartupVisibility::kUnknown, - .is_trial_active = true}, + .extend_safe_mode = true}, StartupVisibilityTestParams{ .test_name = "BackgroundVisibility", .startup_visibility = metrics::StartupVisibility::kBackground, - .is_trial_active = false}, + .extend_safe_mode = false}, StartupVisibilityTestParams{ .test_name = "ForegroundVisibility", .startup_visibility = metrics::StartupVisibility::kForeground, - .is_trial_active = true}), + .extend_safe_mode = true}), [](const ::testing::TestParamInfo<StartupVisibilityTestParams>& params) { return params.param.test_name; }); @@ -897,18 +995,19 @@ TEST_P(FieldTrialCreatorTestWithStartupVisibility, .WillByDefault(Return(false)); NiceMock<MockVariationsServiceClient> variations_service_client; + version_info::Channel channel = version_info::Channel::DEV; ON_CALL(variations_service_client, GetChannel()) - .WillByDefault(Return(version_info::Channel::DEV)); + .WillByDefault(Return(channel)); StartupVisibilityTestParams params = GetParam(); TestVariationsFieldTrialCreator field_trial_creator( pref_service.get(), &variations_service_client, &safe_seed_manager, - base::FilePath(), params.startup_visibility); - ASSERT_TRUE(field_trial_creator.SetupFieldTrials()); + channel, base::FilePath(), params.startup_visibility); + ASSERT_TRUE(field_trial_creator.SetUpFieldTrials()); - // Verify that the experiment is active (or inactive). - EXPECT_EQ(base::FieldTrialList::IsTrialActive(kExtendedSafeModeTrial), - params.is_trial_active); + // Verify that MaybeExtendVariationsSafeMode() was (or wasn't) called. + EXPECT_EQ(field_trial_creator.was_maybe_extend_variations_safe_mode_called(), + params.extend_safe_mode); base::FeatureList::ClearInstanceForTesting(); } @@ -924,18 +1023,26 @@ TEST_F(FieldTrialCreatorSafeModeExperimentTest, ON_CALL(safe_seed_manager, ShouldRunInSafeMode()) .WillByDefault(Return(false)); +// For desktop and iOS, the Extended Variations Safe Mode experiment is enabled +// on pre-stable channels; for Android Chrome, on canary and dev. +#if defined(OS_ANDROID) std::vector<version_info::Channel> channels = {version_info::Channel::BETA, version_info::Channel::STABLE}; +#else + std::vector<version_info::Channel> channels = {version_info::Channel::STABLE}; +#endif // defined(OS_ANDROID) + for (const version_info::Channel channel : channels) { NiceMock<MockVariationsServiceClient> variations_service_client; ON_CALL(variations_service_client, GetChannel()) .WillByDefault(Return(channel)); TestVariationsFieldTrialCreator field_trial_creator( - pref_service.get(), &variations_service_client, &safe_seed_manager); + pref_service.get(), &variations_service_client, &safe_seed_manager, + channel); base::HistogramTester histogram_tester; - ASSERT_TRUE(field_trial_creator.SetupFieldTrials()); + ASSERT_TRUE(field_trial_creator.SetUpFieldTrials()); // Verify that the experiment is not active. EXPECT_FALSE(base::FieldTrialList::IsTrialActive(kExtendedSafeModeTrial)); @@ -957,21 +1064,25 @@ TEST_F(FieldTrialCreatorSafeModeExperimentTest, std::unique_ptr<PrefService> pref_service(CreatePrefService()); NiceMock<MockVariationsServiceClient> variations_service_client; + version_info::Channel channel = version_info::Channel::CANARY; ON_CALL(variations_service_client, GetChannel()) - .WillByDefault(Return(version_info::Channel::CANARY)); + .WillByDefault(Return(channel)); // Ensure that variations safe mode is not triggered. NiceMock<MockSafeSeedManager> safe_seed_manager(pref_service.get()); ON_CALL(safe_seed_manager, ShouldRunInSafeMode()) .WillByDefault(Return(false)); - TestVariationsFieldTrialCreator field_trial_creator( - pref_service.get(), &variations_service_client, &safe_seed_manager); - + // Assign the client to a specific experiment group before creating the + // TestVariationsFieldTrialCreator so that the CleanExitBeacon uses the + // desired group. int active_group = SetUpExtendedSafeModeExperiment(kControlGroup); + TestVariationsFieldTrialCreator field_trial_creator( + pref_service.get(), &variations_service_client, &safe_seed_manager, + channel); base::HistogramTester histogram_tester; - ASSERT_TRUE(field_trial_creator.SetupFieldTrials()); + ASSERT_TRUE(field_trial_creator.SetUpFieldTrials()); // Verify that the field trial is active and that the client is in the // control group. @@ -979,97 +1090,12 @@ TEST_F(FieldTrialCreatorSafeModeExperimentTest, EXPECT_EQ(active_group, base::FieldTrialList::FindValue(kExtendedSafeModeTrial)); - // Check that no prefs were written and that the WritePrefsTime metric was not + // Check that no prefs were written and that the WritePrefsTime metric was // recorded. std::string pref_file_contents; ASSERT_TRUE(base::ReadFileToString(prefs_file(), &pref_file_contents)); EXPECT_EQ(kEmptyPrefsFile, pref_file_contents); histogram_tester.ExpectTotalCount( - "Variations.ExtendedSafeMode.WritePrefsTime", 0); - - // Verify that the Variations Safe Mode file does not exist. - EXPECT_FALSE(base::PathExists( - user_data_dir_path().Append(variations::kVariationsFilename))); -} - -TEST_F(FieldTrialCreatorSafeModeExperimentTest, - EnableExperimentOnDev_WriteSynchronouslyViaPrefServiceGroup) { - std::unique_ptr<PrefService> pref_service(CreatePrefService()); - - NiceMock<MockVariationsServiceClient> variations_service_client; - ON_CALL(variations_service_client, GetChannel()) - .WillByDefault(Return(version_info::Channel::DEV)); - - // Ensure that variations safe mode is not triggered. - NiceMock<MockSafeSeedManager> safe_seed_manager(pref_service.get()); - ON_CALL(safe_seed_manager, ShouldRunInSafeMode()) - .WillByDefault(Return(false)); - - TestVariationsFieldTrialCreator field_trial_creator( - pref_service.get(), &variations_service_client, &safe_seed_manager, - user_data_dir_path()); - - int active_group = - SetUpExtendedSafeModeExperiment(kWriteSynchronouslyViaPrefServiceGroup); - - base::HistogramTester histogram_tester; - ASSERT_TRUE(field_trial_creator.SetupFieldTrials()); - - // Verify that the field trial is active and that the client is in the - // WriteSynchronouslyViaPrefService group. - EXPECT_TRUE(base::FieldTrialList::IsTrialActive(kExtendedSafeModeTrial)); - EXPECT_EQ(active_group, - base::FieldTrialList::FindValue(kExtendedSafeModeTrial)); - - // Check that prefs were written and do not contain kStabilityExitedCleanly. - // Also, check that the WritePrefsTime metric was recorded. - std::string pref_file_contents; - ASSERT_TRUE(base::ReadFileToString(prefs_file(), &pref_file_contents)); - EXPECT_NE(kEmptyPrefsFile, pref_file_contents); - EXPECT_FALSE(base::Contains(pref_file_contents, "exited_cleanly")); - histogram_tester.ExpectTotalCount( - "Variations.ExtendedSafeMode.WritePrefsTime", 1); - - // Verify that the Variations Safe Mode file does not exist. - EXPECT_FALSE(base::PathExists( - user_data_dir_path().Append(variations::kVariationsFilename))); -} - -TEST_F(FieldTrialCreatorSafeModeExperimentTest, - EnableExperimentOnDev_SignalAndWriteSynchronouslyViaPrefServiceGroup) { - std::unique_ptr<PrefService> pref_service(CreatePrefService()); - - NiceMock<MockVariationsServiceClient> variations_service_client; - ON_CALL(variations_service_client, GetChannel()) - .WillByDefault(Return(version_info::Channel::DEV)); - - // Ensure that variations safe mode is not triggered. - NiceMock<MockSafeSeedManager> safe_seed_manager(pref_service.get()); - ON_CALL(safe_seed_manager, ShouldRunInSafeMode()) - .WillByDefault(Return(false)); - - TestVariationsFieldTrialCreator field_trial_creator( - pref_service.get(), &variations_service_client, &safe_seed_manager, - user_data_dir_path()); - - int active_group = SetUpExtendedSafeModeExperiment( - kSignalAndWriteSynchronouslyViaPrefServiceGroup); - - base::HistogramTester histogram_tester; - ASSERT_TRUE(field_trial_creator.SetupFieldTrials()); - - // Verify that the field trial is active and that the client is in the - // SignalAndWriteSynchronouslyViaPrefService group. - EXPECT_TRUE(base::FieldTrialList::IsTrialActive(kExtendedSafeModeTrial)); - EXPECT_EQ(active_group, - base::FieldTrialList::FindValue(kExtendedSafeModeTrial)); - - // Check that prefs were written and contain kStabilityExitedCleanly. Also, - // check that the WritePrefsTime metric was recorded. - std::string pref_file_contents; - ASSERT_TRUE(base::ReadFileToString(prefs_file(), &pref_file_contents)); - EXPECT_TRUE(base::Contains(pref_file_contents, "\"exited_cleanly\":false")); - histogram_tester.ExpectTotalCount( "Variations.ExtendedSafeMode.WritePrefsTime", 1); // Verify that the Variations Safe Mode file does not exist. @@ -1082,23 +1108,26 @@ TEST_F(FieldTrialCreatorSafeModeExperimentTest, std::unique_ptr<PrefService> pref_service(CreatePrefService()); NiceMock<MockVariationsServiceClient> variations_service_client; + version_info::Channel channel = version_info::Channel::DEV; ON_CALL(variations_service_client, GetChannel()) - .WillByDefault(Return(version_info::Channel::DEV)); + .WillByDefault(Return(channel)); // Ensure that variations safe mode is not triggered. NiceMock<MockSafeSeedManager> safe_seed_manager(pref_service.get()); ON_CALL(safe_seed_manager, ShouldRunInSafeMode()) .WillByDefault(Return(false)); - TestVariationsFieldTrialCreator field_trial_creator( - pref_service.get(), &variations_service_client, &safe_seed_manager, - user_data_dir_path()); - + // Assign the client to a specific experiment group before creating the + // TestVariationsFieldTrialCreator so that the CleanExitBeacon uses the + // desired group. int active_group = SetUpExtendedSafeModeExperiment(kSignalAndWriteViaFileUtilGroup); + TestVariationsFieldTrialCreator field_trial_creator( + pref_service.get(), &variations_service_client, &safe_seed_manager, + channel, user_data_dir_path()); base::HistogramTester histogram_tester; - ASSERT_TRUE(field_trial_creator.SetupFieldTrials()); + ASSERT_TRUE(field_trial_creator.SetUpFieldTrials()); // Verify that the field trial is active and that the client is in the // SignalAndWriteViaFileUtil group. @@ -1127,6 +1156,5 @@ TEST_F(FieldTrialCreatorSafeModeExperimentTest, ASSERT_TRUE(base::ReadFileToString(prefs_file(), &pref_file_contents)); EXPECT_EQ(kEmptyPrefsFile, pref_file_contents); } -#endif // !defined(OS_ANDROID) } // namespace variations diff --git a/chromium/components/variations/service/variations_safe_mode_constants.cc b/chromium/components/variations/service/variations_safe_mode_constants.cc index f3b5732737c..8b73a7730f2 100644 --- a/chromium/components/variations/service/variations_safe_mode_constants.cc +++ b/chromium/components/variations/service/variations_safe_mode_constants.cc @@ -9,13 +9,9 @@ namespace variations { const base::FilePath::CharType kVariationsFilename[] = FILE_PATH_LITERAL("Variations"); -const char kExtendedSafeModeTrial[] = "ExtendedVariationsSafeMode2"; -const char kControlGroup[] = "Control2"; -const char kDefaultGroup[] = "Default2"; -const char kSignalAndWriteSynchronouslyViaPrefServiceGroup[] = - "SignalAndWriteSynchronouslyViaPrefService"; -const char kSignalAndWriteViaFileUtilGroup[] = "SignalAndWriteViaFileUtil"; -const char kWriteSynchronouslyViaPrefServiceGroup[] = - "WriteSynchronouslyViaPrefService"; +const char kExtendedSafeModeTrial[] = "ExtendedVariationsSafeMode4"; +const char kControlGroup[] = "Control4"; +const char kDefaultGroup[] = "Default4"; +const char kSignalAndWriteViaFileUtilGroup[] = "SignalAndWriteViaFileUtil4"; } // namespace variations diff --git a/chromium/components/variations/service/variations_safe_mode_constants.h b/chromium/components/variations/service/variations_safe_mode_constants.h index 2295c972b3d..87695d2927d 100644 --- a/chromium/components/variations/service/variations_safe_mode_constants.h +++ b/chromium/components/variations/service/variations_safe_mode_constants.h @@ -20,9 +20,7 @@ extern const base::FilePath::CharType kVariationsFilename[]; extern const char kExtendedSafeModeTrial[]; extern const char kControlGroup[]; extern const char kDefaultGroup[]; -extern const char kSignalAndWriteSynchronouslyViaPrefServiceGroup[]; extern const char kSignalAndWriteViaFileUtilGroup[]; -extern const char kWriteSynchronouslyViaPrefServiceGroup[]; } // namespace variations diff --git a/chromium/components/variations/service/variations_service.cc b/chromium/components/variations/service/variations_service.cc index 6173c8e4c68..b812395e6c3 100644 --- a/chromium/components/variations/service/variations_service.cc +++ b/chromium/components/variations/service/variations_service.cc @@ -67,10 +67,6 @@ #endif // OS_ANDROID namespace variations { - -const base::Feature kHttpRetryFeature{"VariationsHttpRetry", - base::FEATURE_ENABLED_BY_DEFAULT}; - namespace { // Constants used for encrypting the if-none-match header if we are retrieving a @@ -482,12 +478,10 @@ GURL VariationsService::GetVariationsServerURL(HttpOptions http_options) { } // Add milestone to the request URL. - std::string version = version_info::GetVersionNumber(); - std::vector<std::string> version_parts = base::SplitString( - version, ".", base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY); - if (version_parts.size() > 0) { - server_url = net::AppendOrReplaceQueryParameter(server_url, "milestone", - version_parts[0]); + const std::string milestone = version_info::GetMajorVersionNumber(); + if (!milestone.empty()) { + server_url = + net::AppendOrReplaceQueryParameter(server_url, "milestone", milestone); } DCHECK(server_url.is_valid()); @@ -720,12 +714,9 @@ void VariationsService::InitResourceRequestedAllowedNotifier() { void VariationsService::StartRepeatedVariationsSeedFetch() { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - // Initialize the Variations server URL. + // Initialize Variations server URLs. variations_server_url_ = GetVariationsServerURL(USE_HTTPS); - - // Initialize the fallback HTTP URL if the HTTP retry feature is enabled. - if (base::FeatureList::IsEnabled(kHttpRetryFeature)) - insecure_variations_server_url_ = GetVariationsServerURL(USE_HTTP); + insecure_variations_server_url_ = GetVariationsServerURL(USE_HTTP); DCHECK(!request_scheduler_); request_scheduler_.reset(VariationsRequestScheduler::Create( @@ -958,13 +949,13 @@ std::string VariationsService::GetLatestCountry() const { return field_trial_creator_.GetLatestCountry(); } -bool VariationsService::SetupFieldTrials( +bool VariationsService::SetUpFieldTrials( const std::vector<std::string>& variation_ids, const std::vector<base::FeatureList::FeatureOverrideInfo>& extra_overrides, std::unique_ptr<base::FeatureList> feature_list, variations::PlatformFieldTrials* platform_field_trials, bool extend_variations_safe_mode) { - return field_trial_creator_.SetupFieldTrials( + return field_trial_creator_.SetUpFieldTrials( variation_ids, extra_overrides, CreateLowEntropyProvider(), std::move(feature_list), state_manager_, platform_field_trials, &safe_seed_manager_, state_manager_->GetLowEntropySource(), @@ -1005,8 +996,9 @@ std::string VariationsService::GetStoredPermanentCountry() { local_state_->GetList(prefs::kVariationsPermanentConsistencyCountry); std::string stored_country; - if (list_value->GetList().size() == 2) { - list_value->GetString(1, &stored_country); + base::Value::ConstListView list_view = list_value->GetList(); + if (list_view.size() == 2 && list_view[1].is_string()) { + stored_country = list_view[1].GetString(); } return stored_country; diff --git a/chromium/components/variations/service/variations_service.h b/chromium/components/variations/service/variations_service.h index 850b1e73278..a0883a82349 100644 --- a/chromium/components/variations/service/variations_service.h +++ b/chromium/components/variations/service/variations_service.h @@ -11,7 +11,7 @@ #include "base/compiler_specific.h" #include "base/gtest_prod_util.h" -#include "base/macros.h" +#include "base/memory/raw_ptr.h" #include "base/memory/weak_ptr.h" #include "base/metrics/field_trial.h" #include "base/observer_list.h" @@ -59,12 +59,8 @@ namespace variations { class DeviceVariationsRestrictionByPolicyApplicator; #endif -// If enabled, seed fetches will be retried over HTTP after an HTTPS request -// fails. -extern const base::Feature kHttpRetryFeature; - -// Used to setup field trials based on stored variations seed data, and fetch -// new seed data from the variations server. +// Used to (a) set up field trials based on stored variations seed data and (b) +// fetch new seed data from the variations server. class VariationsService : public web_resource::ResourceRequestAllowedNotifier::Observer { public: @@ -190,9 +186,9 @@ class VariationsService return resource_request_allowed_notifier_.get(); } - // Wrapper around VariationsFieldTrialCreator::SetupFieldTrials(). + // Wrapper around VariationsFieldTrialCreator::SetUpFieldTrials(). // TODO(crbug/1245646): Remove |extend_variations_safe_mode| param. - bool SetupFieldTrials( + bool SetUpFieldTrials( const std::vector<std::string>& variation_ids, const std::vector<base::FeatureList::FeatureOverrideInfo>& extra_overrides, @@ -357,15 +353,15 @@ class VariationsService std::unique_ptr<VariationsServiceClient> client_; // The pref service used to store persist the variations seed. - PrefService* local_state_; + raw_ptr<PrefService> local_state_; // Used for instantiating entropy providers for variations seed simulation. // Weak pointer. - metrics::MetricsStateManager* state_manager_; + raw_ptr<metrics::MetricsStateManager> state_manager_; // Used to obtain policy-related preferences. Depending on the platform, will // either be Local State or Profile prefs. - PrefService* policy_pref_service_; + raw_ptr<PrefService> policy_pref_service_; // Contains the scheduler instance that handles timing for requests to the // server. Initially NULL and instantiated when the initial fetch is diff --git a/chromium/components/variations/service/variations_service_unittest.cc b/chromium/components/variations/service/variations_service_unittest.cc index a8409da11d9..71905308c67 100644 --- a/chromium/components/variations/service/variations_service_unittest.cc +++ b/chromium/components/variations/service/variations_service_unittest.cc @@ -17,7 +17,7 @@ #include "base/feature_list.h" #include "base/files/file_path.h" #include "base/json/json_string_value_serializer.h" -#include "base/macros.h" +#include "base/memory/raw_ptr.h" #include "base/run_loop.h" #include "base/strings/string_number_conversions.h" #include "base/strings/string_split.h" @@ -359,7 +359,7 @@ class VariationsServiceTest : public ::testing::Test { protected: TestingPrefServiceSimple prefs_; - network::TestNetworkConnectionTracker* network_tracker_; + raw_ptr<network::TestNetworkConnectionTracker> network_tracker_; private: base::test::TaskEnvironment task_environment_; diff --git a/chromium/components/variations/study_filtering_unittest.cc b/chromium/components/variations/study_filtering_unittest.cc index d0e14069a5b..cef6c287506 100644 --- a/chromium/components/variations/study_filtering_unittest.cc +++ b/chromium/components/variations/study_filtering_unittest.cc @@ -13,7 +13,6 @@ #include "base/bind.h" #include "base/callback_helpers.h" #include "base/cxx17_backports.h" -#include "base/macros.h" #include "base/strings/strcat.h" #include "base/strings/string_number_conversions.h" #include "base/strings/string_split.h" diff --git a/chromium/components/variations/synthetic_trial_registry_unittest.cc b/chromium/components/variations/synthetic_trial_registry_unittest.cc index d786e1045bd..97c452ebf64 100644 --- a/chromium/components/variations/synthetic_trial_registry_unittest.cc +++ b/chromium/components/variations/synthetic_trial_registry_unittest.cc @@ -193,8 +193,8 @@ TEST_F(SyntheticTrialRegistryTest, RegisterExternalExperiments_WithAllowlist) { TEST_F(SyntheticTrialRegistryTest, GetSyntheticFieldTrialActiveGroups) { SyntheticTrialRegistry registry; - // Instantiate and setup the corresponding singleton observer which tracks the - // creation of all SyntheticTrialGroups. + // Instantiate and set up the corresponding singleton observer which tracks + // the creation of all SyntheticTrialGroups. registry.AddSyntheticTrialObserver( SyntheticTrialsActiveGroupIdProvider::GetInstance()); diff --git a/chromium/components/variations/synthetic_trials_active_group_id_provider.h b/chromium/components/variations/synthetic_trials_active_group_id_provider.h index c6b4eff33d5..f508ae790c9 100644 --- a/chromium/components/variations/synthetic_trials_active_group_id_provider.h +++ b/chromium/components/variations/synthetic_trials_active_group_id_provider.h @@ -8,7 +8,6 @@ #include <vector> #include "base/component_export.h" -#include "base/macros.h" #include "base/synchronization/lock.h" #include "components/variations/active_field_trials.h" #include "components/variations/synthetic_trials.h" diff --git a/chromium/components/variations/variations_associated_data.cc b/chromium/components/variations/variations_associated_data.cc index 551b6591b2d..25100ac5382 100644 --- a/chromium/components/variations/variations_associated_data.cc +++ b/chromium/components/variations/variations_associated_data.cc @@ -8,7 +8,6 @@ #include <utility> #include <vector> -#include "base/macros.h" #include "base/memory/singleton.h" #include "base/metrics/field_trial_param_associator.h" #include "base/metrics/field_trial_params.h" diff --git a/chromium/components/variations/variations_associated_data_unittest.cc b/chromium/components/variations/variations_associated_data_unittest.cc index 110c81375cc..4ffe5d4c188 100644 --- a/chromium/components/variations/variations_associated_data_unittest.cc +++ b/chromium/components/variations/variations_associated_data_unittest.cc @@ -4,7 +4,6 @@ #include "components/variations/variations_associated_data.h" -#include "base/macros.h" #include "base/metrics/field_trial.h" #include "testing/gtest/include/gtest/gtest.h" diff --git a/chromium/components/variations/variations_crash_keys_chromeos.h b/chromium/components/variations/variations_crash_keys_chromeos.h index eebd2abb7cd..dc7c6e9dfea 100644 --- a/chromium/components/variations/variations_crash_keys_chromeos.h +++ b/chromium/components/variations/variations_crash_keys_chromeos.h @@ -6,7 +6,7 @@ #define COMPONENTS_VARIATIONS_VARIATIONS_CRASH_KEYS_CHROMEOS_H_ #include "base/component_export.h" -#include "base/sequenced_task_runner.h" +#include "base/task/sequenced_task_runner.h" #include "components/variations/variations_crash_keys.h" namespace variations { diff --git a/chromium/components/variations/variations_ids_provider.h b/chromium/components/variations/variations_ids_provider.h index 84bcd138738..525e3824ab9 100644 --- a/chromium/components/variations/variations_ids_provider.h +++ b/chromium/components/variations/variations_ids_provider.h @@ -13,7 +13,7 @@ #include "base/component_export.h" #include "base/gtest_prod_util.h" -#include "base/macros.h" +#include "base/memory/raw_ptr.h" #include "base/metrics/field_trial.h" #include "base/observer_list.h" #include "base/synchronization/lock.h" @@ -285,7 +285,7 @@ class COMPONENT_EXPORT(VARIATIONS) VariationsIdsProvider // https://crbug.com/1051937 this isn't currently possible. base::ObserverList<Observer>::Unchecked observer_list_; - const VariationsClient* variations_client_ = nullptr; + raw_ptr<const VariationsClient> variations_client_ = nullptr; }; } // namespace variations diff --git a/chromium/components/variations/variations_params_manager.h b/chromium/components/variations/variations_params_manager.h index 8dbecc1ff61..e16d1546ec9 100644 --- a/chromium/components/variations/variations_params_manager.h +++ b/chromium/components/variations/variations_params_manager.h @@ -10,7 +10,6 @@ #include <set> #include <string> -#include "base/macros.h" #include "base/test/scoped_field_trial_list_resetter.h" namespace base { @@ -84,7 +83,7 @@ class VariationParamsManager { // // This static method is useful in situations where using // VariationParamsManager directly would have resulted in initializing - // FieldTrialList twice (once from ChromeBrowserMainParts::SetupFieldTrials + // FieldTrialList twice (once from ChromeBrowserMainParts::SetUpFieldTrials // and once from VariationParamsManager). static void AppendVariationParams( const std::string& trial_name, diff --git a/chromium/components/variations/variations_request_scheduler.h b/chromium/components/variations/variations_request_scheduler.h index 85de6db1f1f..f0edb94142c 100644 --- a/chromium/components/variations/variations_request_scheduler.h +++ b/chromium/components/variations/variations_request_scheduler.h @@ -8,7 +8,6 @@ #include "base/bind.h" #include "base/component_export.h" #include "base/gtest_prod_util.h" -#include "base/macros.h" #include "base/time/time.h" #include "base/timer/timer.h" diff --git a/chromium/components/variations/variations_request_scheduler_mobile.h b/chromium/components/variations/variations_request_scheduler_mobile.h index d40fbf5894d..c7a02d505bc 100644 --- a/chromium/components/variations/variations_request_scheduler_mobile.h +++ b/chromium/components/variations/variations_request_scheduler_mobile.h @@ -8,7 +8,7 @@ #include "base/bind.h" #include "base/component_export.h" #include "base/gtest_prod_util.h" -#include "base/macros.h" +#include "base/memory/raw_ptr.h" #include "base/timer/timer.h" #include "components/variations/variations_request_scheduler.h" @@ -16,12 +16,12 @@ class PrefService; namespace variations { -// A specialized VariationsRequestScheduler that manages request cycles for +// A specialized VariationsRequestScheduler that manages request cycles for the // VariationsService on mobile platforms. class COMPONENT_EXPORT(VARIATIONS) VariationsRequestSchedulerMobile : public VariationsRequestScheduler { public: - // |task} is the closure to call when the scheduler deems ready. |local_state| + // |task| is the closure to call when the scheduler deems ready. |local_state| // is the PrefService that contains the time of the last fetch. VariationsRequestSchedulerMobile(const base::RepeatingClosure& task, PrefService* local_state); @@ -33,7 +33,7 @@ class COMPONENT_EXPORT(VARIATIONS) VariationsRequestSchedulerMobile ~VariationsRequestSchedulerMobile() override; - // Base class overrides. + // VariationsRequestScheduler: void Start() override; void Reset() override; void OnAppEnterForeground() override; @@ -47,7 +47,7 @@ class COMPONENT_EXPORT(VARIATIONS) VariationsRequestSchedulerMobile OnAppEnterForegroundOnStartup); // The local state instance that provides the last fetch time. - PrefService* local_state_; + raw_ptr<PrefService> local_state_; // Timer used for triggering a delayed fetch for ScheduleFetch(). base::OneShotTimer schedule_fetch_timer_; diff --git a/chromium/components/variations/variations_seed_processor.cc b/chromium/components/variations/variations_seed_processor.cc index 010f43f2efa..dfe929a01a9 100644 --- a/chromium/components/variations/variations_seed_processor.cc +++ b/chromium/components/variations/variations_seed_processor.cc @@ -12,6 +12,7 @@ #include "base/command_line.h" #include "base/feature_list.h" #include "base/metrics/field_trial.h" +#include "base/metrics/histogram_functions.h" #include "base/metrics/histogram_macros.h" #include "base/strings/utf_string_conversions.h" #include "components/variations/client_filterable_state.h" @@ -188,11 +189,9 @@ bool ShouldForceExperiment(const Study_Experiment& experiment, } // namespace -VariationsSeedProcessor::VariationsSeedProcessor() { -} +VariationsSeedProcessor::VariationsSeedProcessor() = default; -VariationsSeedProcessor::~VariationsSeedProcessor() { -} +VariationsSeedProcessor::~VariationsSeedProcessor() = default; void VariationsSeedProcessor::CreateTrialsFromSeed( const VariationsSeed& seed, @@ -200,6 +199,8 @@ void VariationsSeedProcessor::CreateTrialsFromSeed( const UIStringOverrideCallback& override_callback, const base::FieldTrial::EntropyProvider* low_entropy_provider, base::FeatureList* feature_list) { + base::UmaHistogramCounts1000("Variations.AppliedSeed.StudyCount", + seed.study().size()); std::vector<ProcessedStudy> filtered_studies; VariationsLayers layers(seed, low_entropy_provider); FilterAndValidateStudies(seed, client_state, layers, &filtered_studies); diff --git a/chromium/components/variations/variations_seed_processor.h b/chromium/components/variations/variations_seed_processor.h index d26f298d018..afcb2322d2a 100644 --- a/chromium/components/variations/variations_seed_processor.h +++ b/chromium/components/variations/variations_seed_processor.h @@ -13,7 +13,6 @@ #include "base/compiler_specific.h" #include "base/component_export.h" #include "base/gtest_prod_util.h" -#include "base/macros.h" #include "base/metrics/field_trial.h" #include "base/version.h" #include "components/variations/proto/study.pb.h" diff --git a/chromium/components/variations/variations_seed_processor_unittest.cc b/chromium/components/variations/variations_seed_processor_unittest.cc index 567f55f0a56..827118f102b 100644 --- a/chromium/components/variations/variations_seed_processor_unittest.cc +++ b/chromium/components/variations/variations_seed_processor_unittest.cc @@ -10,6 +10,7 @@ #include <map> #include <memory> #include <utility> +#include <vector> #include "base/bind.h" #include "base/callback_helpers.h" @@ -17,10 +18,10 @@ #include "base/cxx17_backports.h" #include "base/feature_list.h" #include "base/format_macros.h" -#include "base/macros.h" #include "base/strings/string_split.h" #include "base/strings/stringprintf.h" #include "base/strings/utf_string_conversions.h" +#include "base/test/metrics/histogram_tester.h" #include "base/test/mock_entropy_provider.h" #include "base/test/scoped_feature_list.h" #include "base/test/scoped_field_trial_list_resetter.h" @@ -175,7 +176,7 @@ class VariationsSeedProcessorTest : public ::testing::Test { client_state.reference_date = base::Time::Now(); client_state.version = base::Version("20.0.0.0"); client_state.channel = Study::STABLE; - client_state.form_factor = Study::DESKTOP; + client_state.form_factor = Study::PHONE; client_state.platform = Study::PLATFORM_ANDROID; base::FeatureList feature_list; @@ -190,6 +191,29 @@ class VariationsSeedProcessorTest : public ::testing::Test { TestOverrideStringCallback override_callback_; }; +TEST_F(VariationsSeedProcessorTest, EmitStudyCountMetric) { + struct StudyCountMetricTestParams { + VariationsSeed seed; + int expected_study_count; + }; + + VariationsSeed zero_study_seed; + VariationsSeed one_study_seed; + Study* study = one_study_seed.add_study(); + study->set_name("MyStudy"); + AddExperiment("Enabled", 1, study); + std::vector<StudyCountMetricTestParams> test_cases = { + {.seed = zero_study_seed, .expected_study_count = 0}, + {.seed = one_study_seed, .expected_study_count = 1}}; + + for (const StudyCountMetricTestParams& test_case : test_cases) { + base::HistogramTester histogram_tester; + CreateTrialsFromSeed(test_case.seed); + histogram_tester.ExpectUniqueSample("Variations.AppliedSeed.StudyCount", + test_case.expected_study_count, 1); + } +} + TEST_F(VariationsSeedProcessorTest, AllowForceGroupAndVariationId) { base::CommandLine::ForCurrentProcess()->AppendSwitch(kForcingFlag1); diff --git a/chromium/components/variations/variations_seed_simulator.h b/chromium/components/variations/variations_seed_simulator.h index 90bfedca2bb..d24269e34d7 100644 --- a/chromium/components/variations/variations_seed_simulator.h +++ b/chromium/components/variations/variations_seed_simulator.h @@ -10,7 +10,6 @@ #include "base/compiler_specific.h" #include "base/component_export.h" -#include "base/macros.h" #include "base/metrics/field_trial.h" #include "base/version.h" #include "components/variations/proto/study.pb.h" diff --git a/chromium/components/variations/variations_seed_simulator_unittest.cc b/chromium/components/variations/variations_seed_simulator_unittest.cc index 42840221222..8b90004e6cd 100644 --- a/chromium/components/variations/variations_seed_simulator_unittest.cc +++ b/chromium/components/variations/variations_seed_simulator_unittest.cc @@ -8,7 +8,6 @@ #include <map> -#include "base/macros.h" #include "base/strings/stringprintf.h" #include "base/test/mock_entropy_provider.h" #include "components/variations/processed_study.h" diff --git a/chromium/components/variations/variations_seed_store.cc b/chromium/components/variations/variations_seed_store.cc index cd43ff314d9..7f2a99c3883 100644 --- a/chromium/components/variations/variations_seed_store.cc +++ b/chromium/components/variations/variations_seed_store.cc @@ -10,7 +10,6 @@ #include "base/base64.h" #include "base/callback_helpers.h" #include "base/logging.h" -#include "base/macros.h" #include "base/metrics/histogram_macros.h" #include "base/numerics/safe_math.h" #include "base/strings/string_number_conversions.h" @@ -20,6 +19,7 @@ #include "components/variations/client_filterable_state.h" #include "components/variations/pref_names.h" #include "components/variations/proto/variations_seed.pb.h" +#include "components/version_info/version_info.h" #include "crypto/signature_verifier.h" #include "third_party/protobuf/src/google/protobuf/io/coded_stream.h" #include "third_party/zlib/google/compression_utils.h" @@ -116,10 +116,10 @@ UpdateSeedDateResult GetSeedDateChangeState( StoreSeedResult Uncompress(const std::string& compressed, std::string* result) { DCHECK(result); if (!compression::GzipUncompress(compressed, result)) - return StoreSeedResult::FAILED_UNGZIP; + return StoreSeedResult::kFailedUngzip; if (result->empty()) - return StoreSeedResult::FAILED_EMPTY_GZIP_CONTENTS; - return StoreSeedResult::SUCCESS; + return StoreSeedResult::kFailedEmptyGzipContents; + return StoreSeedResult::kSuccess; } } // namespace @@ -156,43 +156,6 @@ bool VariationsSeedStore::LoadSeed(VariationsSeed* seed, return true; } -StoreSeedResult VariationsSeedStore::ResolveDelta( - const std::string& delta_bytes, - std::string* seed_bytes) { - DCHECK(seed_bytes); - std::string existing_seed_bytes; - LoadSeedResult read_result = - ReadSeedData(SeedType::LATEST, &existing_seed_bytes); - if (read_result != LoadSeedResult::kSuccess) - return StoreSeedResult::FAILED_DELTA_READ_SEED; - if (!ApplyDeltaPatch(existing_seed_bytes, delta_bytes, seed_bytes)) - return StoreSeedResult::FAILED_DELTA_APPLY; - return StoreSeedResult::SUCCESS; -} - -StoreSeedResult VariationsSeedStore::ResolveInstanceManipulations( - const std::string& data, - const InstanceManipulations& im, - std::string* seed_bytes) { - DCHECK(seed_bytes); - // If the data is gzip compressed, first uncompress it. - std::string ungzipped_data; - if (im.gzip_compressed) { - StoreSeedResult result = Uncompress(data, &ungzipped_data); - if (result != StoreSeedResult::SUCCESS) - return result; - } else { - ungzipped_data = data; - } - - if (!im.delta_compressed) { - seed_bytes->swap(ungzipped_data); - return StoreSeedResult::SUCCESS; - } - - return ResolveDelta(ungzipped_data, seed_bytes); -} - bool VariationsSeedStore::StoreSeedData( const std::string& data, const std::string& base64_seed_signature, @@ -211,7 +174,7 @@ bool VariationsSeedStore::StoreSeedData( std::string seed_bytes; StoreSeedResult im_result = ResolveInstanceManipulations(data, im, &seed_bytes); - if (im_result != StoreSeedResult::SUCCESS) { + if (im_result != StoreSeedResult::kSuccess) { RecordStoreSeedResult(im_result); return false; }; @@ -219,19 +182,19 @@ bool VariationsSeedStore::StoreSeedData( ValidatedSeed validated; StoreSeedResult validate_result = ValidateSeedBytes( seed_bytes, base64_seed_signature, SeedType::LATEST, &validated); - if (validate_result != StoreSeedResult::SUCCESS) { + if (validate_result != StoreSeedResult::kSuccess) { RecordStoreSeedResult(validate_result); if (im.delta_compressed) - RecordStoreSeedResult(StoreSeedResult::FAILED_DELTA_STORE); + RecordStoreSeedResult(StoreSeedResult::kFailedDeltaStore); return false; } StoreSeedResult result = StoreValidatedSeed(validated, country_code, date_fetched); RecordStoreSeedResult(result); - if (result != StoreSeedResult::SUCCESS) { + if (result != StoreSeedResult::kSuccess) { if (im.delta_compressed) - RecordStoreSeedResult(StoreSeedResult::FAILED_DELTA_STORE); + RecordStoreSeedResult(StoreSeedResult::kFailedDeltaStore); return false; } if (parsed_seed) @@ -250,6 +213,9 @@ LoadSeedResult VariationsSeedStore::LoadSafeSeed( if (result != LoadSeedResult::kSuccess) return result; + // TODO(crbug/1261685): While it's not immediately obvious, |client_state| is + // not used for successfully loaded safe seeds that are rejected after + // additional validation (expiry and future milestone). client_state->reference_date = local_state_->GetTime(prefs::kVariationsSafeSeedDate); client_state->locale = @@ -264,88 +230,22 @@ LoadSeedResult VariationsSeedStore::LoadSafeSeed( bool VariationsSeedStore::StoreSafeSeed( const std::string& seed_data, const std::string& base64_seed_signature, + int seed_milestone, const ClientFilterableState& client_state, base::Time seed_fetch_time) { std::string base64_seed_data; - ValidatedSeed validated; + ValidatedSeed seed; StoreSeedResult validation_result = ValidateSeedBytes( - seed_data, base64_seed_signature, SeedType::SAFE, &validated); - if (validation_result != StoreSeedResult::SUCCESS) { + seed_data, base64_seed_signature, SeedType::SAFE, &seed); + if (validation_result != StoreSeedResult::kSuccess) { RecordStoreSafeSeedResult(validation_result); return false; } - StoreSeedResult result = - StoreValidatedSafeSeed(validated, client_state, seed_fetch_time); + StoreSeedResult result = StoreValidatedSafeSeed( + seed, seed_milestone, client_state, seed_fetch_time); RecordStoreSafeSeedResult(result); - return result == StoreSeedResult::SUCCESS; -} - -StoreSeedResult VariationsSeedStore::StoreValidatedSafeSeed( - const ValidatedSeed& validated, - const ClientFilterableState& client_state, - base::Time seed_fetch_time) { - std::string base64_seed_data; - StoreSeedResult result = CompressSeedBytes(validated, &base64_seed_data); - if (result != StoreSeedResult::SUCCESS) - return result; - // As a performance optimization, avoid an expensive no-op of overwriting - // the previous safe seed with an identical copy. - std::string previous_safe_seed = - local_state_->GetString(prefs::kVariationsSafeCompressedSeed); - if (base64_seed_data != previous_safe_seed) { - // It's theoretically possible to overwrite an existing safe seed value, - // which was identical to the latest seed, with a new value. This could - // happen, for example, if: - // (1) Seed A is received from the server and saved as both the safe and - // latest seed value. - // (2) Seed B is received from the server and saved as the latest seed - // value. - // (3) The user restarts Chrome, which is now running with the - // configuration from seed B. - // (4) Seed A is received again from the server, perhaps due to a - // rollback. - // In this situation, seed A should be saved as the latest seed, while - // seed B should be saved as the safe seed, i.e. the previously saved - // values should be swapped. Indeed, it is guaranteed that the latest seed - // value should be overwritten in this case, as a seed should not be - // considered safe unless a new seed can be both received *and saved* from - // the server. - std::string latest_seed = - local_state_->GetString(prefs::kVariationsCompressedSeed); - if (latest_seed == kIdenticalToSafeSeedSentinel) { - local_state_->SetString(prefs::kVariationsCompressedSeed, - previous_safe_seed); - } - local_state_->SetString(prefs::kVariationsSafeCompressedSeed, - base64_seed_data); - } - - local_state_->SetString(prefs::kVariationsSafeSeedSignature, - validated.base64_seed_signature); - local_state_->SetTime(prefs::kVariationsSafeSeedDate, - client_state.reference_date); - local_state_->SetString(prefs::kVariationsSafeSeedLocale, - client_state.locale); - local_state_->SetString(prefs::kVariationsSafeSeedPermanentConsistencyCountry, - client_state.permanent_consistency_country); - local_state_->SetString(prefs::kVariationsSafeSeedSessionConsistencyCountry, - client_state.session_consistency_country); - - // As a space optimization, overwrite the stored latest seed data with an - // alias to the safe seed, if they are identical. - if (base64_seed_data == - local_state_->GetString(prefs::kVariationsCompressedSeed)) { - local_state_->SetString(prefs::kVariationsCompressedSeed, - kIdenticalToSafeSeedSentinel); - - // Moreover, in this case, the last fetch time for the safe seed should - // match the latest seed's. - seed_fetch_time = GetLastFetchTime(); - } - local_state_->SetTime(prefs::kVariationsSafeSeedFetchTime, seed_fetch_time); - - return StoreSeedResult::SUCCESS; + return result == StoreSeedResult::kSuccess; } base::Time VariationsSeedStore::GetLastFetchTime() const { @@ -404,9 +304,11 @@ const std::string& VariationsSeedStore::GetLatestSerialNumber() { // static void VariationsSeedStore::RegisterPrefs(PrefRegistrySimple* registry) { + // Regular seed prefs: registry->RegisterStringPref(prefs::kVariationsCompressedSeed, std::string()); registry->RegisterStringPref(prefs::kVariationsCountry, std::string()); registry->RegisterTimePref(prefs::kVariationsLastFetchTime, base::Time()); + registry->RegisterIntegerPref(prefs::kVariationsSeedMilestone, 0); registry->RegisterTimePref(prefs::kVariationsSeedDate, base::Time()); registry->RegisterStringPref(prefs::kVariationsSeedSignature, std::string()); @@ -416,6 +318,7 @@ void VariationsSeedStore::RegisterPrefs(PrefRegistrySimple* registry) { registry->RegisterTimePref(prefs::kVariationsSafeSeedDate, base::Time()); registry->RegisterTimePref(prefs::kVariationsSafeSeedFetchTime, base::Time()); registry->RegisterStringPref(prefs::kVariationsSafeSeedLocale, std::string()); + registry->RegisterIntegerPref(prefs::kVariationsSafeSeedMilestone, 0); registry->RegisterStringPref( prefs::kVariationsSafeSeedPermanentConsistencyCountry, std::string()); registry->RegisterStringPref( @@ -431,6 +334,17 @@ VerifySignatureResult VariationsSeedStore::VerifySeedSignatureForTesting( return VerifySeedSignature(seed_bytes, base64_seed_signature); } +// It is intentional that country-related prefs are retained for regular seeds +// and cleared for safe seeds. +// +// For regular seeds, the prefs are kept for two reasons. First, it's better to +// have some idea of a country recently associated with the device. Second, some +// past, country-gated launches started relying on the VariationsService- +// provided country when they retired server-side configs. +// +// The safe seed prefs are needed to correctly apply a safe seed, so if the safe +// seed is cleared, there's no reason to retain them as they may be incorrect +// for the next safe seed. void VariationsSeedStore::ClearPrefs(SeedType seed_type) { if (seed_type == SeedType::LATEST) { local_state_->ClearPref(prefs::kVariationsCompressedSeed); @@ -445,6 +359,7 @@ void VariationsSeedStore::ClearPrefs(SeedType seed_type) { local_state_->ClearPref(prefs::kVariationsSafeSeedDate); local_state_->ClearPref(prefs::kVariationsSafeSeedFetchTime); local_state_->ClearPref(prefs::kVariationsSafeSeedLocale); + local_state_->ClearPref(prefs::kVariationsSafeSeedMilestone); local_state_->ClearPref( prefs::kVariationsSafeSeedPermanentConsistencyCountry); local_state_->ClearPref(prefs::kVariationsSafeSeedSessionConsistencyCountry); @@ -556,41 +471,41 @@ LoadSeedResult VariationsSeedStore::ReadSeedData(SeedType seed_type, return LoadSeedResult::kSuccess; } -StoreSeedResult VariationsSeedStore::StoreValidatedSeed( - const ValidatedSeed& validated, - const std::string& country_code, - const base::Time& date_fetched) { - std::string base64_seed_data; - StoreSeedResult result = CompressSeedBytes(validated, &base64_seed_data); - if (result != StoreSeedResult::SUCCESS) - return result; -#if defined(OS_ANDROID) - // If currently we do not have any stored pref then we mark seed storing as - // successful on the Java side to avoid repeated seed fetches. - if (local_state_->GetString(prefs::kVariationsCompressedSeed).empty() && - use_first_run_prefs_) { - android::MarkVariationsSeedAsStored(); - } -#endif +StoreSeedResult VariationsSeedStore::ResolveDelta( + const std::string& delta_bytes, + std::string* seed_bytes) { + DCHECK(seed_bytes); + std::string existing_seed_bytes; + LoadSeedResult read_result = + ReadSeedData(SeedType::LATEST, &existing_seed_bytes); + if (read_result != LoadSeedResult::kSuccess) + return StoreSeedResult::kFailedDeltaReadSeed; + if (!ApplyDeltaPatch(existing_seed_bytes, delta_bytes, seed_bytes)) + return StoreSeedResult::kFailedDeltaApply; + return StoreSeedResult::kSuccess; +} - // Update the saved country code only if one was returned from the server. - if (!country_code.empty()) - local_state_->SetString(prefs::kVariationsCountry, country_code); +StoreSeedResult VariationsSeedStore::ResolveInstanceManipulations( + const std::string& data, + const InstanceManipulations& im, + std::string* seed_bytes) { + DCHECK(seed_bytes); + // If the data is gzip compressed, first uncompress it. + std::string ungzipped_data; + if (im.gzip_compressed) { + StoreSeedResult result = Uncompress(data, &ungzipped_data); + if (result != StoreSeedResult::kSuccess) + return result; + } else { + ungzipped_data = data; + } - // As a space optimization, store an alias to the safe seed if the contents - // are identical. - bool matches_safe_seed = - (base64_seed_data == - local_state_->GetString(prefs::kVariationsSafeCompressedSeed)); - local_state_->SetString( - prefs::kVariationsCompressedSeed, - matches_safe_seed ? kIdenticalToSafeSeedSentinel : base64_seed_data); + if (!im.delta_compressed) { + seed_bytes->swap(ungzipped_data); + return StoreSeedResult::kSuccess; + } - UpdateSeedDateAndLogDayChange(date_fetched); - local_state_->SetString(prefs::kVariationsSeedSignature, - validated.base64_seed_signature); - latest_serial_number_ = validated.parsed.serial_number(); - return StoreSeedResult::SUCCESS; + return ResolveDelta(ungzipped_data, seed_bytes); } StoreSeedResult VariationsSeedStore::ValidateSeedBytes( @@ -600,12 +515,12 @@ StoreSeedResult VariationsSeedStore::ValidateSeedBytes( ValidatedSeed* result) { DCHECK(result); if (seed_bytes.empty()) - return StoreSeedResult::FAILED_EMPTY_GZIP_CONTENTS; + return StoreSeedResult::kFailedEmptyGzipContents; // Only store the seed data if it parses correctly. VariationsSeed seed; if (!seed.ParseFromString(seed_bytes)) - return StoreSeedResult::FAILED_PARSE; + return StoreSeedResult::kFailedParse; if (signature_verification_enabled_) { const VerifySignatureResult verify_result = @@ -624,12 +539,12 @@ StoreSeedResult VariationsSeedStore::ValidateSeedBytes( } if (verify_result != VerifySignatureResult::VALID_SIGNATURE) - return StoreSeedResult::FAILED_SIGNATURE; + return StoreSeedResult::kFailedSignature; } result->bytes = seed_bytes; result->base64_seed_signature = base64_seed_signature; result->parsed.Swap(&seed); - return StoreSeedResult::SUCCESS; + return StoreSeedResult::kSuccess; } StoreSeedResult VariationsSeedStore::CompressSeedBytes( @@ -638,10 +553,120 @@ StoreSeedResult VariationsSeedStore::CompressSeedBytes( // Compress the seed before base64-encoding and storing. std::string compressed_seed_data; if (!compression::GzipCompress(seed.bytes, &compressed_seed_data)) - return StoreSeedResult::FAILED_GZIP; + return StoreSeedResult::kFailedGzip; base::Base64Encode(compressed_seed_data, base64_seed_data); - return StoreSeedResult::SUCCESS; + return StoreSeedResult::kSuccess; +} + +StoreSeedResult VariationsSeedStore::StoreValidatedSeed( + const ValidatedSeed& seed, + const std::string& country_code, + const base::Time& date_fetched) { + std::string base64_seed_data; + StoreSeedResult result = CompressSeedBytes(seed, &base64_seed_data); + if (result != StoreSeedResult::kSuccess) + return result; +#if defined(OS_ANDROID) + // If currently we do not have any stored pref then we mark seed storing as + // successful on the Java side to avoid repeated seed fetches. + if (local_state_->GetString(prefs::kVariationsCompressedSeed).empty() && + use_first_run_prefs_) { + android::MarkVariationsSeedAsStored(); + } +#endif + + // Update the saved country code only if one was returned from the server. + if (!country_code.empty()) + local_state_->SetString(prefs::kVariationsCountry, country_code); + + int milestone; + if (base::StringToInt(version_info::GetMajorVersionNumber(), &milestone)) + local_state_->SetInteger(prefs::kVariationsSeedMilestone, milestone); + + // As a space optimization, store an alias to the safe seed if the contents + // are identical. + bool matches_safe_seed = + (base64_seed_data == + local_state_->GetString(prefs::kVariationsSafeCompressedSeed)); + local_state_->SetString( + prefs::kVariationsCompressedSeed, + matches_safe_seed ? kIdenticalToSafeSeedSentinel : base64_seed_data); + + UpdateSeedDateAndLogDayChange(date_fetched); + local_state_->SetString(prefs::kVariationsSeedSignature, + seed.base64_seed_signature); + latest_serial_number_ = seed.parsed.serial_number(); + return StoreSeedResult::kSuccess; +} + +StoreSeedResult VariationsSeedStore::StoreValidatedSafeSeed( + const ValidatedSeed& seed, + int seed_milestone, + const ClientFilterableState& client_state, + base::Time seed_fetch_time) { + std::string base64_seed_data; + StoreSeedResult result = CompressSeedBytes(seed, &base64_seed_data); + if (result != StoreSeedResult::kSuccess) + return result; + // As a performance optimization, avoid an expensive no-op of overwriting + // the previous safe seed with an identical copy. + std::string previous_safe_seed = + local_state_->GetString(prefs::kVariationsSafeCompressedSeed); + if (base64_seed_data != previous_safe_seed) { + // It's theoretically possible to overwrite an existing safe seed value, + // which was identical to the latest seed, with a new value. This could + // happen, for example, if: + // (1) Seed A is received from the server and saved as both the safe and + // latest seed value. + // (2) Seed B is received from the server and saved as the latest seed + // value. + // (3) The user restarts Chrome, which is now running with the + // configuration from seed B. + // (4) Seed A is received again from the server, perhaps due to a + // rollback. + // In this situation, seed A should be saved as the latest seed, while + // seed B should be saved as the safe seed, i.e. the previously saved + // values should be swapped. Indeed, it is guaranteed that the latest seed + // value should be overwritten in this case, as a seed should not be + // considered safe unless a new seed can be both received *and saved* from + // the server. + std::string latest_seed = + local_state_->GetString(prefs::kVariationsCompressedSeed); + if (latest_seed == kIdenticalToSafeSeedSentinel) { + local_state_->SetString(prefs::kVariationsCompressedSeed, + previous_safe_seed); + } + local_state_->SetString(prefs::kVariationsSafeCompressedSeed, + base64_seed_data); + } + + local_state_->SetString(prefs::kVariationsSafeSeedSignature, + seed.base64_seed_signature); + local_state_->SetTime(prefs::kVariationsSafeSeedDate, + client_state.reference_date); + local_state_->SetString(prefs::kVariationsSafeSeedLocale, + client_state.locale); + local_state_->SetInteger(prefs::kVariationsSafeSeedMilestone, seed_milestone); + local_state_->SetString(prefs::kVariationsSafeSeedPermanentConsistencyCountry, + client_state.permanent_consistency_country); + local_state_->SetString(prefs::kVariationsSafeSeedSessionConsistencyCountry, + client_state.session_consistency_country); + + // As a space optimization, overwrite the stored latest seed data with an + // alias to the safe seed, if they are identical. + if (base64_seed_data == + local_state_->GetString(prefs::kVariationsCompressedSeed)) { + local_state_->SetString(prefs::kVariationsCompressedSeed, + kIdenticalToSafeSeedSentinel); + + // Moreover, in this case, the last fetch time for the safe seed should + // match the latest seed's. + seed_fetch_time = GetLastFetchTime(); + } + local_state_->SetTime(prefs::kVariationsSafeSeedFetchTime, seed_fetch_time); + + return StoreSeedResult::kSuccess; } // static diff --git a/chromium/components/variations/variations_seed_store.h b/chromium/components/variations/variations_seed_store.h index 7dfa9d519ec..bc0f40c9b65 100644 --- a/chromium/components/variations/variations_seed_store.h +++ b/chromium/components/variations/variations_seed_store.h @@ -12,7 +12,7 @@ #include "base/compiler_specific.h" #include "base/component_export.h" #include "base/gtest_prod_util.h" -#include "base/macros.h" +#include "base/memory/raw_ptr.h" #include "base/time/time.h" #include "build/build_config.h" #include "components/variations/metrics.h" @@ -110,6 +110,7 @@ class COMPONENT_EXPORT(VARIATIONS) VariationsSeedStore { // Virtual for testing. virtual bool StoreSafeSeed(const std::string& seed_data, const std::string& base64_seed_signature, + int seed_milestone, const ClientFilterableState& client_state, base::Time seed_fetch_time); @@ -232,7 +233,8 @@ class COMPONENT_EXPORT(VARIATIONS) VariationsSeedStore { // Updates the safe seed with validated data. StoreSeedResult StoreValidatedSafeSeed( - const ValidatedSeed& validated, + const ValidatedSeed& seed, + int seed_milestone, const ClientFilterableState& client_state, base::Time seed_fetch_time) WARN_UNUSED_RESULT; @@ -243,7 +245,7 @@ class COMPONENT_EXPORT(VARIATIONS) VariationsSeedStore { std::string* output) WARN_UNUSED_RESULT; // The pref service used to persist the variations seed. - PrefService* local_state_; + raw_ptr<PrefService> local_state_; // Cached serial number from the most recently fetched variations seed. std::string latest_serial_number_; diff --git a/chromium/components/variations/variations_seed_store_unittest.cc b/chromium/components/variations/variations_seed_store_unittest.cc index 1b311378d5e..c139844609f 100644 --- a/chromium/components/variations/variations_seed_store_unittest.cc +++ b/chromium/components/variations/variations_seed_store_unittest.cc @@ -9,7 +9,6 @@ #include "base/base64.h" #include "base/callback_helpers.h" -#include "base/macros.h" #include "base/test/metrics/histogram_tester.h" #include "base/time/time.h" #include "base/version.h" @@ -38,6 +37,10 @@ namespace { // if the constant used internally in the implementation changes. constexpr char kIdenticalToSafeSeedSentinel[] = "safe_seed_content"; +// TODO(crbug/1205645): Consider consolidating TestVariationsSeedStore and +// SignatureVerifyingVariationsSeedStore. Outside of tests, signature +// verification is enabled although prior to crrev.com/c/2181564, signature +// verification was not done on iOS or Android. class TestVariationsSeedStore : public VariationsSeedStore { public: explicit TestVariationsSeedStore( @@ -60,9 +63,6 @@ class TestVariationsSeedStore : public VariationsSeedStore { } }; -// Signature verification is disabled on Android and iOS for performance -// reasons. This class re-enables it for tests, which don't mind the (small) -// performance penalty. class SignatureVerifyingVariationsSeedStore : public VariationsSeedStore { public: explicit SignatureVerifyingVariationsSeedStore(PrefService* local_state) @@ -158,6 +158,7 @@ void SetAllSeedPrefsToNonDefaultValues(PrefService* prefs) { prefs->SetTime(prefs::kVariationsSafeSeedDate, now - delta * 2); prefs->SetTime(prefs::kVariationsSafeSeedFetchTime, now - delta * 3); prefs->SetString(prefs::kVariationsSafeSeedLocale, "en-MX"); + prefs->SetInteger(prefs::kVariationsSafeSeedMilestone, 90); prefs->SetString(prefs::kVariationsSafeSeedPermanentConsistencyCountry, "mx"); prefs->SetString(prefs::kVariationsSafeSeedSessionConsistencyCountry, "gt"); prefs->SetString(prefs::kVariationsSafeSeedSignature, "mustard"); @@ -189,6 +190,7 @@ void CheckSafeSeedPrefsAreSet(const TestingPrefServiceSimple& prefs) { EXPECT_FALSE(PrefHasDefaultValue(prefs, prefs::kVariationsSafeSeedDate)); EXPECT_FALSE(PrefHasDefaultValue(prefs, prefs::kVariationsSafeSeedFetchTime)); EXPECT_FALSE(PrefHasDefaultValue(prefs, prefs::kVariationsSafeSeedLocale)); + EXPECT_FALSE(PrefHasDefaultValue(prefs, prefs::kVariationsSafeSeedMilestone)); EXPECT_FALSE(PrefHasDefaultValue( prefs, prefs::kVariationsSafeSeedPermanentConsistencyCountry)); EXPECT_FALSE(PrefHasDefaultValue( @@ -201,6 +203,7 @@ void CheckSafeSeedPrefsAreCleared(const TestingPrefServiceSimple& prefs) { EXPECT_TRUE(PrefHasDefaultValue(prefs, prefs::kVariationsSafeSeedDate)); EXPECT_TRUE(PrefHasDefaultValue(prefs, prefs::kVariationsSafeSeedFetchTime)); EXPECT_TRUE(PrefHasDefaultValue(prefs, prefs::kVariationsSafeSeedLocale)); + EXPECT_TRUE(PrefHasDefaultValue(prefs, prefs::kVariationsSafeSeedMilestone)); EXPECT_TRUE(PrefHasDefaultValue( prefs, prefs::kVariationsSafeSeedPermanentConsistencyCountry)); EXPECT_TRUE(PrefHasDefaultValue( @@ -210,6 +213,17 @@ void CheckSafeSeedPrefsAreCleared(const TestingPrefServiceSimple& prefs) { } // namespace +struct InvalidSafeSeedTestParams { + const std::string test_name; + const std::string seed; + const std::string signature; + StoreSeedResult store_seed_result; + absl::optional<VerifySignatureResult> verify_signature_result = absl::nullopt; +}; + +using StoreInvalidSafeSeedTest = + ::testing::TestWithParam<InvalidSafeSeedTestParams>; + TEST(VariationsSeedStoreTest, LoadSeed_ValidSeed) { // Store good seed data to test if loading from prefs works. const VariationsSeed seed = CreateTestSeed(); @@ -600,229 +614,169 @@ TEST(VariationsSeedStoreTest, LoadSafeSeed_EmptySeed) { LoadSeedResult::kEmpty, 1); } -TEST(VariationsSeedStoreTest, StoreSafeSeed_ValidSeed) { - const VariationsSeed seed = CreateTestSeed(); - const std::string serialized_seed = SerializeSeed(seed); - const std::string signature = "a completely ignored signature"; - ClientFilterableState client_state(base::BindOnce([] { return false; })); - client_state.locale = "en-US"; - client_state.reference_date = WrapTime(12345); - client_state.session_consistency_country = "US"; - client_state.permanent_consistency_country = "CA"; - const base::Time fetch_time = WrapTime(99999); - +INSTANTIATE_TEST_SUITE_P( + All, + StoreInvalidSafeSeedTest, + ::testing::Values( + InvalidSafeSeedTestParams{ + .test_name = "EmptySeed", + .seed = "", + .signature = "unused signature", + .store_seed_result = StoreSeedResult::kFailedEmptyGzipContents}, + InvalidSafeSeedTestParams{ + .test_name = "InvalidSeed", + .seed = "invalid seed", + .signature = "unused signature", + .store_seed_result = StoreSeedResult::kFailedParse}, + InvalidSafeSeedTestParams{ + .test_name = "InvalidSignature", + .seed = SerializeSeed(CreateTestSeed()), + // A well-formed signature that does not correspond to the seed. + .signature = kTestSeedData.base64_signature, + .store_seed_result = StoreSeedResult::kFailedSignature, + .verify_signature_result = VerifySignatureResult::INVALID_SEED}), + [](const ::testing::TestParamInfo<InvalidSafeSeedTestParams>& params) { + return params.param.test_name; + }); + +// Verify that attempting to store an invalid safe seed fails and does not +// modify Local State's existing safe-seed-related prefs. +TEST_P(StoreInvalidSafeSeedTest, StoreSafeSeed) { TestingPrefServiceSimple prefs; VariationsSeedStore::RegisterPrefs(prefs.registry()); - TestVariationsSeedStore seed_store(&prefs); - base::HistogramTester histogram_tester; - EXPECT_TRUE(seed_store.StoreSafeSeed(serialized_seed, signature, client_state, - fetch_time)); + // Set a safe seed and its associated prefs to their expected values. Also, + // specify different safe seed pref values that are later attempted to be + // stored. + const std::string expected_seed = "a seed"; + InvalidSafeSeedTestParams params = GetParam(); + const std::string seed_to_store = params.seed; + prefs.SetString(prefs::kVariationsSafeCompressedSeed, expected_seed); - // Verify the stored data. - std::string loaded_compressed_seed = - prefs.GetString(prefs::kVariationsSafeCompressedSeed); - std::string decoded_compressed_seed; - ASSERT_TRUE( - base::Base64Decode(loaded_compressed_seed, &decoded_compressed_seed)); - EXPECT_EQ(Compress(serialized_seed), decoded_compressed_seed); - EXPECT_EQ(signature, prefs.GetString(prefs::kVariationsSafeSeedSignature)); - EXPECT_EQ("en-US", prefs.GetString(prefs::kVariationsSafeSeedLocale)); - EXPECT_EQ(WrapTime(12345), prefs.GetTime(prefs::kVariationsSafeSeedDate)); - EXPECT_EQ(WrapTime(99999), - prefs.GetTime(prefs::kVariationsSafeSeedFetchTime)); - EXPECT_EQ("US", prefs.GetString( - prefs::kVariationsSafeSeedSessionConsistencyCountry)); - EXPECT_EQ("CA", prefs.GetString( - prefs::kVariationsSafeSeedPermanentConsistencyCountry)); + const std::string expected_signature = "a signature"; + const std::string signature_to_store = params.signature; + prefs.SetString(prefs::kVariationsSafeSeedSignature, expected_signature); - // Verify metrics. - histogram_tester.ExpectUniqueSample( - "Variations.SafeMode.StoreSafeSeed.Result", StoreSeedResult::SUCCESS, 1); -} + const int expected_milestone = 90; + const int milestone_to_store = 91; + prefs.SetInteger(prefs::kVariationsSafeSeedMilestone, expected_milestone); -TEST(VariationsSeedStoreTest, StoreSafeSeed_EmptySeed) { - const std::string serialized_seed; - const std::string signature = "a completely ignored signature"; - ClientFilterableState client_state(base::BindOnce([] { return false; })); - client_state.locale = "en-US"; - client_state.reference_date = WrapTime(54321); - client_state.session_consistency_country = "US"; - client_state.permanent_consistency_country = "CA"; - base::Time fetch_time = WrapTime(99999); - - TestingPrefServiceSimple prefs; - VariationsSeedStore::RegisterPrefs(prefs.registry()); - prefs.SetString(prefs::kVariationsSafeCompressedSeed, "a seed"); - prefs.SetString(prefs::kVariationsSafeSeedSignature, "a signature"); - prefs.SetString(prefs::kVariationsSafeSeedLocale, "en-US"); - prefs.SetString(prefs::kVariationsSafeSeedPermanentConsistencyCountry, "CA"); - prefs.SetString(prefs::kVariationsSafeSeedSessionConsistencyCountry, "US"); - prefs.SetTime(prefs::kVariationsSafeSeedDate, WrapTime(12345)); - prefs.SetTime(prefs::kVariationsSafeSeedFetchTime, WrapTime(34567)); - - TestVariationsSeedStore seed_store(&prefs); - - base::HistogramTester histogram_tester; - EXPECT_FALSE(seed_store.StoreSafeSeed(serialized_seed, signature, - client_state, fetch_time)); - - // Verify that none of the prefs were overwritten. - EXPECT_EQ("a seed", prefs.GetString(prefs::kVariationsSafeCompressedSeed)); - EXPECT_EQ("a signature", - prefs.GetString(prefs::kVariationsSafeSeedSignature)); - EXPECT_EQ("en-US", prefs.GetString(prefs::kVariationsSafeSeedLocale)); - EXPECT_EQ("CA", prefs.GetString( - prefs::kVariationsSafeSeedPermanentConsistencyCountry)); - EXPECT_EQ("US", prefs.GetString( - prefs::kVariationsSafeSeedSessionConsistencyCountry)); - EXPECT_EQ(WrapTime(12345), prefs.GetTime(prefs::kVariationsSafeSeedDate)); - EXPECT_EQ(WrapTime(34567), - prefs.GetTime(prefs::kVariationsSafeSeedFetchTime)); - - // Verify metrics. - histogram_tester.ExpectUniqueSample( - "Variations.SafeMode.StoreSafeSeed.Result", - StoreSeedResult::FAILED_EMPTY_GZIP_CONTENTS, 1); -} + const base::Time now = base::Time::Now(); + const base::Time expected_fetch_time = now - base::Hours(3); + const base::Time fetch_time_to_store = now - base::Hours(1); + prefs.SetTime(prefs::kVariationsSafeSeedFetchTime, expected_fetch_time); -TEST(VariationsSeedStoreTest, StoreSafeSeed_InvalidSeed) { - const std::string serialized_seed = "a nonsense seed"; - const std::string signature = "a completely ignored signature"; ClientFilterableState client_state(base::BindOnce([] { return false; })); - client_state.locale = "en-US"; - client_state.reference_date = WrapTime(12345); - client_state.session_consistency_country = "US"; - client_state.permanent_consistency_country = "CA"; - base::Time fetch_time = WrapTime(54321); - TestingPrefServiceSimple prefs; - VariationsSeedStore::RegisterPrefs(prefs.registry()); - prefs.SetString(prefs::kVariationsSafeCompressedSeed, "a previous seed"); - prefs.SetString(prefs::kVariationsSafeSeedSignature, "a previous signature"); - prefs.SetString(prefs::kVariationsSafeSeedLocale, "en-CA"); - prefs.SetString(prefs::kVariationsSafeSeedPermanentConsistencyCountry, "IN"); - prefs.SetString(prefs::kVariationsSafeSeedSessionConsistencyCountry, "MX"); - prefs.SetTime(prefs::kVariationsSafeSeedDate, WrapTime(67890)); - prefs.SetTime(prefs::kVariationsSafeSeedFetchTime, WrapTime(13579)); - - SignatureVerifyingVariationsSeedStore seed_store(&prefs); - - base::HistogramTester histogram_tester; - EXPECT_FALSE(seed_store.StoreSafeSeed(serialized_seed, signature, - client_state, fetch_time)); + const std::string expected_locale = "en-US"; + client_state.locale = "pt-PT"; + prefs.SetString(prefs::kVariationsSafeSeedLocale, expected_locale); - // Verify that none of the prefs were overwritten. - EXPECT_EQ("a previous seed", - prefs.GetString(prefs::kVariationsSafeCompressedSeed)); - EXPECT_EQ("a previous signature", - prefs.GetString(prefs::kVariationsSafeSeedSignature)); - EXPECT_EQ("en-CA", prefs.GetString(prefs::kVariationsSafeSeedLocale)); - EXPECT_EQ("IN", prefs.GetString( - prefs::kVariationsSafeSeedPermanentConsistencyCountry)); - EXPECT_EQ("MX", prefs.GetString( - prefs::kVariationsSafeSeedSessionConsistencyCountry)); - EXPECT_EQ(WrapTime(67890), prefs.GetTime(prefs::kVariationsSafeSeedDate)); - EXPECT_EQ(WrapTime(13579), - prefs.GetTime(prefs::kVariationsSafeSeedFetchTime)); - - // Verify metrics. - histogram_tester.ExpectUniqueSample( - "Variations.SafeMode.StoreSafeSeed.Result", StoreSeedResult::FAILED_PARSE, - 1); -} - -TEST(VariationsSeedStoreTest, StoreSafeSeed_InvalidSignature) { - const VariationsSeed seed = CreateTestSeed(); - const std::string serialized_seed = SerializeSeed(seed); - // A valid signature, but for a different seed. - const std::string signature = kTestSeedData.base64_signature; - ClientFilterableState client_state(base::BindOnce([] { return false; })); - client_state.locale = "en-US"; - client_state.reference_date = WrapTime(12345); - client_state.session_consistency_country = "US"; + const std::string expected_permanent_consistency_country = "US"; client_state.permanent_consistency_country = "CA"; - const base::Time fetch_time = WrapTime(34567); + prefs.SetString(prefs::kVariationsSafeSeedPermanentConsistencyCountry, + expected_permanent_consistency_country); - TestingPrefServiceSimple prefs; - VariationsSeedStore::RegisterPrefs(prefs.registry()); - prefs.SetString(prefs::kVariationsSafeCompressedSeed, "a previous seed"); - prefs.SetString(prefs::kVariationsSafeSeedSignature, "a previous signature"); - prefs.SetString(prefs::kVariationsSafeSeedLocale, "en-CA"); - prefs.SetString(prefs::kVariationsSafeSeedPermanentConsistencyCountry, "IN"); - prefs.SetString(prefs::kVariationsSafeSeedSessionConsistencyCountry, "MX"); - prefs.SetTime(prefs::kVariationsSafeSeedDate, WrapTime(67890)); - prefs.SetTime(prefs::kVariationsSafeSeedFetchTime, WrapTime(24680)); + const std::string expected_session_consistency_country = "BR"; + client_state.session_consistency_country = "PT"; + prefs.SetString(prefs::kVariationsSafeSeedSessionConsistencyCountry, + expected_session_consistency_country); - SignatureVerifyingVariationsSeedStore seed_store(&prefs); + const base::Time expected_date = now - base::Days(2); + client_state.reference_date = now - base::Days(1); + prefs.SetTime(prefs::kVariationsSafeSeedDate, expected_date); + SignatureVerifyingVariationsSeedStore seed_store(&prefs); base::HistogramTester histogram_tester; - EXPECT_FALSE(seed_store.StoreSafeSeed(serialized_seed, signature, - client_state, fetch_time)); - // Verify that none of the prefs were overwritten. - EXPECT_EQ("a previous seed", - prefs.GetString(prefs::kVariationsSafeCompressedSeed)); - EXPECT_EQ("a previous signature", - prefs.GetString(prefs::kVariationsSafeSeedSignature)); - EXPECT_EQ("en-CA", prefs.GetString(prefs::kVariationsSafeSeedLocale)); - EXPECT_EQ("IN", prefs.GetString( - prefs::kVariationsSafeSeedPermanentConsistencyCountry)); - EXPECT_EQ("MX", prefs.GetString( - prefs::kVariationsSafeSeedSessionConsistencyCountry)); - EXPECT_EQ(WrapTime(67890), prefs.GetTime(prefs::kVariationsSafeSeedDate)); - EXPECT_EQ(WrapTime(24680), - prefs.GetTime(prefs::kVariationsSafeSeedFetchTime)); + // Verify that attempting to store an invalid seed fails. + EXPECT_FALSE(seed_store.StoreSafeSeed(seed_to_store, signature_to_store, + milestone_to_store, client_state, + fetch_time_to_store)); + + // Verify that none of the safe seed prefs were overwritten. + EXPECT_EQ(prefs.GetString(prefs::kVariationsSafeCompressedSeed), + expected_seed); + EXPECT_EQ(prefs.GetString(prefs::kVariationsSafeSeedSignature), + expected_signature); + EXPECT_EQ(prefs.GetString(prefs::kVariationsSafeSeedLocale), expected_locale); + EXPECT_EQ(prefs.GetInteger(prefs::kVariationsSafeSeedMilestone), + expected_milestone); + EXPECT_EQ( + prefs.GetString(prefs::kVariationsSafeSeedPermanentConsistencyCountry), + expected_permanent_consistency_country); + EXPECT_EQ( + prefs.GetString(prefs::kVariationsSafeSeedSessionConsistencyCountry), + expected_session_consistency_country); + EXPECT_EQ(prefs.GetTime(prefs::kVariationsSafeSeedDate), expected_date); + EXPECT_EQ(prefs.GetTime(prefs::kVariationsSafeSeedFetchTime), + expected_fetch_time); // Verify metrics. histogram_tester.ExpectUniqueSample( - "Variations.SafeMode.StoreSafeSeed.Result", - StoreSeedResult::FAILED_SIGNATURE, 1); - histogram_tester.ExpectUniqueSample( - "Variations.SafeMode.StoreSafeSeed.SignatureValidity", - VerifySignatureResult::INVALID_SEED, 1); + "Variations.SafeMode.StoreSafeSeed.Result", params.store_seed_result, 1); + if (params.verify_signature_result.has_value()) { + histogram_tester.ExpectUniqueSample( + "Variations.SafeMode.StoreSafeSeed.SignatureValidity", + params.verify_signature_result.value(), 1); + } } TEST(VariationsSeedStoreTest, StoreSafeSeed_ValidSignature) { - std::string serialized_seed; + std::string expected_seed; ASSERT_TRUE(base::Base64Decode(kTestSeedData.base64_uncompressed_data, - &serialized_seed)); - const std::string signature = kTestSeedData.base64_signature; + &expected_seed)); + const std::string expected_signature = kTestSeedData.base64_signature; + const int expected_seed_milestone = 92; + ClientFilterableState client_state(base::BindOnce([] { return false; })); - client_state.locale = "en-US"; - client_state.reference_date = WrapTime(12345); - client_state.session_consistency_country = "US"; - client_state.permanent_consistency_country = "CA"; - const base::Time fetch_time = WrapTime(34567); + const std::string expected_locale = "en-US"; + client_state.locale = expected_locale; + const base::Time now = base::Time::Now(); + const base::Time expected_date = now - base::Days(1); + client_state.reference_date = expected_date; + const std::string expected_permanent_consistency_country = "US"; + client_state.permanent_consistency_country = + expected_permanent_consistency_country; + const std::string expected_session_consistency_country = "CA"; + client_state.session_consistency_country = + expected_session_consistency_country; + const base::Time expected_fetch_time = now - base::Hours(6); TestingPrefServiceSimple prefs; VariationsSeedStore::RegisterPrefs(prefs.registry()); SignatureVerifyingVariationsSeedStore seed_store(&prefs); - base::HistogramTester histogram_tester; - EXPECT_TRUE(seed_store.StoreSafeSeed(serialized_seed, signature, client_state, - fetch_time)); - // Verify the stored data. - std::string loaded_compressed_seed = + // Verify that storing the safe seed succeeded. + EXPECT_TRUE(seed_store.StoreSafeSeed(expected_seed, expected_signature, + expected_seed_milestone, client_state, + expected_fetch_time)); + + // Verify that safe-seed-related prefs were successfully stored. + const std::string safe_seed = prefs.GetString(prefs::kVariationsSafeCompressedSeed); std::string decoded_compressed_seed; - ASSERT_TRUE( - base::Base64Decode(loaded_compressed_seed, &decoded_compressed_seed)); - EXPECT_EQ(Compress(serialized_seed), decoded_compressed_seed); - EXPECT_EQ(signature, prefs.GetString(prefs::kVariationsSafeSeedSignature)); - EXPECT_EQ("en-US", prefs.GetString(prefs::kVariationsSafeSeedLocale)); - EXPECT_EQ(WrapTime(12345), prefs.GetTime(prefs::kVariationsSafeSeedDate)); - EXPECT_EQ(WrapTime(34567), - prefs.GetTime(prefs::kVariationsSafeSeedFetchTime)); - EXPECT_EQ("US", prefs.GetString( - prefs::kVariationsSafeSeedSessionConsistencyCountry)); - EXPECT_EQ("CA", prefs.GetString( - prefs::kVariationsSafeSeedPermanentConsistencyCountry)); + ASSERT_TRUE(base::Base64Decode(safe_seed, &decoded_compressed_seed)); + EXPECT_EQ(Compress(expected_seed), decoded_compressed_seed); + EXPECT_EQ(prefs.GetString(prefs::kVariationsSafeSeedSignature), + expected_signature); + EXPECT_EQ(prefs.GetString(prefs::kVariationsSafeSeedLocale), expected_locale); + EXPECT_EQ(prefs.GetInteger(prefs::kVariationsSafeSeedMilestone), + expected_seed_milestone); + EXPECT_EQ( + prefs.GetString(prefs::kVariationsSafeSeedPermanentConsistencyCountry), + expected_permanent_consistency_country); + EXPECT_EQ( + prefs.GetString(prefs::kVariationsSafeSeedSessionConsistencyCountry), + expected_session_consistency_country); + EXPECT_EQ(prefs.GetTime(prefs::kVariationsSafeSeedDate), expected_date); + EXPECT_EQ(prefs.GetTime(prefs::kVariationsSafeSeedFetchTime), + expected_fetch_time); // Verify metrics. histogram_tester.ExpectUniqueSample( - "Variations.SafeMode.StoreSafeSeed.Result", StoreSeedResult::SUCCESS, 1); + "Variations.SafeMode.StoreSafeSeed.Result", StoreSeedResult::kSuccess, 1); histogram_tester.ExpectUniqueSample( "Variations.SafeMode.StoreSafeSeed.SignatureValidity", VerifySignatureResult::VALID_SIGNATURE, 1); @@ -835,6 +789,7 @@ TEST(VariationsSeedStoreTest, StoreSafeSeed_IdenticalToLatestSeed) { const std::string signature = "a completely ignored signature"; ClientFilterableState unused_client_state( base::BindOnce([] { return false; })); + const int unused_seed_milestone = 92; const base::Time safe_seed_fetch_time = WrapTime(12345); TestingPrefServiceSimple prefs; @@ -846,7 +801,8 @@ TEST(VariationsSeedStoreTest, StoreSafeSeed_IdenticalToLatestSeed) { TestVariationsSeedStore seed_store(&prefs); base::HistogramTester histogram_tester; EXPECT_TRUE(seed_store.StoreSafeSeed( - serialized_seed, signature, unused_client_state, safe_seed_fetch_time)); + serialized_seed, signature, unused_seed_milestone, unused_client_state, + safe_seed_fetch_time)); // Verify the latest seed value was migrated to a sentinel value, rather than // the full string. @@ -874,7 +830,7 @@ TEST(VariationsSeedStoreTest, StoreSafeSeed_IdenticalToLatestSeed) { // Verify metrics. histogram_tester.ExpectUniqueSample( - "Variations.SafeMode.StoreSafeSeed.Result", StoreSeedResult::SUCCESS, 1); + "Variations.SafeMode.StoreSafeSeed.Result", StoreSeedResult::kSuccess, 1); } TEST(VariationsSeedStoreTest, StoreSafeSeed_PreviouslyIdenticalToLatestSeed) { @@ -894,6 +850,7 @@ TEST(VariationsSeedStoreTest, StoreSafeSeed_PreviouslyIdenticalToLatestSeed) { const base::Time fetch_time = WrapTime(12345); ClientFilterableState unused_client_state( base::BindOnce([] { return false; })); + const int unused_seed_milestone = 92; TestingPrefServiceSimple prefs; VariationsSeedStore::RegisterPrefs(prefs.registry()); @@ -904,6 +861,7 @@ TEST(VariationsSeedStoreTest, StoreSafeSeed_PreviouslyIdenticalToLatestSeed) { TestVariationsSeedStore seed_store(&prefs); base::HistogramTester histogram_tester; EXPECT_TRUE(seed_store.StoreSafeSeed(serialized_new_seed, signature, + unused_seed_milestone, unused_client_state, fetch_time)); // Verify the latest seed value was copied before the safe seed was @@ -932,7 +890,7 @@ TEST(VariationsSeedStoreTest, StoreSafeSeed_PreviouslyIdenticalToLatestSeed) { // Verify metrics. histogram_tester.ExpectUniqueSample( - "Variations.SafeMode.StoreSafeSeed.Result", StoreSeedResult::SUCCESS, 1); + "Variations.SafeMode.StoreSafeSeed.Result", StoreSeedResult::kSuccess, 1); } TEST(VariationsSeedStoreTest, StoreSeedData_GzippedEmptySeed) { diff --git a/chromium/components/variations/variations_test_utils_unittest.cc b/chromium/components/variations/variations_test_utils_unittest.cc index b717044ec78..6e0260270fb 100644 --- a/chromium/components/variations/variations_test_utils_unittest.cc +++ b/chromium/components/variations/variations_test_utils_unittest.cc @@ -67,8 +67,8 @@ TEST_P(SignedSeedDataTest, HasStudyNames) { signed_seed_data.study_names)); } -INSTANTIATE_TEST_CASE_P(VariationsTestUtils, - SignedSeedDataTest, - ::testing::Values(kTestSeedData, kCrashingSeedData)); +INSTANTIATE_TEST_SUITE_P(VariationsTestUtils, + SignedSeedDataTest, + ::testing::Values(kTestSeedData, kCrashingSeedData)); -} // namespace variations
\ No newline at end of file +} // namespace variations |