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