diff options
author | rkaplow@chromium.org <rkaplow@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2014-05-02 04:36:55 +0000 |
---|---|---|
committer | rkaplow@chromium.org <rkaplow@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2014-05-02 04:36:55 +0000 |
commit | bca259407943b3c9db090adc4ba97bd31361818d (patch) | |
tree | 8f8b06045cb52b024812f063fabd804a84644557 | |
parent | d667e6e08e142695dcc77624d425b25270ac6d6b (diff) | |
download | chromium_src-bca259407943b3c9db090adc4ba97bd31361818d.zip chromium_src-bca259407943b3c9db090adc4ba97bd31361818d.tar.gz chromium_src-bca259407943b3c9db090adc4ba97bd31361818d.tar.bz2 |
Support hardware_class filtering in variations for ChromeOS devices.
BUG=366807
Review URL: https://codereview.chromium.org/259663002
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@267741 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r-- | chrome/browser/metrics/variations/variations_service.cc | 14 | ||||
-rw-r--r-- | components/variations/proto/study.proto | 18 | ||||
-rw-r--r-- | components/variations/study_filtering.cc | 48 | ||||
-rw-r--r-- | components/variations/study_filtering.h | 13 | ||||
-rw-r--r-- | components/variations/study_filtering_unittest.cc | 61 | ||||
-rw-r--r-- | components/variations/variations_seed_processor.cc | 5 | ||||
-rw-r--r-- | components/variations/variations_seed_processor.h | 6 | ||||
-rw-r--r-- | components/variations/variations_seed_processor_unittest.cc | 6 | ||||
-rw-r--r-- | components/variations/variations_seed_simulator.cc | 5 | ||||
-rw-r--r-- | components/variations/variations_seed_simulator.h | 3 |
10 files changed, 159 insertions, 20 deletions
diff --git a/chrome/browser/metrics/variations/variations_service.cc b/chrome/browser/metrics/variations/variations_service.cc index 4d3aec7..e8fe57d 100644 --- a/chrome/browser/metrics/variations/variations_service.cc +++ b/chrome/browser/metrics/variations/variations_service.cc @@ -12,6 +12,7 @@ #include "base/metrics/sparse_histogram.h" #include "base/prefs/pref_registry_simple.h" #include "base/prefs/pref_service.h" +#include "base/sys_info.h" #include "base/version.h" #include "chrome/browser/browser_process.h" #include "chrome/browser/network_time/network_time_tracker.h" @@ -156,7 +157,7 @@ ResourceRequestsAllowedState ResourceRequestStateToHistogramValue( } -// Get current form factor and convert it from enum DeviceFormFactor to enum +// Gets current form factor and converts it from enum DeviceFormFactor to enum // Study_FormFactor. Study_FormFactor GetCurrentFormFactor() { switch (ui::GetDeviceFormFactor()) { @@ -171,6 +172,15 @@ Study_FormFactor GetCurrentFormFactor() { return Study_FormFactor_DESKTOP; } +// Gets the hardware class and returns it as a string. This returns an empty +// string if the client is not ChromeOS. +std::string GetHardwareClass() { +#if defined(OS_CHROMEOS) + return base::SysInfo::GetLsbReleaseBoard(); +#endif // OS_CHROMEOS + return std::string(); +} + // Returns the date that should be used by the VariationsSeedProcessor to do // expiry and start date checks. base::Time GetReferenceDateForExpiryChecks(PrefService* local_state) { @@ -230,7 +240,7 @@ bool VariationsService::CreateTrialsFromSeed() { VariationsSeedProcessor().CreateTrialsFromSeed( seed, g_browser_process->GetApplicationLocale(), GetReferenceDateForExpiryChecks(local_state_), current_version, - GetChannelForVariations(), GetCurrentFormFactor()); + GetChannelForVariations(), GetCurrentFormFactor(), GetHardwareClass()); // Log the "freshness" of the seed that was just used. The freshness is the // time between the last successful seed download and now. diff --git a/components/variations/proto/study.proto b/components/variations/proto/study.proto index 384c0ec..28ac183 100644 --- a/components/variations/proto/study.proto +++ b/components/variations/proto/study.proto @@ -146,7 +146,7 @@ message Study { // Filtering criteria specifying whether this study is applicable to a given // Chrome instance. // - // Next tag: 8 + // Next tag: 10 message Filter { // The start date of the study in Unix time format. (Seconds since midnight // January 1, 1970 UTC). See: http://en.wikipedia.org/wiki/Unix_time @@ -186,6 +186,22 @@ message Study { // applies to all form factors. // Ex: [PHONE, TABLET] repeated FormFactor form_factor = 7; + + // List of ChromeOS hardware classes that will receive this study. Each + // entry is treated as a substring of the actual device hardware_class, + // so "FOO" will match the client's hardware class "Device FOOBAR". If + // omitted, the study applies to all hardware classes unless + // |exclude_hardware_class| is specified. Mutually exclusive with + // |exclude_hardware_class|. + repeated string hardware_class = 8; + + // List of ChromeOS hardware classes that will be excluded in this + // study. Each entry is treated as a substring of the actual device + // hardware_class, so "FOO" will match the client's hardware class + // "Device FOOBAR". If omitted, the study applies to all hardware classes + // unless |hardware_class| is specified. Mutually exclusive with + // |hardware_class|. + repeated string exclude_hardware_class = 9; } // Filtering criteria for this study. A study that is filtered out for a given diff --git a/components/variations/study_filtering.cc b/components/variations/study_filtering.cc index aeb36cc..7f35e18 100644 --- a/components/variations/study_filtering.cc +++ b/components/variations/study_filtering.cc @@ -64,6 +64,41 @@ bool CheckStudyFormFactor(const Study_Filter& filter, return false; } +bool CheckStudyHardwareClass(const Study_Filter& filter, + const std::string& hardware_class) { + // Empty hardware_class and exclude_hardware_class matches all. + if (filter.hardware_class_size() == 0 && + filter.exclude_hardware_class_size() == 0) { + return true; + } + + // Checks if we are supposed to filter for a specified set of + // hardware_classes. Note that this means this overrides the + // exclude_hardware_class in case that ever occurs (which it shouldn't). + if (filter.hardware_class_size() > 0) { + for (int i = 0; i < filter.hardware_class_size(); ++i) { + // Check if the entry is a substring of |hardware_class|. + size_t position = hardware_class.find(filter.hardware_class(i)); + if (position != std::string::npos) + return true; + } + // None of the requested hardware_classes match. + return false; + } + + // Omit if matches any of the exclude entries. + for (int i = 0; i < filter.exclude_hardware_class_size(); ++i) { + // Check if the entry is a substring of |hardware_class|. + size_t position = hardware_class.find( + filter.exclude_hardware_class(i)); + if (position != std::string::npos) + return false; + } + + // None of the exclusions match, so this accepts. + return true; +} + bool CheckStudyLocale(const Study_Filter& filter, const std::string& locale) { // An empty locale list matches all locales. if (filter.locale_size() == 0) @@ -130,7 +165,8 @@ bool ShouldAddStudy( const base::Time& reference_date, const base::Version& version, Study_Channel channel, - Study_FormFactor form_factor) { + Study_FormFactor form_factor, + const std::string& hardware_class) { if (study.has_filter()) { if (!CheckStudyChannel(study.filter(), channel)) { DVLOG(1) << "Filtered out study " << study.name() << " due to channel."; @@ -163,6 +199,13 @@ bool ShouldAddStudy( " due to start date."; return false; } + + if (!CheckStudyHardwareClass(study.filter(), hardware_class)) { + DVLOG(1) << "Filtered out study " << study.name() << + " due to hardware_class."; + return false; + } + } DVLOG(1) << "Kept study " << study.name() << "."; @@ -178,6 +221,7 @@ void FilterAndValidateStudies( const base::Version& version, Study_Channel channel, Study_FormFactor form_factor, + const std::string& hardware_class, std::vector<ProcessedStudy>* filtered_studies) { DCHECK(version.IsValid()); @@ -191,7 +235,7 @@ void FilterAndValidateStudies( for (int i = 0; i < seed.study_size(); ++i) { const Study& study = seed.study(i); if (!internal::ShouldAddStudy(study, locale, reference_date, version, - channel, form_factor)) { + channel, form_factor, hardware_class)) { continue; } diff --git a/components/variations/study_filtering.h b/components/variations/study_filtering.h index 1c14fc9..bb8b09d 100644 --- a/components/variations/study_filtering.h +++ b/components/variations/study_filtering.h @@ -28,6 +28,11 @@ bool CheckStudyChannel(const Study_Filter& filter, Study_Channel channel); bool CheckStudyFormFactor(const Study_Filter& filter, Study_FormFactor form_factor); +// Checks whether a study is applicable for the given |hardware_class| per +// |filter|. +bool CheckStudyHardwareClass(const Study_Filter& filter, + const std::string& hardware_class); + // Checks whether a study is applicable for the given |locale| per |filter|. bool CheckStudyLocale(const Study_Filter& filter, const std::string& locale); @@ -46,15 +51,14 @@ bool CheckStudyVersion(const Study_Filter& filter, bool IsStudyExpired(const Study& study, const base::Time& date_time); // Returns whether |study| should be disabled according to its restriction -// parameters. Uses |version_info| for min / max version checks, -// |reference_date| for the start date check and |channel| for channel -// checks. +// parameters. bool ShouldAddStudy(const Study& study, const std::string& locale, const base::Time& reference_date, const base::Version& version, Study_Channel channel, - Study_FormFactor form_factor); + Study_FormFactor form_factor, + const std::string& hardware_class); } // namespace internal @@ -67,6 +71,7 @@ void FilterAndValidateStudies(const VariationsSeed& seed, const base::Version& version, Study_Channel channel, Study_FormFactor form_factor, + const std::string& hardware_class, std::vector<ProcessedStudy>* filtered_studies); } // namespace chrome_variations diff --git a/components/variations/study_filtering_unittest.cc b/components/variations/study_filtering_unittest.cc index 84c5cf7..ff39d80 100644 --- a/components/variations/study_filtering_unittest.cc +++ b/components/variations/study_filtering_unittest.cc @@ -313,6 +313,65 @@ TEST(VariationsStudyFilteringTest, CheckStudyVersion) { } } +TEST(VariationsStudyFilteringTest, CheckStudyHardwareClass) { + struct { + const char* hardware_class; + const char* exclude_hardware_class; + const char* actual_hardware_class; + bool expected_result; + } test_cases[] = { + // Neither filtered nor excluded set: + // True since empty is always a match. + {"", "", "fancy INTEL pear device", true}, + {"", "", "", true}, + + // Filtered set: + {"apple,pear,orange", "", "apple", true}, + {"apple,pear,orange", "", "fancy INTEL pear device", true}, + {"apple,pear,orange", "", "fancy INTEL GRAPE device", false}, + // Somehow tagged as both, but still valid. + {"apple,pear,orange", "", "fancy INTEL pear GRAPE device", true}, + // Substring, so still valid. + {"apple,pear,orange", "", "fancy INTEL SNapple device", true}, + // No issues with doubling. + {"apple,pear,orange", "", "fancy orange orange device", true}, + // Empty, which is what would happen for non ChromeOS platforms. + {"apple,pear,orange", "", "", false}, + + // Excluded set: + {"", "apple,pear,orange", "apple", false}, + {"", "apple,pear,orange", "fancy INTEL pear device", false}, + {"", "apple,pear,orange", "fancy INTEL GRAPE device", true}, + // Somehow tagged as both. Very excluded! + {"", "apple,pear,orange", "fancy INTEL pear GRAPE device", false}, + // Substring, so still invalid. + {"", "apple,pear,orange", "fancy INTEL SNapple device", false}, + // Empty. + {"", "apple,pear,orange", "", true}, + + // Not testing when both are set as it should never occur and should be + // considered undefined. + }; + + for (size_t i = 0; i < ARRAYSIZE_UNSAFE(test_cases); ++i) { + Study_Filter filter; + std::vector<std::string> hardware_class; + base::SplitString(test_cases[i].hardware_class, ',', &hardware_class); + for (size_t j = 0; j < hardware_class.size(); ++j) + filter.add_hardware_class(hardware_class[j]); + + std::vector<std::string> exclude_hardware_class; + base::SplitString(test_cases[i].exclude_hardware_class, ',', + &exclude_hardware_class); + for (size_t j = 0; j < exclude_hardware_class.size(); ++j) + filter.add_exclude_hardware_class(exclude_hardware_class[j]); + + EXPECT_EQ(test_cases[i].expected_result, + internal::CheckStudyHardwareClass( + filter, test_cases[i].actual_hardware_class)); + } +} + TEST(VariationsStudyFilteringTest, FilterAndValidateStudies) { const std::string kTrial1Name = "A"; const std::string kGroup1Name = "Group1"; @@ -339,7 +398,7 @@ TEST(VariationsStudyFilteringTest, FilterAndValidateStudies) { std::vector<ProcessedStudy> processed_studies; FilterAndValidateStudies( seed, "en-CA", base::Time::Now(), base::Version("20.0.0.0"), - Study_Channel_STABLE, Study_FormFactor_DESKTOP, &processed_studies); + Study_Channel_STABLE, Study_FormFactor_DESKTOP, "", &processed_studies); // Check that only the first kTrial1Name study was kept. ASSERT_EQ(2U, processed_studies.size()); diff --git a/components/variations/variations_seed_processor.cc b/components/variations/variations_seed_processor.cc index e155100..e06474a 100644 --- a/components/variations/variations_seed_processor.cc +++ b/components/variations/variations_seed_processor.cc @@ -64,10 +64,11 @@ void VariationsSeedProcessor::CreateTrialsFromSeed( const base::Time& reference_date, const base::Version& version, Study_Channel channel, - Study_FormFactor form_factor) { + Study_FormFactor form_factor, + const std::string& hardware_class) { std::vector<ProcessedStudy> filtered_studies; FilterAndValidateStudies(seed, locale, reference_date, version, channel, - form_factor, &filtered_studies); + form_factor, hardware_class, &filtered_studies); for (size_t i = 0; i < filtered_studies.size(); ++i) CreateTrialFromStudy(filtered_studies[i]); diff --git a/components/variations/variations_seed_processor.h b/components/variations/variations_seed_processor.h index f6760ac..dd4d0c8 100644 --- a/components/variations/variations_seed_processor.h +++ b/components/variations/variations_seed_processor.h @@ -27,13 +27,15 @@ class VariationsSeedProcessor { virtual ~VariationsSeedProcessor(); // Creates field trials from the specified variations |seed|, based on the - // specified configuration (locale, current date, version and channel). + // specified configuration (locale, current date, version, channel, form + // factor and hardware_class). void CreateTrialsFromSeed(const VariationsSeed& seed, const std::string& locale, const base::Time& reference_date, const base::Version& version, Study_Channel channel, - Study_FormFactor form_factor); + Study_FormFactor form_factor, + const std::string& hardware_class); private: friend class VariationsSeedProcessorTest; diff --git a/components/variations/variations_seed_processor_unittest.cc b/components/variations/variations_seed_processor_unittest.cc index d882aed..833b5e0 100644 --- a/components/variations/variations_seed_processor_unittest.cc +++ b/components/variations/variations_seed_processor_unittest.cc @@ -196,7 +196,7 @@ TEST_F(VariationsSeedProcessorTest, study1->set_expiry_date(TimeToProtoTime(year_ago)); seed_processor.CreateTrialsFromSeed(seed, "en-CA", base::Time::Now(), version, Study_Channel_STABLE, - Study_FormFactor_DESKTOP); + Study_FormFactor_DESKTOP, ""); EXPECT_EQ(kGroup1Name, base::FieldTrialList::FindFullName(kTrialName)); } @@ -208,7 +208,7 @@ TEST_F(VariationsSeedProcessorTest, study2->set_expiry_date(TimeToProtoTime(year_ago)); seed_processor.CreateTrialsFromSeed(seed, "en-CA", base::Time::Now(), version, Study_Channel_STABLE, - Study_FormFactor_DESKTOP); + Study_FormFactor_DESKTOP, ""); EXPECT_EQ(kGroup1Name, base::FieldTrialList::FindFullName(kTrialName)); } } @@ -323,7 +323,7 @@ TEST_F(VariationsSeedProcessorTest, StartsActive) { seed_processor.CreateTrialsFromSeed(seed, "en-CA", base::Time::Now(), base::Version("20.0.0.0"), Study_Channel_STABLE, - Study_FormFactor_DESKTOP); + Study_FormFactor_DESKTOP, ""); // Non-specified and ACTIVATION_EXPLICIT should not start active, but // ACTIVATION_AUTO should. diff --git a/components/variations/variations_seed_simulator.cc b/components/variations/variations_seed_simulator.cc index 94e4fbb..62b9aaa 100644 --- a/components/variations/variations_seed_simulator.cc +++ b/components/variations/variations_seed_simulator.cc @@ -114,10 +114,11 @@ VariationsSeedSimulator::Result VariationsSeedSimulator::SimulateSeedStudies( const base::Time& reference_date, const base::Version& version, Study_Channel channel, - Study_FormFactor form_factor) { + Study_FormFactor form_factor, + const std::string& hardware_class) { std::vector<ProcessedStudy> filtered_studies; FilterAndValidateStudies(seed, locale, reference_date, version, channel, - form_factor, &filtered_studies); + form_factor, hardware_class, &filtered_studies); return ComputeDifferences(filtered_studies); } diff --git a/components/variations/variations_seed_simulator.h b/components/variations/variations_seed_simulator.h index ef9207b..36110ce 100644 --- a/components/variations/variations_seed_simulator.h +++ b/components/variations/variations_seed_simulator.h @@ -58,7 +58,8 @@ class VariationsSeedSimulator { const base::Time& reference_date, const base::Version& version, Study_Channel channel, - Study_FormFactor form_factor); + Study_FormFactor form_factor, + const std::string& hardware_class); private: friend class VariationsSeedSimulatorTest; |