summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorrkaplow@chromium.org <rkaplow@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2014-05-02 04:36:55 +0000
committerrkaplow@chromium.org <rkaplow@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2014-05-02 04:36:55 +0000
commitbca259407943b3c9db090adc4ba97bd31361818d (patch)
tree8f8b06045cb52b024812f063fabd804a84644557
parentd667e6e08e142695dcc77624d425b25270ac6d6b (diff)
downloadchromium_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.cc14
-rw-r--r--components/variations/proto/study.proto18
-rw-r--r--components/variations/study_filtering.cc48
-rw-r--r--components/variations/study_filtering.h13
-rw-r--r--components/variations/study_filtering_unittest.cc61
-rw-r--r--components/variations/variations_seed_processor.cc5
-rw-r--r--components/variations/variations_seed_processor.h6
-rw-r--r--components/variations/variations_seed_processor_unittest.cc6
-rw-r--r--components/variations/variations_seed_simulator.cc5
-rw-r--r--components/variations/variations_seed_simulator.h3
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;