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