• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2012 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 // The FieldTrial class handles the lower level configuration of running A/B
6 // tests.
7 //
8 // Most server-side experiments should be configured using Features which
9 // have a simpler interface. See base/feature_list.h for details on
10 // configurating a Feature for an experiment.
11 
12 // In certain cases you may still need to use FieldTrial directly. This is
13 // generally for either:
14 // - Client-configured experiments:
15 //     The experiment is controlled directly in the code. For example, if the
16 //     server controlled behavior is not yet available. See below documentation.
17 // - Synthetic field trials:
18 //     These act like field trials for reporting purposes, but the group
19 //     placement is controlled directly. See RegisterSyntheticFieldTrial().
20 
21 // If you have access, see go/client-side-field-trials for additional context.
22 
23 //------------------------------------------------------------------------------
24 // Details:
25 
26 // FieldTrial is a class for handling details of statistical experiments
27 // performed by actual users in the field (i.e., in a shipped or beta product).
28 // All code is called exclusively on the UI thread currently. It only handles
29 // the lower level details, server-side experiments should use
30 // generally use Features (see above).
31 //
32 // The simplest example is an experiment to see whether one of two options
33 // produces "better" results across our user population.  In that scenario, UMA
34 // data is uploaded to aggregate the test results, and this FieldTrial class
35 // manages the state of each such experiment (state == which option was
36 // pseudo-randomly selected).
37 //
38 // States are typically generated randomly, either based on a one time
39 // randomization (which will yield the same results, in terms of selecting
40 // the client for a field trial or not, for every run of the program on a
41 // given machine), or by a session randomization (generated each time the
42 // application starts up, but held constant during the duration of the
43 // process).
44 
45 //------------------------------------------------------------------------------
46 // Example:  Suppose we have an experiment involving memory, such as determining
47 // the impact of some pruning algorithm. Note that using this API directly is
48 // not recommended, see above.
49 
50 // // FieldTrials are reference counted, and persist automagically until
51 // // process teardown, courtesy of their automatic registration in
52 // // FieldTrialList.
53 // scoped_refptr<base::FieldTrial> trial(
54 //     base::FieldTrialList::FactoryGetFieldTrial(
55 //         "MemoryExperiment", 1000, "StandardMem", entropy_provider);
56 //
57 // trial->AppendGroup("HighMem", 20);  // 2% in HighMem group.
58 // trial->AppendGroup("LowMem", 20);   // 2% in LowMem group.
59 // // Take action depending of which group we randomly land in.
60 // if (trial->group_name() == "HighMem")
61 //   SetPruningAlgorithm(kType1);
62 // else if (trial->group_name() == "LowMem")
63 //   SetPruningAlgorithm(kType2);
64 
65 //------------------------------------------------------------------------------
66 
67 #ifndef BASE_METRICS_FIELD_TRIAL_H_
68 #define BASE_METRICS_FIELD_TRIAL_H_
69 
70 #include <stddef.h>
71 #include <stdint.h>
72 
73 #include <atomic>
74 #include <functional>
75 #include <map>
76 #include <memory>
77 #include <string>
78 #include <vector>
79 
80 #include "base/atomicops.h"
81 #include "base/base_export.h"
82 #include "base/command_line.h"
83 #include "base/feature_list.h"
84 #include "base/gtest_prod_util.h"
85 #include "base/memory/raw_ptr.h"
86 #include "base/memory/read_only_shared_memory_region.h"
87 #include "base/memory/ref_counted.h"
88 #include "base/memory/shared_memory_mapping.h"
89 #include "base/metrics/persistent_memory_allocator.h"
90 #include "base/pickle.h"
91 #include "base/strings/string_piece.h"
92 #include "base/synchronization/lock.h"
93 #include "base/types/pass_key.h"
94 #include "build/build_config.h"
95 
96 namespace base {
97 
98 namespace test {
99 class ScopedFeatureList;
100 }  // namespace test
101 
102 class CompareActiveGroupToFieldTrialMatcher;
103 class FieldTrialList;
104 struct LaunchOptions;
105 
106 class BASE_EXPORT FieldTrial : public RefCounted<FieldTrial> {
107  public:
108   typedef int Probability;  // Probability type for being selected in a trial.
109 
110   // EntropyProvider is an interface for providing entropy for one-time
111   // randomized (persistent) field trials.
112   class BASE_EXPORT EntropyProvider {
113    public:
114     virtual ~EntropyProvider();
115 
116     // Returns a double in the range of [0, 1) to be used for the dice roll for
117     // the specified field trial. If |randomization_seed| is not 0, it will be
118     // used in preference to |trial_name| for generating the entropy by entropy
119     // providers that support it. A given instance should always return the same
120     // value given the same input |trial_name| and |randomization_seed| values.
121     virtual double GetEntropyForTrial(StringPiece trial_name,
122                                       uint32_t randomization_seed) const = 0;
123 
124     // Returns a pseudorandom integer in [0, output_range).
125     // |salt| is a data parameter for the pseudorandom function.
126     uint32_t GetPseudorandomValue(uint32_t salt, uint32_t output_range) const;
127   };
128 
129   // Separate type from FieldTrial::PickleState so that it can use StringPieces.
130   struct State {
131     StringPiece trial_name;
132     StringPiece group_name;
133     bool activated = false;
134   };
135 
136   // A pair representing a Field Trial and its selected group.
137   struct ActiveGroup {
138     std::string trial_name;
139     std::string group_name;
140   };
141 
142   // A triplet representing a FieldTrial, its selected group and whether it's
143   // active. String members are pointers to the underlying strings owned by the
144   // FieldTrial object. Does not use StringPiece to avoid conversions back to
145   // std::string.
146   struct BASE_EXPORT PickleState {
147     raw_ptr<const std::string, DanglingUntriaged> trial_name = nullptr;
148     raw_ptr<const std::string, DanglingUntriaged> group_name = nullptr;
149     bool activated = false;
150 
151     PickleState();
152     PickleState(const PickleState& other);
153     ~PickleState();
154   };
155 
156   // We create one FieldTrialEntry per field trial in shared memory, via
157   // AddToAllocatorWhileLocked. The FieldTrialEntry is followed by a
158   // base::Pickle object that we unpickle and read from.
159   struct BASE_EXPORT FieldTrialEntry {
160     // SHA1(FieldTrialEntry): Increment this if structure changes!
161     static constexpr uint32_t kPersistentTypeId = 0xABA17E13 + 3;
162 
163     // Expected size for 32/64-bit check.
164     static constexpr size_t kExpectedInstanceSize = 16;
165 
166     // Whether or not this field trial is activated. This is really just a
167     // boolean but using a 32 bit value for portability reasons. It should be
168     // accessed via NoBarrier_Load()/NoBarrier_Store() to prevent the compiler
169     // from doing unexpected optimizations because it thinks that only one
170     // thread is accessing the memory location.
171     subtle::Atomic32 activated;
172 
173     // On e.g. x86, alignof(uint64_t) is 4.  Ensure consistent size and
174     // alignment of `pickle_size` across platforms. This can be considered
175     // to be padding for the final 32 bit value (activated). If this struct
176     // gains or loses fields, consider if this padding is still needed.
177     uint32_t padding;
178 
179     // Size of the pickled structure, NOT the total size of this entry.
180     uint64_t pickle_size;
181 
182     // Calling this is only valid when the entry is initialized. That is, it
183     // resides in shared memory and has a pickle containing the trial name and
184     // group name following it.
185     bool GetTrialAndGroupName(StringPiece* trial_name,
186                               StringPiece* group_name) const;
187 
188     // Calling this is only valid when the entry is initialized as well. Reads
189     // the parameters following the trial and group name and stores them as
190     // key-value mappings in |params|.
191     bool GetParams(std::map<std::string, std::string>* params) const;
192 
193    private:
194     // Returns an iterator over the data containing names and params.
195     PickleIterator GetPickleIterator() const;
196 
197     // Takes the iterator and writes out the first two items into |trial_name|
198     // and |group_name|.
199     bool ReadStringPair(PickleIterator* iter,
200                         StringPiece* trial_name,
201                         StringPiece* group_name) const;
202   };
203 
204   typedef std::vector<ActiveGroup> ActiveGroups;
205 
206   // A return value to indicate that a given instance has not yet had a group
207   // assignment (and hence is not yet participating in the trial).
208   static const int kNotFinalized;
209 
210   FieldTrial(const FieldTrial&) = delete;
211   FieldTrial& operator=(const FieldTrial&) = delete;
212 
213   // Establishes the name and probability of the next group in this trial.
214   // Sometimes, based on construction randomization, this call may cause the
215   // provided group to be *THE* group selected for use in this instance.
216   // AppendGroup can be called after calls to group() but it should be avoided
217   // if possible. Doing so may be confusing since it won't change the group
218   // selection.
219   void AppendGroup(const std::string& name, Probability group_probability);
220 
221   // Return the name of the FieldTrial (excluding the group name).
trial_name()222   const std::string& trial_name() const { return trial_name_; }
223 
224   // Finalizes the group assignment and notifies any/all observers. This is a
225   // no-op if the trial is already active. Note this will force an instance to
226   // participate, and make it illegal to attempt to probabilistically add any
227   // other groups to the trial.
228   void Activate();
229 
230   // If the group's name is empty, a string version containing the group number
231   // is used as the group name. This causes a winner to be chosen if none was.
232   const std::string& group_name();
233 
234   // Finalizes the group choice and returns the chosen group, but does not mark
235   // the trial as active - so its state will not be reported until group_name()
236   // or similar is called.
237   const std::string& GetGroupNameWithoutActivation();
238 
239   // Set the field trial as forced, meaning that it was setup earlier than
240   // the hard coded registration of the field trial to override it.
241   // This allows the code that was hard coded to register the field trial to
242   // still succeed even though the field trial has already been registered.
243   // This must be called after appending all the groups, since we will make
244   // the group choice here. Note that this is a NOOP for already forced trials.
245   // And, as the rest of the FieldTrial code, this is not thread safe and must
246   // be done from the UI thread.
247   void SetForced();
248 
249   // Supports benchmarking by causing field trials' default groups to be chosen.
250   static void EnableBenchmarking();
251 
252   // Creates a FieldTrial object with the specified parameters, to be used for
253   // simulation of group assignment without actually affecting global field
254   // trial state in the running process. Group assignment will be done based on
255   // |entropy_value|, which must have a range of [0, 1).
256   //
257   // Note: Using this function will not register the field trial globally in the
258   // running process - for that, use FieldTrialList::FactoryGetFieldTrial().
259   //
260   // The ownership of the returned FieldTrial is transfered to the caller which
261   // is responsible for deref'ing it (e.g. by using scoped_refptr<FieldTrial>).
262   static FieldTrial* CreateSimulatedFieldTrial(StringPiece trial_name,
263                                                Probability total_probability,
264                                                StringPiece default_group_name,
265                                                double entropy_value);
266 
267   // Whether this field trial is low anonymity or not (see
268   // |FieldTrialListIncludingLowAnonymity|).
269   // TODO(crbug.com/1431156): remove this once all call sites have been properly
270   // migrated to use an appropriate observer.
is_low_anonymity()271   bool is_low_anonymity() { return is_low_anonymity_; }
272 
273  private:
274   // Allow tests to access our innards for testing purposes.
275   FRIEND_TEST_ALL_PREFIXES(FieldTrialTest, Registration);
276   FRIEND_TEST_ALL_PREFIXES(FieldTrialTest, AbsoluteProbabilities);
277   FRIEND_TEST_ALL_PREFIXES(FieldTrialTest, RemainingProbability);
278   FRIEND_TEST_ALL_PREFIXES(FieldTrialTest, FiftyFiftyProbability);
279   FRIEND_TEST_ALL_PREFIXES(FieldTrialTest, MiddleProbabilities);
280   FRIEND_TEST_ALL_PREFIXES(FieldTrialTest, OneWinner);
281   FRIEND_TEST_ALL_PREFIXES(FieldTrialTest, DisableProbability);
282   FRIEND_TEST_ALL_PREFIXES(FieldTrialTest, ActiveGroups);
283   FRIEND_TEST_ALL_PREFIXES(FieldTrialTest, AllGroups);
284   FRIEND_TEST_ALL_PREFIXES(FieldTrialTest, ActiveGroupsNotFinalized);
285   FRIEND_TEST_ALL_PREFIXES(FieldTrialTest, Save);
286   FRIEND_TEST_ALL_PREFIXES(FieldTrialTest, SaveAll);
287   FRIEND_TEST_ALL_PREFIXES(FieldTrialTest, DuplicateRestore);
288   FRIEND_TEST_ALL_PREFIXES(FieldTrialTest, SetForcedTurnFeatureOff);
289   FRIEND_TEST_ALL_PREFIXES(FieldTrialTest, SetForcedTurnFeatureOn);
290   FRIEND_TEST_ALL_PREFIXES(FieldTrialTest, SetForcedChangeDefault_Default);
291   FRIEND_TEST_ALL_PREFIXES(FieldTrialTest, SetForcedChangeDefault_NonDefault);
292   FRIEND_TEST_ALL_PREFIXES(FieldTrialTest, ObserveReentrancy);
293   FRIEND_TEST_ALL_PREFIXES(FieldTrialTest, FloatBoundariesGiveEqualGroupSizes);
294   FRIEND_TEST_ALL_PREFIXES(FieldTrialTest, DoesNotSurpassTotalProbability);
295   FRIEND_TEST_ALL_PREFIXES(FieldTrialListTest,
296                            DoNotAddSimulatedFieldTrialsToAllocator);
297   FRIEND_TEST_ALL_PREFIXES(FieldTrialListTest, ClearParamsFromSharedMemory);
298   FRIEND_TEST_ALL_PREFIXES(FieldTrialListTest,
299                            TestGetRandomizedFieldTrialCount);
300   FRIEND_TEST_ALL_PREFIXES(FieldTrialTest, SetLowAnonymity);
301 
302   // MATCHER(CompareActiveGroupToFieldTrialMatcher, "")
303   friend class base::CompareActiveGroupToFieldTrialMatcher;
304 
305   friend class base::FieldTrialList;
306 
307   friend class RefCounted<FieldTrial>;
308 
309   using FieldTrialRef = PersistentMemoryAllocator::Reference;
310 
311   // This is the group number of the 'default' group when a choice wasn't forced
312   // by a call to FieldTrialList::CreateFieldTrial. It is kept private so that
313   // consumers don't use it by mistake in cases where the group was forced.
314   static const int kDefaultGroupNumber;
315 
316   // Creates a field trial with the specified parameters. Group assignment will
317   // be done based on |entropy_value|, which must have a range of [0, 1).
318   FieldTrial(StringPiece trial_name,
319              Probability total_probability,
320              StringPiece default_group_name,
321              double entropy_value,
322              bool is_low_anonymity);
323 
324   virtual ~FieldTrial();
325 
326   // Marks this trial as having been registered with the FieldTrialList. Must be
327   // called no more than once and before any |group()| calls have occurred.
328   void SetTrialRegistered();
329 
330   // Sets the chosen group name and number.
331   void SetGroupChoice(const std::string& group_name, int number);
332 
333   // Ensures that a group is chosen, if it hasn't yet been. The field trial
334   // might yet be disabled, so this call will *not* notify observers of the
335   // status.
336   void FinalizeGroupChoice();
337 
338   // Returns the trial name and selected group name for this field trial via
339   // the output parameter |active_group|, but only if the group has already
340   // been chosen and has been externally observed via |group()| and the trial
341   // has not been disabled. In that case, true is returned and |active_group|
342   // is filled in; otherwise, the result is false and |active_group| is left
343   // untouched.
344   bool GetActiveGroup(ActiveGroup* active_group) const;
345 
346   // Returns the trial name and selected group name for this field trial via
347   // the output parameter |field_trial_state| for all the studies.
348   void GetStateWhileLocked(PickleState* field_trial_state);
349 
350   // Returns the group_name. A winner need not have been chosen.
group_name_internal()351   const std::string& group_name_internal() const { return group_name_; }
352 
353   // The name of the field trial, as can be found via the FieldTrialList.
354   const std::string trial_name_;
355 
356   // The maximum sum of all probabilities supplied, which corresponds to 100%.
357   // This is the scaling factor used to adjust supplied probabilities.
358   const Probability divisor_;
359 
360   // The name of the default group.
361   const std::string default_group_name_;
362 
363   // The randomly selected probability that is used to select a group (or have
364   // the instance not participate).  It is the product of divisor_ and a random
365   // number between [0, 1).
366   Probability random_;
367 
368   // Sum of the probabilities of all appended groups.
369   Probability accumulated_group_probability_;
370 
371   // The number that will be returned by the next AppendGroup() call.
372   int next_group_number_;
373 
374   // The pseudo-randomly assigned group number.
375   // This is kNotFinalized if no group has been assigned.
376   int group_;
377 
378   // A textual name for the randomly selected group. Valid after |group()|
379   // has been called.
380   std::string group_name_;
381 
382   // When forced_ is true, we return the chosen group from AppendGroup when
383   // appropriate.
384   bool forced_;
385 
386   // Specifies whether the group choice has been reported to observers.
387   bool group_reported_;
388 
389   // Whether this trial is registered with the global FieldTrialList and thus
390   // should notify it when its group is queried.
391   bool trial_registered_;
392 
393   // Reference to related field trial struct and data in shared memory.
394   FieldTrialRef ref_;
395 
396   // Denotes whether benchmarking is enabled. In this case, field trials all
397   // revert to the default group.
398   static bool enable_benchmarking_;
399 
400   // Whether this field trial is potentially low anonymity (eg. only a small
401   // set of users are included).
402   const bool is_low_anonymity_ = false;
403 };
404 
405 //------------------------------------------------------------------------------
406 // Class with a list of all active field trials.  A trial is active if it has
407 // been registered, which includes evaluating its state based on its
408 // probability. Only one instance of this class exists and outside of testing,
409 // will live for the entire life time of the process.
410 class BASE_EXPORT FieldTrialList {
411  public:
412   using FieldTrialAllocator = PersistentMemoryAllocator;
413 
414   // Type for function pointer passed to |AllParamsToString| used to escape
415   // special characters from |input|.
416   typedef std::string (*EscapeDataFunc)(const std::string& input);
417 
418   // Observer is notified when a FieldTrial's group is selected.
419   class BASE_EXPORT Observer {
420    public:
421     // Notify observers when FieldTrials's group is selected.
422     virtual void OnFieldTrialGroupFinalized(const std::string& trial_name,
423                                             const std::string& group_name) = 0;
424 
425    protected:
426     virtual ~Observer();
427   };
428 
429   // This singleton holds the global list of registered FieldTrials.
430   FieldTrialList();
431   FieldTrialList(const FieldTrialList&) = delete;
432   FieldTrialList& operator=(const FieldTrialList&) = delete;
433 
434   // Destructor Release()'s references to all registered FieldTrial instances.
435   ~FieldTrialList();
436 
437   // Gets a FieldTrial instance from the factory.
438   //
439   // |trial_name| (a) is used to register the instance with the FieldTrialList
440   // class and (b) can be used to find the trial (only one trial can be present
441   // for each name). |default_group_name| is the name of the group that is
442   // chosen if none of the subsequent appended groups are chosen. Note that the
443   // default group is also chosen whenever |enable_benchmarking_| is true.
444   //
445   // Group probabilities that are later supplied must sum to less than or equal
446   // to the |total_probability|.
447   //
448   // The |entropy_provider| is used for randomizing group selection. The
449   // |randomization_seed| will be passed to the EntropyProvider in addition
450   // to the trial name, and it's handling is defined by the EntropyProvider.
451   // * SessionEntropyProvider requires it to be 0 by DCHECK.
452   // * SHA1 and NormalizedMurmurHash providers will use a non-zero value as a
453   //   salt _instead_ of using the trial name.
454   //
455   // Some field trials may be targeted in such way that a relatively small
456   // number of users are in a particular experiment group. Such trials should
457   // have |is_low_anonymity| set to true, and their visitbility is restricted
458   // to specific callers only, via |FieldTrialListIncludingLowAnonymity|.
459   //
460   // This static method can be used to get a startup-randomized FieldTrial or a
461   // previously created forced FieldTrial.
462   static FieldTrial* FactoryGetFieldTrial(
463       StringPiece trial_name,
464       FieldTrial::Probability total_probability,
465       StringPiece default_group_name,
466       const FieldTrial::EntropyProvider& entropy_provider,
467       uint32_t randomization_seed = 0,
468       bool is_low_anonymity = false);
469 
470   // The Find() method can be used to test to see if a named trial was already
471   // registered, or to retrieve a pointer to it from the global map.
472   static FieldTrial* Find(StringPiece trial_name);
473 
474   // Returns the group name chosen for the named trial, or the empty string if
475   // the trial does not exist. The first call of this function on a given field
476   // trial will mark it as active, so that its state will be reported with usage
477   // metrics, crashes, etc.
478   // Note: Direct use of this function and related FieldTrial functions is
479   // generally discouraged - instead please use base::Feature when possible.
480   static std::string FindFullName(StringPiece trial_name);
481 
482   // Returns true if the named trial has been registered.
483   static bool TrialExists(StringPiece trial_name);
484 
485   // Returns true if the named trial exists and has been activated.
486   static bool IsTrialActive(StringPiece trial_name);
487 
488   // Creates a persistent representation of all FieldTrial instances for
489   // resurrection in another process. This allows randomization to be done in
490   // one process, and secondary processes can be synchronized on the result.
491   // The resulting string contains the name and group name pairs of all
492   // registered FieldTrials,
493   // with "/" used to separate all names and to terminate the string. All
494   // activated trials have their name prefixed with "*". This string is parsed
495   // by |CreateTrialsFromString()|.
496   static void AllStatesToString(std::string* output);
497 
498   // Creates a persistent representation of all FieldTrial params for
499   // resurrection in another process. The returned string contains the trial
500   // name and group name pairs of all registered FieldTrials. The pair is
501   // followed by ':' separator and list of param name and values separated by
502   // '/'. It also takes |encode_data_func| function pointer for encodeing
503   // special characters. This string is parsed by
504   // |AssociateParamsFromString()|.
505   static std::string AllParamsToString(EscapeDataFunc encode_data_func);
506 
507   // Fills in the supplied vector |active_groups| (which must be empty when
508   // called) with a snapshot of all registered FieldTrials for which the group
509   // has been chosen and externally observed (via |group()|) and which have
510   // not been disabled.
511   //
512   // This does not return low anonymity field trials. Callers who need access to
513   // low anonymity field trials should use
514   // |FieldTrialListIncludingLowAnonymity.GetActiveFieldTrialGroups()|.
515   static void GetActiveFieldTrialGroups(
516       FieldTrial::ActiveGroups* active_groups);
517 
518   // Returns the field trials that are marked active in |trials_string|.
519   static void GetActiveFieldTrialGroupsFromString(
520       const std::string& trials_string,
521       FieldTrial::ActiveGroups* active_groups);
522 
523   // Returns the field trials that were active when the process was
524   // created. Either parses the field trial string or the shared memory
525   // holding field trial information.
526   // Must be called only after a call to CreateTrialsFromCommandLine().
527   static void GetInitiallyActiveFieldTrials(
528       const CommandLine& command_line,
529       FieldTrial::ActiveGroups* active_groups);
530 
531   // Use a state string (re: AllStatesToString()) to augment the current list of
532   // field trials to include the supplied trials, and using a 100% probability
533   // for each trial, force them to have the same group string. This is commonly
534   // used in a non-browser process, to carry randomly selected state in a
535   // browser process into this non-browser process, but could also be invoked
536   // through a command line argument to the browser process. Created field
537   // trials will be marked "used" for the purposes of active trial reporting
538   // if they are prefixed with |kActivationMarker|.
539   static bool CreateTrialsFromString(const std::string& trials_string);
540 
541   // Achieves the same thing as CreateTrialsFromString, except wraps the logic
542   // by taking in the trials from the command line, either via shared memory
543   // handle or command line argument.
544   // On non-Mac POSIX platforms, we simply get the trials from opening |fd_key|
545   // if using shared memory. The argument is needed here since //base can't
546   // depend on //content. |fd_key| is unused on other platforms.
547   // On other platforms, we expect the |cmd_line| switch for kFieldTrialHandle
548   // to contain the shared memory handle that contains the field trial
549   // allocator.
550   static void CreateTrialsFromCommandLine(const CommandLine& cmd_line,
551                                           uint32_t fd_key);
552 
553   // Creates base::Feature overrides from the command line by first trying to
554   // use shared memory and then falling back to the command line if it fails.
555   static void CreateFeaturesFromCommandLine(const CommandLine& command_line,
556                                             FeatureList* feature_list);
557 
558 #if !BUILDFLAG(IS_IOS)
559   // Populates |command_line| and |launch_options| with the handles and command
560   // line arguments necessary for a child process to inherit the shared-memory
561   // object containing the FieldTrial configuration.
562   static void PopulateLaunchOptionsWithFieldTrialState(
563       CommandLine* command_line,
564       LaunchOptions* launch_options);
565 #endif  // !BUILDFLAG(IS_IOS)
566 
567 #if BUILDFLAG(IS_POSIX) && !BUILDFLAG(IS_APPLE) && !BUILDFLAG(IS_NACL)
568   // On POSIX, we also need to explicitly pass down this file descriptor that
569   // should be shared with the child process. Returns -1 if it was not
570   // initialized properly. The current process remains the onwer of the passed
571   // descriptor.
572   static int GetFieldTrialDescriptor();
573 #endif  // BUILDFLAG(IS_POSIX) && !BUILDFLAG(IS_APPLE) && !BUILDFLAG(IS_NACL)
574 
575   static ReadOnlySharedMemoryRegion DuplicateFieldTrialSharedMemoryForTesting();
576 
577   // Create a FieldTrial with the given |name| and using 100% probability for
578   // the FieldTrial, force FieldTrial to have the same group string as
579   // |group_name|. This is commonly used in a non-browser process, to carry
580   // randomly selected state in a browser process into this non-browser process.
581   // It returns NULL if there is a FieldTrial that is already registered with
582   // the same |name| but has different finalized group string (|group_name|).
583   //
584   // Visibility of field trials with |is_low_anonymity| set to true is
585   // restricted to specific callers only, see
586   // |FieldTrialListIncludingLowAnonymity|.
587   static FieldTrial* CreateFieldTrial(StringPiece name,
588                                       StringPiece group_name,
589                                       bool is_low_anonymity = false);
590 
591   // Add an observer to be notified when a field trial is irrevocably committed
592   // to being part of some specific field_group (and hence the group_name is
593   // also finalized for that field_trial). Returns false and does nothing if
594   // there is no FieldTrialList singleton. The observer can be notified on any
595   // sequence; it must be thread-safe.
596   //
597   // Low anonymity field trials are not notified to this observer. Callers
598   // who need to be notified of low anonymity field trials should use
599   // |FieldTrialListIncludingLowAnonymity.AddObserver()|.
600   static bool AddObserver(Observer* observer);
601 
602   // Remove an observer. This cannot be invoked concurrently with
603   // FieldTrial::group() (typically, this means that no other thread should be
604   // running when this is invoked).
605   //
606   // Removes observers added via the |AddObserver()| method of this class.
607   static void RemoveObserver(Observer* observer);
608 
609   // Notify all observers that a group has been finalized for |field_trial|.
610   static void NotifyFieldTrialGroupSelection(FieldTrial* field_trial);
611 
612   // Return the number of active field trials.
613   static size_t GetFieldTrialCount();
614 
615   // Return the number of active field trials registered as randomized trials.
616   // Trials created using the CreateFieldTrial() do not count towards this
617   // total.
618   static size_t GetRandomizedFieldTrialCount();
619 
620   // Gets the parameters for |field_trial| from shared memory and stores them in
621   // |params|. This is only exposed for use by FieldTrialParamAssociator and
622   // shouldn't be used by anything else.
623   static bool GetParamsFromSharedMemory(
624       FieldTrial* field_trial,
625       std::map<std::string, std::string>* params);
626 
627   // Clears all the params in the allocator.
628   static void ClearParamsFromSharedMemoryForTesting();
629 
630   // Dumps field trial state to an allocator so that it can be analyzed after a
631   // crash.
632   static void DumpAllFieldTrialsToPersistentAllocator(
633       PersistentMemoryAllocator* allocator);
634 
635   // Retrieves field trial state from an allocator so that it can be analyzed
636   // after a crash. The pointers in the returned vector are into the persistent
637   // memory segment and so are only valid as long as the allocator is valid.
638   static std::vector<const FieldTrial::FieldTrialEntry*>
639   GetAllFieldTrialsFromPersistentAllocator(
640       PersistentMemoryAllocator const& allocator);
641 
642   // Returns a pointer to the global instance. This is exposed so that it can
643   // be used in a DCHECK in FeatureList and ScopedFeatureList test-only logic
644   // and is not intended to be used widely beyond those cases.
645   static FieldTrialList* GetInstance();
646 
647   // For testing, sets the global instance to null and returns the previous one.
648   static FieldTrialList* BackupInstanceForTesting();
649 
650   // For testing, sets the global instance to |instance|.
651   static void RestoreInstanceForTesting(FieldTrialList* instance);
652 
653   // Creates a list of FieldTrial::State for all FieldTrial instances.
654   // StringPiece members are bound to the lifetime of the corresponding
655   // FieldTrial.
656   static std::vector<FieldTrial::State> GetAllFieldTrialStates(
657       PassKey<test::ScopedFeatureList>);
658 
659   // Create FieldTrials from a list of FieldTrial::State. This method is only
660   // available to ScopedFeatureList for testing. The most typical usescase is:
661   // (1) AllStatesToFieldTrialStates(&field_trials);
662   // (2) backup_ = BackupInstanceForTesting();
663   //     // field_trials depends on backup_'s lifetype.
664   // (3) field_trial_list_ = new FieldTrialList();
665   // (4) CreateTrialsFromFieldTrialStates(field_trials);
666   //     // Copy backup_'s fieldtrials to the new field_trial_list_ while
667   //     // backup_ is alive.
668   // For resurrestion in another process, need to use AllStatesToString and
669   // CreateFieldTrialsFromString.
670   static bool CreateTrialsFromFieldTrialStates(
671       PassKey<test::ScopedFeatureList>,
672       const std::vector<FieldTrial::State>& entries);
673 
674  private:
675   // Allow tests to access our innards for testing purposes.
676   FRIEND_TEST_ALL_PREFIXES(FieldTrialListTest, InstantiateAllocator);
677   FRIEND_TEST_ALL_PREFIXES(FieldTrialListTest, AddTrialsToAllocator);
678   FRIEND_TEST_ALL_PREFIXES(FieldTrialListTest,
679                            DoNotAddSimulatedFieldTrialsToAllocator);
680   FRIEND_TEST_ALL_PREFIXES(FieldTrialListTest, AssociateFieldTrialParams);
681   FRIEND_TEST_ALL_PREFIXES(FieldTrialListTest, ClearParamsFromSharedMemory);
682   FRIEND_TEST_ALL_PREFIXES(FieldTrialListTest,
683                            SerializeSharedMemoryRegionMetadata);
684   friend int SerializeSharedMemoryRegionMetadata();
685   FRIEND_TEST_ALL_PREFIXES(FieldTrialListTest, CheckReadOnlySharedMemoryRegion);
686 
687   // Required so that |FieldTrialListIncludingLowAnonymity| can expose APIs from
688   // this class to its friends.
689   friend class FieldTrialListIncludingLowAnonymity;
690 
691 #if !BUILDFLAG(IS_NACL) && !BUILDFLAG(IS_IOS)
692   // Serialization is used to pass information about the shared memory handle
693   // to child processes. This is achieved by passing a stringified reference to
694   // the relevant OS resources to the child process.
695   //
696   // Serialization populates |launch_options| with the relevant OS handles to
697   // transfer or copy to the child process and returns serialized information
698   // to be passed to the kFieldTrialHandle command-line switch.
699   // Note: On non-Mac POSIX platforms, it is necessary to pass down the file
700   // descriptor for the shared memory separately. It can be accessed via the
701   // GetFieldTrialDescriptor() API.
702   static std::string SerializeSharedMemoryRegionMetadata(
703       const ReadOnlySharedMemoryRegion& shm,
704       LaunchOptions* launch_options);
705 
706   // Deserialization instantiates the shared memory region for FieldTrials from
707   // the serialized information contained in |switch_value|. Returns an invalid
708   // ReadOnlySharedMemoryRegion on failure.
709   // |fd| is used on non-Mac POSIX platforms to instantiate the shared memory
710   // region via a file descriptor.
711   static ReadOnlySharedMemoryRegion DeserializeSharedMemoryRegionMetadata(
712       const std::string& switch_value,
713       int fd);
714 
715   // Takes in |handle_switch| from the command line which represents the shared
716   // memory handle for field trials, parses it, and creates the field trials.
717   // Returns true on success, false on failure.
718   // |switch_value| also contains the serialized GUID.
719   // |fd_key| is used on non-Mac POSIX platforms as the file descriptor passed
720   // down to the child process for the shared memory region.
721   static bool CreateTrialsFromSwitchValue(const std::string& switch_value,
722                                           uint32_t fd_key);
723 #endif  // !BUILDFLAG(IS_NACL) && !BUILDFLAG(IS_IOS)
724 
725   // Takes an unmapped ReadOnlySharedMemoryRegion, maps it with the correct size
726   // and creates field trials via CreateTrialsFromSharedMemoryMapping(). Returns
727   // true if successful and false otherwise.
728   static bool CreateTrialsFromSharedMemoryRegion(
729       const ReadOnlySharedMemoryRegion& shm_region);
730 
731   // Expects a mapped piece of shared memory |shm_mapping| that was created from
732   // the browser process's field_trial_allocator and shared via the command
733   // line. This function recreates the allocator, iterates through all the field
734   // trials in it, and creates them via CreateFieldTrial(). Returns true if
735   // successful and false otherwise.
736   static bool CreateTrialsFromSharedMemoryMapping(
737       ReadOnlySharedMemoryMapping shm_mapping);
738 
739   // Instantiate the field trial allocator, add all existing field trials to it,
740   // and duplicates its handle to a read-only handle, which gets stored in
741   // |readonly_allocator_handle|.
742   static void InstantiateFieldTrialAllocatorIfNeeded();
743 
744   // Adds the field trial to the allocator. Caller must hold a lock before
745   // calling this.
746   static void AddToAllocatorWhileLocked(PersistentMemoryAllocator* allocator,
747                                         FieldTrial* field_trial);
748 
749   // Activate the corresponding field trial entry struct in shared memory.
750   static void ActivateFieldTrialEntryWhileLocked(FieldTrial* field_trial);
751 
752   // A map from FieldTrial names to the actual instances.
753   typedef std::map<std::string, FieldTrial*, std::less<>> RegistrationMap;
754 
755   // Helper function should be called only while holding lock_.
756   FieldTrial* PreLockedFind(StringPiece name) EXCLUSIVE_LOCKS_REQUIRED(lock_);
757 
758   // Register() stores a pointer to the given trial in a global map.
759   // This method also AddRef's the indicated trial.
760   // This should always be called after creating a new FieldTrial instance.
761   // If the caller wants to select the instance's group randomly,
762   // |is_randomized_trial| should be true to count the number of randomized
763   // trials correctly. Otherwise, false.
764   static void Register(FieldTrial* trial, bool is_randomized_trial);
765 
766   // Returns all the registered trials.
767   static RegistrationMap GetRegisteredTrials();
768 
769   // Create field trials from a list of FieldTrial::State.
770   // CreateTrialsFromString() and CreateTrialsFromFieldTrialStates() use this
771   // method internally.
772   static bool CreateTrialsFromFieldTrialStatesInternal(
773       const std::vector<FieldTrial::State>& entries);
774 
775   // The same as |GetActiveFieldTrialGroups| but also gives access to low
776   // anonymity field trials.
777   // Restricted to specifically allowed friends - access via
778   // |FieldTrialListIncludingLowAnonymity::GetActiveFieldTrialGroups|.
779   static void GetActiveFieldTrialGroupsInternal(
780       FieldTrial::ActiveGroups* active_groups,
781       bool include_low_anonymity);
782 
783   // The same as |AddObserver| but is notified for low anonymity field trials
784   // too.
785   // Restricted to specifically allowed friends - access via
786   // |FieldTrialListIncludingLowAnonymity::AddObserver|.
787   static bool AddObserverInternal(Observer* observer,
788                                   bool include_low_anonymity);
789 
790   // The same as |RemoveObserver| but is notified for low anonymity field trials
791   // too.
792   // Restricted to specifically allowed friends - access via
793   // |FieldTrialListIncludingLowAnonymity::RemoveObserver|.
794   static void RemoveObserverInternal(Observer* observer,
795                                      bool include_low_anonymity);
796 
797   static FieldTrialList* global_;  // The singleton of this class.
798 
799   // Lock for access to |registered_|, |observers_|,
800   // |observers_including_low_anonymity_|,
801   // |count_of_manually_created_field_trials_|.
802   Lock lock_;
803   RegistrationMap registered_ GUARDED_BY(lock_);
804 
805   // Counts the number of field trials whose groups are selected randomly.
806   size_t num_registered_randomized_trials_ GUARDED_BY(lock_) = 0;
807 
808   // List of observers to be notified when a group is selected for a FieldTrial.
809   // Excludes low anonymity field trials.
810   std::vector<Observer*> observers_ GUARDED_BY(lock_);
811 
812   // List of observers to be notified when a group is selected for a FieldTrial.
813   // Includes low anonymity field trials.
814   std::vector<Observer*> observers_including_low_anonymity_ GUARDED_BY(lock_);
815 
816   // Counts the ongoing calls to
817   // FieldTrialList::NotifyFieldTrialGroupSelection(). Used to ensure that
818   // RemoveObserver() isn't called while notifying observers.
819   std::atomic_int num_ongoing_notify_field_trial_group_selection_calls_{0};
820 
821   // Allocator in shared memory containing field trial data. Used in both
822   // browser and child processes, but readonly in the child.
823   // In the future, we may want to move this to a more generic place if we want
824   // to start passing more data other than field trials.
825   std::unique_ptr<FieldTrialAllocator> field_trial_allocator_;
826 
827   // Readonly copy of the region to the allocator. Needs to be a member variable
828   // because it's needed from multiple methods.
829   ReadOnlySharedMemoryRegion readonly_allocator_region_;
830 
831   // Tracks whether CreateTrialsFromCommandLine() has been called.
832   bool create_trials_from_command_line_called_ = false;
833 };
834 
835 }  // namespace base
836 
837 #endif  // BASE_METRICS_FIELD_TRIAL_H_
838