Home | History | Annotate | Download | only in metrics
      1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "base/metrics/field_trial.h"
      6 
      7 #include <algorithm>
      8 #include <utility>
      9 
     10 #include "base/base_switches.h"
     11 #include "base/build_time.h"
     12 #include "base/command_line.h"
     13 #include "base/debug/activity_tracker.h"
     14 #include "base/logging.h"
     15 #include "base/metrics/field_trial_param_associator.h"
     16 #include "base/process/memory.h"
     17 #include "base/rand_util.h"
     18 #include "base/strings/string_number_conversions.h"
     19 #include "base/strings/string_util.h"
     20 #include "base/strings/stringprintf.h"
     21 #include "base/strings/utf_string_conversions.h"
     22 
     23 // On POSIX, the fd is shared using the mapping in GlobalDescriptors.
     24 #if defined(OS_POSIX) && !defined(OS_NACL)
     25 #include "base/posix/global_descriptors.h"
     26 #endif
     27 
     28 namespace base {
     29 
     30 namespace {
     31 
     32 // Define a separator character to use when creating a persistent form of an
     33 // instance.  This is intended for use as a command line argument, passed to a
     34 // second process to mimic our state (i.e., provide the same group name).
     35 const char kPersistentStringSeparator = '/';  // Currently a slash.
     36 
     37 // Define a marker character to be used as a prefix to a trial name on the
     38 // command line which forces its activation.
     39 const char kActivationMarker = '*';
     40 
     41 // Use shared memory to communicate field trial (experiment) state. Set to false
     42 // for now while the implementation is fleshed out (e.g. data format, single
     43 // shared memory segment). See https://codereview.chromium.org/2365273004/ and
     44 // crbug.com/653874
     45 // The browser is the only process that has write access to the shared memory.
     46 // This is safe from race conditions because MakeIterable is a release operation
     47 // and GetNextOfType is an acquire operation, so memory writes before
     48 // MakeIterable happen before memory reads after GetNextOfType.
     49 const bool kUseSharedMemoryForFieldTrials = true;
     50 
     51 // Constants for the field trial allocator.
     52 const char kAllocatorName[] = "FieldTrialAllocator";
     53 
     54 // We allocate 128 KiB to hold all the field trial data. This should be enough,
     55 // as most people use 3 - 25 KiB for field trials (as of 11/25/2016).
     56 // This also doesn't allocate all 128 KiB at once -- the pages only get mapped
     57 // to physical memory when they are touched. If the size of the allocated field
     58 // trials does get larger than 128 KiB, then we will drop some field trials in
     59 // child processes, leading to an inconsistent view between browser and child
     60 // processes and possibly causing crashes (see crbug.com/661617).
     61 const size_t kFieldTrialAllocationSize = 128 << 10;  // 128 KiB
     62 
     63 // Writes out string1 and then string2 to pickle.
     64 bool WriteStringPair(Pickle* pickle,
     65                      const StringPiece& string1,
     66                      const StringPiece& string2) {
     67   if (!pickle->WriteString(string1))
     68     return false;
     69   if (!pickle->WriteString(string2))
     70     return false;
     71   return true;
     72 }
     73 
     74 // Writes out the field trial's contents (via trial_state) to the pickle. The
     75 // format of the pickle looks like:
     76 // TrialName, GroupName, ParamKey1, ParamValue1, ParamKey2, ParamValue2, ...
     77 // If there are no parameters, then it just ends at GroupName.
     78 bool PickleFieldTrial(const FieldTrial::State& trial_state, Pickle* pickle) {
     79   if (!WriteStringPair(pickle, *trial_state.trial_name,
     80                        *trial_state.group_name)) {
     81     return false;
     82   }
     83 
     84   // Get field trial params.
     85   std::map<std::string, std::string> params;
     86   FieldTrialParamAssociator::GetInstance()->GetFieldTrialParamsWithoutFallback(
     87       *trial_state.trial_name, *trial_state.group_name, &params);
     88 
     89   // Write params to pickle.
     90   for (const auto& param : params) {
     91     if (!WriteStringPair(pickle, param.first, param.second))
     92       return false;
     93   }
     94   return true;
     95 }
     96 
     97 // Created a time value based on |year|, |month| and |day_of_month| parameters.
     98 Time CreateTimeFromParams(int year, int month, int day_of_month) {
     99   DCHECK_GT(year, 1970);
    100   DCHECK_GT(month, 0);
    101   DCHECK_LT(month, 13);
    102   DCHECK_GT(day_of_month, 0);
    103   DCHECK_LT(day_of_month, 32);
    104 
    105   Time::Exploded exploded;
    106   exploded.year = year;
    107   exploded.month = month;
    108   exploded.day_of_week = 0;  // Should be unused.
    109   exploded.day_of_month = day_of_month;
    110   exploded.hour = 0;
    111   exploded.minute = 0;
    112   exploded.second = 0;
    113   exploded.millisecond = 0;
    114   Time out_time;
    115   if (!Time::FromLocalExploded(exploded, &out_time)) {
    116     // TODO(maksims): implement failure handling.
    117     // We might just return |out_time|, which is Time(0).
    118     NOTIMPLEMENTED();
    119   }
    120 
    121   return out_time;
    122 }
    123 
    124 // Returns the boundary value for comparing against the FieldTrial's added
    125 // groups for a given |divisor| (total probability) and |entropy_value|.
    126 FieldTrial::Probability GetGroupBoundaryValue(
    127     FieldTrial::Probability divisor,
    128     double entropy_value) {
    129   // Add a tiny epsilon value to get consistent results when converting floating
    130   // points to int. Without it, boundary values have inconsistent results, e.g.:
    131   //
    132   //   static_cast<FieldTrial::Probability>(100 * 0.56) == 56
    133   //   static_cast<FieldTrial::Probability>(100 * 0.57) == 56
    134   //   static_cast<FieldTrial::Probability>(100 * 0.58) == 57
    135   //   static_cast<FieldTrial::Probability>(100 * 0.59) == 59
    136   const double kEpsilon = 1e-8;
    137   const FieldTrial::Probability result =
    138       static_cast<FieldTrial::Probability>(divisor * entropy_value + kEpsilon);
    139   // Ensure that adding the epsilon still results in a value < |divisor|.
    140   return std::min(result, divisor - 1);
    141 }
    142 
    143 // Separate type from FieldTrial::State so that it can use StringPieces.
    144 struct FieldTrialStringEntry {
    145   StringPiece trial_name;
    146   StringPiece group_name;
    147   bool activated = false;
    148 };
    149 
    150 // Parses the --force-fieldtrials string |trials_string| into |entries|.
    151 // Returns true if the string was parsed correctly. On failure, the |entries|
    152 // array may end up being partially filled.
    153 bool ParseFieldTrialsString(const std::string& trials_string,
    154                             std::vector<FieldTrialStringEntry>* entries) {
    155   const StringPiece trials_string_piece(trials_string);
    156 
    157   size_t next_item = 0;
    158   while (next_item < trials_string.length()) {
    159     size_t name_end = trials_string.find(kPersistentStringSeparator, next_item);
    160     if (name_end == trials_string.npos || next_item == name_end)
    161       return false;
    162     size_t group_name_end =
    163         trials_string.find(kPersistentStringSeparator, name_end + 1);
    164     if (name_end + 1 == group_name_end)
    165       return false;
    166     if (group_name_end == trials_string.npos)
    167       group_name_end = trials_string.length();
    168 
    169     FieldTrialStringEntry entry;
    170     // Verify if the trial should be activated or not.
    171     if (trials_string[next_item] == kActivationMarker) {
    172       // Name cannot be only the indicator.
    173       if (name_end - next_item == 1)
    174         return false;
    175       next_item++;
    176       entry.activated = true;
    177     }
    178     entry.trial_name =
    179         trials_string_piece.substr(next_item, name_end - next_item);
    180     entry.group_name =
    181         trials_string_piece.substr(name_end + 1, group_name_end - name_end - 1);
    182     next_item = group_name_end + 1;
    183 
    184     entries->push_back(std::move(entry));
    185   }
    186   return true;
    187 }
    188 
    189 void AddFeatureAndFieldTrialFlags(const char* enable_features_switch,
    190                                   const char* disable_features_switch,
    191                                   CommandLine* cmd_line) {
    192   std::string enabled_features;
    193   std::string disabled_features;
    194   FeatureList::GetInstance()->GetFeatureOverrides(&enabled_features,
    195                                                   &disabled_features);
    196 
    197   if (!enabled_features.empty())
    198     cmd_line->AppendSwitchASCII(enable_features_switch, enabled_features);
    199   if (!disabled_features.empty())
    200     cmd_line->AppendSwitchASCII(disable_features_switch, disabled_features);
    201 
    202   std::string field_trial_states;
    203   FieldTrialList::AllStatesToString(&field_trial_states);
    204   if (!field_trial_states.empty()) {
    205     cmd_line->AppendSwitchASCII(switches::kForceFieldTrials,
    206                                 field_trial_states);
    207   }
    208 }
    209 
    210 #if defined(OS_WIN)
    211 HANDLE CreateReadOnlyHandle(FieldTrialList::FieldTrialAllocator* allocator) {
    212   HANDLE src = allocator->shared_memory()->handle().GetHandle();
    213   ProcessHandle process = GetCurrentProcess();
    214   DWORD access = SECTION_MAP_READ | SECTION_QUERY;
    215   HANDLE dst;
    216   if (!::DuplicateHandle(process, src, process, &dst, access, true, 0))
    217     return kInvalidPlatformFile;
    218   return dst;
    219 }
    220 #endif
    221 
    222 #if defined(OS_POSIX) && !defined(OS_NACL)
    223 int CreateReadOnlyHandle(FieldTrialList::FieldTrialAllocator* allocator) {
    224   SharedMemoryHandle new_handle;
    225   allocator->shared_memory()->ShareReadOnlyToProcess(GetCurrentProcessHandle(),
    226                                                      &new_handle);
    227   return SharedMemory::GetFdFromSharedMemoryHandle(new_handle);
    228 }
    229 #endif
    230 
    231 void OnOutOfMemory(size_t size) {
    232 #if defined(OS_NACL)
    233   NOTREACHED();
    234 #else
    235   TerminateBecauseOutOfMemory(size);
    236 #endif
    237 }
    238 
    239 }  // namespace
    240 
    241 // statics
    242 const int FieldTrial::kNotFinalized = -1;
    243 const int FieldTrial::kDefaultGroupNumber = 0;
    244 bool FieldTrial::enable_benchmarking_ = false;
    245 
    246 int FieldTrialList::kNoExpirationYear = 0;
    247 
    248 //------------------------------------------------------------------------------
    249 // FieldTrial methods and members.
    250 
    251 FieldTrial::EntropyProvider::~EntropyProvider() {
    252 }
    253 
    254 FieldTrial::State::State() {}
    255 
    256 FieldTrial::State::State(const State& other) = default;
    257 
    258 FieldTrial::State::~State() {}
    259 
    260 bool FieldTrial::FieldTrialEntry::GetTrialAndGroupName(
    261     StringPiece* trial_name,
    262     StringPiece* group_name) const {
    263   PickleIterator iter = GetPickleIterator();
    264   return ReadStringPair(&iter, trial_name, group_name);
    265 }
    266 
    267 bool FieldTrial::FieldTrialEntry::GetParams(
    268     std::map<std::string, std::string>* params) const {
    269   PickleIterator iter = GetPickleIterator();
    270   StringPiece tmp;
    271   // Skip reading trial and group name.
    272   if (!ReadStringPair(&iter, &tmp, &tmp))
    273     return false;
    274 
    275   while (true) {
    276     StringPiece key;
    277     StringPiece value;
    278     if (!ReadStringPair(&iter, &key, &value))
    279       return key.empty();  // Non-empty is bad: got one of a pair.
    280     (*params)[key.as_string()] = value.as_string();
    281   }
    282 }
    283 
    284 PickleIterator FieldTrial::FieldTrialEntry::GetPickleIterator() const {
    285   const char* src =
    286       reinterpret_cast<const char*>(this) + sizeof(FieldTrialEntry);
    287 
    288   Pickle pickle(src, pickle_size);
    289   return PickleIterator(pickle);
    290 }
    291 
    292 bool FieldTrial::FieldTrialEntry::ReadStringPair(
    293     PickleIterator* iter,
    294     StringPiece* trial_name,
    295     StringPiece* group_name) const {
    296   if (!iter->ReadStringPiece(trial_name))
    297     return false;
    298   if (!iter->ReadStringPiece(group_name))
    299     return false;
    300   return true;
    301 }
    302 
    303 void FieldTrial::Disable() {
    304   DCHECK(!group_reported_);
    305   enable_field_trial_ = false;
    306 
    307   // In case we are disabled after initialization, we need to switch
    308   // the trial to the default group.
    309   if (group_ != kNotFinalized) {
    310     // Only reset when not already the default group, because in case we were
    311     // forced to the default group, the group number may not be
    312     // kDefaultGroupNumber, so we should keep it as is.
    313     if (group_name_ != default_group_name_)
    314       SetGroupChoice(default_group_name_, kDefaultGroupNumber);
    315   }
    316 }
    317 
    318 int FieldTrial::AppendGroup(const std::string& name,
    319                             Probability group_probability) {
    320   // When the group choice was previously forced, we only need to return the
    321   // the id of the chosen group, and anything can be returned for the others.
    322   if (forced_) {
    323     DCHECK(!group_name_.empty());
    324     if (name == group_name_) {
    325       // Note that while |group_| may be equal to |kDefaultGroupNumber| on the
    326       // forced trial, it will not have the same value as the default group
    327       // number returned from the non-forced |FactoryGetFieldTrial()| call,
    328       // which takes care to ensure that this does not happen.
    329       return group_;
    330     }
    331     DCHECK_NE(next_group_number_, group_);
    332     // We still return different numbers each time, in case some caller need
    333     // them to be different.
    334     return next_group_number_++;
    335   }
    336 
    337   DCHECK_LE(group_probability, divisor_);
    338   DCHECK_GE(group_probability, 0);
    339 
    340   if (enable_benchmarking_ || !enable_field_trial_)
    341     group_probability = 0;
    342 
    343   accumulated_group_probability_ += group_probability;
    344 
    345   DCHECK_LE(accumulated_group_probability_, divisor_);
    346   if (group_ == kNotFinalized && accumulated_group_probability_ > random_) {
    347     // This is the group that crossed the random line, so we do the assignment.
    348     SetGroupChoice(name, next_group_number_);
    349   }
    350   return next_group_number_++;
    351 }
    352 
    353 int FieldTrial::group() {
    354   FinalizeGroupChoice();
    355   if (trial_registered_)
    356     FieldTrialList::NotifyFieldTrialGroupSelection(this);
    357   return group_;
    358 }
    359 
    360 const std::string& FieldTrial::group_name() {
    361   // Call |group()| to ensure group gets assigned and observers are notified.
    362   group();
    363   DCHECK(!group_name_.empty());
    364   return group_name_;
    365 }
    366 
    367 const std::string& FieldTrial::GetGroupNameWithoutActivation() {
    368   FinalizeGroupChoice();
    369   return group_name_;
    370 }
    371 
    372 void FieldTrial::SetForced() {
    373   // We might have been forced before (e.g., by CreateFieldTrial) and it's
    374   // first come first served, e.g., command line switch has precedence.
    375   if (forced_)
    376     return;
    377 
    378   // And we must finalize the group choice before we mark ourselves as forced.
    379   FinalizeGroupChoice();
    380   forced_ = true;
    381 }
    382 
    383 // static
    384 void FieldTrial::EnableBenchmarking() {
    385   DCHECK_EQ(0u, FieldTrialList::GetFieldTrialCount());
    386   enable_benchmarking_ = true;
    387 }
    388 
    389 // static
    390 FieldTrial* FieldTrial::CreateSimulatedFieldTrial(
    391     const std::string& trial_name,
    392     Probability total_probability,
    393     const std::string& default_group_name,
    394     double entropy_value) {
    395   return new FieldTrial(trial_name, total_probability, default_group_name,
    396                         entropy_value);
    397 }
    398 
    399 FieldTrial::FieldTrial(const std::string& trial_name,
    400                        const Probability total_probability,
    401                        const std::string& default_group_name,
    402                        double entropy_value)
    403     : trial_name_(trial_name),
    404       divisor_(total_probability),
    405       default_group_name_(default_group_name),
    406       random_(GetGroupBoundaryValue(total_probability, entropy_value)),
    407       accumulated_group_probability_(0),
    408       next_group_number_(kDefaultGroupNumber + 1),
    409       group_(kNotFinalized),
    410       enable_field_trial_(true),
    411       forced_(false),
    412       group_reported_(false),
    413       trial_registered_(false),
    414       ref_(FieldTrialList::FieldTrialAllocator::kReferenceNull) {
    415   DCHECK_GT(total_probability, 0);
    416   DCHECK(!trial_name_.empty());
    417   DCHECK(!default_group_name_.empty());
    418 }
    419 
    420 FieldTrial::~FieldTrial() {}
    421 
    422 void FieldTrial::SetTrialRegistered() {
    423   DCHECK_EQ(kNotFinalized, group_);
    424   DCHECK(!trial_registered_);
    425   trial_registered_ = true;
    426 }
    427 
    428 void FieldTrial::SetGroupChoice(const std::string& group_name, int number) {
    429   group_ = number;
    430   if (group_name.empty())
    431     StringAppendF(&group_name_, "%d", group_);
    432   else
    433     group_name_ = group_name;
    434   DVLOG(1) << "Field trial: " << trial_name_ << " Group choice:" << group_name_;
    435 }
    436 
    437 void FieldTrial::FinalizeGroupChoice() {
    438   FinalizeGroupChoiceImpl(false);
    439 }
    440 
    441 void FieldTrial::FinalizeGroupChoiceImpl(bool is_locked) {
    442   if (group_ != kNotFinalized)
    443     return;
    444   accumulated_group_probability_ = divisor_;
    445   // Here it's OK to use |kDefaultGroupNumber| since we can't be forced and not
    446   // finalized.
    447   DCHECK(!forced_);
    448   SetGroupChoice(default_group_name_, kDefaultGroupNumber);
    449 
    450   // Add the field trial to shared memory.
    451   if (kUseSharedMemoryForFieldTrials && trial_registered_)
    452     FieldTrialList::OnGroupFinalized(is_locked, this);
    453 }
    454 
    455 bool FieldTrial::GetActiveGroup(ActiveGroup* active_group) const {
    456   if (!group_reported_ || !enable_field_trial_)
    457     return false;
    458   DCHECK_NE(group_, kNotFinalized);
    459   active_group->trial_name = trial_name_;
    460   active_group->group_name = group_name_;
    461   return true;
    462 }
    463 
    464 bool FieldTrial::GetState(State* field_trial_state) {
    465   if (!enable_field_trial_)
    466     return false;
    467   FinalizeGroupChoice();
    468   field_trial_state->trial_name = &trial_name_;
    469   field_trial_state->group_name = &group_name_;
    470   field_trial_state->activated = group_reported_;
    471   return true;
    472 }
    473 
    474 bool FieldTrial::GetStateWhileLocked(State* field_trial_state) {
    475   if (!enable_field_trial_)
    476     return false;
    477   FinalizeGroupChoiceImpl(true);
    478   field_trial_state->trial_name = &trial_name_;
    479   field_trial_state->group_name = &group_name_;
    480   field_trial_state->activated = group_reported_;
    481   return true;
    482 }
    483 
    484 //------------------------------------------------------------------------------
    485 // FieldTrialList methods and members.
    486 
    487 // static
    488 FieldTrialList* FieldTrialList::global_ = NULL;
    489 
    490 // static
    491 bool FieldTrialList::used_without_global_ = false;
    492 
    493 FieldTrialList::Observer::~Observer() {
    494 }
    495 
    496 FieldTrialList::FieldTrialList(
    497     std::unique_ptr<const FieldTrial::EntropyProvider> entropy_provider)
    498     : entropy_provider_(std::move(entropy_provider)),
    499       observer_list_(new ObserverListThreadSafe<FieldTrialList::Observer>(
    500           ObserverListBase<FieldTrialList::Observer>::NOTIFY_EXISTING_ONLY)) {
    501   DCHECK(!global_);
    502   DCHECK(!used_without_global_);
    503   global_ = this;
    504 
    505   Time two_years_from_build_time = GetBuildTime() + TimeDelta::FromDays(730);
    506   Time::Exploded exploded;
    507   two_years_from_build_time.LocalExplode(&exploded);
    508   kNoExpirationYear = exploded.year;
    509 }
    510 
    511 FieldTrialList::~FieldTrialList() {
    512   AutoLock auto_lock(lock_);
    513   while (!registered_.empty()) {
    514     RegistrationMap::iterator it = registered_.begin();
    515     it->second->Release();
    516     registered_.erase(it->first);
    517   }
    518   DCHECK_EQ(this, global_);
    519   global_ = NULL;
    520 }
    521 
    522 // static
    523 FieldTrial* FieldTrialList::FactoryGetFieldTrial(
    524     const std::string& trial_name,
    525     FieldTrial::Probability total_probability,
    526     const std::string& default_group_name,
    527     const int year,
    528     const int month,
    529     const int day_of_month,
    530     FieldTrial::RandomizationType randomization_type,
    531     int* default_group_number) {
    532   return FactoryGetFieldTrialWithRandomizationSeed(
    533       trial_name, total_probability, default_group_name, year, month,
    534       day_of_month, randomization_type, 0, default_group_number, NULL);
    535 }
    536 
    537 // static
    538 FieldTrial* FieldTrialList::FactoryGetFieldTrialWithRandomizationSeed(
    539     const std::string& trial_name,
    540     FieldTrial::Probability total_probability,
    541     const std::string& default_group_name,
    542     const int year,
    543     const int month,
    544     const int day_of_month,
    545     FieldTrial::RandomizationType randomization_type,
    546     uint32_t randomization_seed,
    547     int* default_group_number,
    548     const FieldTrial::EntropyProvider* override_entropy_provider) {
    549   if (default_group_number)
    550     *default_group_number = FieldTrial::kDefaultGroupNumber;
    551   // Check if the field trial has already been created in some other way.
    552   FieldTrial* existing_trial = Find(trial_name);
    553   if (existing_trial) {
    554     CHECK(existing_trial->forced_);
    555     // If the default group name differs between the existing forced trial
    556     // and this trial, then use a different value for the default group number.
    557     if (default_group_number &&
    558         default_group_name != existing_trial->default_group_name()) {
    559       // If the new default group number corresponds to the group that was
    560       // chosen for the forced trial (which has been finalized when it was
    561       // forced), then set the default group number to that.
    562       if (default_group_name == existing_trial->group_name_internal()) {
    563         *default_group_number = existing_trial->group_;
    564       } else {
    565         // Otherwise, use |kNonConflictingGroupNumber| (-2) for the default
    566         // group number, so that it does not conflict with the |AppendGroup()|
    567         // result for the chosen group.
    568         const int kNonConflictingGroupNumber = -2;
    569         static_assert(
    570             kNonConflictingGroupNumber != FieldTrial::kDefaultGroupNumber,
    571             "The 'non-conflicting' group number conflicts");
    572         static_assert(kNonConflictingGroupNumber != FieldTrial::kNotFinalized,
    573                       "The 'non-conflicting' group number conflicts");
    574         *default_group_number = kNonConflictingGroupNumber;
    575       }
    576     }
    577     return existing_trial;
    578   }
    579 
    580   double entropy_value;
    581   if (randomization_type == FieldTrial::ONE_TIME_RANDOMIZED) {
    582     // If an override entropy provider is given, use it.
    583     const FieldTrial::EntropyProvider* entropy_provider =
    584         override_entropy_provider ? override_entropy_provider
    585                                   : GetEntropyProviderForOneTimeRandomization();
    586     CHECK(entropy_provider);
    587     entropy_value = entropy_provider->GetEntropyForTrial(trial_name,
    588                                                          randomization_seed);
    589   } else {
    590     DCHECK_EQ(FieldTrial::SESSION_RANDOMIZED, randomization_type);
    591     DCHECK_EQ(0U, randomization_seed);
    592     entropy_value = RandDouble();
    593   }
    594 
    595   FieldTrial* field_trial = new FieldTrial(trial_name, total_probability,
    596                                            default_group_name, entropy_value);
    597   if (GetBuildTime() > CreateTimeFromParams(year, month, day_of_month))
    598     field_trial->Disable();
    599   FieldTrialList::Register(field_trial);
    600   return field_trial;
    601 }
    602 
    603 // static
    604 FieldTrial* FieldTrialList::Find(const std::string& trial_name) {
    605   if (!global_)
    606     return NULL;
    607   AutoLock auto_lock(global_->lock_);
    608   return global_->PreLockedFind(trial_name);
    609 }
    610 
    611 // static
    612 int FieldTrialList::FindValue(const std::string& trial_name) {
    613   FieldTrial* field_trial = Find(trial_name);
    614   if (field_trial)
    615     return field_trial->group();
    616   return FieldTrial::kNotFinalized;
    617 }
    618 
    619 // static
    620 std::string FieldTrialList::FindFullName(const std::string& trial_name) {
    621   FieldTrial* field_trial = Find(trial_name);
    622   if (field_trial)
    623     return field_trial->group_name();
    624   return std::string();
    625 }
    626 
    627 // static
    628 bool FieldTrialList::TrialExists(const std::string& trial_name) {
    629   return Find(trial_name) != NULL;
    630 }
    631 
    632 // static
    633 bool FieldTrialList::IsTrialActive(const std::string& trial_name) {
    634   FieldTrial* field_trial = Find(trial_name);
    635   FieldTrial::ActiveGroup active_group;
    636   return field_trial && field_trial->GetActiveGroup(&active_group);
    637 }
    638 
    639 // static
    640 void FieldTrialList::StatesToString(std::string* output) {
    641   FieldTrial::ActiveGroups active_groups;
    642   GetActiveFieldTrialGroups(&active_groups);
    643   for (FieldTrial::ActiveGroups::const_iterator it = active_groups.begin();
    644        it != active_groups.end(); ++it) {
    645     DCHECK_EQ(std::string::npos,
    646               it->trial_name.find(kPersistentStringSeparator));
    647     DCHECK_EQ(std::string::npos,
    648               it->group_name.find(kPersistentStringSeparator));
    649     output->append(it->trial_name);
    650     output->append(1, kPersistentStringSeparator);
    651     output->append(it->group_name);
    652     output->append(1, kPersistentStringSeparator);
    653   }
    654 }
    655 
    656 // static
    657 void FieldTrialList::AllStatesToString(std::string* output) {
    658   if (!global_)
    659     return;
    660   AutoLock auto_lock(global_->lock_);
    661 
    662   for (const auto& registered : global_->registered_) {
    663     FieldTrial::State trial;
    664     if (!registered.second->GetStateWhileLocked(&trial))
    665       continue;
    666     DCHECK_EQ(std::string::npos,
    667               trial.trial_name->find(kPersistentStringSeparator));
    668     DCHECK_EQ(std::string::npos,
    669               trial.group_name->find(kPersistentStringSeparator));
    670     if (trial.activated)
    671       output->append(1, kActivationMarker);
    672     output->append(*trial.trial_name);
    673     output->append(1, kPersistentStringSeparator);
    674     output->append(*trial.group_name);
    675     output->append(1, kPersistentStringSeparator);
    676   }
    677 }
    678 
    679 // static
    680 void FieldTrialList::GetActiveFieldTrialGroups(
    681     FieldTrial::ActiveGroups* active_groups) {
    682   DCHECK(active_groups->empty());
    683   if (!global_)
    684     return;
    685   AutoLock auto_lock(global_->lock_);
    686 
    687   for (RegistrationMap::iterator it = global_->registered_.begin();
    688        it != global_->registered_.end(); ++it) {
    689     FieldTrial::ActiveGroup active_group;
    690     if (it->second->GetActiveGroup(&active_group))
    691       active_groups->push_back(active_group);
    692   }
    693 }
    694 
    695 // static
    696 void FieldTrialList::GetActiveFieldTrialGroupsFromString(
    697     const std::string& trials_string,
    698     FieldTrial::ActiveGroups* active_groups) {
    699   std::vector<FieldTrialStringEntry> entries;
    700   if (!ParseFieldTrialsString(trials_string, &entries))
    701     return;
    702 
    703   for (const auto& entry : entries) {
    704     if (entry.activated) {
    705       FieldTrial::ActiveGroup group;
    706       group.trial_name = entry.trial_name.as_string();
    707       group.group_name = entry.group_name.as_string();
    708       active_groups->push_back(group);
    709     }
    710   }
    711 }
    712 
    713 // static
    714 void FieldTrialList::GetInitiallyActiveFieldTrials(
    715     const base::CommandLine& command_line,
    716     FieldTrial::ActiveGroups* active_groups) {
    717   DCHECK(global_->create_trials_from_command_line_called_);
    718 
    719   if (!global_->field_trial_allocator_) {
    720     GetActiveFieldTrialGroupsFromString(
    721         command_line.GetSwitchValueASCII(switches::kForceFieldTrials),
    722         active_groups);
    723     return;
    724   }
    725 
    726   FieldTrialAllocator* allocator = global_->field_trial_allocator_.get();
    727   FieldTrialAllocator::Iterator mem_iter(allocator);
    728   const FieldTrial::FieldTrialEntry* entry;
    729   while ((entry = mem_iter.GetNextOfObject<FieldTrial::FieldTrialEntry>()) !=
    730          nullptr) {
    731     StringPiece trial_name;
    732     StringPiece group_name;
    733     if (subtle::NoBarrier_Load(&entry->activated) &&
    734         entry->GetTrialAndGroupName(&trial_name, &group_name)) {
    735       FieldTrial::ActiveGroup group;
    736       group.trial_name = trial_name.as_string();
    737       group.group_name = group_name.as_string();
    738       active_groups->push_back(group);
    739     }
    740   }
    741 }
    742 
    743 // static
    744 bool FieldTrialList::CreateTrialsFromString(
    745     const std::string& trials_string,
    746     const std::set<std::string>& ignored_trial_names) {
    747   DCHECK(global_);
    748   if (trials_string.empty() || !global_)
    749     return true;
    750 
    751   std::vector<FieldTrialStringEntry> entries;
    752   if (!ParseFieldTrialsString(trials_string, &entries))
    753     return false;
    754 
    755   for (const auto& entry : entries) {
    756     const std::string trial_name = entry.trial_name.as_string();
    757     const std::string group_name = entry.group_name.as_string();
    758 
    759     if (ContainsKey(ignored_trial_names, trial_name))
    760       continue;
    761 
    762     FieldTrial* trial = CreateFieldTrial(trial_name, group_name);
    763     if (!trial)
    764       return false;
    765     if (entry.activated) {
    766       // Call |group()| to mark the trial as "used" and notify observers, if
    767       // any. This is useful to ensure that field trials created in child
    768       // processes are properly reported in crash reports.
    769       trial->group();
    770     }
    771   }
    772   return true;
    773 }
    774 
    775 // static
    776 void FieldTrialList::CreateTrialsFromCommandLine(
    777     const CommandLine& cmd_line,
    778     const char* field_trial_handle_switch,
    779     int fd_key) {
    780   global_->create_trials_from_command_line_called_ = true;
    781 
    782 #if defined(OS_WIN)
    783   if (cmd_line.HasSwitch(field_trial_handle_switch)) {
    784     std::string handle_switch =
    785         cmd_line.GetSwitchValueASCII(field_trial_handle_switch);
    786     bool result = CreateTrialsFromHandleSwitch(handle_switch);
    787     DCHECK(result);
    788   }
    789 #endif
    790 
    791 #if defined(OS_POSIX) && !defined(OS_NACL)
    792   // On POSIX, we check if the handle is valid by seeing if the browser process
    793   // sent over the switch (we don't care about the value). Invalid handles
    794   // occur in some browser tests which don't initialize the allocator.
    795   if (cmd_line.HasSwitch(field_trial_handle_switch)) {
    796     bool result = CreateTrialsFromDescriptor(fd_key);
    797     DCHECK(result);
    798   }
    799 #endif
    800 
    801   if (cmd_line.HasSwitch(switches::kForceFieldTrials)) {
    802     bool result = FieldTrialList::CreateTrialsFromString(
    803         cmd_line.GetSwitchValueASCII(switches::kForceFieldTrials),
    804         std::set<std::string>());
    805     DCHECK(result);
    806   }
    807 }
    808 
    809 // static
    810 void FieldTrialList::CreateFeaturesFromCommandLine(
    811     const base::CommandLine& command_line,
    812     const char* enable_features_switch,
    813     const char* disable_features_switch,
    814     FeatureList* feature_list) {
    815   // Fallback to command line if not using shared memory.
    816   if (!kUseSharedMemoryForFieldTrials ||
    817       !global_->field_trial_allocator_.get()) {
    818     return feature_list->InitializeFromCommandLine(
    819         command_line.GetSwitchValueASCII(enable_features_switch),
    820         command_line.GetSwitchValueASCII(disable_features_switch));
    821   }
    822 
    823   feature_list->InitializeFromSharedMemory(
    824       global_->field_trial_allocator_.get());
    825 }
    826 
    827 #if defined(OS_WIN)
    828 // static
    829 void FieldTrialList::AppendFieldTrialHandleIfNeeded(
    830     HandlesToInheritVector* handles) {
    831   if (!global_)
    832     return;
    833   if (kUseSharedMemoryForFieldTrials) {
    834     InstantiateFieldTrialAllocatorIfNeeded();
    835     if (global_->readonly_allocator_handle_)
    836       handles->push_back(global_->readonly_allocator_handle_);
    837   }
    838 }
    839 #endif
    840 
    841 #if defined(OS_POSIX) && !defined(OS_NACL)
    842 // static
    843 int FieldTrialList::GetFieldTrialHandle() {
    844   if (global_ && kUseSharedMemoryForFieldTrials) {
    845     InstantiateFieldTrialAllocatorIfNeeded();
    846     // We check for an invalid handle where this gets called.
    847     return global_->readonly_allocator_handle_;
    848   }
    849   return kInvalidPlatformFile;
    850 }
    851 #endif
    852 
    853 // static
    854 void FieldTrialList::CopyFieldTrialStateToFlags(
    855     const char* field_trial_handle_switch,
    856     const char* enable_features_switch,
    857     const char* disable_features_switch,
    858     CommandLine* cmd_line) {
    859   // TODO(lawrencewu): Ideally, having the global would be guaranteed. However,
    860   // content browser tests currently don't create a FieldTrialList because they
    861   // don't run ChromeBrowserMainParts code where it's done for Chrome.
    862   // Some tests depend on the enable and disable features flag switch, though,
    863   // so we can still add those even though AllStatesToString() will be a no-op.
    864   if (!global_) {
    865     AddFeatureAndFieldTrialFlags(enable_features_switch,
    866                                  disable_features_switch, cmd_line);
    867     return;
    868   }
    869 
    870   // Use shared memory to pass the state if the feature is enabled, otherwise
    871   // fallback to passing it via the command line as a string.
    872   if (kUseSharedMemoryForFieldTrials) {
    873     InstantiateFieldTrialAllocatorIfNeeded();
    874     // If the readonly handle didn't get duplicated properly, then fallback to
    875     // original behavior.
    876     if (global_->readonly_allocator_handle_ == kInvalidPlatformFile) {
    877       AddFeatureAndFieldTrialFlags(enable_features_switch,
    878                                    disable_features_switch, cmd_line);
    879       return;
    880     }
    881 
    882     global_->field_trial_allocator_->UpdateTrackingHistograms();
    883 
    884 #if defined(OS_WIN)
    885     // We need to pass a named anonymous handle to shared memory over the
    886     // command line on Windows, since the child doesn't know which of the
    887     // handles it inherited it should open.
    888     // PlatformFile is typedef'd to HANDLE which is typedef'd to void *. We
    889     // basically cast the handle into an int (uintptr_t, to be exact), stringify
    890     // the int, and pass it as a command-line flag. The child process will do
    891     // the reverse conversions to retrieve the handle. See
    892     // http://stackoverflow.com/a/153077
    893     auto uintptr_handle =
    894         reinterpret_cast<uintptr_t>(global_->readonly_allocator_handle_);
    895     std::string field_trial_handle = std::to_string(uintptr_handle);
    896     cmd_line->AppendSwitchASCII(field_trial_handle_switch, field_trial_handle);
    897 #elif defined(OS_POSIX)
    898     // On POSIX, we dup the fd into a fixed fd kFieldTrialDescriptor, so we
    899     // don't have to pass over the handle (it's not even the right handle
    900     // anyways). But some browser tests don't create the allocator, so we need
    901     // to be able to distinguish valid and invalid handles. We do that by just
    902     // checking that the flag is set with a dummy value.
    903     cmd_line->AppendSwitchASCII(field_trial_handle_switch, "1");
    904 #else
    905 #error Unsupported OS
    906 #endif
    907     return;
    908   }
    909 
    910   AddFeatureAndFieldTrialFlags(enable_features_switch, disable_features_switch,
    911                                cmd_line);
    912 }
    913 
    914 // static
    915 FieldTrial* FieldTrialList::CreateFieldTrial(
    916     const std::string& name,
    917     const std::string& group_name) {
    918   DCHECK(global_);
    919   DCHECK_GE(name.size(), 0u);
    920   DCHECK_GE(group_name.size(), 0u);
    921   if (name.empty() || group_name.empty() || !global_)
    922     return NULL;
    923 
    924   FieldTrial* field_trial = FieldTrialList::Find(name);
    925   if (field_trial) {
    926     // In single process mode, or when we force them from the command line,
    927     // we may have already created the field trial.
    928     if (field_trial->group_name_internal() != group_name)
    929       return NULL;
    930     return field_trial;
    931   }
    932   const int kTotalProbability = 100;
    933   field_trial = new FieldTrial(name, kTotalProbability, group_name, 0);
    934   FieldTrialList::Register(field_trial);
    935   // Force the trial, which will also finalize the group choice.
    936   field_trial->SetForced();
    937   return field_trial;
    938 }
    939 
    940 // static
    941 void FieldTrialList::AddObserver(Observer* observer) {
    942   if (!global_)
    943     return;
    944   global_->observer_list_->AddObserver(observer);
    945 }
    946 
    947 // static
    948 void FieldTrialList::RemoveObserver(Observer* observer) {
    949   if (!global_)
    950     return;
    951   global_->observer_list_->RemoveObserver(observer);
    952 }
    953 
    954 // static
    955 void FieldTrialList::OnGroupFinalized(bool is_locked, FieldTrial* field_trial) {
    956   if (!global_)
    957     return;
    958   if (is_locked) {
    959     AddToAllocatorWhileLocked(global_->field_trial_allocator_.get(),
    960                               field_trial);
    961   } else {
    962     AutoLock auto_lock(global_->lock_);
    963     AddToAllocatorWhileLocked(global_->field_trial_allocator_.get(),
    964                               field_trial);
    965   }
    966 }
    967 
    968 // static
    969 void FieldTrialList::NotifyFieldTrialGroupSelection(FieldTrial* field_trial) {
    970   if (!global_)
    971     return;
    972 
    973   {
    974     AutoLock auto_lock(global_->lock_);
    975     if (field_trial->group_reported_)
    976       return;
    977     field_trial->group_reported_ = true;
    978 
    979     if (!field_trial->enable_field_trial_)
    980       return;
    981 
    982     if (kUseSharedMemoryForFieldTrials)
    983       ActivateFieldTrialEntryWhileLocked(field_trial);
    984   }
    985 
    986   // Recording for stability debugging has to be done inline as a task posted
    987   // to an observer may not get executed before a crash.
    988   base::debug::GlobalActivityTracker* tracker =
    989       base::debug::GlobalActivityTracker::Get();
    990   if (tracker) {
    991     tracker->RecordFieldTrial(field_trial->trial_name(),
    992                               field_trial->group_name_internal());
    993   }
    994 
    995   global_->observer_list_->Notify(
    996       FROM_HERE, &FieldTrialList::Observer::OnFieldTrialGroupFinalized,
    997       field_trial->trial_name(), field_trial->group_name_internal());
    998 }
    999 
   1000 // static
   1001 size_t FieldTrialList::GetFieldTrialCount() {
   1002   if (!global_)
   1003     return 0;
   1004   AutoLock auto_lock(global_->lock_);
   1005   return global_->registered_.size();
   1006 }
   1007 
   1008 // static
   1009 bool FieldTrialList::GetParamsFromSharedMemory(
   1010     FieldTrial* field_trial,
   1011     std::map<std::string, std::string>* params) {
   1012   DCHECK(global_);
   1013   // If the field trial allocator is not set up yet, then there are several
   1014   // cases:
   1015   //   - We are in the browser process and the allocator has not been set up
   1016   //   yet. If we got here, then we couldn't find the params in
   1017   //   FieldTrialParamAssociator, so it's definitely not here. Return false.
   1018   //   - Using shared memory for field trials is not enabled. If we got here,
   1019   //   then there's nothing in shared memory. Return false.
   1020   //   - We are in the child process and the allocator has not been set up yet.
   1021   //   If this is the case, then you are calling this too early. The field trial
   1022   //   allocator should get set up very early in the lifecycle. Try to see if
   1023   //   you can call it after it's been set up.
   1024   AutoLock auto_lock(global_->lock_);
   1025   if (!global_->field_trial_allocator_)
   1026     return false;
   1027 
   1028   // If ref_ isn't set, then the field trial data can't be in shared memory.
   1029   if (!field_trial->ref_)
   1030     return false;
   1031 
   1032   const FieldTrial::FieldTrialEntry* entry =
   1033       global_->field_trial_allocator_->GetAsObject<FieldTrial::FieldTrialEntry>(
   1034           field_trial->ref_);
   1035 
   1036   size_t allocated_size =
   1037       global_->field_trial_allocator_->GetAllocSize(field_trial->ref_);
   1038   size_t actual_size = sizeof(FieldTrial::FieldTrialEntry) + entry->pickle_size;
   1039   if (allocated_size < actual_size)
   1040     return false;
   1041 
   1042   return entry->GetParams(params);
   1043 }
   1044 
   1045 // static
   1046 void FieldTrialList::ClearParamsFromSharedMemoryForTesting() {
   1047   if (!global_)
   1048     return;
   1049 
   1050   AutoLock auto_lock(global_->lock_);
   1051   if (!global_->field_trial_allocator_)
   1052     return;
   1053 
   1054   // To clear the params, we iterate through every item in the allocator, copy
   1055   // just the trial and group name into a newly-allocated segment and then clear
   1056   // the existing item.
   1057   FieldTrialAllocator* allocator = global_->field_trial_allocator_.get();
   1058   FieldTrialAllocator::Iterator mem_iter(allocator);
   1059 
   1060   // List of refs to eventually be made iterable. We can't make it in the loop,
   1061   // since it would go on forever.
   1062   std::vector<FieldTrial::FieldTrialRef> new_refs;
   1063 
   1064   FieldTrial::FieldTrialRef prev_ref;
   1065   while ((prev_ref = mem_iter.GetNextOfType<FieldTrial::FieldTrialEntry>()) !=
   1066          FieldTrialAllocator::kReferenceNull) {
   1067     // Get the existing field trial entry in shared memory.
   1068     const FieldTrial::FieldTrialEntry* prev_entry =
   1069         allocator->GetAsObject<FieldTrial::FieldTrialEntry>(prev_ref);
   1070     StringPiece trial_name;
   1071     StringPiece group_name;
   1072     if (!prev_entry->GetTrialAndGroupName(&trial_name, &group_name))
   1073       continue;
   1074 
   1075     // Write a new entry, minus the params.
   1076     Pickle pickle;
   1077     pickle.WriteString(trial_name);
   1078     pickle.WriteString(group_name);
   1079     size_t total_size = sizeof(FieldTrial::FieldTrialEntry) + pickle.size();
   1080     FieldTrial::FieldTrialEntry* new_entry =
   1081         allocator->New<FieldTrial::FieldTrialEntry>(total_size);
   1082     subtle::NoBarrier_Store(&new_entry->activated,
   1083                             subtle::NoBarrier_Load(&prev_entry->activated));
   1084     new_entry->pickle_size = pickle.size();
   1085 
   1086     // TODO(lawrencewu): Modify base::Pickle to be able to write over a section
   1087     // in memory, so we can avoid this memcpy.
   1088     char* dst = reinterpret_cast<char*>(new_entry) +
   1089                 sizeof(FieldTrial::FieldTrialEntry);
   1090     memcpy(dst, pickle.data(), pickle.size());
   1091 
   1092     // Update the ref on the field trial and add it to the list to be made
   1093     // iterable.
   1094     FieldTrial::FieldTrialRef new_ref = allocator->GetAsReference(new_entry);
   1095     FieldTrial* trial = global_->PreLockedFind(trial_name.as_string());
   1096     trial->ref_ = new_ref;
   1097     new_refs.push_back(new_ref);
   1098 
   1099     // Mark the existing entry as unused.
   1100     allocator->ChangeType(prev_ref, 0,
   1101                           FieldTrial::FieldTrialEntry::kPersistentTypeId,
   1102                           /*clear=*/false);
   1103   }
   1104 
   1105   for (const auto& ref : new_refs) {
   1106     allocator->MakeIterable(ref);
   1107   }
   1108 }
   1109 
   1110 // static
   1111 void FieldTrialList::DumpAllFieldTrialsToPersistentAllocator(
   1112     PersistentMemoryAllocator* allocator) {
   1113   if (!global_)
   1114     return;
   1115   AutoLock auto_lock(global_->lock_);
   1116   for (const auto& registered : global_->registered_) {
   1117     AddToAllocatorWhileLocked(allocator, registered.second);
   1118   }
   1119 }
   1120 
   1121 // static
   1122 std::vector<const FieldTrial::FieldTrialEntry*>
   1123 FieldTrialList::GetAllFieldTrialsFromPersistentAllocator(
   1124     PersistentMemoryAllocator const& allocator) {
   1125   std::vector<const FieldTrial::FieldTrialEntry*> entries;
   1126   FieldTrialAllocator::Iterator iter(&allocator);
   1127   const FieldTrial::FieldTrialEntry* entry;
   1128   while ((entry = iter.GetNextOfObject<FieldTrial::FieldTrialEntry>()) !=
   1129          nullptr) {
   1130     entries.push_back(entry);
   1131   }
   1132   return entries;
   1133 }
   1134 
   1135 #if defined(OS_WIN)
   1136 // static
   1137 bool FieldTrialList::CreateTrialsFromHandleSwitch(
   1138     const std::string& handle_switch) {
   1139   int field_trial_handle = std::stoi(handle_switch);
   1140   HANDLE handle = reinterpret_cast<HANDLE>(field_trial_handle);
   1141   SharedMemoryHandle shm_handle(handle, GetCurrentProcId());
   1142   return FieldTrialList::CreateTrialsFromSharedMemoryHandle(shm_handle);
   1143 }
   1144 #endif
   1145 
   1146 #if defined(OS_POSIX) && !defined(OS_NACL)
   1147 // static
   1148 bool FieldTrialList::CreateTrialsFromDescriptor(int fd_key) {
   1149   if (!kUseSharedMemoryForFieldTrials)
   1150     return false;
   1151 
   1152   if (fd_key == -1)
   1153     return false;
   1154 
   1155   int fd = GlobalDescriptors::GetInstance()->MaybeGet(fd_key);
   1156   if (fd == -1)
   1157     return false;
   1158 
   1159 #if defined(OS_MACOSX) && !defined(OS_IOS)
   1160   SharedMemoryHandle shm_handle(FileDescriptor(fd, true));
   1161 #else
   1162   SharedMemoryHandle shm_handle(fd, true);
   1163 #endif
   1164 
   1165   bool result = FieldTrialList::CreateTrialsFromSharedMemoryHandle(shm_handle);
   1166   DCHECK(result);
   1167   return true;
   1168 }
   1169 #endif
   1170 
   1171 // static
   1172 bool FieldTrialList::CreateTrialsFromSharedMemoryHandle(
   1173     SharedMemoryHandle shm_handle) {
   1174   // shm gets deleted when it gets out of scope, but that's OK because we need
   1175   // it only for the duration of this method.
   1176   std::unique_ptr<SharedMemory> shm(new SharedMemory(shm_handle, true));
   1177   if (!shm.get()->Map(kFieldTrialAllocationSize))
   1178     OnOutOfMemory(kFieldTrialAllocationSize);
   1179 
   1180   return FieldTrialList::CreateTrialsFromSharedMemory(std::move(shm));
   1181 }
   1182 
   1183 // static
   1184 bool FieldTrialList::CreateTrialsFromSharedMemory(
   1185     std::unique_ptr<SharedMemory> shm) {
   1186   global_->field_trial_allocator_.reset(
   1187       new FieldTrialAllocator(std::move(shm), 0, kAllocatorName, true));
   1188   FieldTrialAllocator* shalloc = global_->field_trial_allocator_.get();
   1189   FieldTrialAllocator::Iterator mem_iter(shalloc);
   1190 
   1191   const FieldTrial::FieldTrialEntry* entry;
   1192   while ((entry = mem_iter.GetNextOfObject<FieldTrial::FieldTrialEntry>()) !=
   1193          nullptr) {
   1194     StringPiece trial_name;
   1195     StringPiece group_name;
   1196     if (!entry->GetTrialAndGroupName(&trial_name, &group_name))
   1197       return false;
   1198 
   1199     // TODO(lawrencewu): Convert the API for CreateFieldTrial to take
   1200     // StringPieces.
   1201     FieldTrial* trial =
   1202         CreateFieldTrial(trial_name.as_string(), group_name.as_string());
   1203 
   1204     trial->ref_ = mem_iter.GetAsReference(entry);
   1205     if (subtle::NoBarrier_Load(&entry->activated)) {
   1206       // Call |group()| to mark the trial as "used" and notify observers, if
   1207       // any. This is useful to ensure that field trials created in child
   1208       // processes are properly reported in crash reports.
   1209       trial->group();
   1210     }
   1211   }
   1212   return true;
   1213 }
   1214 
   1215 // static
   1216 void FieldTrialList::InstantiateFieldTrialAllocatorIfNeeded() {
   1217   if (!global_)
   1218     return;
   1219   AutoLock auto_lock(global_->lock_);
   1220   // Create the allocator if not already created and add all existing trials.
   1221   if (global_->field_trial_allocator_ != nullptr)
   1222     return;
   1223 
   1224   SharedMemoryCreateOptions options;
   1225   options.size = kFieldTrialAllocationSize;
   1226   options.share_read_only = true;
   1227 #if defined(OS_MACOSX) && !defined(OS_IOS)
   1228   options.type = SharedMemoryHandle::POSIX;
   1229 #endif
   1230 
   1231   std::unique_ptr<SharedMemory> shm(new SharedMemory());
   1232   if (!shm->Create(options))
   1233     OnOutOfMemory(kFieldTrialAllocationSize);
   1234 
   1235   if (!shm->Map(kFieldTrialAllocationSize))
   1236     OnOutOfMemory(kFieldTrialAllocationSize);
   1237 
   1238   global_->field_trial_allocator_.reset(
   1239       new FieldTrialAllocator(std::move(shm), 0, kAllocatorName, false));
   1240   global_->field_trial_allocator_->CreateTrackingHistograms(kAllocatorName);
   1241 
   1242   // Add all existing field trials.
   1243   for (const auto& registered : global_->registered_) {
   1244     AddToAllocatorWhileLocked(global_->field_trial_allocator_.get(),
   1245                               registered.second);
   1246   }
   1247 
   1248   // Add all existing features.
   1249   FeatureList::GetInstance()->AddFeaturesToAllocator(
   1250       global_->field_trial_allocator_.get());
   1251 
   1252 #if !defined(OS_NACL)
   1253   // Set |readonly_allocator_handle_| so we can pass it to be inherited and
   1254   // via the command line.
   1255   global_->readonly_allocator_handle_ =
   1256       CreateReadOnlyHandle(global_->field_trial_allocator_.get());
   1257 #endif
   1258 }
   1259 
   1260 // static
   1261 void FieldTrialList::AddToAllocatorWhileLocked(
   1262     PersistentMemoryAllocator* allocator,
   1263     FieldTrial* field_trial) {
   1264   // Don't do anything if the allocator hasn't been instantiated yet.
   1265   if (allocator == nullptr)
   1266     return;
   1267 
   1268   // Or if the allocator is read only, which means we are in a child process and
   1269   // shouldn't be writing to it.
   1270   if (allocator->IsReadonly())
   1271     return;
   1272 
   1273   FieldTrial::State trial_state;
   1274   if (!field_trial->GetStateWhileLocked(&trial_state))
   1275     return;
   1276 
   1277   // Or if we've already added it. We must check after GetState since it can
   1278   // also add to the allocator.
   1279   if (field_trial->ref_)
   1280     return;
   1281 
   1282   Pickle pickle;
   1283   if (!PickleFieldTrial(trial_state, &pickle)) {
   1284     NOTREACHED();
   1285     return;
   1286   }
   1287 
   1288   size_t total_size = sizeof(FieldTrial::FieldTrialEntry) + pickle.size();
   1289   FieldTrial::FieldTrialRef ref = allocator->Allocate(
   1290       total_size, FieldTrial::FieldTrialEntry::kPersistentTypeId);
   1291   if (ref == FieldTrialAllocator::kReferenceNull) {
   1292     NOTREACHED();
   1293     return;
   1294   }
   1295 
   1296   FieldTrial::FieldTrialEntry* entry =
   1297       allocator->GetAsObject<FieldTrial::FieldTrialEntry>(ref);
   1298   subtle::NoBarrier_Store(&entry->activated, trial_state.activated);
   1299   entry->pickle_size = pickle.size();
   1300 
   1301   // TODO(lawrencewu): Modify base::Pickle to be able to write over a section in
   1302   // memory, so we can avoid this memcpy.
   1303   char* dst =
   1304       reinterpret_cast<char*>(entry) + sizeof(FieldTrial::FieldTrialEntry);
   1305   memcpy(dst, pickle.data(), pickle.size());
   1306 
   1307   allocator->MakeIterable(ref);
   1308   field_trial->ref_ = ref;
   1309 }
   1310 
   1311 // static
   1312 void FieldTrialList::ActivateFieldTrialEntryWhileLocked(
   1313     FieldTrial* field_trial) {
   1314   FieldTrialAllocator* allocator = global_->field_trial_allocator_.get();
   1315 
   1316   // Check if we're in the child process and return early if so.
   1317   if (allocator && allocator->IsReadonly())
   1318     return;
   1319 
   1320   FieldTrial::FieldTrialRef ref = field_trial->ref_;
   1321   if (ref == FieldTrialAllocator::kReferenceNull) {
   1322     // It's fine to do this even if the allocator hasn't been instantiated
   1323     // yet -- it'll just return early.
   1324     AddToAllocatorWhileLocked(global_->field_trial_allocator_.get(),
   1325                               field_trial);
   1326   } else {
   1327     // It's also okay to do this even though the callee doesn't have a lock --
   1328     // the only thing that happens on a stale read here is a slight performance
   1329     // hit from the child re-synchronizing activation state.
   1330     FieldTrial::FieldTrialEntry* entry =
   1331         allocator->GetAsObject<FieldTrial::FieldTrialEntry>(ref);
   1332     subtle::NoBarrier_Store(&entry->activated, 1);
   1333   }
   1334 }
   1335 
   1336 // static
   1337 const FieldTrial::EntropyProvider*
   1338     FieldTrialList::GetEntropyProviderForOneTimeRandomization() {
   1339   if (!global_) {
   1340     used_without_global_ = true;
   1341     return NULL;
   1342   }
   1343 
   1344   return global_->entropy_provider_.get();
   1345 }
   1346 
   1347 FieldTrial* FieldTrialList::PreLockedFind(const std::string& name) {
   1348   RegistrationMap::iterator it = registered_.find(name);
   1349   if (registered_.end() == it)
   1350     return NULL;
   1351   return it->second;
   1352 }
   1353 
   1354 // static
   1355 void FieldTrialList::Register(FieldTrial* trial) {
   1356   if (!global_) {
   1357     used_without_global_ = true;
   1358     return;
   1359   }
   1360   AutoLock auto_lock(global_->lock_);
   1361   CHECK(!global_->PreLockedFind(trial->trial_name())) << trial->trial_name();
   1362   trial->AddRef();
   1363   trial->SetTrialRegistered();
   1364   global_->registered_[trial->trial_name()] = trial;
   1365 }
   1366 
   1367 }  // namespace base
   1368