• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 // FieldTrial is a class for handling details of statistical experiments
6 // performed by actual users in the field (i.e., in a shipped or beta product).
7 // All code is called exclusively on the UI thread currently.
8 //
9 // The simplest example is an experiment to see whether one of two options
10 // produces "better" results across our user population.  In that scenario, UMA
11 // data is uploaded to aggregate the test results, and this FieldTrial class
12 // manages the state of each such experiment (state == which option was
13 // pseudo-randomly selected).
14 //
15 // States are typically generated randomly, either based on a one time
16 // randomization (which will yield the same results, in terms of selecting
17 // the client for a field trial or not, for every run of the program on a
18 // given machine), or by a session randomization (generated each time the
19 // application starts up, but held constant during the duration of the
20 // process).
21 
22 //------------------------------------------------------------------------------
23 // Example:  Suppose we have an experiment involving memory, such as determining
24 // the impact of some pruning algorithm.
25 // We assume that we already have a histogram of memory usage, such as:
26 
27 //   UMA_HISTOGRAM_COUNTS("Memory.RendererTotal", count);
28 
29 // Somewhere in main thread initialization code, we'd probably define an
30 // instance of a FieldTrial, with code such as:
31 
32 // // FieldTrials are reference counted, and persist automagically until
33 // // process teardown, courtesy of their automatic registration in
34 // // FieldTrialList.
35 // // Note: This field trial will run in Chrome instances compiled through
36 // //       8 July, 2015, and after that all instances will be in "StandardMem".
37 // scoped_refptr<base::FieldTrial> trial(
38 //     base::FieldTrialList::FactoryGetFieldTrial(
39 //         "MemoryExperiment", 1000, "StandardMem", 2015, 7, 8,
40 //         base::FieldTrial::ONE_TIME_RANDOMIZED, NULL));
41 //
42 // const int high_mem_group =
43 //     trial->AppendGroup("HighMem", 20);  // 2% in HighMem group.
44 // const int low_mem_group =
45 //     trial->AppendGroup("LowMem", 20);   // 2% in LowMem group.
46 // // Take action depending of which group we randomly land in.
47 // if (trial->group() == high_mem_group)
48 //   SetPruningAlgorithm(kType1);  // Sample setting of browser state.
49 // else if (trial->group() == low_mem_group)
50 //   SetPruningAlgorithm(kType2);  // Sample alternate setting.
51 
52 //------------------------------------------------------------------------------
53 
54 #ifndef BASE_METRICS_FIELD_TRIAL_H_
55 #define BASE_METRICS_FIELD_TRIAL_H_
56 
57 #include <stddef.h>
58 #include <stdint.h>
59 
60 #include <map>
61 #include <memory>
62 #include <set>
63 #include <string>
64 #include <vector>
65 
66 #include "base/atomicops.h"
67 #include "base/base_export.h"
68 #include "base/command_line.h"
69 #include "base/feature_list.h"
70 #include "base/files/file.h"
71 #include "base/gtest_prod_util.h"
72 #include "base/macros.h"
73 #include "base/memory/ref_counted.h"
74 #include "base/memory/shared_memory.h"
75 #include "base/metrics/persistent_memory_allocator.h"
76 #include "base/observer_list_threadsafe.h"
77 #include "base/pickle.h"
78 #include "base/process/launch.h"
79 #include "base/strings/string_piece.h"
80 #include "base/synchronization/lock.h"
81 #include "base/time/time.h"
82 
83 namespace base {
84 
85 class FieldTrialList;
86 
87 class BASE_EXPORT FieldTrial : public RefCounted<FieldTrial> {
88  public:
89   typedef int Probability;  // Probability type for being selected in a trial.
90 
91   // TODO(665129): Make private again after crash has been resolved.
92   typedef SharedPersistentMemoryAllocator::Reference FieldTrialRef;
93 
94   // Specifies the persistence of the field trial group choice.
95   enum RandomizationType {
96     // One time randomized trials will persist the group choice between
97     // restarts, which is recommended for most trials, especially those that
98     // change user visible behavior.
99     ONE_TIME_RANDOMIZED,
100     // Session randomized trials will roll the dice to select a group on every
101     // process restart.
102     SESSION_RANDOMIZED,
103   };
104 
105   // EntropyProvider is an interface for providing entropy for one-time
106   // randomized (persistent) field trials.
107   class BASE_EXPORT EntropyProvider {
108    public:
109     virtual ~EntropyProvider();
110 
111     // Returns a double in the range of [0, 1) to be used for the dice roll for
112     // the specified field trial. If |randomization_seed| is not 0, it will be
113     // used in preference to |trial_name| for generating the entropy by entropy
114     // providers that support it. A given instance should always return the same
115     // value given the same input |trial_name| and |randomization_seed| values.
116     virtual double GetEntropyForTrial(const std::string& trial_name,
117                                       uint32_t randomization_seed) const = 0;
118   };
119 
120   // A pair representing a Field Trial and its selected group.
121   struct ActiveGroup {
122     std::string trial_name;
123     std::string group_name;
124   };
125 
126   // A triplet representing a FieldTrial, its selected group and whether it's
127   // active. String members are pointers to the underlying strings owned by the
128   // FieldTrial object. Does not use StringPiece to avoid conversions back to
129   // std::string.
130   struct BASE_EXPORT State {
131     const std::string* trial_name = nullptr;
132     const std::string* group_name = nullptr;
133     bool activated = false;
134 
135     State();
136     State(const State& other);
137     ~State();
138   };
139 
140   // We create one FieldTrialEntry per field trial in shared memory, via
141   // AddToAllocatorWhileLocked. The FieldTrialEntry is followed by a
142   // base::Pickle object that we unpickle and read from.
143   struct BASE_EXPORT FieldTrialEntry {
144     // SHA1(FieldTrialEntry): Increment this if structure changes!
145     static constexpr uint32_t kPersistentTypeId = 0xABA17E13 + 2;
146 
147     // Expected size for 32/64-bit check.
148     static constexpr size_t kExpectedInstanceSize = 8;
149 
150     // Whether or not this field trial is activated. This is really just a
151     // boolean but using a 32 bit value for portability reasons. It should be
152     // accessed via NoBarrier_Load()/NoBarrier_Store() to prevent the compiler
153     // from doing unexpected optimizations because it thinks that only one
154     // thread is accessing the memory location.
155     subtle::Atomic32 activated;
156 
157     // Size of the pickled structure, NOT the total size of this entry.
158     uint32_t pickle_size;
159 
160     // Calling this is only valid when the entry is initialized. That is, it
161     // resides in shared memory and has a pickle containing the trial name and
162     // group name following it.
163     bool GetTrialAndGroupName(StringPiece* trial_name,
164                               StringPiece* group_name) const;
165 
166     // Calling this is only valid when the entry is initialized as well. Reads
167     // the parameters following the trial and group name and stores them as
168     // key-value mappings in |params|.
169     bool GetParams(std::map<std::string, std::string>* params) const;
170 
171    private:
172     // Returns an iterator over the data containing names and params.
173     PickleIterator GetPickleIterator() const;
174 
175     // Takes the iterator and writes out the first two items into |trial_name|
176     // and |group_name|.
177     bool ReadStringPair(PickleIterator* iter,
178                         StringPiece* trial_name,
179                         StringPiece* group_name) const;
180   };
181 
182   typedef std::vector<ActiveGroup> ActiveGroups;
183 
184   // A return value to indicate that a given instance has not yet had a group
185   // assignment (and hence is not yet participating in the trial).
186   static const int kNotFinalized;
187 
188   // Disables this trial, meaning it always determines the default group
189   // has been selected. May be called immediately after construction, or
190   // at any time after initialization (should not be interleaved with
191   // AppendGroup calls). Once disabled, there is no way to re-enable a
192   // trial.
193   // TODO(mad): http://code.google.com/p/chromium/issues/detail?id=121446
194   // This doesn't properly reset to Default when a group was forced.
195   void Disable();
196 
197   // Establish the name and probability of the next group in this trial.
198   // Sometimes, based on construction randomization, this call may cause the
199   // provided group to be *THE* group selected for use in this instance.
200   // The return value is the group number of the new group.
201   int AppendGroup(const std::string& name, Probability group_probability);
202 
203   // Return the name of the FieldTrial (excluding the group name).
trial_name()204   const std::string& trial_name() const { return trial_name_; }
205 
206   // Return the randomly selected group number that was assigned, and notify
207   // any/all observers that this finalized group number has presumably been used
208   // (queried), and will never change. Note that this will force an instance to
209   // participate, and make it illegal to attempt to probabilistically add any
210   // other groups to the trial.
211   int group();
212 
213   // If the group's name is empty, a string version containing the group number
214   // is used as the group name. This causes a winner to be chosen if none was.
215   const std::string& group_name();
216 
217   // Finalizes the group choice and returns the chosen group, but does not mark
218   // the trial as active - so its state will not be reported until group_name()
219   // or similar is called.
220   const std::string& GetGroupNameWithoutActivation();
221 
222   // Set the field trial as forced, meaning that it was setup earlier than
223   // the hard coded registration of the field trial to override it.
224   // This allows the code that was hard coded to register the field trial to
225   // still succeed even though the field trial has already been registered.
226   // This must be called after appending all the groups, since we will make
227   // the group choice here. Note that this is a NOOP for already forced trials.
228   // And, as the rest of the FieldTrial code, this is not thread safe and must
229   // be done from the UI thread.
230   void SetForced();
231 
232   // Enable benchmarking sets field trials to a common setting.
233   static void EnableBenchmarking();
234 
235   // Creates a FieldTrial object with the specified parameters, to be used for
236   // simulation of group assignment without actually affecting global field
237   // trial state in the running process. Group assignment will be done based on
238   // |entropy_value|, which must have a range of [0, 1).
239   //
240   // Note: Using this function will not register the field trial globally in the
241   // running process - for that, use FieldTrialList::FactoryGetFieldTrial().
242   //
243   // The ownership of the returned FieldTrial is transfered to the caller which
244   // is responsible for deref'ing it (e.g. by using scoped_refptr<FieldTrial>).
245   static FieldTrial* CreateSimulatedFieldTrial(
246       const std::string& trial_name,
247       Probability total_probability,
248       const std::string& default_group_name,
249       double entropy_value);
250 
251  private:
252   // Allow tests to access our innards for testing purposes.
253   FRIEND_TEST_ALL_PREFIXES(FieldTrialTest, Registration);
254   FRIEND_TEST_ALL_PREFIXES(FieldTrialTest, AbsoluteProbabilities);
255   FRIEND_TEST_ALL_PREFIXES(FieldTrialTest, RemainingProbability);
256   FRIEND_TEST_ALL_PREFIXES(FieldTrialTest, FiftyFiftyProbability);
257   FRIEND_TEST_ALL_PREFIXES(FieldTrialTest, MiddleProbabilities);
258   FRIEND_TEST_ALL_PREFIXES(FieldTrialTest, OneWinner);
259   FRIEND_TEST_ALL_PREFIXES(FieldTrialTest, DisableProbability);
260   FRIEND_TEST_ALL_PREFIXES(FieldTrialTest, ActiveGroups);
261   FRIEND_TEST_ALL_PREFIXES(FieldTrialTest, AllGroups);
262   FRIEND_TEST_ALL_PREFIXES(FieldTrialTest, ActiveGroupsNotFinalized);
263   FRIEND_TEST_ALL_PREFIXES(FieldTrialTest, Save);
264   FRIEND_TEST_ALL_PREFIXES(FieldTrialTest, SaveAll);
265   FRIEND_TEST_ALL_PREFIXES(FieldTrialTest, DuplicateRestore);
266   FRIEND_TEST_ALL_PREFIXES(FieldTrialTest, SetForcedTurnFeatureOff);
267   FRIEND_TEST_ALL_PREFIXES(FieldTrialTest, SetForcedTurnFeatureOn);
268   FRIEND_TEST_ALL_PREFIXES(FieldTrialTest, SetForcedChangeDefault_Default);
269   FRIEND_TEST_ALL_PREFIXES(FieldTrialTest, SetForcedChangeDefault_NonDefault);
270   FRIEND_TEST_ALL_PREFIXES(FieldTrialTest, FloatBoundariesGiveEqualGroupSizes);
271   FRIEND_TEST_ALL_PREFIXES(FieldTrialTest, DoesNotSurpassTotalProbability);
272   FRIEND_TEST_ALL_PREFIXES(FieldTrialListTest,
273                            DoNotAddSimulatedFieldTrialsToAllocator);
274   FRIEND_TEST_ALL_PREFIXES(FieldTrialListTest, ClearParamsFromSharedMemory);
275 
276   friend class base::FieldTrialList;
277 
278   friend class RefCounted<FieldTrial>;
279 
280   // This is the group number of the 'default' group when a choice wasn't forced
281   // by a call to FieldTrialList::CreateFieldTrial. It is kept private so that
282   // consumers don't use it by mistake in cases where the group was forced.
283   static const int kDefaultGroupNumber;
284 
285   // Creates a field trial with the specified parameters. Group assignment will
286   // be done based on |entropy_value|, which must have a range of [0, 1).
287   FieldTrial(const std::string& trial_name,
288              Probability total_probability,
289              const std::string& default_group_name,
290              double entropy_value);
291   virtual ~FieldTrial();
292 
293   // Return the default group name of the FieldTrial.
default_group_name()294   std::string default_group_name() const { return default_group_name_; }
295 
296   // Marks this trial as having been registered with the FieldTrialList. Must be
297   // called no more than once and before any |group()| calls have occurred.
298   void SetTrialRegistered();
299 
300   // Sets the chosen group name and number.
301   void SetGroupChoice(const std::string& group_name, int number);
302 
303   // Ensures that a group is chosen, if it hasn't yet been. The field trial
304   // might yet be disabled, so this call will *not* notify observers of the
305   // status.
306   void FinalizeGroupChoice();
307 
308   // Implements FinalizeGroupChoice() with the added flexibility of being
309   // deadlock-free if |is_locked| is true and the caller is holding a lock.
310   void FinalizeGroupChoiceImpl(bool is_locked);
311 
312   // Returns the trial name and selected group name for this field trial via
313   // the output parameter |active_group|, but only if the group has already
314   // been chosen and has been externally observed via |group()| and the trial
315   // has not been disabled. In that case, true is returned and |active_group|
316   // is filled in; otherwise, the result is false and |active_group| is left
317   // untouched.
318   bool GetActiveGroup(ActiveGroup* active_group) const;
319 
320   // Returns the trial name and selected group name for this field trial via
321   // the output parameter |field_trial_state|, but only if the trial has not
322   // been disabled. In that case, true is returned and |field_trial_state| is
323   // filled in; otherwise, the result is false and |field_trial_state| is left
324   // untouched.
325   bool GetState(State* field_trial_state);
326 
327   // Does the same thing as above, but is deadlock-free if the caller is holding
328   // a lock.
329   bool GetStateWhileLocked(State* field_trial_state);
330 
331   // Returns the group_name. A winner need not have been chosen.
group_name_internal()332   std::string group_name_internal() const { return group_name_; }
333 
334   // The name of the field trial, as can be found via the FieldTrialList.
335   const std::string trial_name_;
336 
337   // The maximum sum of all probabilities supplied, which corresponds to 100%.
338   // This is the scaling factor used to adjust supplied probabilities.
339   const Probability divisor_;
340 
341   // The name of the default group.
342   const std::string default_group_name_;
343 
344   // The randomly selected probability that is used to select a group (or have
345   // the instance not participate).  It is the product of divisor_ and a random
346   // number between [0, 1).
347   Probability random_;
348 
349   // Sum of the probabilities of all appended groups.
350   Probability accumulated_group_probability_;
351 
352   // The number that will be returned by the next AppendGroup() call.
353   int next_group_number_;
354 
355   // The pseudo-randomly assigned group number.
356   // This is kNotFinalized if no group has been assigned.
357   int group_;
358 
359   // A textual name for the randomly selected group. Valid after |group()|
360   // has been called.
361   std::string group_name_;
362 
363   // When enable_field_trial_ is false, field trial reverts to the 'default'
364   // group.
365   bool enable_field_trial_;
366 
367   // When forced_ is true, we return the chosen group from AppendGroup when
368   // appropriate.
369   bool forced_;
370 
371   // Specifies whether the group choice has been reported to observers.
372   bool group_reported_;
373 
374   // Whether this trial is registered with the global FieldTrialList and thus
375   // should notify it when its group is queried.
376   bool trial_registered_;
377 
378   // Reference to related field trial struct and data in shared memory.
379   FieldTrialRef ref_;
380 
381   // When benchmarking is enabled, field trials all revert to the 'default'
382   // group.
383   static bool enable_benchmarking_;
384 
385   DISALLOW_COPY_AND_ASSIGN(FieldTrial);
386 };
387 
388 //------------------------------------------------------------------------------
389 // Class with a list of all active field trials.  A trial is active if it has
390 // been registered, which includes evaluating its state based on its probaility.
391 // Only one instance of this class exists.
392 class BASE_EXPORT FieldTrialList {
393  public:
394   typedef SharedPersistentMemoryAllocator FieldTrialAllocator;
395 
396   // Year that is guaranteed to not be expired when instantiating a field trial
397   // via |FactoryGetFieldTrial()|.  Set to two years from the build date.
398   static int kNoExpirationYear;
399 
400   // Observer is notified when a FieldTrial's group is selected.
401   class BASE_EXPORT Observer {
402    public:
403     // Notify observers when FieldTrials's group is selected.
404     virtual void OnFieldTrialGroupFinalized(const std::string& trial_name,
405                                             const std::string& group_name) = 0;
406 
407    protected:
408     virtual ~Observer();
409   };
410 
411   // This singleton holds the global list of registered FieldTrials.
412   //
413   // To support one-time randomized field trials, specify a non-null
414   // |entropy_provider| which should be a source of uniformly distributed
415   // entropy values. If one time randomization is not desired, pass in null for
416   // |entropy_provider|.
417   explicit FieldTrialList(
418       std::unique_ptr<const FieldTrial::EntropyProvider> entropy_provider);
419 
420   // Destructor Release()'s references to all registered FieldTrial instances.
421   ~FieldTrialList();
422 
423   // Get a FieldTrial instance from the factory.
424   //
425   // |name| is used to register the instance with the FieldTrialList class,
426   // and can be used to find the trial (only one trial can be present for each
427   // name). |default_group_name| is the name of the default group which will
428   // be chosen if none of the subsequent appended groups get to be chosen.
429   // |default_group_number| can receive the group number of the default group as
430   // AppendGroup returns the number of the subsequence groups. |trial_name| and
431   // |default_group_name| may not be empty but |default_group_number| can be
432   // NULL if the value is not needed.
433   //
434   // Group probabilities that are later supplied must sum to less than or equal
435   // to the |total_probability|. Arguments |year|, |month| and |day_of_month|
436   // specify the expiration time. If the build time is after the expiration time
437   // then the field trial reverts to the 'default' group.
438   //
439   // Use this static method to get a startup-randomized FieldTrial or a
440   // previously created forced FieldTrial.
441   static FieldTrial* FactoryGetFieldTrial(
442       const std::string& trial_name,
443       FieldTrial::Probability total_probability,
444       const std::string& default_group_name,
445       const int year,
446       const int month,
447       const int day_of_month,
448       FieldTrial::RandomizationType randomization_type,
449       int* default_group_number);
450 
451   // Same as FactoryGetFieldTrial(), but allows specifying a custom seed to be
452   // used on one-time randomized field trials (instead of a hash of the trial
453   // name, which is used otherwise or if |randomization_seed| has value 0). The
454   // |randomization_seed| value (other than 0) should never be the same for two
455   // trials, else this would result in correlated group assignments.  Note:
456   // Using a custom randomization seed is only supported by the
457   // PermutedEntropyProvider (which is used when UMA is not enabled). If
458   // |override_entropy_provider| is not null, then it will be used for
459   // randomization instead of the provider given when the FieldTrialList was
460   // instantiated.
461   static FieldTrial* FactoryGetFieldTrialWithRandomizationSeed(
462       const std::string& trial_name,
463       FieldTrial::Probability total_probability,
464       const std::string& default_group_name,
465       const int year,
466       const int month,
467       const int day_of_month,
468       FieldTrial::RandomizationType randomization_type,
469       uint32_t randomization_seed,
470       int* default_group_number,
471       const FieldTrial::EntropyProvider* override_entropy_provider);
472 
473   // The Find() method can be used to test to see if a named trial was already
474   // registered, or to retrieve a pointer to it from the global map.
475   static FieldTrial* Find(const std::string& trial_name);
476 
477   // Returns the group number chosen for the named trial, or
478   // FieldTrial::kNotFinalized if the trial does not exist.
479   static int FindValue(const std::string& trial_name);
480 
481   // Returns the group name chosen for the named trial, or the empty string if
482   // the trial does not exist. The first call of this function on a given field
483   // trial will mark it as active, so that its state will be reported with usage
484   // metrics, crashes, etc.
485   static std::string FindFullName(const std::string& trial_name);
486 
487   // Returns true if the named trial has been registered.
488   static bool TrialExists(const std::string& trial_name);
489 
490   // Returns true if the named trial exists and has been activated.
491   static bool IsTrialActive(const std::string& trial_name);
492 
493   // Creates a persistent representation of active FieldTrial instances for
494   // resurrection in another process. This allows randomization to be done in
495   // one process, and secondary processes can be synchronized on the result.
496   // The resulting string contains the name and group name pairs of all
497   // registered FieldTrials for which the group has been chosen and externally
498   // observed (via |group()|) and which have not been disabled, with "/" used
499   // to separate all names and to terminate the string. This string is parsed
500   // by |CreateTrialsFromString()|.
501   static void StatesToString(std::string* output);
502 
503   // Creates a persistent representation of all FieldTrial instances for
504   // resurrection in another process. This allows randomization to be done in
505   // one process, and secondary processes can be synchronized on the result.
506   // The resulting string contains the name and group name pairs of all
507   // registered FieldTrials which have not been disabled, with "/" used
508   // to separate all names and to terminate the string. All activated trials
509   // have their name prefixed with "*". This string is parsed by
510   // |CreateTrialsFromString()|.
511   static void AllStatesToString(std::string* output);
512 
513   // Fills in the supplied vector |active_groups| (which must be empty when
514   // called) with a snapshot of all registered FieldTrials for which the group
515   // has been chosen and externally observed (via |group()|) and which have
516   // not been disabled.
517   static void GetActiveFieldTrialGroups(
518       FieldTrial::ActiveGroups* active_groups);
519 
520   // Returns the field trials that are marked active in |trials_string|.
521   static void GetActiveFieldTrialGroupsFromString(
522       const std::string& trials_string,
523       FieldTrial::ActiveGroups* active_groups);
524 
525   // Returns the field trials that were active when the process was
526   // created. Either parses the field trial string or the shared memory
527   // holding field trial information.
528   // Must be called only after a call to CreateTrialsFromCommandLine().
529   static void GetInitiallyActiveFieldTrials(
530       const base::CommandLine& command_line,
531       FieldTrial::ActiveGroups* active_groups);
532 
533   // Use a state string (re: StatesToString()) to augment the current list of
534   // field trials to include the supplied trials, and using a 100% probability
535   // for each trial, force them to have the same group string. This is commonly
536   // used in a non-browser process, to carry randomly selected state in a
537   // browser process into this non-browser process, but could also be invoked
538   // through a command line argument to the browser process. Created field
539   // trials will be marked "used" for the purposes of active trial reporting
540   // if they are prefixed with |kActivationMarker|. Trial names in
541   // |ignored_trial_names| are ignored when parsing |trials_string|.
542   static bool CreateTrialsFromString(
543       const std::string& trials_string,
544       const std::set<std::string>& ignored_trial_names);
545 
546   // Achieves the same thing as CreateTrialsFromString, except wraps the logic
547   // by taking in the trials from the command line, either via shared memory
548   // handle or command line argument. A bit of a misnomer since on POSIX we
549   // simply get the trials from opening |fd_key| if using shared memory. On
550   // Windows, we expect the |cmd_line| switch for |field_trial_handle_switch| to
551   // contain the shared memory handle that contains the field trial allocator.
552   // We need the |field_trial_handle_switch| and |fd_key| arguments to be passed
553   // in since base/ can't depend on content/.
554   static void CreateTrialsFromCommandLine(const base::CommandLine& cmd_line,
555                                           const char* field_trial_handle_switch,
556                                           int fd_key);
557 
558   // Creates base::Feature overrides from the command line by first trying to
559   // use shared memory and then falling back to the command line if it fails.
560   static void CreateFeaturesFromCommandLine(
561       const base::CommandLine& command_line,
562       const char* enable_features_switch,
563       const char* disable_features_switch,
564       FeatureList* feature_list);
565 
566 #if defined(OS_WIN)
567   // On Windows, we need to explicitly pass down any handles to be inherited.
568   // This function adds the shared memory handle to field trial state to the
569   // list of handles to be inherited.
570   static void AppendFieldTrialHandleIfNeeded(
571       base::HandlesToInheritVector* handles);
572 #endif
573 
574 #if defined(OS_POSIX) && !defined(OS_NACL)
575   // On POSIX, we also need to explicitly pass down this file descriptor that
576   // should be shared with the child process. Returns kInvalidPlatformFile if no
577   // handle exists or was not initialized properly.
578   static PlatformFile GetFieldTrialHandle();
579 #endif
580 
581   // Adds a switch to the command line containing the field trial state as a
582   // string (if not using shared memory to share field trial state), or the
583   // shared memory handle + length.
584   // Needs the |field_trial_handle_switch| argument to be passed in since base/
585   // can't depend on content/.
586   static void CopyFieldTrialStateToFlags(const char* field_trial_handle_switch,
587                                          const char* enable_features_switch,
588                                          const char* disable_features_switch,
589                                          base::CommandLine* cmd_line);
590 
591   // Create a FieldTrial with the given |name| and using 100% probability for
592   // the FieldTrial, force FieldTrial to have the same group string as
593   // |group_name|. This is commonly used in a non-browser process, to carry
594   // randomly selected state in a browser process into this non-browser process.
595   // It returns NULL if there is a FieldTrial that is already registered with
596   // the same |name| but has different finalized group string (|group_name|).
597   static FieldTrial* CreateFieldTrial(const std::string& name,
598                                       const std::string& group_name);
599 
600   // Add an observer to be notified when a field trial is irrevocably committed
601   // to being part of some specific field_group (and hence the group_name is
602   // also finalized for that field_trial).
603   static void AddObserver(Observer* observer);
604 
605   // Remove an observer.
606   static void RemoveObserver(Observer* observer);
607 
608   // Grabs the lock if necessary and adds the field trial to the allocator. This
609   // should only be called from FinalizeGroupChoice().
610   static void OnGroupFinalized(bool is_locked, FieldTrial* field_trial);
611 
612   // Notify all observers that a group has been finalized for |field_trial|.
613   static void NotifyFieldTrialGroupSelection(FieldTrial* field_trial);
614 
615   // Return the number of active field trials.
616   static size_t GetFieldTrialCount();
617 
618   // Gets the parameters for |field_trial| from shared memory and stores them in
619   // |params|. This is only exposed for use by FieldTrialParamAssociator and
620   // shouldn't be used by anything else.
621   static bool GetParamsFromSharedMemory(
622       FieldTrial* field_trial,
623       std::map<std::string, std::string>* params);
624 
625   // Clears all the params in the allocator.
626   static void ClearParamsFromSharedMemoryForTesting();
627 
628   // Dumps field trial state to an allocator so that it can be analyzed after a
629   // crash.
630   static void DumpAllFieldTrialsToPersistentAllocator(
631       PersistentMemoryAllocator* allocator);
632 
633   // Retrieves field trial state from an allocator so that it can be analyzed
634   // after a crash. The pointers in the returned vector are into the persistent
635   // memory segment and so are only valid as long as the allocator is valid.
636   static std::vector<const FieldTrial::FieldTrialEntry*>
637   GetAllFieldTrialsFromPersistentAllocator(
638       PersistentMemoryAllocator const& allocator);
639 
640  private:
641   // Allow tests to access our innards for testing purposes.
642   FRIEND_TEST_ALL_PREFIXES(FieldTrialListTest, InstantiateAllocator);
643   FRIEND_TEST_ALL_PREFIXES(FieldTrialListTest, AddTrialsToAllocator);
644   FRIEND_TEST_ALL_PREFIXES(FieldTrialListTest,
645                            DoNotAddSimulatedFieldTrialsToAllocator);
646   FRIEND_TEST_ALL_PREFIXES(FieldTrialListTest, AssociateFieldTrialParams);
647   FRIEND_TEST_ALL_PREFIXES(FieldTrialListTest, ClearParamsFromSharedMemory);
648 
649 #if defined(OS_WIN)
650   // Takes in |handle_switch| from the command line which represents the shared
651   // memory handle for field trials, parses it, and creates the field trials.
652   // Returns true on success, false on failure.
653   static bool CreateTrialsFromHandleSwitch(const std::string& handle_switch);
654 #endif
655 
656 #if defined(OS_POSIX) && !defined(OS_NACL)
657   // On POSIX systems that use the zygote, we look up the correct fd that backs
658   // the shared memory segment containing the field trials by looking it up via
659   // an fd key in GlobalDescriptors. Returns true on success, false on failure.
660   static bool CreateTrialsFromDescriptor(int fd_key);
661 #endif
662 
663   // Takes an unmapped SharedMemoryHandle, creates a SharedMemory object from it
664   // and maps it with the correct size.
665   static bool CreateTrialsFromSharedMemoryHandle(SharedMemoryHandle shm_handle);
666 
667   // Expects a mapped piece of shared memory |shm| that was created from the
668   // browser process's field_trial_allocator and shared via the command line.
669   // This function recreates the allocator, iterates through all the field
670   // trials in it, and creates them via CreateFieldTrial(). Returns true if
671   // successful and false otherwise.
672   static bool CreateTrialsFromSharedMemory(
673       std::unique_ptr<base::SharedMemory> shm);
674 
675   // Instantiate the field trial allocator, add all existing field trials to it,
676   // and duplicates its handle to a read-only handle, which gets stored in
677   // |readonly_allocator_handle|.
678   static void InstantiateFieldTrialAllocatorIfNeeded();
679 
680   // Adds the field trial to the allocator. Caller must hold a lock before
681   // calling this.
682   static void AddToAllocatorWhileLocked(PersistentMemoryAllocator* allocator,
683                                         FieldTrial* field_trial);
684 
685   // Activate the corresponding field trial entry struct in shared memory.
686   static void ActivateFieldTrialEntryWhileLocked(FieldTrial* field_trial);
687 
688   // A map from FieldTrial names to the actual instances.
689   typedef std::map<std::string, FieldTrial*> RegistrationMap;
690 
691   // If one-time randomization is enabled, returns a weak pointer to the
692   // corresponding EntropyProvider. Otherwise, returns NULL.
693   static const FieldTrial::EntropyProvider*
694       GetEntropyProviderForOneTimeRandomization();
695 
696   // Helper function should be called only while holding lock_.
697   FieldTrial* PreLockedFind(const std::string& name);
698 
699   // Register() stores a pointer to the given trial in a global map.
700   // This method also AddRef's the indicated trial.
701   // This should always be called after creating a new FieldTrial instance.
702   static void Register(FieldTrial* trial);
703 
704   static FieldTrialList* global_;  // The singleton of this class.
705 
706   // This will tell us if there is an attempt to register a field
707   // trial or check if one-time randomization is enabled without
708   // creating the FieldTrialList. This is not an error, unless a
709   // FieldTrialList is created after that.
710   static bool used_without_global_;
711 
712   // Lock for access to registered_ and field_trial_allocator_.
713   Lock lock_;
714   RegistrationMap registered_;
715 
716   std::map<std::string, std::string> seen_states_;
717 
718   // Entropy provider to be used for one-time randomized field trials. If NULL,
719   // one-time randomization is not supported.
720   std::unique_ptr<const FieldTrial::EntropyProvider> entropy_provider_;
721 
722   // List of observers to be notified when a group is selected for a FieldTrial.
723   scoped_refptr<ObserverListThreadSafe<Observer> > observer_list_;
724 
725   // Allocator in shared memory containing field trial data. Used in both
726   // browser and child processes, but readonly in the child.
727   // In the future, we may want to move this to a more generic place if we want
728   // to start passing more data other than field trials.
729   std::unique_ptr<FieldTrialAllocator> field_trial_allocator_ = nullptr;
730 
731   // Readonly copy of the handle to the allocator. Needs to be a member variable
732   // because it's needed from both CopyFieldTrialStateToFlags() and
733   // AppendFieldTrialHandleIfNeeded().
734   PlatformFile readonly_allocator_handle_ = kInvalidPlatformFile;
735 
736   // Tracks whether CreateTrialsFromCommandLine() has been called.
737   bool create_trials_from_command_line_called_ = false;
738 
739   DISALLOW_COPY_AND_ASSIGN(FieldTrialList);
740 };
741 
742 }  // namespace base
743 
744 #endif  // BASE_METRICS_FIELD_TRIAL_H_
745