| Index: base/metrics/field_trial.cc
|
| diff --git a/base/metrics/field_trial.cc b/base/metrics/field_trial.cc
|
| index 4b83451e12b534914cd02399e64cddc267348b3a..fcfd50d139bd7f744284cad1123d761a5d768b2f 100644
|
| --- a/base/metrics/field_trial.cc
|
| +++ b/base/metrics/field_trial.cc
|
| @@ -51,28 +51,61 @@ const size_t kFieldTrialAllocationSize = 4 << 10; // 4 KiB = one page
|
| // AddToAllocatorWhileLocked. The FieldTrialEntry is followed by a base::Pickle
|
| // object that we unpickle and read from.
|
| struct FieldTrialEntry {
|
| + // Whether or not this field trial is activated.
|
| bool activated;
|
|
|
| // Size of the pickled structure, NOT the total size of this entry.
|
| uint32_t size;
|
|
|
| - // Calling this is only valid when the entry is initialized. That is, it
|
| - // resides in shared memory and has a pickle containing the trial name and
|
| - // group name following it.
|
| - bool GetTrialAndGroupName(StringPiece* trial_name,
|
| - StringPiece* group_name) const {
|
| + // Returns an iterator over the data used for getting names and params.
|
| + PickleIterator GetPickleIterator() const {
|
| char* src = reinterpret_cast<char*>(const_cast<FieldTrialEntry*>(this)) +
|
| sizeof(FieldTrialEntry);
|
|
|
| Pickle pickle(src, size);
|
| - PickleIterator pickle_iter(pickle);
|
| + return PickleIterator(pickle);
|
| + }
|
|
|
| - if (!pickle_iter.ReadStringPiece(trial_name))
|
| + // Takes the iterator and writes out the first two items into |trial_name| and
|
| + // |group_name|.
|
| + bool ReadStringPair(PickleIterator iter,
|
| + StringPiece* trial_name,
|
| + StringPiece* group_name) const {
|
| + if (!iter.ReadStringPiece(trial_name))
|
| return false;
|
| - if (!pickle_iter.ReadStringPiece(group_name))
|
| + if (!iter.ReadStringPiece(group_name))
|
| return false;
|
| return true;
|
| }
|
| +
|
| + // Calling this is only valid when the entry is initialized. That is, it
|
| + // resides in shared memory and has a pickle containing the trial name and
|
| + // group name following it.
|
| + bool GetTrialAndGroupName(StringPiece* trial_name,
|
| + StringPiece* group_name) const {
|
| + PickleIterator iter = GetPickleIterator();
|
| + return ReadStringPair(iter, trial_name, group_name);
|
| + }
|
| +
|
| + bool GetParams(FieldTrialParamAssociator::FieldTrialParams* params) const {
|
| + PickleIterator iter = GetPickleIterator();
|
| + StringPiece tmp;
|
| + if (!ReadStringPair(iter, &tmp, &tmp))
|
| + return false;
|
| +
|
| + while (true) {
|
| + StringPiece key;
|
| + StringPiece value;
|
| + if (!iter.ReadStringPiece(&key))
|
| + return true; // No more params to read.
|
| + if (!iter.ReadStringPiece(&value))
|
| + return false;
|
| + (*params)[key.as_string()] = value.as_string();
|
| + }
|
| +
|
| + NOTREACHED() << "Hit field trial param limit";
|
| + return false;
|
| + }
|
| };
|
|
|
| // Created a time value based on |year|, |month| and |day_of_month| parameters.
|
| @@ -181,6 +214,26 @@ HANDLE CreateReadOnlyHandle(SharedPersistentMemoryAllocator* allocator) {
|
| }
|
| #endif
|
|
|
| +bool PickleFieldTrialState(const FieldTrial::State& trial_state,
|
| + Pickle* pickle) {
|
| + pickle->WriteString(trial_state.trial_name);
|
| + pickle->WriteString(trial_state.group_name);
|
| +
|
| + std::map<std::string, std::string> params;
|
| + if (!FieldTrialParamAssociator::GetInstance()
|
| + ->GetFieldTrialParamsWithGroupName(
|
| + trial_state.trial_name.as_string(),
|
| + trial_state.group_name.as_string(), ¶ms)) {
|
| + return false;
|
| + }
|
| +
|
| + for (const auto& param : params) {
|
| + pickle->WriteString(StringPiece(param.first));
|
| + pickle->WriteString(StringPiece(param.second));
|
| + }
|
| + return true;
|
| +}
|
| +
|
| } // namespace
|
|
|
| // statics
|
| @@ -527,6 +580,30 @@ std::string FieldTrialList::FindFullName(const std::string& trial_name) {
|
| }
|
|
|
| // static
|
| +bool FieldTrialList::FindParams(
|
| + const std::string& trial_name,
|
| + FieldTrialParamAssociator::FieldTrialParams* params) {
|
| + // Check that the allocator exists (it may not exist on Linux or macOS). This
|
| + // shouldn't ever happen on Windows, as child processes should get an
|
| + // allocator during initialization, and browser processes won't hit this
|
| + // function since it has the mapping in FieldTrialParamAssociator.
|
| + SharedPersistentMemoryAllocator* allocator =
|
| + global_->field_trial_allocator_.get();
|
| + if (allocator == nullptr)
|
| + return false;
|
| +
|
| + // Get the field trial's corresponding reference in shared memory. This
|
| + // shouldn't happen for on Windows the same reasons above.
|
| + FieldTrial* field_trial = Find(trial_name);
|
| + if (field_trial->ref_ == SharedPersistentMemoryAllocator::kReferenceNull)
|
| + return false;
|
| +
|
| + FieldTrialEntry* entry = allocator->GetAsObject<FieldTrialEntry>(
|
| + field_trial->ref_, kFieldTrialType);
|
| + return entry->GetParams(params);
|
| +}
|
| +
|
| +// static
|
| bool FieldTrialList::TrialExists(const std::string& trial_name) {
|
| return Find(trial_name) != NULL;
|
| }
|
| @@ -823,15 +900,17 @@ size_t FieldTrialList::GetFieldTrialCount() {
|
| // static
|
| void FieldTrialList::CreateTrialsFromSharedMemory(
|
| std::unique_ptr<SharedMemory> shm) {
|
| - const SharedPersistentMemoryAllocator shalloc(std::move(shm), 0,
|
| - kAllocatorName, true);
|
| - PersistentMemoryAllocator::Iterator mem_iter(&shalloc);
|
| + global_->field_trial_allocator_.reset(new SharedPersistentMemoryAllocator(
|
| + std::move(shm), 0, kAllocatorName, true));
|
| + SharedPersistentMemoryAllocator* shalloc =
|
| + global_->field_trial_allocator_.get();
|
| + PersistentMemoryAllocator::Iterator mem_iter(shalloc);
|
|
|
| SharedPersistentMemoryAllocator::Reference ref;
|
| while ((ref = mem_iter.GetNextOfType(kFieldTrialType)) !=
|
| SharedPersistentMemoryAllocator::kReferenceNull) {
|
| const FieldTrialEntry* entry =
|
| - shalloc.GetAsObject<const FieldTrialEntry>(ref, kFieldTrialType);
|
| + shalloc->GetAsObject<const FieldTrialEntry>(ref, kFieldTrialType);
|
|
|
| StringPiece trial_name;
|
| StringPiece group_name;
|
| @@ -904,8 +983,8 @@ void FieldTrialList::AddToAllocatorWhileLocked(FieldTrial* field_trial) {
|
| return;
|
|
|
| Pickle pickle;
|
| - pickle.WriteString(trial_state.trial_name);
|
| - pickle.WriteString(trial_state.group_name);
|
| + if (!PickleFieldTrialState(trial_state, &pickle))
|
| + return;
|
|
|
| size_t total_size = sizeof(FieldTrialEntry) + pickle.size();
|
| SharedPersistentMemoryAllocator::Reference ref =
|
|
|