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_); |