field_trial.h 38 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806
  1. // Copyright (c) 2012 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. // FieldTrial is a class for handling details of statistical experiments
  5. // performed by actual users in the field (i.e., in a shipped or beta product).
  6. // All code is called exclusively on the UI thread currently.
  7. //
  8. // The simplest example is an experiment to see whether one of two options
  9. // produces "better" results across our user population. In that scenario, UMA
  10. // data is uploaded to aggregate the test results, and this FieldTrial class
  11. // manages the state of each such experiment (state == which option was
  12. // pseudo-randomly selected).
  13. //
  14. // States are typically generated randomly, either based on a one time
  15. // randomization (which will yield the same results, in terms of selecting
  16. // the client for a field trial or not, for every run of the program on a
  17. // given machine), or by a session randomization (generated each time the
  18. // application starts up, but held constant during the duration of the
  19. // process).
  20. //------------------------------------------------------------------------------
  21. // Example: Suppose we have an experiment involving memory, such as determining
  22. // the impact of some pruning algorithm.
  23. // We assume that we already have a histogram of memory usage, such as:
  24. // UMA_HISTOGRAM_COUNTS_1M("Memory.RendererTotal", count);
  25. // Somewhere in main thread initialization code, we'd probably define an
  26. // instance of a FieldTrial, with code such as:
  27. // // FieldTrials are reference counted, and persist automagically until
  28. // // process teardown, courtesy of their automatic registration in
  29. // // FieldTrialList.
  30. // // Note: This field trial will run in Chrome instances compiled through
  31. // // 8 July, 2015, and after that all instances will be in "StandardMem".
  32. // scoped_refptr<base::FieldTrial> trial(
  33. // base::FieldTrialList::FactoryGetFieldTrial(
  34. // "MemoryExperiment", 1000, "StandardMem",
  35. // base::FieldTrial::ONE_TIME_RANDOMIZED, nullptr));
  36. //
  37. // const int high_mem_group =
  38. // trial->AppendGroup("HighMem", 20); // 2% in HighMem group.
  39. // const int low_mem_group =
  40. // trial->AppendGroup("LowMem", 20); // 2% in LowMem group.
  41. // // Take action depending of which group we randomly land in.
  42. // if (trial->group() == high_mem_group)
  43. // SetPruningAlgorithm(kType1); // Sample setting of browser state.
  44. // else if (trial->group() == low_mem_group)
  45. // SetPruningAlgorithm(kType2); // Sample alternate setting.
  46. //------------------------------------------------------------------------------
  47. #ifndef BASE_METRICS_FIELD_TRIAL_H_
  48. #define BASE_METRICS_FIELD_TRIAL_H_
  49. #include <stddef.h>
  50. #include <stdint.h>
  51. #include <map>
  52. #include <memory>
  53. #include <string>
  54. #include <vector>
  55. #include "base/atomicops.h"
  56. #include "base/base_export.h"
  57. #include "base/command_line.h"
  58. #include "base/feature_list.h"
  59. #include "base/gtest_prod_util.h"
  60. #include "base/memory/read_only_shared_memory_region.h"
  61. #include "base/memory/ref_counted.h"
  62. #include "base/memory/shared_memory_mapping.h"
  63. #include "base/metrics/persistent_memory_allocator.h"
  64. #include "base/observer_list_threadsafe.h"
  65. #include "base/pickle.h"
  66. #include "base/process/launch.h"
  67. #include "base/strings/string_piece.h"
  68. #include "base/synchronization/lock.h"
  69. #include "build/build_config.h"
  70. #if defined(OS_MAC)
  71. #include "base/mac/mach_port_rendezvous.h"
  72. #endif
  73. namespace base {
  74. class FieldTrialList;
  75. class BASE_EXPORT FieldTrial : public RefCounted<FieldTrial> {
  76. public:
  77. typedef int Probability; // Probability type for being selected in a trial.
  78. // Specifies the persistence of the field trial group choice.
  79. enum RandomizationType {
  80. // One time randomized trials will persist the group choice between
  81. // restarts, which is recommended for most trials, especially those that
  82. // change user visible behavior.
  83. ONE_TIME_RANDOMIZED,
  84. // Session randomized trials will roll the dice to select a group on every
  85. // process restart.
  86. SESSION_RANDOMIZED,
  87. };
  88. // EntropyProvider is an interface for providing entropy for one-time
  89. // randomized (persistent) field trials.
  90. class BASE_EXPORT EntropyProvider {
  91. public:
  92. virtual ~EntropyProvider();
  93. // Returns a double in the range of [0, 1) to be used for the dice roll for
  94. // the specified field trial. If |randomization_seed| is not 0, it will be
  95. // used in preference to |trial_name| for generating the entropy by entropy
  96. // providers that support it. A given instance should always return the same
  97. // value given the same input |trial_name| and |randomization_seed| values.
  98. virtual double GetEntropyForTrial(const std::string& trial_name,
  99. uint32_t randomization_seed) const = 0;
  100. };
  101. // A pair representing a Field Trial and its selected group.
  102. struct ActiveGroup {
  103. std::string trial_name;
  104. std::string group_name;
  105. };
  106. // A triplet representing a FieldTrial, its selected group and whether it's
  107. // active. String members are pointers to the underlying strings owned by the
  108. // FieldTrial object. Does not use StringPiece to avoid conversions back to
  109. // std::string.
  110. struct BASE_EXPORT State {
  111. const std::string* trial_name = nullptr;
  112. const std::string* group_name = nullptr;
  113. bool activated = false;
  114. State();
  115. State(const State& other);
  116. ~State();
  117. };
  118. // We create one FieldTrialEntry per field trial in shared memory, via
  119. // AddToAllocatorWhileLocked. The FieldTrialEntry is followed by a
  120. // base::Pickle object that we unpickle and read from.
  121. struct BASE_EXPORT FieldTrialEntry {
  122. // SHA1(FieldTrialEntry): Increment this if structure changes!
  123. static constexpr uint32_t kPersistentTypeId = 0xABA17E13 + 2;
  124. // Expected size for 32/64-bit check.
  125. static constexpr size_t kExpectedInstanceSize = 8;
  126. // Whether or not this field trial is activated. This is really just a
  127. // boolean but using a 32 bit value for portability reasons. It should be
  128. // accessed via NoBarrier_Load()/NoBarrier_Store() to prevent the compiler
  129. // from doing unexpected optimizations because it thinks that only one
  130. // thread is accessing the memory location.
  131. subtle::Atomic32 activated;
  132. // Size of the pickled structure, NOT the total size of this entry.
  133. uint32_t pickle_size;
  134. // Calling this is only valid when the entry is initialized. That is, it
  135. // resides in shared memory and has a pickle containing the trial name and
  136. // group name following it.
  137. bool GetTrialAndGroupName(StringPiece* trial_name,
  138. StringPiece* group_name) const;
  139. // Calling this is only valid when the entry is initialized as well. Reads
  140. // the parameters following the trial and group name and stores them as
  141. // key-value mappings in |params|.
  142. bool GetParams(std::map<std::string, std::string>* params) const;
  143. private:
  144. // Returns an iterator over the data containing names and params.
  145. PickleIterator GetPickleIterator() const;
  146. // Takes the iterator and writes out the first two items into |trial_name|
  147. // and |group_name|.
  148. bool ReadStringPair(PickleIterator* iter,
  149. StringPiece* trial_name,
  150. StringPiece* group_name) const;
  151. };
  152. typedef std::vector<ActiveGroup> ActiveGroups;
  153. // A return value to indicate that a given instance has not yet had a group
  154. // assignment (and hence is not yet participating in the trial).
  155. static const int kNotFinalized;
  156. FieldTrial(const FieldTrial&) = delete;
  157. FieldTrial& operator=(const FieldTrial&) = delete;
  158. // Disables this trial, meaning it always determines the default group
  159. // has been selected. May be called immediately after construction, or
  160. // at any time after initialization (should not be interleaved with
  161. // AppendGroup calls). Once disabled, there is no way to re-enable a
  162. // trial.
  163. // TODO(mad): http://code.google.com/p/chromium/issues/detail?id=121446
  164. // This doesn't properly reset to Default when a group was forced.
  165. void Disable();
  166. // Establish the name and probability of the next group in this trial.
  167. // Sometimes, based on construction randomization, this call may cause the
  168. // provided group to be *THE* group selected for use in this instance.
  169. // The return value is the group number of the new group.
  170. int AppendGroup(const std::string& name, Probability group_probability);
  171. // Return the name of the FieldTrial (excluding the group name).
  172. const std::string& trial_name() const { return trial_name_; }
  173. // Return the randomly selected group number that was assigned, and notify
  174. // any/all observers that this finalized group number has presumably been used
  175. // (queried), and will never change. Note that this will force an instance to
  176. // participate, and make it illegal to attempt to probabilistically add any
  177. // other groups to the trial.
  178. int group();
  179. // If the group's name is empty, a string version containing the group number
  180. // is used as the group name. This causes a winner to be chosen if none was.
  181. const std::string& group_name();
  182. // Finalizes the group choice and returns the chosen group, but does not mark
  183. // the trial as active - so its state will not be reported until group_name()
  184. // or similar is called.
  185. const std::string& GetGroupNameWithoutActivation();
  186. // Set the field trial as forced, meaning that it was setup earlier than
  187. // the hard coded registration of the field trial to override it.
  188. // This allows the code that was hard coded to register the field trial to
  189. // still succeed even though the field trial has already been registered.
  190. // This must be called after appending all the groups, since we will make
  191. // the group choice here. Note that this is a NOOP for already forced trials.
  192. // And, as the rest of the FieldTrial code, this is not thread safe and must
  193. // be done from the UI thread.
  194. void SetForced();
  195. // Enable benchmarking sets field trials to a common setting.
  196. static void EnableBenchmarking();
  197. // Creates a FieldTrial object with the specified parameters, to be used for
  198. // simulation of group assignment without actually affecting global field
  199. // trial state in the running process. Group assignment will be done based on
  200. // |entropy_value|, which must have a range of [0, 1).
  201. //
  202. // Note: Using this function will not register the field trial globally in the
  203. // running process - for that, use FieldTrialList::FactoryGetFieldTrial().
  204. //
  205. // The ownership of the returned FieldTrial is transfered to the caller which
  206. // is responsible for deref'ing it (e.g. by using scoped_refptr<FieldTrial>).
  207. static FieldTrial* CreateSimulatedFieldTrial(
  208. const std::string& trial_name,
  209. Probability total_probability,
  210. const std::string& default_group_name,
  211. double entropy_value);
  212. private:
  213. // Allow tests to access our innards for testing purposes.
  214. FRIEND_TEST_ALL_PREFIXES(FieldTrialTest, Registration);
  215. FRIEND_TEST_ALL_PREFIXES(FieldTrialTest, AbsoluteProbabilities);
  216. FRIEND_TEST_ALL_PREFIXES(FieldTrialTest, RemainingProbability);
  217. FRIEND_TEST_ALL_PREFIXES(FieldTrialTest, FiftyFiftyProbability);
  218. FRIEND_TEST_ALL_PREFIXES(FieldTrialTest, MiddleProbabilities);
  219. FRIEND_TEST_ALL_PREFIXES(FieldTrialTest, OneWinner);
  220. FRIEND_TEST_ALL_PREFIXES(FieldTrialTest, DisableProbability);
  221. FRIEND_TEST_ALL_PREFIXES(FieldTrialTest, ActiveGroups);
  222. FRIEND_TEST_ALL_PREFIXES(FieldTrialTest, AllGroups);
  223. FRIEND_TEST_ALL_PREFIXES(FieldTrialTest, ActiveGroupsNotFinalized);
  224. FRIEND_TEST_ALL_PREFIXES(FieldTrialTest, Save);
  225. FRIEND_TEST_ALL_PREFIXES(FieldTrialTest, SaveAll);
  226. FRIEND_TEST_ALL_PREFIXES(FieldTrialTest, DuplicateRestore);
  227. FRIEND_TEST_ALL_PREFIXES(FieldTrialTest, SetForcedTurnFeatureOff);
  228. FRIEND_TEST_ALL_PREFIXES(FieldTrialTest, SetForcedTurnFeatureOn);
  229. FRIEND_TEST_ALL_PREFIXES(FieldTrialTest, SetForcedChangeDefault_Default);
  230. FRIEND_TEST_ALL_PREFIXES(FieldTrialTest, SetForcedChangeDefault_NonDefault);
  231. FRIEND_TEST_ALL_PREFIXES(FieldTrialTest, FloatBoundariesGiveEqualGroupSizes);
  232. FRIEND_TEST_ALL_PREFIXES(FieldTrialTest, DoesNotSurpassTotalProbability);
  233. FRIEND_TEST_ALL_PREFIXES(FieldTrialListTest,
  234. DoNotAddSimulatedFieldTrialsToAllocator);
  235. FRIEND_TEST_ALL_PREFIXES(FieldTrialListTest, ClearParamsFromSharedMemory);
  236. friend class base::FieldTrialList;
  237. friend class RefCounted<FieldTrial>;
  238. using FieldTrialRef = PersistentMemoryAllocator::Reference;
  239. // This is the group number of the 'default' group when a choice wasn't forced
  240. // by a call to FieldTrialList::CreateFieldTrial. It is kept private so that
  241. // consumers don't use it by mistake in cases where the group was forced.
  242. static const int kDefaultGroupNumber;
  243. // Creates a field trial with the specified parameters. Group assignment will
  244. // be done based on |entropy_value|, which must have a range of [0, 1).
  245. FieldTrial(const std::string& trial_name,
  246. Probability total_probability,
  247. const std::string& default_group_name,
  248. double entropy_value);
  249. virtual ~FieldTrial();
  250. // Return the default group name of the FieldTrial.
  251. std::string default_group_name() const { return default_group_name_; }
  252. // Marks this trial as having been registered with the FieldTrialList. Must be
  253. // called no more than once and before any |group()| calls have occurred.
  254. void SetTrialRegistered();
  255. // Sets the chosen group name and number.
  256. void SetGroupChoice(const std::string& group_name, int number);
  257. // Ensures that a group is chosen, if it hasn't yet been. The field trial
  258. // might yet be disabled, so this call will *not* notify observers of the
  259. // status.
  260. void FinalizeGroupChoice();
  261. // Implements FinalizeGroupChoice() with the added flexibility of being
  262. // deadlock-free if |is_locked| is true and the caller is holding a lock.
  263. void FinalizeGroupChoiceImpl(bool is_locked);
  264. // Returns the trial name and selected group name for this field trial via
  265. // the output parameter |active_group|, but only if the group has already
  266. // been chosen and has been externally observed via |group()| and the trial
  267. // has not been disabled. In that case, true is returned and |active_group|
  268. // is filled in; otherwise, the result is false and |active_group| is left
  269. // untouched.
  270. bool GetActiveGroup(ActiveGroup* active_group) const;
  271. // Returns the trial name and selected group name for this field trial via
  272. // the output parameter |field_trial_state| for all the studies when
  273. // |include_disabled| is true. In case when |include_disabled| is false, if
  274. // the trial has not been disabled true is returned and |field_trial_state|
  275. // is filled in; otherwise, the result is false and |field_trial_state| is
  276. // left untouched.
  277. bool GetStateWhileLocked(State* field_trial_state, bool include_disabled);
  278. // Returns the group_name. A winner need not have been chosen.
  279. std::string group_name_internal() const { return group_name_; }
  280. // The name of the field trial, as can be found via the FieldTrialList.
  281. const std::string trial_name_;
  282. // The maximum sum of all probabilities supplied, which corresponds to 100%.
  283. // This is the scaling factor used to adjust supplied probabilities.
  284. const Probability divisor_;
  285. // The name of the default group.
  286. const std::string default_group_name_;
  287. // The randomly selected probability that is used to select a group (or have
  288. // the instance not participate). It is the product of divisor_ and a random
  289. // number between [0, 1).
  290. Probability random_;
  291. // Sum of the probabilities of all appended groups.
  292. Probability accumulated_group_probability_;
  293. // The number that will be returned by the next AppendGroup() call.
  294. int next_group_number_;
  295. // The pseudo-randomly assigned group number.
  296. // This is kNotFinalized if no group has been assigned.
  297. int group_;
  298. // A textual name for the randomly selected group. Valid after |group()|
  299. // has been called.
  300. std::string group_name_;
  301. // When enable_field_trial_ is false, field trial reverts to the 'default'
  302. // group.
  303. bool enable_field_trial_;
  304. // When forced_ is true, we return the chosen group from AppendGroup when
  305. // appropriate.
  306. bool forced_;
  307. // Specifies whether the group choice has been reported to observers.
  308. bool group_reported_;
  309. // Whether this trial is registered with the global FieldTrialList and thus
  310. // should notify it when its group is queried.
  311. bool trial_registered_;
  312. // Reference to related field trial struct and data in shared memory.
  313. FieldTrialRef ref_;
  314. // When benchmarking is enabled, field trials all revert to the 'default'
  315. // group.
  316. static bool enable_benchmarking_;
  317. };
  318. //------------------------------------------------------------------------------
  319. // Class with a list of all active field trials. A trial is active if it has
  320. // been registered, which includes evaluating its state based on its probaility.
  321. // Only one instance of this class exists and outside of testing, will live for
  322. // the entire life time of the process.
  323. class BASE_EXPORT FieldTrialList {
  324. public:
  325. using FieldTrialAllocator = PersistentMemoryAllocator;
  326. // Type for function pointer passed to |AllParamsToString| used to escape
  327. // special characters from |input|.
  328. typedef std::string (*EscapeDataFunc)(const std::string& input);
  329. // Observer is notified when a FieldTrial's group is selected.
  330. class BASE_EXPORT Observer {
  331. public:
  332. // Notify observers when FieldTrials's group is selected.
  333. virtual void OnFieldTrialGroupFinalized(const std::string& trial_name,
  334. const std::string& group_name) = 0;
  335. protected:
  336. virtual ~Observer();
  337. };
  338. // This singleton holds the global list of registered FieldTrials.
  339. //
  340. // To support one-time randomized field trials, specify a non-null
  341. // |entropy_provider| which should be a source of uniformly distributed
  342. // entropy values. If one time randomization is not desired, pass in null for
  343. // |entropy_provider|.
  344. explicit FieldTrialList(
  345. std::unique_ptr<const FieldTrial::EntropyProvider> entropy_provider);
  346. FieldTrialList(const FieldTrialList&) = delete;
  347. FieldTrialList& operator=(const FieldTrialList&) = delete;
  348. // Destructor Release()'s references to all registered FieldTrial instances.
  349. ~FieldTrialList();
  350. // Get a FieldTrial instance from the factory.
  351. //
  352. // |name| is used to register the instance with the FieldTrialList class,
  353. // and can be used to find the trial (only one trial can be present for each
  354. // name). |default_group_name| is the name of the default group which will
  355. // be chosen if none of the subsequent appended groups get to be chosen.
  356. // |default_group_number| can receive the group number of the default group as
  357. // AppendGroup returns the number of the subsequence groups. |trial_name| and
  358. // |default_group_name| may not be empty but |default_group_number| can be
  359. // null if the value is not needed.
  360. //
  361. // Group probabilities that are later supplied must sum to less than or equal
  362. // to the |total_probability|.
  363. //
  364. // Use this static method to get a startup-randomized FieldTrial or a
  365. // previously created forced FieldTrial.
  366. static FieldTrial* FactoryGetFieldTrial(
  367. const std::string& trial_name,
  368. FieldTrial::Probability total_probability,
  369. const std::string& default_group_name,
  370. FieldTrial::RandomizationType randomization_type,
  371. int* default_group_number);
  372. // Same as FactoryGetFieldTrial(), but allows specifying a custom seed to be
  373. // used on one-time randomized field trials (instead of a hash of the trial
  374. // name, which is used otherwise or if |randomization_seed| has value 0). The
  375. // |randomization_seed| value (other than 0) should never be the same for two
  376. // trials, else this would result in correlated group assignments. Note:
  377. // Using a custom randomization seed is only supported by the
  378. // NormalizedMurmurHashEntropyProvider, which is used when UMA is not enabled
  379. // (and is always used in Android WebView, where UMA is enabled
  380. // asyncronously). If |override_entropy_provider| is not null, then it will be
  381. // used for randomization instead of the provider given when the
  382. // FieldTrialList was instantiated.
  383. static FieldTrial* FactoryGetFieldTrialWithRandomizationSeed(
  384. const std::string& trial_name,
  385. FieldTrial::Probability total_probability,
  386. const std::string& default_group_name,
  387. FieldTrial::RandomizationType randomization_type,
  388. uint32_t randomization_seed,
  389. int* default_group_number,
  390. const FieldTrial::EntropyProvider* override_entropy_provider);
  391. // The Find() method can be used to test to see if a named trial was already
  392. // registered, or to retrieve a pointer to it from the global map.
  393. static FieldTrial* Find(const std::string& trial_name);
  394. // Returns the group number chosen for the named trial, or
  395. // FieldTrial::kNotFinalized if the trial does not exist.
  396. static int FindValue(const std::string& trial_name);
  397. // Returns the group name chosen for the named trial, or the empty string if
  398. // the trial does not exist. The first call of this function on a given field
  399. // trial will mark it as active, so that its state will be reported with usage
  400. // metrics, crashes, etc.
  401. // Note: Direct use of this function and related FieldTrial functions is
  402. // generally discouraged - instead please use base::Feature when possible.
  403. static std::string FindFullName(const std::string& trial_name);
  404. // Returns true if the named trial has been registered.
  405. static bool TrialExists(const std::string& trial_name);
  406. // Returns true if the named trial exists and has been activated.
  407. static bool IsTrialActive(const std::string& trial_name);
  408. // Creates a persistent representation of active FieldTrial instances for
  409. // resurrection in another process. This allows randomization to be done in
  410. // one process, and secondary processes can be synchronized on the result.
  411. // The resulting string contains the name and group name pairs of all
  412. // registered FieldTrials for which the group has been chosen and externally
  413. // observed (via |group()|) and which have not been disabled, with "/" used
  414. // to separate all names and to terminate the string. This string is parsed
  415. // by |CreateTrialsFromString()|.
  416. static void StatesToString(std::string* output);
  417. // Creates a persistent representation of all FieldTrial instances for
  418. // resurrection in another process. This allows randomization to be done in
  419. // one process, and secondary processes can be synchronized on the result.
  420. // The resulting string contains the name and group name pairs of all
  421. // registered FieldTrials including disabled based on |include_disabled|,
  422. // with "/" used to separate all names and to terminate the string. All
  423. // activated trials have their name prefixed with "*". This string is parsed
  424. // by |CreateTrialsFromString()|.
  425. static void AllStatesToString(std::string* output, bool include_disabled);
  426. // Creates a persistent representation of all FieldTrial params for
  427. // resurrection in another process. The returned string contains the trial
  428. // name and group name pairs of all registered FieldTrials including disabled
  429. // based on |include_disabled| separated by '.'. The pair is followed by ':'
  430. // separator and list of param name and values separated by '/'. It also takes
  431. // |encode_data_func| function pointer for encodeing special charactors.
  432. // This string is parsed by |AssociateParamsFromString()|.
  433. static std::string AllParamsToString(bool include_disabled,
  434. EscapeDataFunc encode_data_func);
  435. // Fills in the supplied vector |active_groups| (which must be empty when
  436. // called) with a snapshot of all registered FieldTrials for which the group
  437. // has been chosen and externally observed (via |group()|) and which have
  438. // not been disabled.
  439. static void GetActiveFieldTrialGroups(
  440. FieldTrial::ActiveGroups* active_groups);
  441. // Returns the field trials that are marked active in |trials_string|.
  442. static void GetActiveFieldTrialGroupsFromString(
  443. const std::string& trials_string,
  444. FieldTrial::ActiveGroups* active_groups);
  445. // Returns the field trials that were active when the process was
  446. // created. Either parses the field trial string or the shared memory
  447. // holding field trial information.
  448. // Must be called only after a call to CreateTrialsFromCommandLine().
  449. static void GetInitiallyActiveFieldTrials(
  450. const CommandLine& command_line,
  451. FieldTrial::ActiveGroups* active_groups);
  452. // Use a state string (re: StatesToString()) to augment the current list of
  453. // field trials to include the supplied trials, and using a 100% probability
  454. // for each trial, force them to have the same group string. This is commonly
  455. // used in a non-browser process, to carry randomly selected state in a
  456. // browser process into this non-browser process, but could also be invoked
  457. // through a command line argument to the browser process. Created field
  458. // trials will be marked "used" for the purposes of active trial reporting
  459. // if they are prefixed with |kActivationMarker|.
  460. static bool CreateTrialsFromString(const std::string& trials_string);
  461. // Achieves the same thing as CreateTrialsFromString, except wraps the logic
  462. // by taking in the trials from the command line, either via shared memory
  463. // handle or command line argument. A bit of a misnomer since on POSIX we
  464. // simply get the trials from opening |fd_key| if using shared memory. On
  465. // Windows, we expect the |cmd_line| switch for |field_trial_handle_switch| to
  466. // contain the shared memory handle that contains the field trial allocator.
  467. // We need the |field_trial_handle_switch| and |fd_key| arguments to be passed
  468. // in since base/ can't depend on content/.
  469. static void CreateTrialsFromCommandLine(const CommandLine& cmd_line,
  470. const char* field_trial_handle_switch,
  471. int fd_key);
  472. // Creates base::Feature overrides from the command line by first trying to
  473. // use shared memory and then falling back to the command line if it fails.
  474. static void CreateFeaturesFromCommandLine(const CommandLine& command_line,
  475. const char* enable_features_switch,
  476. const char* disable_features_switch,
  477. FeatureList* feature_list);
  478. #if defined(OS_WIN)
  479. // On Windows, we need to explicitly pass down any handles to be inherited.
  480. // This function adds the shared memory handle to field trial state to the
  481. // list of handles to be inherited.
  482. static void AppendFieldTrialHandleIfNeeded(HandlesToInheritVector* handles);
  483. #elif defined(OS_FUCHSIA)
  484. // TODO(fuchsia): Implement shared-memory configuration (crbug.com/752368).
  485. #elif defined(OS_MAC)
  486. // On Mac, the field trial shared memory is accessed via a Mach server, which
  487. // the child looks up directly.
  488. static void InsertFieldTrialHandleIfNeeded(
  489. MachPortsForRendezvous* rendezvous_ports);
  490. #elif defined(OS_POSIX) && !defined(OS_NACL)
  491. // On POSIX, we also need to explicitly pass down this file descriptor that
  492. // should be shared with the child process. Returns -1 if it was not
  493. // initialized properly. The current process remains the onwer of the passed
  494. // descriptor.
  495. static int GetFieldTrialDescriptor();
  496. #endif
  497. static ReadOnlySharedMemoryRegion DuplicateFieldTrialSharedMemoryForTesting();
  498. // Adds a switch to the command line containing the field trial state as a
  499. // string (if not using shared memory to share field trial state), or the
  500. // shared memory handle + length.
  501. // Needs the |field_trial_handle_switch| argument to be passed in since base/
  502. // can't depend on content/.
  503. static void CopyFieldTrialStateToFlags(const char* field_trial_handle_switch,
  504. const char* enable_features_switch,
  505. const char* disable_features_switch,
  506. CommandLine* cmd_line);
  507. // Create a FieldTrial with the given |name| and using 100% probability for
  508. // the FieldTrial, force FieldTrial to have the same group string as
  509. // |group_name|. This is commonly used in a non-browser process, to carry
  510. // randomly selected state in a browser process into this non-browser process.
  511. // It returns NULL if there is a FieldTrial that is already registered with
  512. // the same |name| but has different finalized group string (|group_name|).
  513. static FieldTrial* CreateFieldTrial(const std::string& name,
  514. const std::string& group_name);
  515. // Add an observer to be notified when a field trial is irrevocably committed
  516. // to being part of some specific field_group (and hence the group_name is
  517. // also finalized for that field_trial). Returns false and does nothing if
  518. // there is no FieldTrialList singleton.
  519. static bool AddObserver(Observer* observer);
  520. // Remove an observer.
  521. static void RemoveObserver(Observer* observer);
  522. // Similar to AddObserver(), but the passed observer will be notified
  523. // synchronously when a field trial is activated and its group selected. It
  524. // will be notified synchronously on the same thread where the activation and
  525. // group selection happened. It is the responsibility of the observer to make
  526. // sure that this is a safe operation and the operation must be fast, as this
  527. // work is done synchronously as part of group() or related APIs. Only a
  528. // single such observer is supported, exposed specifically for crash
  529. // reporting. Must be called on the main thread before any other threads
  530. // have been started.
  531. static void SetSynchronousObserver(Observer* observer);
  532. // Removes the single synchronous observer.
  533. static void RemoveSynchronousObserver(Observer* observer);
  534. // Grabs the lock if necessary and adds the field trial to the allocator. This
  535. // should only be called from FinalizeGroupChoice().
  536. static void OnGroupFinalized(bool is_locked, FieldTrial* field_trial);
  537. // Notify all observers that a group has been finalized for |field_trial|.
  538. static void NotifyFieldTrialGroupSelection(FieldTrial* field_trial);
  539. // Return the number of active field trials.
  540. static size_t GetFieldTrialCount();
  541. // Gets the parameters for |field_trial| from shared memory and stores them in
  542. // |params|. This is only exposed for use by FieldTrialParamAssociator and
  543. // shouldn't be used by anything else.
  544. static bool GetParamsFromSharedMemory(
  545. FieldTrial* field_trial,
  546. std::map<std::string, std::string>* params);
  547. // Clears all the params in the allocator.
  548. static void ClearParamsFromSharedMemoryForTesting();
  549. // Dumps field trial state to an allocator so that it can be analyzed after a
  550. // crash.
  551. static void DumpAllFieldTrialsToPersistentAllocator(
  552. PersistentMemoryAllocator* allocator);
  553. // Retrieves field trial state from an allocator so that it can be analyzed
  554. // after a crash. The pointers in the returned vector are into the persistent
  555. // memory segment and so are only valid as long as the allocator is valid.
  556. static std::vector<const FieldTrial::FieldTrialEntry*>
  557. GetAllFieldTrialsFromPersistentAllocator(
  558. PersistentMemoryAllocator const& allocator);
  559. // Returns a pointer to the global instance. This is exposed so that it can
  560. // be used in a DCHECK in FeatureList and ScopedFeatureList test-only logic
  561. // and is not intended to be used widely beyond those cases.
  562. static FieldTrialList* GetInstance();
  563. // For testing, sets the global instance to null and returns the previous one.
  564. static FieldTrialList* BackupInstanceForTesting();
  565. // For testing, sets the global instance to |instance|.
  566. static void RestoreInstanceForTesting(FieldTrialList* instance);
  567. private:
  568. // Allow tests to access our innards for testing purposes.
  569. FRIEND_TEST_ALL_PREFIXES(FieldTrialListTest, InstantiateAllocator);
  570. FRIEND_TEST_ALL_PREFIXES(FieldTrialListTest, AddTrialsToAllocator);
  571. FRIEND_TEST_ALL_PREFIXES(FieldTrialListTest,
  572. DoNotAddSimulatedFieldTrialsToAllocator);
  573. FRIEND_TEST_ALL_PREFIXES(FieldTrialListTest, AssociateFieldTrialParams);
  574. FRIEND_TEST_ALL_PREFIXES(FieldTrialListTest, ClearParamsFromSharedMemory);
  575. FRIEND_TEST_ALL_PREFIXES(FieldTrialListTest,
  576. SerializeSharedMemoryRegionMetadata);
  577. friend int SerializeSharedMemoryRegionMetadata(void);
  578. FRIEND_TEST_ALL_PREFIXES(FieldTrialListTest, CheckReadOnlySharedMemoryRegion);
  579. // Serialization is used to pass information about the handle to child
  580. // processes. It passes a reference to the relevant OS resource, and it passes
  581. // a GUID. Serialization and deserialization doesn't actually transport the
  582. // underlying OS resource - that must be done by the Process launcher.
  583. static std::string SerializeSharedMemoryRegionMetadata(
  584. const ReadOnlySharedMemoryRegion& shm);
  585. #if defined(OS_WIN) || defined(OS_FUCHSIA) || defined(OS_MAC)
  586. static ReadOnlySharedMemoryRegion DeserializeSharedMemoryRegionMetadata(
  587. const std::string& switch_value);
  588. #elif defined(OS_POSIX) && !defined(OS_NACL)
  589. static ReadOnlySharedMemoryRegion DeserializeSharedMemoryRegionMetadata(
  590. int fd,
  591. const std::string& switch_value);
  592. #endif
  593. #if defined(OS_WIN) || defined(OS_FUCHSIA) || defined(OS_MAC)
  594. // Takes in |handle_switch| from the command line which represents the shared
  595. // memory handle for field trials, parses it, and creates the field trials.
  596. // Returns true on success, false on failure.
  597. // |switch_value| also contains the serialized GUID.
  598. static bool CreateTrialsFromSwitchValue(const std::string& switch_value);
  599. #elif defined(OS_POSIX) && !defined(OS_NACL)
  600. // On POSIX systems that use the zygote, we look up the correct fd that backs
  601. // the shared memory segment containing the field trials by looking it up via
  602. // an fd key in GlobalDescriptors. Returns true on success, false on failure.
  603. // |switch_value| also contains the serialized GUID.
  604. static bool CreateTrialsFromDescriptor(int fd_key,
  605. const std::string& switch_value);
  606. #endif
  607. // Takes an unmapped ReadOnlySharedMemoryRegion, maps it with the correct size
  608. // and creates field trials via CreateTrialsFromSharedMemoryMapping(). Returns
  609. // true if successful and false otherwise.
  610. static bool CreateTrialsFromSharedMemoryRegion(
  611. const ReadOnlySharedMemoryRegion& shm_region);
  612. // Expects a mapped piece of shared memory |shm_mapping| that was created from
  613. // the browser process's field_trial_allocator and shared via the command
  614. // line. This function recreates the allocator, iterates through all the field
  615. // trials in it, and creates them via CreateFieldTrial(). Returns true if
  616. // successful and false otherwise.
  617. static bool CreateTrialsFromSharedMemoryMapping(
  618. ReadOnlySharedMemoryMapping shm_mapping);
  619. // Instantiate the field trial allocator, add all existing field trials to it,
  620. // and duplicates its handle to a read-only handle, which gets stored in
  621. // |readonly_allocator_handle|.
  622. static void InstantiateFieldTrialAllocatorIfNeeded();
  623. // Adds the field trial to the allocator. Caller must hold a lock before
  624. // calling this.
  625. static void AddToAllocatorWhileLocked(PersistentMemoryAllocator* allocator,
  626. FieldTrial* field_trial);
  627. // Activate the corresponding field trial entry struct in shared memory.
  628. static void ActivateFieldTrialEntryWhileLocked(FieldTrial* field_trial);
  629. // A map from FieldTrial names to the actual instances.
  630. typedef std::map<std::string, FieldTrial*> RegistrationMap;
  631. // If one-time randomization is enabled, returns a weak pointer to the
  632. // corresponding EntropyProvider. Otherwise, returns NULL.
  633. static const FieldTrial::EntropyProvider*
  634. GetEntropyProviderForOneTimeRandomization();
  635. // Helper function should be called only while holding lock_.
  636. FieldTrial* PreLockedFind(const std::string& name);
  637. // Register() stores a pointer to the given trial in a global map.
  638. // This method also AddRef's the indicated trial.
  639. // This should always be called after creating a new FieldTrial instance.
  640. static void Register(FieldTrial* trial);
  641. // Returns all the registered trials.
  642. static RegistrationMap GetRegisteredTrials();
  643. static FieldTrialList* global_; // The singleton of this class.
  644. // This will tell us if there is an attempt to register a field
  645. // trial or check if one-time randomization is enabled without
  646. // creating the FieldTrialList. This is not an error, unless a
  647. // FieldTrialList is created after that.
  648. static bool used_without_global_;
  649. // Lock for access to registered_ and field_trial_allocator_.
  650. Lock lock_;
  651. RegistrationMap registered_;
  652. std::map<std::string, std::string> seen_states_;
  653. // Entropy provider to be used for one-time randomized field trials. If NULL,
  654. // one-time randomization is not supported.
  655. std::unique_ptr<const FieldTrial::EntropyProvider> entropy_provider_;
  656. // List of observers to be notified when a group is selected for a FieldTrial.
  657. scoped_refptr<ObserverListThreadSafe<Observer> > observer_list_;
  658. // Single synchronous observer to be notified when a trial group is chosen.
  659. Observer* synchronous_observer_ = nullptr;
  660. // Allocator in shared memory containing field trial data. Used in both
  661. // browser and child processes, but readonly in the child.
  662. // In the future, we may want to move this to a more generic place if we want
  663. // to start passing more data other than field trials.
  664. std::unique_ptr<FieldTrialAllocator> field_trial_allocator_ = nullptr;
  665. // Readonly copy of the region to the allocator. Needs to be a member variable
  666. // because it's needed from both CopyFieldTrialStateToFlags() and
  667. // AppendFieldTrialHandleIfNeeded().
  668. ReadOnlySharedMemoryRegion readonly_allocator_region_;
  669. // Tracks whether CreateTrialsFromCommandLine() has been called.
  670. bool create_trials_from_command_line_called_ = false;
  671. };
  672. } // namespace base
  673. #endif // BASE_METRICS_FIELD_TRIAL_H_