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