1b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat// Copyright (c) 2012 The Chromium Authors. All rights reserved.
2b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat// Use of this source code is governed by a BSD-style license that can be
3b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat// found in the LICENSE file.
4b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat
5b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat// FieldTrial is a class for handling details of statistical experiments
6b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat// performed by actual users in the field (i.e., in a shipped or beta product).
7b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat// All code is called exclusively on the UI thread currently.
8b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat//
9b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat// The simplest example is an experiment to see whether one of two options
10b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat// produces "better" results across our user population.  In that scenario, UMA
11b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat// data is uploaded to aggregate the test results, and this FieldTrial class
12b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat// manages the state of each such experiment (state == which option was
13b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat// pseudo-randomly selected).
14b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat//
15b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat// States are typically generated randomly, either based on a one time
16b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat// randomization (which will yield the same results, in terms of selecting
17b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat// the client for a field trial or not, for every run of the program on a
18b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat// given machine), or by a session randomization (generated each time the
19b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat// application starts up, but held constant during the duration of the
20b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat// process).
21b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat
22b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat//------------------------------------------------------------------------------
23b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat// Example:  Suppose we have an experiment involving memory, such as determining
24b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat// the impact of some pruning algorithm.
25b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat// We assume that we already have a histogram of memory usage, such as:
26b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat
27b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat//   UMA_HISTOGRAM_COUNTS("Memory.RendererTotal", count);
28b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat
29b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat// Somewhere in main thread initialization code, we'd probably define an
30b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat// instance of a FieldTrial, with code such as:
31b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat
32b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat// // FieldTrials are reference counted, and persist automagically until
33b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat// // process teardown, courtesy of their automatic registration in
34b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat// // FieldTrialList.
35b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat// // Note: This field trial will run in Chrome instances compiled through
36b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat// //       8 July, 2015, and after that all instances will be in "StandardMem".
37b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat// scoped_refptr<base::FieldTrial> trial(
38b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat//     base::FieldTrialList::FactoryGetFieldTrial(
39b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat//         "MemoryExperiment", 1000, "StandardMem", 2015, 7, 8,
40b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat//         base::FieldTrial::ONE_TIME_RANDOMIZED, NULL));
41b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat//
42b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat// const int high_mem_group =
43b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat//     trial->AppendGroup("HighMem", 20);  // 2% in HighMem group.
44b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat// const int low_mem_group =
45b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat//     trial->AppendGroup("LowMem", 20);   // 2% in LowMem group.
46b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat// // Take action depending of which group we randomly land in.
47b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat// if (trial->group() == high_mem_group)
48b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat//   SetPruningAlgorithm(kType1);  // Sample setting of browser state.
49b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat// else if (trial->group() == low_mem_group)
50b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat//   SetPruningAlgorithm(kType2);  // Sample alternate setting.
51b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat
52b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat//------------------------------------------------------------------------------
53b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat
54b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat#ifndef BASE_METRICS_FIELD_TRIAL_H_
55b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat#define BASE_METRICS_FIELD_TRIAL_H_
56b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat
570d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko#include <stddef.h>
580d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko#include <stdint.h>
590d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko
60b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat#include <map>
61b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat#include <set>
62b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat#include <string>
63b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat#include <vector>
64b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat
65b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat#include "base/base_export.h"
66b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat#include "base/gtest_prod_util.h"
670d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko#include "base/macros.h"
68b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat#include "base/memory/ref_counted.h"
69b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat#include "base/observer_list_threadsafe.h"
700d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko#include "base/strings/string_piece.h"
71b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat#include "base/synchronization/lock.h"
72b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat#include "base/time/time.h"
73b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat
74b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Eratnamespace base {
75b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat
76b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Eratclass FieldTrialList;
77b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat
78b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Eratclass BASE_EXPORT FieldTrial : public RefCounted<FieldTrial> {
79b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat public:
80b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  typedef int Probability;  // Probability type for being selected in a trial.
81b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat
82b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  // Specifies the persistence of the field trial group choice.
83b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  enum RandomizationType {
84b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat    // One time randomized trials will persist the group choice between
85b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat    // restarts, which is recommended for most trials, especially those that
86b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat    // change user visible behavior.
87b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat    ONE_TIME_RANDOMIZED,
88b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat    // Session randomized trials will roll the dice to select a group on every
89b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat    // process restart.
90b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat    SESSION_RANDOMIZED,
91b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  };
92b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat
93b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  // EntropyProvider is an interface for providing entropy for one-time
94b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  // randomized (persistent) field trials.
95b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  class BASE_EXPORT EntropyProvider {
96b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat   public:
97b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat    virtual ~EntropyProvider();
98b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat
99b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat    // Returns a double in the range of [0, 1) to be used for the dice roll for
100b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat    // the specified field trial. If |randomization_seed| is not 0, it will be
101b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat    // used in preference to |trial_name| for generating the entropy by entropy
102b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat    // providers that support it. A given instance should always return the same
103b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat    // value given the same input |trial_name| and |randomization_seed| values.
104b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat    virtual double GetEntropyForTrial(const std::string& trial_name,
1050d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko                                      uint32_t randomization_seed) const = 0;
106b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  };
107b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat
108b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  // A pair representing a Field Trial and its selected group.
109b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  struct ActiveGroup {
110b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat    std::string trial_name;
111b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat    std::string group_name;
112b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  };
113b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat
114b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  // A triplet representing a FieldTrial, its selected group and whether it's
115b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  // active.
1160d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko  struct BASE_EXPORT State {
1170d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko    StringPiece trial_name;
1180d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko    StringPiece group_name;
119b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat    bool activated;
1200d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko
1210d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko    State();
12245779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko    State(const State& other);
1230d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko    ~State();
124b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  };
125b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat
126b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  typedef std::vector<ActiveGroup> ActiveGroups;
127b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat
128b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  // A return value to indicate that a given instance has not yet had a group
129b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  // assignment (and hence is not yet participating in the trial).
130b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  static const int kNotFinalized;
131b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat
132b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  // Disables this trial, meaning it always determines the default group
133b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  // has been selected. May be called immediately after construction, or
134b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  // at any time after initialization (should not be interleaved with
135b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  // AppendGroup calls). Once disabled, there is no way to re-enable a
136b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  // trial.
137b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  // TODO(mad): http://code.google.com/p/chromium/issues/detail?id=121446
138b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  // This doesn't properly reset to Default when a group was forced.
139b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  void Disable();
140b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat
141b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  // Establish the name and probability of the next group in this trial.
142b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  // Sometimes, based on construction randomization, this call may cause the
143b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  // provided group to be *THE* group selected for use in this instance.
144b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  // The return value is the group number of the new group.
145b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  int AppendGroup(const std::string& name, Probability group_probability);
146b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat
147b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  // Return the name of the FieldTrial (excluding the group name).
148b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  const std::string& trial_name() const { return trial_name_; }
149b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat
150b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  // Return the randomly selected group number that was assigned, and notify
151b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  // any/all observers that this finalized group number has presumably been used
152b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  // (queried), and will never change. Note that this will force an instance to
153b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  // participate, and make it illegal to attempt to probabilistically add any
154b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  // other groups to the trial.
155b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  int group();
156b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat
157b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  // If the group's name is empty, a string version containing the group number
158b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  // is used as the group name. This causes a winner to be chosen if none was.
159b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  const std::string& group_name();
160b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat
1610d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko  // Finalizes the group choice and returns the chosen group, but does not mark
1620d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko  // the trial as active - so its state will not be reported until group_name()
1630d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko  // or similar is called.
1640d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko  const std::string& GetGroupNameWithoutActivation();
1650d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko
166b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  // Set the field trial as forced, meaning that it was setup earlier than
167b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  // the hard coded registration of the field trial to override it.
168b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  // This allows the code that was hard coded to register the field trial to
169b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  // still succeed even though the field trial has already been registered.
170b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  // This must be called after appending all the groups, since we will make
171b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  // the group choice here. Note that this is a NOOP for already forced trials.
172b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  // And, as the rest of the FieldTrial code, this is not thread safe and must
173b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  // be done from the UI thread.
174b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  void SetForced();
175b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat
176b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  // Enable benchmarking sets field trials to a common setting.
177b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  static void EnableBenchmarking();
178b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat
179b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  // Creates a FieldTrial object with the specified parameters, to be used for
180b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  // simulation of group assignment without actually affecting global field
181b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  // trial state in the running process. Group assignment will be done based on
182b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  // |entropy_value|, which must have a range of [0, 1).
183b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  //
184b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  // Note: Using this function will not register the field trial globally in the
185b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  // running process - for that, use FieldTrialList::FactoryGetFieldTrial().
186b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  //
187b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  // The ownership of the returned FieldTrial is transfered to the caller which
188b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  // is responsible for deref'ing it (e.g. by using scoped_refptr<FieldTrial>).
189b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  static FieldTrial* CreateSimulatedFieldTrial(
190b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat      const std::string& trial_name,
191b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat      Probability total_probability,
192b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat      const std::string& default_group_name,
193b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat      double entropy_value);
194b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat
195b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat private:
196b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  // Allow tests to access our innards for testing purposes.
197b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  FRIEND_TEST_ALL_PREFIXES(FieldTrialTest, Registration);
198b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  FRIEND_TEST_ALL_PREFIXES(FieldTrialTest, AbsoluteProbabilities);
199b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  FRIEND_TEST_ALL_PREFIXES(FieldTrialTest, RemainingProbability);
200b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  FRIEND_TEST_ALL_PREFIXES(FieldTrialTest, FiftyFiftyProbability);
201b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  FRIEND_TEST_ALL_PREFIXES(FieldTrialTest, MiddleProbabilities);
202b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  FRIEND_TEST_ALL_PREFIXES(FieldTrialTest, OneWinner);
203b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  FRIEND_TEST_ALL_PREFIXES(FieldTrialTest, DisableProbability);
204b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  FRIEND_TEST_ALL_PREFIXES(FieldTrialTest, ActiveGroups);
205b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  FRIEND_TEST_ALL_PREFIXES(FieldTrialTest, AllGroups);
206b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  FRIEND_TEST_ALL_PREFIXES(FieldTrialTest, ActiveGroupsNotFinalized);
207b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  FRIEND_TEST_ALL_PREFIXES(FieldTrialTest, Save);
208b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  FRIEND_TEST_ALL_PREFIXES(FieldTrialTest, SaveAll);
209b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  FRIEND_TEST_ALL_PREFIXES(FieldTrialTest, DuplicateRestore);
210b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  FRIEND_TEST_ALL_PREFIXES(FieldTrialTest, SetForcedTurnFeatureOff);
211b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  FRIEND_TEST_ALL_PREFIXES(FieldTrialTest, SetForcedTurnFeatureOn);
212b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  FRIEND_TEST_ALL_PREFIXES(FieldTrialTest, SetForcedChangeDefault_Default);
213b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  FRIEND_TEST_ALL_PREFIXES(FieldTrialTest, SetForcedChangeDefault_NonDefault);
214b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  FRIEND_TEST_ALL_PREFIXES(FieldTrialTest, FloatBoundariesGiveEqualGroupSizes);
215b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  FRIEND_TEST_ALL_PREFIXES(FieldTrialTest, DoesNotSurpassTotalProbability);
216b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat
217b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  friend class base::FieldTrialList;
218b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat
219b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  friend class RefCounted<FieldTrial>;
220b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat
221b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  // This is the group number of the 'default' group when a choice wasn't forced
222b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  // by a call to FieldTrialList::CreateFieldTrial. It is kept private so that
223b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  // consumers don't use it by mistake in cases where the group was forced.
224b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  static const int kDefaultGroupNumber;
225b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat
226b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  // Creates a field trial with the specified parameters. Group assignment will
227b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  // be done based on |entropy_value|, which must have a range of [0, 1).
228b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  FieldTrial(const std::string& trial_name,
229b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat             Probability total_probability,
230b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat             const std::string& default_group_name,
231b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat             double entropy_value);
232b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  virtual ~FieldTrial();
233b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat
234b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  // Return the default group name of the FieldTrial.
235b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  std::string default_group_name() const { return default_group_name_; }
236b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat
237b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  // Marks this trial as having been registered with the FieldTrialList. Must be
238b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  // called no more than once and before any |group()| calls have occurred.
239b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  void SetTrialRegistered();
240b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat
241b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  // Sets the chosen group name and number.
242b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  void SetGroupChoice(const std::string& group_name, int number);
243b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat
244b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  // Ensures that a group is chosen, if it hasn't yet been. The field trial
245b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  // might yet be disabled, so this call will *not* notify observers of the
246b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  // status.
247b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  void FinalizeGroupChoice();
248b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat
249b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  // Returns the trial name and selected group name for this field trial via
250b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  // the output parameter |active_group|, but only if the group has already
251b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  // been chosen and has been externally observed via |group()| and the trial
252b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  // has not been disabled. In that case, true is returned and |active_group|
253b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  // is filled in; otherwise, the result is false and |active_group| is left
254b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  // untouched.
255b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  bool GetActiveGroup(ActiveGroup* active_group) const;
256b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat
257b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  // Returns the trial name and selected group name for this field trial via
258b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  // the output parameter |field_trial_state|, but only if the trial has not
259b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  // been disabled. In that case, true is returned and |field_trial_state| is
260b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  // filled in; otherwise, the result is false and |field_trial_state| is left
261b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  // untouched.
2620d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko  bool GetState(State* field_trial_state);
263b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat
264b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  // Returns the group_name. A winner need not have been chosen.
265b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  std::string group_name_internal() const { return group_name_; }
266b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat
267b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  // The name of the field trial, as can be found via the FieldTrialList.
268b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  const std::string trial_name_;
269b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat
270b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  // The maximum sum of all probabilities supplied, which corresponds to 100%.
271b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  // This is the scaling factor used to adjust supplied probabilities.
272b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  const Probability divisor_;
273b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat
274b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  // The name of the default group.
275b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  const std::string default_group_name_;
276b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat
277b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  // The randomly selected probability that is used to select a group (or have
278b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  // the instance not participate).  It is the product of divisor_ and a random
279b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  // number between [0, 1).
280b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  Probability random_;
281b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat
282b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  // Sum of the probabilities of all appended groups.
283b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  Probability accumulated_group_probability_;
284b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat
285b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  // The number that will be returned by the next AppendGroup() call.
286b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  int next_group_number_;
287b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat
288b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  // The pseudo-randomly assigned group number.
289b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  // This is kNotFinalized if no group has been assigned.
290b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  int group_;
291b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat
292b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  // A textual name for the randomly selected group. Valid after |group()|
293b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  // has been called.
294b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  std::string group_name_;
295b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat
296b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  // When enable_field_trial_ is false, field trial reverts to the 'default'
297b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  // group.
298b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  bool enable_field_trial_;
299b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat
300b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  // When forced_ is true, we return the chosen group from AppendGroup when
301b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  // appropriate.
302b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  bool forced_;
303b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat
304b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  // Specifies whether the group choice has been reported to observers.
305b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  bool group_reported_;
306b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat
307b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  // Whether this trial is registered with the global FieldTrialList and thus
308b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  // should notify it when its group is queried.
309b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  bool trial_registered_;
310b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat
311b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  // When benchmarking is enabled, field trials all revert to the 'default'
312b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  // group.
313b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  static bool enable_benchmarking_;
314b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat
315b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  DISALLOW_COPY_AND_ASSIGN(FieldTrial);
316b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat};
317b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat
318b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat//------------------------------------------------------------------------------
319b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat// Class with a list of all active field trials.  A trial is active if it has
320b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat// been registered, which includes evaluating its state based on its probaility.
321b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat// Only one instance of this class exists.
322b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Eratclass BASE_EXPORT FieldTrialList {
323b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat public:
324b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  // Year that is guaranteed to not be expired when instantiating a field trial
325b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  // via |FactoryGetFieldTrial()|.  Set to two years from the build date.
326b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  static int kNoExpirationYear;
327b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat
328b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  // Observer is notified when a FieldTrial's group is selected.
329b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  class BASE_EXPORT Observer {
330b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat   public:
331b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat    // Notify observers when FieldTrials's group is selected.
332b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat    virtual void OnFieldTrialGroupFinalized(const std::string& trial_name,
333b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat                                            const std::string& group_name) = 0;
334b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat
335b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat   protected:
336b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat    virtual ~Observer();
337b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  };
338b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat
339b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  // This singleton holds the global list of registered FieldTrials.
340b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  //
341b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  // To support one-time randomized field trials, specify a non-NULL
342b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  // |entropy_provider| which should be a source of uniformly distributed
343b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  // entropy values. Takes ownership of |entropy_provider|. If one time
344b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  // randomization is not desired, pass in NULL for |entropy_provider|.
345b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  explicit FieldTrialList(const FieldTrial::EntropyProvider* entropy_provider);
346b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat
347b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  // Destructor Release()'s references to all registered FieldTrial instances.
348b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  ~FieldTrialList();
349b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat
350b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  // Get a FieldTrial instance from the factory.
351b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  //
352b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  // |name| is used to register the instance with the FieldTrialList class,
353b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  // and can be used to find the trial (only one trial can be present for each
354b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  // name). |default_group_name| is the name of the default group which will
355b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  // be chosen if none of the subsequent appended groups get to be chosen.
356b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  // |default_group_number| can receive the group number of the default group as
357b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  // AppendGroup returns the number of the subsequence groups. |trial_name| and
358b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  // |default_group_name| may not be empty but |default_group_number| can be
359b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  // NULL if the value is not needed.
360b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  //
361b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  // Group probabilities that are later supplied must sum to less than or equal
362b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  // to the |total_probability|. Arguments |year|, |month| and |day_of_month|
363b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  // specify the expiration time. If the build time is after the expiration time
364b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  // then the field trial reverts to the 'default' group.
365b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  //
366b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  // Use this static method to get a startup-randomized FieldTrial or a
367b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  // previously created forced FieldTrial.
368b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  static FieldTrial* FactoryGetFieldTrial(
369b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat      const std::string& trial_name,
370b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat      FieldTrial::Probability total_probability,
371b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat      const std::string& default_group_name,
372b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat      const int year,
373b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat      const int month,
374b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat      const int day_of_month,
375b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat      FieldTrial::RandomizationType randomization_type,
376b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat      int* default_group_number);
377b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat
378b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  // Same as FactoryGetFieldTrial(), but allows specifying a custom seed to be
379b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  // used on one-time randomized field trials (instead of a hash of the trial
380b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  // name, which is used otherwise or if |randomization_seed| has value 0). The
381b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  // |randomization_seed| value (other than 0) should never be the same for two
38294ffa55491333f3dcc701befd0d2652922916d99Luis Hector Chavez  // trials, else this would result in correlated group assignments.  Note:
38394ffa55491333f3dcc701befd0d2652922916d99Luis Hector Chavez  // Using a custom randomization seed is only supported by the
38494ffa55491333f3dcc701befd0d2652922916d99Luis Hector Chavez  // PermutedEntropyProvider (which is used when UMA is not enabled). If
38594ffa55491333f3dcc701befd0d2652922916d99Luis Hector Chavez  // |override_entropy_provider| is not null, then it will be used for
38694ffa55491333f3dcc701befd0d2652922916d99Luis Hector Chavez  // randomization instead of the provider given when the FieldTrialList was
38794ffa55491333f3dcc701befd0d2652922916d99Luis Hector Chavez  // instanciated.
388b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  static FieldTrial* FactoryGetFieldTrialWithRandomizationSeed(
389b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat      const std::string& trial_name,
390b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat      FieldTrial::Probability total_probability,
391b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat      const std::string& default_group_name,
392b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat      const int year,
393b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat      const int month,
394b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat      const int day_of_month,
395b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat      FieldTrial::RandomizationType randomization_type,
3960d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko      uint32_t randomization_seed,
39794ffa55491333f3dcc701befd0d2652922916d99Luis Hector Chavez      int* default_group_number,
39894ffa55491333f3dcc701befd0d2652922916d99Luis Hector Chavez      const FieldTrial::EntropyProvider* override_entropy_provider);
399b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat
4000d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko  // The Find() method can be used to test to see if a named trial was already
401b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  // registered, or to retrieve a pointer to it from the global map.
4020d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko  static FieldTrial* Find(const std::string& trial_name);
403b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat
404b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  // Returns the group number chosen for the named trial, or
405b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  // FieldTrial::kNotFinalized if the trial does not exist.
4060d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko  static int FindValue(const std::string& trial_name);
407b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat
4080d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko  // Returns the group name chosen for the named trial, or the empty string if
4090d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko  // the trial does not exist. The first call of this function on a given field
4100d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko  // trial will mark it as active, so that its state will be reported with usage
4110d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko  // metrics, crashes, etc.
4120d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko  static std::string FindFullName(const std::string& trial_name);
413b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat
414b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  // Returns true if the named trial has been registered.
4150d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko  static bool TrialExists(const std::string& trial_name);
4160d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko
4170d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko  // Returns true if the named trial exists and has been activated.
4180d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko  static bool IsTrialActive(const std::string& trial_name);
419b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat
420b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  // Creates a persistent representation of active FieldTrial instances for
421b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  // resurrection in another process. This allows randomization to be done in
422b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  // one process, and secondary processes can be synchronized on the result.
423b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  // The resulting string contains the name and group name pairs of all
424b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  // registered FieldTrials for which the group has been chosen and externally
425b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  // observed (via |group()|) and which have not been disabled, with "/" used
426b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  // to separate all names and to terminate the string. This string is parsed
427b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  // by |CreateTrialsFromString()|.
428b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  static void StatesToString(std::string* output);
429b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat
430b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  // Creates a persistent representation of all FieldTrial instances for
431b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  // resurrection in another process. This allows randomization to be done in
432b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  // one process, and secondary processes can be synchronized on the result.
433b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  // The resulting string contains the name and group name pairs of all
434b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  // registered FieldTrials which have not been disabled, with "/" used
435b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  // to separate all names and to terminate the string. All activated trials
436b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  // have their name prefixed with "*". This string is parsed by
437b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  // |CreateTrialsFromString()|.
438b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  static void AllStatesToString(std::string* output);
439b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat
440b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  // Fills in the supplied vector |active_groups| (which must be empty when
441b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  // called) with a snapshot of all registered FieldTrials for which the group
442b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  // has been chosen and externally observed (via |group()|) and which have
443b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  // not been disabled.
444b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  static void GetActiveFieldTrialGroups(
445b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat      FieldTrial::ActiveGroups* active_groups);
446b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat
4470d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko  // Returns the field trials that are marked active in |trials_string|.
4480d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko  static void GetActiveFieldTrialGroupsFromString(
4490d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko      const std::string& trials_string,
4500d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko      FieldTrial::ActiveGroups* active_groups);
4510d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko
452b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  // Use a state string (re: StatesToString()) to augment the current list of
453b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  // field trials to include the supplied trials, and using a 100% probability
454b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  // for each trial, force them to have the same group string. This is commonly
455b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  // used in a non-browser process, to carry randomly selected state in a
456b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  // browser process into this non-browser process, but could also be invoked
45745779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko  // through a command line argument to the browser process. Created field
45845779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko  // trials will be marked "used" for the purposes of active trial reporting
45945779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko  // if they are prefixed with |kActivationMarker|. Trial names in
4600d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko  // |ignored_trial_names| are ignored when parsing |trials_string|.
461b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  static bool CreateTrialsFromString(
4620d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko      const std::string& trials_string,
463b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat      const std::set<std::string>& ignored_trial_names);
464b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat
465b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  // Create a FieldTrial with the given |name| and using 100% probability for
466b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  // the FieldTrial, force FieldTrial to have the same group string as
467b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  // |group_name|. This is commonly used in a non-browser process, to carry
468b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  // randomly selected state in a browser process into this non-browser process.
469b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  // It returns NULL if there is a FieldTrial that is already registered with
470b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  // the same |name| but has different finalized group string (|group_name|).
471b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  static FieldTrial* CreateFieldTrial(const std::string& name,
472b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat                                      const std::string& group_name);
473b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat
474b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  // Add an observer to be notified when a field trial is irrevocably committed
475b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  // to being part of some specific field_group (and hence the group_name is
476b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  // also finalized for that field_trial).
477b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  static void AddObserver(Observer* observer);
478b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat
479b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  // Remove an observer.
480b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  static void RemoveObserver(Observer* observer);
481b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat
482b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  // Notify all observers that a group has been finalized for |field_trial|.
483b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  static void NotifyFieldTrialGroupSelection(FieldTrial* field_trial);
484b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat
485b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  // Return the number of active field trials.
486b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  static size_t GetFieldTrialCount();
487b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat
488b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat private:
489b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  // A map from FieldTrial names to the actual instances.
490b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  typedef std::map<std::string, FieldTrial*> RegistrationMap;
491b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat
492b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  // If one-time randomization is enabled, returns a weak pointer to the
493b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  // corresponding EntropyProvider. Otherwise, returns NULL.
494b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  static const FieldTrial::EntropyProvider*
495b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat      GetEntropyProviderForOneTimeRandomization();
496b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat
497b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  // Helper function should be called only while holding lock_.
498b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  FieldTrial* PreLockedFind(const std::string& name);
499b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat
500b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  // Register() stores a pointer to the given trial in a global map.
501b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  // This method also AddRef's the indicated trial.
502b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  // This should always be called after creating a new FieldTrial instance.
503b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  static void Register(FieldTrial* trial);
504b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat
505b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  static FieldTrialList* global_;  // The singleton of this class.
506b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat
507b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  // This will tell us if there is an attempt to register a field
508b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  // trial or check if one-time randomization is enabled without
509b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  // creating the FieldTrialList. This is not an error, unless a
510b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  // FieldTrialList is created after that.
511b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  static bool used_without_global_;
512b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat
513b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  // Lock for access to registered_.
514b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  base::Lock lock_;
515b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  RegistrationMap registered_;
516b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat
51745779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko  std::map<std::string, std::string> seen_states_;
51845779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko
519b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  // Entropy provider to be used for one-time randomized field trials. If NULL,
520b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  // one-time randomization is not supported.
52194ffa55491333f3dcc701befd0d2652922916d99Luis Hector Chavez  std::unique_ptr<const FieldTrial::EntropyProvider> entropy_provider_;
522b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat
523b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  // List of observers to be notified when a group is selected for a FieldTrial.
524b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  scoped_refptr<ObserverListThreadSafe<Observer> > observer_list_;
525b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat
526b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  DISALLOW_COPY_AND_ASSIGN(FieldTrialList);
527b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat};
528b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat
529b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat}  // namespace base
530b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat
531b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat#endif  // BASE_METRICS_FIELD_TRIAL_H_
532