field_trial.h 38 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811
  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 <set>
  54. #include <string>
  55. #include <vector>
  56. #include "base/atomicops.h"
  57. #include "base/base_export.h"
  58. #include "base/command_line.h"
  59. #include "base/feature_list.h"
  60. #include "base/gtest_prod_util.h"
  61. #include "base/macros.h"
  62. #include "base/memory/read_only_shared_memory_region.h"
  63. #include "base/memory/ref_counted.h"
  64. #include "base/memory/shared_memory_mapping.h"
  65. #include "base/metrics/persistent_memory_allocator.h"
  66. #include "base/observer_list_threadsafe.h"
  67. #include "base/pickle.h"
  68. #include "base/process/launch.h"
  69. #include "base/strings/string_piece.h"
  70. #include "base/synchronization/lock.h"
  71. #include "build/build_config.h"
  72. #if defined(OS_MACOSX) && !defined(OS_IOS)
  73. #include "base/mac/mach_port_rendezvous.h"
  74. #endif
  75. namespace base {
  76. class FieldTrialList;
  77. class BASE_EXPORT FieldTrial : public RefCounted<FieldTrial> {
  78. public:
  79. typedef int Probability; // Probability type for being selected in a trial.
  80. // Specifies the persistence of the field trial group choice.
  81. enum RandomizationType {
  82. // One time randomized trials will persist the group choice between
  83. // restarts, which is recommended for most trials, especially those that
  84. // change user visible behavior.
  85. ONE_TIME_RANDOMIZED,
  86. // Session randomized trials will roll the dice to select a group on every
  87. // process restart.
  88. SESSION_RANDOMIZED,
  89. };
  90. // EntropyProvider is an interface for providing entropy for one-time
  91. // randomized (persistent) field trials.
  92. class BASE_EXPORT EntropyProvider {
  93. public:
  94. virtual ~EntropyProvider();
  95. // Returns a double in the range of [0, 1) to be used for the dice roll for
  96. // the specified field trial. If |randomization_seed| is not 0, it will be
  97. // used in preference to |trial_name| for generating the entropy by entropy
  98. // providers that support it. A given instance should always return the same
  99. // value given the same input |trial_name| and |randomization_seed| values.
  100. virtual double GetEntropyForTrial(const std::string& trial_name,
  101. uint32_t randomization_seed) const = 0;
  102. };
  103. // A pair representing a Field Trial and its selected group.
  104. struct ActiveGroup {
  105. std::string trial_name;
  106. std::string group_name;
  107. };
  108. // A triplet representing a FieldTrial, its selected group and whether it's
  109. // active. String members are pointers to the underlying strings owned by the
  110. // FieldTrial object. Does not use StringPiece to avoid conversions back to
  111. // std::string.
  112. struct BASE_EXPORT State {
  113. const std::string* trial_name = nullptr;
  114. const std::string* group_name = nullptr;
  115. bool activated = false;
  116. State();
  117. State(const State& other);
  118. ~State();
  119. };
  120. // We create one FieldTrialEntry per field trial in shared memory, via
  121. // AddToAllocatorWhileLocked. The FieldTrialEntry is followed by a
  122. // base::Pickle object that we unpickle and read from.
  123. struct BASE_EXPORT FieldTrialEntry {
  124. // SHA1(FieldTrialEntry): Increment this if structure changes!
  125. static constexpr uint32_t kPersistentTypeId = 0xABA17E13 + 2;
  126. // Expected size for 32/64-bit check.
  127. static constexpr size_t kExpectedInstanceSize = 8;
  128. // Whether or not this field trial is activated. This is really just a
  129. // boolean but using a 32 bit value for portability reasons. It should be
  130. // accessed via NoBarrier_Load()/NoBarrier_Store() to prevent the compiler
  131. // from doing unexpected optimizations because it thinks that only one
  132. // thread is accessing the memory location.
  133. subtle::Atomic32 activated;
  134. // Size of the pickled structure, NOT the total size of this entry.
  135. uint32_t pickle_size;
  136. // Calling this is only valid when the entry is initialized. That is, it
  137. // resides in shared memory and has a pickle containing the trial name and
  138. // group name following it.
  139. bool GetTrialAndGroupName(StringPiece* trial_name,
  140. StringPiece* group_name) const;
  141. // Calling this is only valid when the entry is initialized as well. Reads
  142. // the parameters following the trial and group name and stores them as
  143. // key-value mappings in |params|.
  144. bool GetParams(std::map<std::string, std::string>* params) const;
  145. private:
  146. // Returns an iterator over the data containing names and params.
  147. PickleIterator GetPickleIterator() const;
  148. // Takes the iterator and writes out the first two items into |trial_name|
  149. // and |group_name|.
  150. bool ReadStringPair(PickleIterator* iter,
  151. StringPiece* trial_name,
  152. StringPiece* group_name) const;
  153. };
  154. typedef std::vector<ActiveGroup> ActiveGroups;
  155. // A return value to indicate that a given instance has not yet had a group
  156. // assignment (and hence is not yet participating in the trial).
  157. static const int kNotFinalized;
  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. DISALLOW_COPY_AND_ASSIGN(FieldTrial);
  318. };
  319. //------------------------------------------------------------------------------
  320. // Class with a list of all active field trials. A trial is active if it has
  321. // been registered, which includes evaluating its state based on its probaility.
  322. // Only one instance of this class exists and outside of testing, will live for
  323. // the entire life time of the process.
  324. class BASE_EXPORT FieldTrialList {
  325. public:
  326. using FieldTrialAllocator = PersistentMemoryAllocator;
  327. // Type for function pointer passed to |AllParamsToString| used to escape
  328. // special characters from |input|.
  329. typedef std::string (*EscapeDataFunc)(const std::string& input);
  330. // Observer is notified when a FieldTrial's group is selected.
  331. class BASE_EXPORT Observer {
  332. public:
  333. // Notify observers when FieldTrials's group is selected.
  334. virtual void OnFieldTrialGroupFinalized(const std::string& trial_name,
  335. const std::string& group_name) = 0;
  336. protected:
  337. virtual ~Observer();
  338. };
  339. // This singleton holds the global list of registered FieldTrials.
  340. //
  341. // To support one-time randomized field trials, specify a non-null
  342. // |entropy_provider| which should be a source of uniformly distributed
  343. // entropy values. If one time randomization is not desired, pass in null for
  344. // |entropy_provider|.
  345. explicit FieldTrialList(
  346. std::unique_ptr<const FieldTrial::EntropyProvider> entropy_provider);
  347. // Destructor Release()'s references to all registered FieldTrial instances.
  348. ~FieldTrialList();
  349. // Get a FieldTrial instance from the factory.
  350. //
  351. // |name| is used to register the instance with the FieldTrialList class,
  352. // and can be used to find the trial (only one trial can be present for each
  353. // name). |default_group_name| is the name of the default group which will
  354. // be chosen if none of the subsequent appended groups get to be chosen.
  355. // |default_group_number| can receive the group number of the default group as
  356. // AppendGroup returns the number of the subsequence groups. |trial_name| and
  357. // |default_group_name| may not be empty but |default_group_number| can be
  358. // null if the value is not needed.
  359. //
  360. // Group probabilities that are later supplied must sum to less than or equal
  361. // to the |total_probability|.
  362. //
  363. // Use this static method to get a startup-randomized FieldTrial or a
  364. // previously created forced FieldTrial.
  365. static FieldTrial* FactoryGetFieldTrial(
  366. const std::string& trial_name,
  367. FieldTrial::Probability total_probability,
  368. const std::string& default_group_name,
  369. FieldTrial::RandomizationType randomization_type,
  370. int* default_group_number);
  371. // Same as FactoryGetFieldTrial(), but allows specifying a custom seed to be
  372. // used on one-time randomized field trials (instead of a hash of the trial
  373. // name, which is used otherwise or if |randomization_seed| has value 0). The
  374. // |randomization_seed| value (other than 0) should never be the same for two
  375. // trials, else this would result in correlated group assignments. Note:
  376. // Using a custom randomization seed is only supported by the
  377. // NormalizedMurmurHashEntropyProvider, which is used when UMA is not enabled
  378. // (and is always used in Android WebView, where UMA is enabled
  379. // asyncronously). If |override_entropy_provider| is not null, then it will be
  380. // used for randomization instead of the provider given when the
  381. // FieldTrialList was instantiated.
  382. static FieldTrial* FactoryGetFieldTrialWithRandomizationSeed(
  383. const std::string& trial_name,
  384. FieldTrial::Probability total_probability,
  385. const std::string& default_group_name,
  386. FieldTrial::RandomizationType randomization_type,
  387. uint32_t randomization_seed,
  388. int* default_group_number,
  389. const FieldTrial::EntropyProvider* override_entropy_provider);
  390. // The Find() method can be used to test to see if a named trial was already
  391. // registered, or to retrieve a pointer to it from the global map.
  392. static FieldTrial* Find(const std::string& trial_name);
  393. // Returns the group number chosen for the named trial, or
  394. // FieldTrial::kNotFinalized if the trial does not exist.
  395. static int FindValue(const std::string& trial_name);
  396. // Returns the group name chosen for the named trial, or the empty string if
  397. // the trial does not exist. The first call of this function on a given field
  398. // trial will mark it as active, so that its state will be reported with usage
  399. // metrics, crashes, etc.
  400. // Note: Direct use of this function and related FieldTrial functions is
  401. // generally discouraged - instead please use base::Feature when possible.
  402. static std::string FindFullName(const std::string& trial_name);
  403. // Returns true if the named trial has been registered.
  404. static bool TrialExists(const std::string& trial_name);
  405. // Returns true if the named trial exists and has been activated.
  406. static bool IsTrialActive(const std::string& trial_name);
  407. // Creates a persistent representation of active FieldTrial instances for
  408. // resurrection in another process. This allows randomization to be done in
  409. // one process, and secondary processes can be synchronized on the result.
  410. // The resulting string contains the name and group name pairs of all
  411. // registered FieldTrials for which the group has been chosen and externally
  412. // observed (via |group()|) and which have not been disabled, with "/" used
  413. // to separate all names and to terminate the string. This string is parsed
  414. // by |CreateTrialsFromString()|.
  415. static void StatesToString(std::string* output);
  416. // Creates a persistent representation of all FieldTrial instances for
  417. // resurrection in another process. This allows randomization to be done in
  418. // one process, and secondary processes can be synchronized on the result.
  419. // The resulting string contains the name and group name pairs of all
  420. // registered FieldTrials including disabled based on |include_disabled|,
  421. // with "/" used to separate all names and to terminate the string. All
  422. // activated trials have their name prefixed with "*". This string is parsed
  423. // by |CreateTrialsFromString()|.
  424. static void AllStatesToString(std::string* output, bool include_disabled);
  425. // Creates a persistent representation of all FieldTrial params for
  426. // resurrection in another process. The returned string contains the trial
  427. // name and group name pairs of all registered FieldTrials including disabled
  428. // based on |include_disabled| separated by '.'. The pair is followed by ':'
  429. // separator and list of param name and values separated by '/'. It also takes
  430. // |encode_data_func| function pointer for encodeing special charactors.
  431. // This string is parsed by |AssociateParamsFromString()|.
  432. static std::string AllParamsToString(bool include_disabled,
  433. EscapeDataFunc encode_data_func);
  434. // Fills in the supplied vector |active_groups| (which must be empty when
  435. // called) with a snapshot of all registered FieldTrials for which the group
  436. // has been chosen and externally observed (via |group()|) and which have
  437. // not been disabled.
  438. static void GetActiveFieldTrialGroups(
  439. FieldTrial::ActiveGroups* active_groups);
  440. // Returns the field trials that are marked active in |trials_string|.
  441. static void GetActiveFieldTrialGroupsFromString(
  442. const std::string& trials_string,
  443. FieldTrial::ActiveGroups* active_groups);
  444. // Returns the field trials that were active when the process was
  445. // created. Either parses the field trial string or the shared memory
  446. // holding field trial information.
  447. // Must be called only after a call to CreateTrialsFromCommandLine().
  448. static void GetInitiallyActiveFieldTrials(
  449. const CommandLine& command_line,
  450. FieldTrial::ActiveGroups* active_groups);
  451. // Use a state string (re: StatesToString()) to augment the current list of
  452. // field trials to include the supplied trials, and using a 100% probability
  453. // for each trial, force them to have the same group string. This is commonly
  454. // used in a non-browser process, to carry randomly selected state in a
  455. // browser process into this non-browser process, but could also be invoked
  456. // through a command line argument to the browser process. Created field
  457. // trials will be marked "used" for the purposes of active trial reporting
  458. // if they are prefixed with |kActivationMarker|. Trial names in
  459. // |ignored_trial_names| are ignored when parsing |trials_string|.
  460. static bool CreateTrialsFromString(
  461. const std::string& trials_string,
  462. const std::set<std::string>& ignored_trial_names);
  463. // Achieves the same thing as CreateTrialsFromString, except wraps the logic
  464. // by taking in the trials from the command line, either via shared memory
  465. // handle or command line argument. A bit of a misnomer since on POSIX we
  466. // simply get the trials from opening |fd_key| if using shared memory. On
  467. // Windows, we expect the |cmd_line| switch for |field_trial_handle_switch| to
  468. // contain the shared memory handle that contains the field trial allocator.
  469. // We need the |field_trial_handle_switch| and |fd_key| arguments to be passed
  470. // in since base/ can't depend on content/.
  471. static void CreateTrialsFromCommandLine(const CommandLine& cmd_line,
  472. const char* field_trial_handle_switch,
  473. int fd_key);
  474. // Creates base::Feature overrides from the command line by first trying to
  475. // use shared memory and then falling back to the command line if it fails.
  476. static void CreateFeaturesFromCommandLine(const CommandLine& command_line,
  477. const char* enable_features_switch,
  478. const char* disable_features_switch,
  479. FeatureList* feature_list);
  480. #if defined(OS_WIN)
  481. // On Windows, we need to explicitly pass down any handles to be inherited.
  482. // This function adds the shared memory handle to field trial state to the
  483. // list of handles to be inherited.
  484. static void AppendFieldTrialHandleIfNeeded(HandlesToInheritVector* handles);
  485. #elif defined(OS_FUCHSIA)
  486. // TODO(fuchsia): Implement shared-memory configuration (crbug.com/752368).
  487. #elif defined(OS_MACOSX) && !defined(OS_IOS)
  488. // On Mac, the field trial shared memory is accessed via a Mach server, which
  489. // the child looks up directly.
  490. static void InsertFieldTrialHandleIfNeeded(
  491. MachPortsForRendezvous* rendezvous_ports);
  492. #elif defined(OS_POSIX) && !defined(OS_NACL)
  493. // On POSIX, we also need to explicitly pass down this file descriptor that
  494. // should be shared with the child process. Returns -1 if it was not
  495. // initialized properly. The current process remains the onwer of the passed
  496. // descriptor.
  497. static int GetFieldTrialDescriptor();
  498. #endif
  499. static ReadOnlySharedMemoryRegion DuplicateFieldTrialSharedMemoryForTesting();
  500. // Adds a switch to the command line containing the field trial state as a
  501. // string (if not using shared memory to share field trial state), or the
  502. // shared memory handle + length.
  503. // Needs the |field_trial_handle_switch| argument to be passed in since base/
  504. // can't depend on content/.
  505. static void CopyFieldTrialStateToFlags(const char* field_trial_handle_switch,
  506. const char* enable_features_switch,
  507. const char* disable_features_switch,
  508. CommandLine* cmd_line);
  509. // Create a FieldTrial with the given |name| and using 100% probability for
  510. // the FieldTrial, force FieldTrial to have the same group string as
  511. // |group_name|. This is commonly used in a non-browser process, to carry
  512. // randomly selected state in a browser process into this non-browser process.
  513. // It returns NULL if there is a FieldTrial that is already registered with
  514. // the same |name| but has different finalized group string (|group_name|).
  515. static FieldTrial* CreateFieldTrial(const std::string& name,
  516. const std::string& group_name);
  517. // Add an observer to be notified when a field trial is irrevocably committed
  518. // to being part of some specific field_group (and hence the group_name is
  519. // also finalized for that field_trial). Returns false and does nothing if
  520. // there is no FieldTrialList singleton.
  521. static bool AddObserver(Observer* observer);
  522. // Remove an observer.
  523. static void RemoveObserver(Observer* observer);
  524. // Similar to AddObserver(), but the passed observer will be notified
  525. // synchronously when a field trial is activated and its group selected. It
  526. // will be notified synchronously on the same thread where the activation and
  527. // group selection happened. It is the responsibility of the observer to make
  528. // sure that this is a safe operation and the operation must be fast, as this
  529. // work is done synchronously as part of group() or related APIs. Only a
  530. // single such observer is supported, exposed specifically for crash
  531. // reporting. Must be called on the main thread before any other threads
  532. // have been started.
  533. static void SetSynchronousObserver(Observer* observer);
  534. // Removes the single synchronous observer.
  535. static void RemoveSynchronousObserver(Observer* observer);
  536. // Grabs the lock if necessary and adds the field trial to the allocator. This
  537. // should only be called from FinalizeGroupChoice().
  538. static void OnGroupFinalized(bool is_locked, FieldTrial* field_trial);
  539. // Notify all observers that a group has been finalized for |field_trial|.
  540. static void NotifyFieldTrialGroupSelection(FieldTrial* field_trial);
  541. // Return the number of active field trials.
  542. static size_t GetFieldTrialCount();
  543. // Gets the parameters for |field_trial| from shared memory and stores them in
  544. // |params|. This is only exposed for use by FieldTrialParamAssociator and
  545. // shouldn't be used by anything else.
  546. static bool GetParamsFromSharedMemory(
  547. FieldTrial* field_trial,
  548. std::map<std::string, std::string>* params);
  549. // Clears all the params in the allocator.
  550. static void ClearParamsFromSharedMemoryForTesting();
  551. // Dumps field trial state to an allocator so that it can be analyzed after a
  552. // crash.
  553. static void DumpAllFieldTrialsToPersistentAllocator(
  554. PersistentMemoryAllocator* allocator);
  555. // Retrieves field trial state from an allocator so that it can be analyzed
  556. // after a crash. The pointers in the returned vector are into the persistent
  557. // memory segment and so are only valid as long as the allocator is valid.
  558. static std::vector<const FieldTrial::FieldTrialEntry*>
  559. GetAllFieldTrialsFromPersistentAllocator(
  560. PersistentMemoryAllocator const& allocator);
  561. // Returns a pointer to the global instance. This is exposed so that it can
  562. // be used in a DCHECK in FeatureList and ScopedFeatureList test-only logic
  563. // and is not intended to be used widely beyond those cases.
  564. static FieldTrialList* GetInstance();
  565. // For testing, sets the global instance to null and returns the previous one.
  566. static FieldTrialList* BackupInstanceForTesting();
  567. // For testing, sets the global instance to |instance|.
  568. static void RestoreInstanceForTesting(FieldTrialList* instance);
  569. private:
  570. // Allow tests to access our innards for testing purposes.
  571. FRIEND_TEST_ALL_PREFIXES(FieldTrialListTest, InstantiateAllocator);
  572. FRIEND_TEST_ALL_PREFIXES(FieldTrialListTest, AddTrialsToAllocator);
  573. FRIEND_TEST_ALL_PREFIXES(FieldTrialListTest,
  574. DoNotAddSimulatedFieldTrialsToAllocator);
  575. FRIEND_TEST_ALL_PREFIXES(FieldTrialListTest, AssociateFieldTrialParams);
  576. FRIEND_TEST_ALL_PREFIXES(FieldTrialListTest, ClearParamsFromSharedMemory);
  577. FRIEND_TEST_ALL_PREFIXES(FieldTrialListTest,
  578. SerializeSharedMemoryRegionMetadata);
  579. friend int SerializeSharedMemoryRegionMetadata(void);
  580. FRIEND_TEST_ALL_PREFIXES(FieldTrialListTest, CheckReadOnlySharedMemoryRegion);
  581. // Serialization is used to pass information about the handle to child
  582. // processes. It passes a reference to the relevant OS resource, and it passes
  583. // a GUID. Serialization and deserialization doesn't actually transport the
  584. // underlying OS resource - that must be done by the Process launcher.
  585. static std::string SerializeSharedMemoryRegionMetadata(
  586. const ReadOnlySharedMemoryRegion& shm);
  587. #if defined(OS_WIN) || defined(OS_FUCHSIA) || \
  588. (defined(OS_MACOSX) && !defined(OS_IOS))
  589. static ReadOnlySharedMemoryRegion DeserializeSharedMemoryRegionMetadata(
  590. const std::string& switch_value);
  591. #elif defined(OS_POSIX) && !defined(OS_NACL)
  592. static ReadOnlySharedMemoryRegion DeserializeSharedMemoryRegionMetadata(
  593. int fd,
  594. const std::string& switch_value);
  595. #endif
  596. #if defined(OS_WIN) || defined(OS_FUCHSIA) || \
  597. (defined(OS_MACOSX) && !defined(OS_IOS))
  598. // Takes in |handle_switch| from the command line which represents the shared
  599. // memory handle for field trials, parses it, and creates the field trials.
  600. // Returns true on success, false on failure.
  601. // |switch_value| also contains the serialized GUID.
  602. static bool CreateTrialsFromSwitchValue(const std::string& switch_value);
  603. #elif defined(OS_POSIX) && !defined(OS_NACL)
  604. // On POSIX systems that use the zygote, we look up the correct fd that backs
  605. // the shared memory segment containing the field trials by looking it up via
  606. // an fd key in GlobalDescriptors. Returns true on success, false on failure.
  607. // |switch_value| also contains the serialized GUID.
  608. static bool CreateTrialsFromDescriptor(int fd_key,
  609. const std::string& switch_value);
  610. #endif
  611. // Takes an unmapped ReadOnlySharedMemoryRegion, maps it with the correct size
  612. // and creates field trials via CreateTrialsFromSharedMemoryMapping(). Returns
  613. // true if successful and false otherwise.
  614. static bool CreateTrialsFromSharedMemoryRegion(
  615. const ReadOnlySharedMemoryRegion& shm_region);
  616. // Expects a mapped piece of shared memory |shm_mapping| that was created from
  617. // the browser process's field_trial_allocator and shared via the command
  618. // line. This function recreates the allocator, iterates through all the field
  619. // trials in it, and creates them via CreateFieldTrial(). Returns true if
  620. // successful and false otherwise.
  621. static bool CreateTrialsFromSharedMemoryMapping(
  622. ReadOnlySharedMemoryMapping shm_mapping);
  623. // Instantiate the field trial allocator, add all existing field trials to it,
  624. // and duplicates its handle to a read-only handle, which gets stored in
  625. // |readonly_allocator_handle|.
  626. static void InstantiateFieldTrialAllocatorIfNeeded();
  627. // Adds the field trial to the allocator. Caller must hold a lock before
  628. // calling this.
  629. static void AddToAllocatorWhileLocked(PersistentMemoryAllocator* allocator,
  630. FieldTrial* field_trial);
  631. // Activate the corresponding field trial entry struct in shared memory.
  632. static void ActivateFieldTrialEntryWhileLocked(FieldTrial* field_trial);
  633. // A map from FieldTrial names to the actual instances.
  634. typedef std::map<std::string, FieldTrial*> RegistrationMap;
  635. // If one-time randomization is enabled, returns a weak pointer to the
  636. // corresponding EntropyProvider. Otherwise, returns NULL.
  637. static const FieldTrial::EntropyProvider*
  638. GetEntropyProviderForOneTimeRandomization();
  639. // Helper function should be called only while holding lock_.
  640. FieldTrial* PreLockedFind(const std::string& name);
  641. // Register() stores a pointer to the given trial in a global map.
  642. // This method also AddRef's the indicated trial.
  643. // This should always be called after creating a new FieldTrial instance.
  644. static void Register(FieldTrial* trial);
  645. // Returns all the registered trials.
  646. static RegistrationMap GetRegisteredTrials();
  647. static FieldTrialList* global_; // The singleton of this class.
  648. // This will tell us if there is an attempt to register a field
  649. // trial or check if one-time randomization is enabled without
  650. // creating the FieldTrialList. This is not an error, unless a
  651. // FieldTrialList is created after that.
  652. static bool used_without_global_;
  653. // Lock for access to registered_ and field_trial_allocator_.
  654. Lock lock_;
  655. RegistrationMap registered_;
  656. std::map<std::string, std::string> seen_states_;
  657. // Entropy provider to be used for one-time randomized field trials. If NULL,
  658. // one-time randomization is not supported.
  659. std::unique_ptr<const FieldTrial::EntropyProvider> entropy_provider_;
  660. // List of observers to be notified when a group is selected for a FieldTrial.
  661. scoped_refptr<ObserverListThreadSafe<Observer> > observer_list_;
  662. // Single synchronous observer to be notified when a trial group is chosen.
  663. Observer* synchronous_observer_ = nullptr;
  664. // Allocator in shared memory containing field trial data. Used in both
  665. // browser and child processes, but readonly in the child.
  666. // In the future, we may want to move this to a more generic place if we want
  667. // to start passing more data other than field trials.
  668. std::unique_ptr<FieldTrialAllocator> field_trial_allocator_ = nullptr;
  669. // Readonly copy of the region to the allocator. Needs to be a member variable
  670. // because it's needed from both CopyFieldTrialStateToFlags() and
  671. // AppendFieldTrialHandleIfNeeded().
  672. ReadOnlySharedMemoryRegion readonly_allocator_region_;
  673. // Tracks whether CreateTrialsFromCommandLine() has been called.
  674. bool create_trials_from_command_line_called_ = false;
  675. DISALLOW_COPY_AND_ASSIGN(FieldTrialList);
  676. };
  677. } // namespace base
  678. #endif // BASE_METRICS_FIELD_TRIAL_H_