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