| Index: base/feature_list.cc
 | 
| diff --git a/base/feature_list.cc b/base/feature_list.cc
 | 
| index 89b105defc6df0119688cb3b0e708f1b905f36df..c2f268b138b479ad1bdca59a855ab61f9b9425b2 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,42 @@ 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 feature. 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 pickle_size;
 | 
| +
 | 
| +  // Reads the feature and trial name from the pickle. Calling this is only
 | 
| +  // valid on an initialized entry that's in shared memory.
 | 
| +  bool GetFeatureAndTrialName(StringPiece* feature_name,
 | 
| +                              StringPiece* trial_name) const {
 | 
| +    const char* src =
 | 
| +        reinterpret_cast<const char*>(this) + sizeof(FeatureEntry);
 | 
| +
 | 
| +    Pickle pickle(src, pickle_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.
 | 
| +    auto sink = pickle_iter.ReadStringPiece(trial_name);
 | 
| +    ALLOW_UNUSED_LOCAL(sink);
 | 
| +    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 +93,31 @@ void FeatureList::InitializeFromCommandLine(
 | 
|    initialized_from_command_line_ = true;
 | 
|  }
 | 
|  
 | 
| +void FeatureList::InitializeFromSharedMemory(
 | 
| +    PersistentMemoryAllocator* allocator) {
 | 
| +  DCHECK(!initialized_);
 | 
| +
 | 
| +  PersistentMemoryAllocator::Iterator iter(allocator);
 | 
| +
 | 
| +  PersistentMemoryAllocator::Reference ref;
 | 
| +  while ((ref = iter.GetNextOfType(kFeatureType)) !=
 | 
| +         PersistentMemoryAllocator::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;
 | 
| +    if (!entry->GetFeatureAndTrialName(&feature_name, &trial_name))
 | 
| +      continue;
 | 
| +
 | 
| +    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 +160,33 @@ void FeatureList::RegisterFieldTrialOverride(const std::string& feature_name,
 | 
|    RegisterOverride(feature_name, override_state, field_trial);
 | 
|  }
 | 
|  
 | 
| +void FeatureList::AddFeaturesToAllocator(PersistentMemoryAllocator* 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();
 | 
| +    PersistentMemoryAllocator::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->pickle_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_);
 | 
| 
 |