| Index: base/feature_list.cc
|
| diff --git a/base/feature_list.cc b/base/feature_list.cc
|
| index 89b105defc6df0119688cb3b0e708f1b905f36df..38e632252c3b895f811cd440f390a50ff2e5600d 100644
|
| --- a/base/feature_list.cc
|
| +++ b/base/feature_list.cc
|
| @@ -12,6 +12,7 @@
|
| #include "base/logging.h"
|
| #include "base/memory/ptr_util.h"
|
| #include "base/metrics/field_trial.h"
|
| +#include "base/pickle.h"
|
| #include "base/strings/string_split.h"
|
| #include "base/strings/string_util.h"
|
|
|
| @@ -27,6 +28,40 @@ FeatureList* g_instance = nullptr;
|
| // Tracks whether the FeatureList instance was initialized via an accessor.
|
| bool g_initialized_from_accessor = false;
|
|
|
| +const uint32_t kFeatureType = 0x06567CA6 + 1; // SHA1(FeatureEntry) v1
|
| +
|
| +// An allocator entry for a feature in shared memory. The FeatureEntry is
|
| +// followed by a base::Pickle object that contains the feature and trial name.
|
| +// Any changes to this structure requires a bump in kFeatureType defined above.
|
| +struct FeatureEntry {
|
| + // Expected size for 32/64-bit check.
|
| + static constexpr size_t kExpectedInstanceSize = 8;
|
| +
|
| + // Specifies whether a feature override enables or disables the future. Same
|
| + // values as the OverrideState enum in feature_list.h
|
| + uint32_t override_state;
|
| +
|
| + // Size of the pickled structure, NOT the total size of this entry.
|
| + uint32_t size;
|
| +
|
| + bool GetFeatureAndTrialName(StringPiece* feature_name,
|
| + StringPiece* trial_name) const {
|
| + char* src = reinterpret_cast<char*>(const_cast<FeatureEntry*>(this)) +
|
| + sizeof(FeatureEntry);
|
| +
|
| + Pickle pickle(src, size);
|
| + PickleIterator pickle_iter(pickle);
|
| +
|
| + if (!pickle_iter.ReadStringPiece(feature_name))
|
| + return false;
|
| +
|
| + // Return true because we are not guaranteed to have a trial name anyways.
|
| + if (!pickle_iter.ReadStringPiece(trial_name))
|
| + return true;
|
| + return true;
|
| + }
|
| +};
|
| +
|
| // Some characters are not allowed to appear in feature names or the associated
|
| // field trial names, as they are used as special characters for command-line
|
| // serialization. This function checks that the strings are ASCII (since they
|
| @@ -56,6 +91,30 @@ void FeatureList::InitializeFromCommandLine(
|
| initialized_from_command_line_ = true;
|
| }
|
|
|
| +void FeatureList::InitializeFromSharedMemory(
|
| + SharedPersistentMemoryAllocator* allocator) {
|
| + DCHECK(!initialized_);
|
| +
|
| + SharedPersistentMemoryAllocator::Iterator iter(allocator);
|
| +
|
| + SharedPersistentMemoryAllocator::Reference ref;
|
| + while ((ref = iter.GetNextOfType(kFeatureType)) !=
|
| + SharedPersistentMemoryAllocator::kReferenceNull) {
|
| + const FeatureEntry* entry =
|
| + allocator->GetAsObject<const FeatureEntry>(ref, kFeatureType);
|
| +
|
| + OverrideState override_state =
|
| + static_cast<OverrideState>(entry->override_state);
|
| +
|
| + StringPiece feature_name;
|
| + StringPiece trial_name;
|
| + entry->GetFeatureAndTrialName(&feature_name, &trial_name);
|
| +
|
| + FieldTrial* trial = FieldTrialList::Find(trial_name.as_string());
|
| + RegisterOverride(feature_name, override_state, trial);
|
| + }
|
| +}
|
| +
|
| bool FeatureList::IsFeatureOverriddenFromCommandLine(
|
| const std::string& feature_name,
|
| OverrideState state) const {
|
| @@ -98,6 +157,34 @@ void FeatureList::RegisterFieldTrialOverride(const std::string& feature_name,
|
| RegisterOverride(feature_name, override_state, field_trial);
|
| }
|
|
|
| +void FeatureList::AddFeaturesToAllocator(
|
| + FieldTrialList::FieldTrialAllocator* allocator) {
|
| + DCHECK(initialized_);
|
| +
|
| + for (const auto& override : overrides_) {
|
| + Pickle pickle;
|
| + pickle.WriteString(override.first);
|
| + if (override.second.field_trial)
|
| + pickle.WriteString(override.second.field_trial->trial_name());
|
| +
|
| + size_t total_size = sizeof(FeatureEntry) + pickle.size();
|
| + SharedPersistentMemoryAllocator::Reference ref =
|
| + allocator->Allocate(total_size, kFeatureType);
|
| + if (!ref)
|
| + return;
|
| +
|
| + FeatureEntry* entry =
|
| + allocator->GetAsObject<FeatureEntry>(ref, kFeatureType);
|
| + entry->override_state = override.second.overridden_state;
|
| + entry->size = pickle.size();
|
| +
|
| + char* dst = reinterpret_cast<char*>(entry) + sizeof(FeatureEntry);
|
| + memcpy(dst, pickle.data(), pickle.size());
|
| +
|
| + allocator->MakeIterable(ref);
|
| + }
|
| +}
|
| +
|
| void FeatureList::GetFeatureOverrides(std::string* enable_overrides,
|
| std::string* disable_overrides) {
|
| DCHECK(initialized_);
|
|
|