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