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