Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(533)

Unified Diff: base/feature_list.cc

Issue 2546653002: Store and retrieve features from shared memory (Closed)
Patch Set: asvitkine@ comments Created 4 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
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
Alexei Svitkine (slow) 2016/12/01 20:05:52 future -> feature
bcwhite 2016/12/01 20:15:14 future => feature
lawrencewu 2016/12/02 19:24:46 Done.
+ // 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.
Alexei Svitkine (slow) 2016/12/01 20:05:52 Nit: Why not name it pickle_size then?
lawrencewu 2016/12/02 19:24:46 Done.
+ uint32_t size;
+
+ bool GetFeatureAndTrialName(StringPiece* feature_name,
Alexei Svitkine (slow) 2016/12/01 20:05:52 Add a comment and document that it's only valid to
lawrencewu 2016/12/02 19:24:46 Done.
+ 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))
bcwhite 2016/12/01 20:15:15 Just remove the if() and keep the comment as to wh
lawrencewu 2016/12/02 19:24:46 The function has warn_unused_result so I think I h
bcwhite 2016/12/02 19:34:57 // Need to return true because... so just ignore t
+ return true;
Alexei Svitkine (slow) 2016/12/01 20:05:52 Seems you can just simplify this to not have the i
lawrencewu 2016/12/02 19:24:46 The function has warn_unused_result so I think I h
+ 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);
Alexei Svitkine (slow) 2016/12/01 20:05:52 Check return value?
lawrencewu 2016/12/02 19:24:46 Not sure if we should return or continue on failur
+
+ 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;
Alexei Svitkine (slow) 2016/12/01 20:05:52 Seems like a bad thing to silently fail on.
lawrencewu 2016/12/02 19:24:46 We do the same thing in field_trial.cc. Maybe Term
+
+ 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_);

Powered by Google App Engine
This is Rietveld 408576698