xref: /aosp_15_r20/external/libchrome/base/metrics/field_trial.cc (revision 635a864187cb8b6c713ff48b7e790a6b21769273)
1*635a8641SAndroid Build Coastguard Worker // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2*635a8641SAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be
3*635a8641SAndroid Build Coastguard Worker // found in the LICENSE file.
4*635a8641SAndroid Build Coastguard Worker 
5*635a8641SAndroid Build Coastguard Worker #include "base/metrics/field_trial.h"
6*635a8641SAndroid Build Coastguard Worker 
7*635a8641SAndroid Build Coastguard Worker #include <algorithm>
8*635a8641SAndroid Build Coastguard Worker #include <utility>
9*635a8641SAndroid Build Coastguard Worker 
10*635a8641SAndroid Build Coastguard Worker #include "base/base_switches.h"
11*635a8641SAndroid Build Coastguard Worker #include "base/build_time.h"
12*635a8641SAndroid Build Coastguard Worker #include "base/command_line.h"
13*635a8641SAndroid Build Coastguard Worker #include "base/debug/activity_tracker.h"
14*635a8641SAndroid Build Coastguard Worker #include "base/logging.h"
15*635a8641SAndroid Build Coastguard Worker #include "base/metrics/field_trial_param_associator.h"
16*635a8641SAndroid Build Coastguard Worker #include "base/process/memory.h"
17*635a8641SAndroid Build Coastguard Worker #include "base/process/process_handle.h"
18*635a8641SAndroid Build Coastguard Worker #include "base/process/process_info.h"
19*635a8641SAndroid Build Coastguard Worker #include "base/rand_util.h"
20*635a8641SAndroid Build Coastguard Worker #include "base/strings/string_number_conversions.h"
21*635a8641SAndroid Build Coastguard Worker #include "base/strings/string_split.h"
22*635a8641SAndroid Build Coastguard Worker #include "base/strings/string_util.h"
23*635a8641SAndroid Build Coastguard Worker #include "base/strings/stringprintf.h"
24*635a8641SAndroid Build Coastguard Worker #include "base/strings/utf_string_conversions.h"
25*635a8641SAndroid Build Coastguard Worker #include "base/unguessable_token.h"
26*635a8641SAndroid Build Coastguard Worker 
27*635a8641SAndroid Build Coastguard Worker // On POSIX, the fd is shared using the mapping in GlobalDescriptors.
28*635a8641SAndroid Build Coastguard Worker #if defined(OS_POSIX) && !defined(OS_NACL)
29*635a8641SAndroid Build Coastguard Worker #include "base/posix/global_descriptors.h"
30*635a8641SAndroid Build Coastguard Worker #endif
31*635a8641SAndroid Build Coastguard Worker 
32*635a8641SAndroid Build Coastguard Worker namespace base {
33*635a8641SAndroid Build Coastguard Worker 
34*635a8641SAndroid Build Coastguard Worker namespace {
35*635a8641SAndroid Build Coastguard Worker 
36*635a8641SAndroid Build Coastguard Worker // Define a separator character to use when creating a persistent form of an
37*635a8641SAndroid Build Coastguard Worker // instance.  This is intended for use as a command line argument, passed to a
38*635a8641SAndroid Build Coastguard Worker // second process to mimic our state (i.e., provide the same group name).
39*635a8641SAndroid Build Coastguard Worker const char kPersistentStringSeparator = '/';  // Currently a slash.
40*635a8641SAndroid Build Coastguard Worker 
41*635a8641SAndroid Build Coastguard Worker // Define a marker character to be used as a prefix to a trial name on the
42*635a8641SAndroid Build Coastguard Worker // command line which forces its activation.
43*635a8641SAndroid Build Coastguard Worker const char kActivationMarker = '*';
44*635a8641SAndroid Build Coastguard Worker 
45*635a8641SAndroid Build Coastguard Worker // Use shared memory to communicate field trial (experiment) state. Set to false
46*635a8641SAndroid Build Coastguard Worker // for now while the implementation is fleshed out (e.g. data format, single
47*635a8641SAndroid Build Coastguard Worker // shared memory segment). See https://codereview.chromium.org/2365273004/ and
48*635a8641SAndroid Build Coastguard Worker // crbug.com/653874
49*635a8641SAndroid Build Coastguard Worker // The browser is the only process that has write access to the shared memory.
50*635a8641SAndroid Build Coastguard Worker // This is safe from race conditions because MakeIterable is a release operation
51*635a8641SAndroid Build Coastguard Worker // and GetNextOfType is an acquire operation, so memory writes before
52*635a8641SAndroid Build Coastguard Worker // MakeIterable happen before memory reads after GetNextOfType.
53*635a8641SAndroid Build Coastguard Worker #if defined(OS_FUCHSIA)  // TODO(752368): Not yet supported on Fuchsia.
54*635a8641SAndroid Build Coastguard Worker const bool kUseSharedMemoryForFieldTrials = false;
55*635a8641SAndroid Build Coastguard Worker #else
56*635a8641SAndroid Build Coastguard Worker const bool kUseSharedMemoryForFieldTrials = true;
57*635a8641SAndroid Build Coastguard Worker #endif
58*635a8641SAndroid Build Coastguard Worker 
59*635a8641SAndroid Build Coastguard Worker // Constants for the field trial allocator.
60*635a8641SAndroid Build Coastguard Worker const char kAllocatorName[] = "FieldTrialAllocator";
61*635a8641SAndroid Build Coastguard Worker 
62*635a8641SAndroid Build Coastguard Worker // We allocate 128 KiB to hold all the field trial data. This should be enough,
63*635a8641SAndroid Build Coastguard Worker // as most people use 3 - 25 KiB for field trials (as of 11/25/2016).
64*635a8641SAndroid Build Coastguard Worker // This also doesn't allocate all 128 KiB at once -- the pages only get mapped
65*635a8641SAndroid Build Coastguard Worker // to physical memory when they are touched. If the size of the allocated field
66*635a8641SAndroid Build Coastguard Worker // trials does get larger than 128 KiB, then we will drop some field trials in
67*635a8641SAndroid Build Coastguard Worker // child processes, leading to an inconsistent view between browser and child
68*635a8641SAndroid Build Coastguard Worker // processes and possibly causing crashes (see crbug.com/661617).
69*635a8641SAndroid Build Coastguard Worker const size_t kFieldTrialAllocationSize = 128 << 10;  // 128 KiB
70*635a8641SAndroid Build Coastguard Worker 
71*635a8641SAndroid Build Coastguard Worker // Writes out string1 and then string2 to pickle.
WriteStringPair(Pickle * pickle,const StringPiece & string1,const StringPiece & string2)72*635a8641SAndroid Build Coastguard Worker void WriteStringPair(Pickle* pickle,
73*635a8641SAndroid Build Coastguard Worker                      const StringPiece& string1,
74*635a8641SAndroid Build Coastguard Worker                      const StringPiece& string2) {
75*635a8641SAndroid Build Coastguard Worker   pickle->WriteString(string1);
76*635a8641SAndroid Build Coastguard Worker   pickle->WriteString(string2);
77*635a8641SAndroid Build Coastguard Worker }
78*635a8641SAndroid Build Coastguard Worker 
79*635a8641SAndroid Build Coastguard Worker // Writes out the field trial's contents (via trial_state) to the pickle. The
80*635a8641SAndroid Build Coastguard Worker // format of the pickle looks like:
81*635a8641SAndroid Build Coastguard Worker // TrialName, GroupName, ParamKey1, ParamValue1, ParamKey2, ParamValue2, ...
82*635a8641SAndroid Build Coastguard Worker // If there are no parameters, then it just ends at GroupName.
PickleFieldTrial(const FieldTrial::State & trial_state,Pickle * pickle)83*635a8641SAndroid Build Coastguard Worker void PickleFieldTrial(const FieldTrial::State& trial_state, Pickle* pickle) {
84*635a8641SAndroid Build Coastguard Worker   WriteStringPair(pickle, *trial_state.trial_name, *trial_state.group_name);
85*635a8641SAndroid Build Coastguard Worker 
86*635a8641SAndroid Build Coastguard Worker   // Get field trial params.
87*635a8641SAndroid Build Coastguard Worker   std::map<std::string, std::string> params;
88*635a8641SAndroid Build Coastguard Worker   FieldTrialParamAssociator::GetInstance()->GetFieldTrialParamsWithoutFallback(
89*635a8641SAndroid Build Coastguard Worker       *trial_state.trial_name, *trial_state.group_name, &params);
90*635a8641SAndroid Build Coastguard Worker 
91*635a8641SAndroid Build Coastguard Worker   // Write params to pickle.
92*635a8641SAndroid Build Coastguard Worker   for (const auto& param : params)
93*635a8641SAndroid Build Coastguard Worker     WriteStringPair(pickle, param.first, param.second);
94*635a8641SAndroid Build Coastguard Worker }
95*635a8641SAndroid Build Coastguard Worker 
96*635a8641SAndroid Build Coastguard Worker // Created a time value based on |year|, |month| and |day_of_month| parameters.
CreateTimeFromParams(int year,int month,int day_of_month)97*635a8641SAndroid Build Coastguard Worker Time CreateTimeFromParams(int year, int month, int day_of_month) {
98*635a8641SAndroid Build Coastguard Worker   DCHECK_GT(year, 1970);
99*635a8641SAndroid Build Coastguard Worker   DCHECK_GT(month, 0);
100*635a8641SAndroid Build Coastguard Worker   DCHECK_LT(month, 13);
101*635a8641SAndroid Build Coastguard Worker   DCHECK_GT(day_of_month, 0);
102*635a8641SAndroid Build Coastguard Worker   DCHECK_LT(day_of_month, 32);
103*635a8641SAndroid Build Coastguard Worker 
104*635a8641SAndroid Build Coastguard Worker   Time::Exploded exploded;
105*635a8641SAndroid Build Coastguard Worker   exploded.year = year;
106*635a8641SAndroid Build Coastguard Worker   exploded.month = month;
107*635a8641SAndroid Build Coastguard Worker   exploded.day_of_week = 0;  // Should be unused.
108*635a8641SAndroid Build Coastguard Worker   exploded.day_of_month = day_of_month;
109*635a8641SAndroid Build Coastguard Worker   exploded.hour = 0;
110*635a8641SAndroid Build Coastguard Worker   exploded.minute = 0;
111*635a8641SAndroid Build Coastguard Worker   exploded.second = 0;
112*635a8641SAndroid Build Coastguard Worker   exploded.millisecond = 0;
113*635a8641SAndroid Build Coastguard Worker   Time out_time;
114*635a8641SAndroid Build Coastguard Worker   if (!Time::FromLocalExploded(exploded, &out_time)) {
115*635a8641SAndroid Build Coastguard Worker     // TODO(maksims): implement failure handling.
116*635a8641SAndroid Build Coastguard Worker     // We might just return |out_time|, which is Time(0).
117*635a8641SAndroid Build Coastguard Worker     NOTIMPLEMENTED();
118*635a8641SAndroid Build Coastguard Worker   }
119*635a8641SAndroid Build Coastguard Worker 
120*635a8641SAndroid Build Coastguard Worker   return out_time;
121*635a8641SAndroid Build Coastguard Worker }
122*635a8641SAndroid Build Coastguard Worker 
123*635a8641SAndroid Build Coastguard Worker // Returns the boundary value for comparing against the FieldTrial's added
124*635a8641SAndroid Build Coastguard Worker // groups for a given |divisor| (total probability) and |entropy_value|.
GetGroupBoundaryValue(FieldTrial::Probability divisor,double entropy_value)125*635a8641SAndroid Build Coastguard Worker FieldTrial::Probability GetGroupBoundaryValue(
126*635a8641SAndroid Build Coastguard Worker     FieldTrial::Probability divisor,
127*635a8641SAndroid Build Coastguard Worker     double entropy_value) {
128*635a8641SAndroid Build Coastguard Worker   // Add a tiny epsilon value to get consistent results when converting floating
129*635a8641SAndroid Build Coastguard Worker   // points to int. Without it, boundary values have inconsistent results, e.g.:
130*635a8641SAndroid Build Coastguard Worker   //
131*635a8641SAndroid Build Coastguard Worker   //   static_cast<FieldTrial::Probability>(100 * 0.56) == 56
132*635a8641SAndroid Build Coastguard Worker   //   static_cast<FieldTrial::Probability>(100 * 0.57) == 56
133*635a8641SAndroid Build Coastguard Worker   //   static_cast<FieldTrial::Probability>(100 * 0.58) == 57
134*635a8641SAndroid Build Coastguard Worker   //   static_cast<FieldTrial::Probability>(100 * 0.59) == 59
135*635a8641SAndroid Build Coastguard Worker   const double kEpsilon = 1e-8;
136*635a8641SAndroid Build Coastguard Worker   const FieldTrial::Probability result =
137*635a8641SAndroid Build Coastguard Worker       static_cast<FieldTrial::Probability>(divisor * entropy_value + kEpsilon);
138*635a8641SAndroid Build Coastguard Worker   // Ensure that adding the epsilon still results in a value < |divisor|.
139*635a8641SAndroid Build Coastguard Worker   return std::min(result, divisor - 1);
140*635a8641SAndroid Build Coastguard Worker }
141*635a8641SAndroid Build Coastguard Worker 
142*635a8641SAndroid Build Coastguard Worker // Separate type from FieldTrial::State so that it can use StringPieces.
143*635a8641SAndroid Build Coastguard Worker struct FieldTrialStringEntry {
144*635a8641SAndroid Build Coastguard Worker   StringPiece trial_name;
145*635a8641SAndroid Build Coastguard Worker   StringPiece group_name;
146*635a8641SAndroid Build Coastguard Worker   bool activated = false;
147*635a8641SAndroid Build Coastguard Worker };
148*635a8641SAndroid Build Coastguard Worker 
149*635a8641SAndroid Build Coastguard Worker // Parses the --force-fieldtrials string |trials_string| into |entries|.
150*635a8641SAndroid Build Coastguard Worker // Returns true if the string was parsed correctly. On failure, the |entries|
151*635a8641SAndroid Build Coastguard Worker // array may end up being partially filled.
ParseFieldTrialsString(const std::string & trials_string,std::vector<FieldTrialStringEntry> * entries)152*635a8641SAndroid Build Coastguard Worker bool ParseFieldTrialsString(const std::string& trials_string,
153*635a8641SAndroid Build Coastguard Worker                             std::vector<FieldTrialStringEntry>* entries) {
154*635a8641SAndroid Build Coastguard Worker   const StringPiece trials_string_piece(trials_string);
155*635a8641SAndroid Build Coastguard Worker 
156*635a8641SAndroid Build Coastguard Worker   size_t next_item = 0;
157*635a8641SAndroid Build Coastguard Worker   while (next_item < trials_string.length()) {
158*635a8641SAndroid Build Coastguard Worker     size_t name_end = trials_string.find(kPersistentStringSeparator, next_item);
159*635a8641SAndroid Build Coastguard Worker     if (name_end == trials_string.npos || next_item == name_end)
160*635a8641SAndroid Build Coastguard Worker       return false;
161*635a8641SAndroid Build Coastguard Worker     size_t group_name_end =
162*635a8641SAndroid Build Coastguard Worker         trials_string.find(kPersistentStringSeparator, name_end + 1);
163*635a8641SAndroid Build Coastguard Worker     if (name_end + 1 == group_name_end)
164*635a8641SAndroid Build Coastguard Worker       return false;
165*635a8641SAndroid Build Coastguard Worker     if (group_name_end == trials_string.npos)
166*635a8641SAndroid Build Coastguard Worker       group_name_end = trials_string.length();
167*635a8641SAndroid Build Coastguard Worker 
168*635a8641SAndroid Build Coastguard Worker     FieldTrialStringEntry entry;
169*635a8641SAndroid Build Coastguard Worker     // Verify if the trial should be activated or not.
170*635a8641SAndroid Build Coastguard Worker     if (trials_string[next_item] == kActivationMarker) {
171*635a8641SAndroid Build Coastguard Worker       // Name cannot be only the indicator.
172*635a8641SAndroid Build Coastguard Worker       if (name_end - next_item == 1)
173*635a8641SAndroid Build Coastguard Worker         return false;
174*635a8641SAndroid Build Coastguard Worker       next_item++;
175*635a8641SAndroid Build Coastguard Worker       entry.activated = true;
176*635a8641SAndroid Build Coastguard Worker     }
177*635a8641SAndroid Build Coastguard Worker     entry.trial_name =
178*635a8641SAndroid Build Coastguard Worker         trials_string_piece.substr(next_item, name_end - next_item);
179*635a8641SAndroid Build Coastguard Worker     entry.group_name =
180*635a8641SAndroid Build Coastguard Worker         trials_string_piece.substr(name_end + 1, group_name_end - name_end - 1);
181*635a8641SAndroid Build Coastguard Worker     next_item = group_name_end + 1;
182*635a8641SAndroid Build Coastguard Worker 
183*635a8641SAndroid Build Coastguard Worker     entries->push_back(std::move(entry));
184*635a8641SAndroid Build Coastguard Worker   }
185*635a8641SAndroid Build Coastguard Worker   return true;
186*635a8641SAndroid Build Coastguard Worker }
187*635a8641SAndroid Build Coastguard Worker 
AddFeatureAndFieldTrialFlags(const char * enable_features_switch,const char * disable_features_switch,CommandLine * cmd_line)188*635a8641SAndroid Build Coastguard Worker void AddFeatureAndFieldTrialFlags(const char* enable_features_switch,
189*635a8641SAndroid Build Coastguard Worker                                   const char* disable_features_switch,
190*635a8641SAndroid Build Coastguard Worker                                   CommandLine* cmd_line) {
191*635a8641SAndroid Build Coastguard Worker   std::string enabled_features;
192*635a8641SAndroid Build Coastguard Worker   std::string disabled_features;
193*635a8641SAndroid Build Coastguard Worker   FeatureList::GetInstance()->GetFeatureOverrides(&enabled_features,
194*635a8641SAndroid Build Coastguard Worker                                                   &disabled_features);
195*635a8641SAndroid Build Coastguard Worker 
196*635a8641SAndroid Build Coastguard Worker   if (!enabled_features.empty())
197*635a8641SAndroid Build Coastguard Worker     cmd_line->AppendSwitchASCII(enable_features_switch, enabled_features);
198*635a8641SAndroid Build Coastguard Worker   if (!disabled_features.empty())
199*635a8641SAndroid Build Coastguard Worker     cmd_line->AppendSwitchASCII(disable_features_switch, disabled_features);
200*635a8641SAndroid Build Coastguard Worker 
201*635a8641SAndroid Build Coastguard Worker   std::string field_trial_states;
202*635a8641SAndroid Build Coastguard Worker   FieldTrialList::AllStatesToString(&field_trial_states, false);
203*635a8641SAndroid Build Coastguard Worker   if (!field_trial_states.empty()) {
204*635a8641SAndroid Build Coastguard Worker     cmd_line->AppendSwitchASCII(switches::kForceFieldTrials,
205*635a8641SAndroid Build Coastguard Worker                                 field_trial_states);
206*635a8641SAndroid Build Coastguard Worker   }
207*635a8641SAndroid Build Coastguard Worker }
208*635a8641SAndroid Build Coastguard Worker 
OnOutOfMemory(size_t size)209*635a8641SAndroid Build Coastguard Worker void OnOutOfMemory(size_t size) {
210*635a8641SAndroid Build Coastguard Worker #if defined(OS_NACL)
211*635a8641SAndroid Build Coastguard Worker   NOTREACHED();
212*635a8641SAndroid Build Coastguard Worker #else
213*635a8641SAndroid Build Coastguard Worker   TerminateBecauseOutOfMemory(size);
214*635a8641SAndroid Build Coastguard Worker #endif
215*635a8641SAndroid Build Coastguard Worker }
216*635a8641SAndroid Build Coastguard Worker 
217*635a8641SAndroid Build Coastguard Worker #if !defined(OS_NACL)
218*635a8641SAndroid Build Coastguard Worker // Returns whether the operation succeeded.
DeserializeGUIDFromStringPieces(base::StringPiece first,base::StringPiece second,base::UnguessableToken * guid)219*635a8641SAndroid Build Coastguard Worker bool DeserializeGUIDFromStringPieces(base::StringPiece first,
220*635a8641SAndroid Build Coastguard Worker                                      base::StringPiece second,
221*635a8641SAndroid Build Coastguard Worker                                      base::UnguessableToken* guid) {
222*635a8641SAndroid Build Coastguard Worker   uint64_t high = 0;
223*635a8641SAndroid Build Coastguard Worker   uint64_t low = 0;
224*635a8641SAndroid Build Coastguard Worker   if (!base::StringToUint64(first, &high) ||
225*635a8641SAndroid Build Coastguard Worker       !base::StringToUint64(second, &low)) {
226*635a8641SAndroid Build Coastguard Worker     return false;
227*635a8641SAndroid Build Coastguard Worker   }
228*635a8641SAndroid Build Coastguard Worker 
229*635a8641SAndroid Build Coastguard Worker   *guid = base::UnguessableToken::Deserialize(high, low);
230*635a8641SAndroid Build Coastguard Worker   return true;
231*635a8641SAndroid Build Coastguard Worker }
232*635a8641SAndroid Build Coastguard Worker 
233*635a8641SAndroid Build Coastguard Worker // Extract a read-only SharedMemoryHandle from an existing |shared_memory|
234*635a8641SAndroid Build Coastguard Worker // handle. Note that on Android, this also makes the whole region read-only.
GetSharedMemoryReadOnlyHandle(SharedMemory * shared_memory)235*635a8641SAndroid Build Coastguard Worker SharedMemoryHandle GetSharedMemoryReadOnlyHandle(SharedMemory* shared_memory) {
236*635a8641SAndroid Build Coastguard Worker   SharedMemoryHandle result = shared_memory->GetReadOnlyHandle();
237*635a8641SAndroid Build Coastguard Worker #if defined(OS_ANDROID)
238*635a8641SAndroid Build Coastguard Worker   // On Android, turn the region read-only. This prevents any future
239*635a8641SAndroid Build Coastguard Worker   // writable mapping attempts, but the original one in |shm| survives
240*635a8641SAndroid Build Coastguard Worker   // and is still usable in the current process.
241*635a8641SAndroid Build Coastguard Worker   result.SetRegionReadOnly();
242*635a8641SAndroid Build Coastguard Worker #endif  // OS_ANDROID
243*635a8641SAndroid Build Coastguard Worker   return result;
244*635a8641SAndroid Build Coastguard Worker }
245*635a8641SAndroid Build Coastguard Worker #endif  // !OS_NACL
246*635a8641SAndroid Build Coastguard Worker 
247*635a8641SAndroid Build Coastguard Worker }  // namespace
248*635a8641SAndroid Build Coastguard Worker 
249*635a8641SAndroid Build Coastguard Worker // statics
250*635a8641SAndroid Build Coastguard Worker const int FieldTrial::kNotFinalized = -1;
251*635a8641SAndroid Build Coastguard Worker const int FieldTrial::kDefaultGroupNumber = 0;
252*635a8641SAndroid Build Coastguard Worker bool FieldTrial::enable_benchmarking_ = false;
253*635a8641SAndroid Build Coastguard Worker 
254*635a8641SAndroid Build Coastguard Worker int FieldTrialList::kNoExpirationYear = 0;
255*635a8641SAndroid Build Coastguard Worker 
256*635a8641SAndroid Build Coastguard Worker //------------------------------------------------------------------------------
257*635a8641SAndroid Build Coastguard Worker // FieldTrial methods and members.
258*635a8641SAndroid Build Coastguard Worker 
259*635a8641SAndroid Build Coastguard Worker FieldTrial::EntropyProvider::~EntropyProvider() = default;
260*635a8641SAndroid Build Coastguard Worker 
261*635a8641SAndroid Build Coastguard Worker FieldTrial::State::State() = default;
262*635a8641SAndroid Build Coastguard Worker 
263*635a8641SAndroid Build Coastguard Worker FieldTrial::State::State(const State& other) = default;
264*635a8641SAndroid Build Coastguard Worker 
265*635a8641SAndroid Build Coastguard Worker FieldTrial::State::~State() = default;
266*635a8641SAndroid Build Coastguard Worker 
GetTrialAndGroupName(StringPiece * trial_name,StringPiece * group_name) const267*635a8641SAndroid Build Coastguard Worker bool FieldTrial::FieldTrialEntry::GetTrialAndGroupName(
268*635a8641SAndroid Build Coastguard Worker     StringPiece* trial_name,
269*635a8641SAndroid Build Coastguard Worker     StringPiece* group_name) const {
270*635a8641SAndroid Build Coastguard Worker   PickleIterator iter = GetPickleIterator();
271*635a8641SAndroid Build Coastguard Worker   return ReadStringPair(&iter, trial_name, group_name);
272*635a8641SAndroid Build Coastguard Worker }
273*635a8641SAndroid Build Coastguard Worker 
GetParams(std::map<std::string,std::string> * params) const274*635a8641SAndroid Build Coastguard Worker bool FieldTrial::FieldTrialEntry::GetParams(
275*635a8641SAndroid Build Coastguard Worker     std::map<std::string, std::string>* params) const {
276*635a8641SAndroid Build Coastguard Worker   PickleIterator iter = GetPickleIterator();
277*635a8641SAndroid Build Coastguard Worker   StringPiece tmp;
278*635a8641SAndroid Build Coastguard Worker   // Skip reading trial and group name.
279*635a8641SAndroid Build Coastguard Worker   if (!ReadStringPair(&iter, &tmp, &tmp))
280*635a8641SAndroid Build Coastguard Worker     return false;
281*635a8641SAndroid Build Coastguard Worker 
282*635a8641SAndroid Build Coastguard Worker   while (true) {
283*635a8641SAndroid Build Coastguard Worker     StringPiece key;
284*635a8641SAndroid Build Coastguard Worker     StringPiece value;
285*635a8641SAndroid Build Coastguard Worker     if (!ReadStringPair(&iter, &key, &value))
286*635a8641SAndroid Build Coastguard Worker       return key.empty();  // Non-empty is bad: got one of a pair.
287*635a8641SAndroid Build Coastguard Worker     (*params)[key.as_string()] = value.as_string();
288*635a8641SAndroid Build Coastguard Worker   }
289*635a8641SAndroid Build Coastguard Worker }
290*635a8641SAndroid Build Coastguard Worker 
GetPickleIterator() const291*635a8641SAndroid Build Coastguard Worker PickleIterator FieldTrial::FieldTrialEntry::GetPickleIterator() const {
292*635a8641SAndroid Build Coastguard Worker   const char* src =
293*635a8641SAndroid Build Coastguard Worker       reinterpret_cast<const char*>(this) + sizeof(FieldTrialEntry);
294*635a8641SAndroid Build Coastguard Worker 
295*635a8641SAndroid Build Coastguard Worker   Pickle pickle(src, pickle_size);
296*635a8641SAndroid Build Coastguard Worker   return PickleIterator(pickle);
297*635a8641SAndroid Build Coastguard Worker }
298*635a8641SAndroid Build Coastguard Worker 
ReadStringPair(PickleIterator * iter,StringPiece * trial_name,StringPiece * group_name) const299*635a8641SAndroid Build Coastguard Worker bool FieldTrial::FieldTrialEntry::ReadStringPair(
300*635a8641SAndroid Build Coastguard Worker     PickleIterator* iter,
301*635a8641SAndroid Build Coastguard Worker     StringPiece* trial_name,
302*635a8641SAndroid Build Coastguard Worker     StringPiece* group_name) const {
303*635a8641SAndroid Build Coastguard Worker   if (!iter->ReadStringPiece(trial_name))
304*635a8641SAndroid Build Coastguard Worker     return false;
305*635a8641SAndroid Build Coastguard Worker   if (!iter->ReadStringPiece(group_name))
306*635a8641SAndroid Build Coastguard Worker     return false;
307*635a8641SAndroid Build Coastguard Worker   return true;
308*635a8641SAndroid Build Coastguard Worker }
309*635a8641SAndroid Build Coastguard Worker 
Disable()310*635a8641SAndroid Build Coastguard Worker void FieldTrial::Disable() {
311*635a8641SAndroid Build Coastguard Worker   DCHECK(!group_reported_);
312*635a8641SAndroid Build Coastguard Worker   enable_field_trial_ = false;
313*635a8641SAndroid Build Coastguard Worker 
314*635a8641SAndroid Build Coastguard Worker   // In case we are disabled after initialization, we need to switch
315*635a8641SAndroid Build Coastguard Worker   // the trial to the default group.
316*635a8641SAndroid Build Coastguard Worker   if (group_ != kNotFinalized) {
317*635a8641SAndroid Build Coastguard Worker     // Only reset when not already the default group, because in case we were
318*635a8641SAndroid Build Coastguard Worker     // forced to the default group, the group number may not be
319*635a8641SAndroid Build Coastguard Worker     // kDefaultGroupNumber, so we should keep it as is.
320*635a8641SAndroid Build Coastguard Worker     if (group_name_ != default_group_name_)
321*635a8641SAndroid Build Coastguard Worker       SetGroupChoice(default_group_name_, kDefaultGroupNumber);
322*635a8641SAndroid Build Coastguard Worker   }
323*635a8641SAndroid Build Coastguard Worker }
324*635a8641SAndroid Build Coastguard Worker 
AppendGroup(const std::string & name,Probability group_probability)325*635a8641SAndroid Build Coastguard Worker int FieldTrial::AppendGroup(const std::string& name,
326*635a8641SAndroid Build Coastguard Worker                             Probability group_probability) {
327*635a8641SAndroid Build Coastguard Worker   // When the group choice was previously forced, we only need to return the
328*635a8641SAndroid Build Coastguard Worker   // the id of the chosen group, and anything can be returned for the others.
329*635a8641SAndroid Build Coastguard Worker   if (forced_) {
330*635a8641SAndroid Build Coastguard Worker     DCHECK(!group_name_.empty());
331*635a8641SAndroid Build Coastguard Worker     if (name == group_name_) {
332*635a8641SAndroid Build Coastguard Worker       // Note that while |group_| may be equal to |kDefaultGroupNumber| on the
333*635a8641SAndroid Build Coastguard Worker       // forced trial, it will not have the same value as the default group
334*635a8641SAndroid Build Coastguard Worker       // number returned from the non-forced |FactoryGetFieldTrial()| call,
335*635a8641SAndroid Build Coastguard Worker       // which takes care to ensure that this does not happen.
336*635a8641SAndroid Build Coastguard Worker       return group_;
337*635a8641SAndroid Build Coastguard Worker     }
338*635a8641SAndroid Build Coastguard Worker     DCHECK_NE(next_group_number_, group_);
339*635a8641SAndroid Build Coastguard Worker     // We still return different numbers each time, in case some caller need
340*635a8641SAndroid Build Coastguard Worker     // them to be different.
341*635a8641SAndroid Build Coastguard Worker     return next_group_number_++;
342*635a8641SAndroid Build Coastguard Worker   }
343*635a8641SAndroid Build Coastguard Worker 
344*635a8641SAndroid Build Coastguard Worker   DCHECK_LE(group_probability, divisor_);
345*635a8641SAndroid Build Coastguard Worker   DCHECK_GE(group_probability, 0);
346*635a8641SAndroid Build Coastguard Worker 
347*635a8641SAndroid Build Coastguard Worker   if (enable_benchmarking_ || !enable_field_trial_)
348*635a8641SAndroid Build Coastguard Worker     group_probability = 0;
349*635a8641SAndroid Build Coastguard Worker 
350*635a8641SAndroid Build Coastguard Worker   accumulated_group_probability_ += group_probability;
351*635a8641SAndroid Build Coastguard Worker 
352*635a8641SAndroid Build Coastguard Worker   DCHECK_LE(accumulated_group_probability_, divisor_);
353*635a8641SAndroid Build Coastguard Worker   if (group_ == kNotFinalized && accumulated_group_probability_ > random_) {
354*635a8641SAndroid Build Coastguard Worker     // This is the group that crossed the random line, so we do the assignment.
355*635a8641SAndroid Build Coastguard Worker     SetGroupChoice(name, next_group_number_);
356*635a8641SAndroid Build Coastguard Worker   }
357*635a8641SAndroid Build Coastguard Worker   return next_group_number_++;
358*635a8641SAndroid Build Coastguard Worker }
359*635a8641SAndroid Build Coastguard Worker 
group()360*635a8641SAndroid Build Coastguard Worker int FieldTrial::group() {
361*635a8641SAndroid Build Coastguard Worker   FinalizeGroupChoice();
362*635a8641SAndroid Build Coastguard Worker   if (trial_registered_)
363*635a8641SAndroid Build Coastguard Worker     FieldTrialList::NotifyFieldTrialGroupSelection(this);
364*635a8641SAndroid Build Coastguard Worker   return group_;
365*635a8641SAndroid Build Coastguard Worker }
366*635a8641SAndroid Build Coastguard Worker 
group_name()367*635a8641SAndroid Build Coastguard Worker const std::string& FieldTrial::group_name() {
368*635a8641SAndroid Build Coastguard Worker   // Call |group()| to ensure group gets assigned and observers are notified.
369*635a8641SAndroid Build Coastguard Worker   group();
370*635a8641SAndroid Build Coastguard Worker   DCHECK(!group_name_.empty());
371*635a8641SAndroid Build Coastguard Worker   return group_name_;
372*635a8641SAndroid Build Coastguard Worker }
373*635a8641SAndroid Build Coastguard Worker 
GetGroupNameWithoutActivation()374*635a8641SAndroid Build Coastguard Worker const std::string& FieldTrial::GetGroupNameWithoutActivation() {
375*635a8641SAndroid Build Coastguard Worker   FinalizeGroupChoice();
376*635a8641SAndroid Build Coastguard Worker   return group_name_;
377*635a8641SAndroid Build Coastguard Worker }
378*635a8641SAndroid Build Coastguard Worker 
SetForced()379*635a8641SAndroid Build Coastguard Worker void FieldTrial::SetForced() {
380*635a8641SAndroid Build Coastguard Worker   // We might have been forced before (e.g., by CreateFieldTrial) and it's
381*635a8641SAndroid Build Coastguard Worker   // first come first served, e.g., command line switch has precedence.
382*635a8641SAndroid Build Coastguard Worker   if (forced_)
383*635a8641SAndroid Build Coastguard Worker     return;
384*635a8641SAndroid Build Coastguard Worker 
385*635a8641SAndroid Build Coastguard Worker   // And we must finalize the group choice before we mark ourselves as forced.
386*635a8641SAndroid Build Coastguard Worker   FinalizeGroupChoice();
387*635a8641SAndroid Build Coastguard Worker   forced_ = true;
388*635a8641SAndroid Build Coastguard Worker }
389*635a8641SAndroid Build Coastguard Worker 
390*635a8641SAndroid Build Coastguard Worker // static
EnableBenchmarking()391*635a8641SAndroid Build Coastguard Worker void FieldTrial::EnableBenchmarking() {
392*635a8641SAndroid Build Coastguard Worker   DCHECK_EQ(0u, FieldTrialList::GetFieldTrialCount());
393*635a8641SAndroid Build Coastguard Worker   enable_benchmarking_ = true;
394*635a8641SAndroid Build Coastguard Worker }
395*635a8641SAndroid Build Coastguard Worker 
396*635a8641SAndroid Build Coastguard Worker // static
CreateSimulatedFieldTrial(const std::string & trial_name,Probability total_probability,const std::string & default_group_name,double entropy_value)397*635a8641SAndroid Build Coastguard Worker FieldTrial* FieldTrial::CreateSimulatedFieldTrial(
398*635a8641SAndroid Build Coastguard Worker     const std::string& trial_name,
399*635a8641SAndroid Build Coastguard Worker     Probability total_probability,
400*635a8641SAndroid Build Coastguard Worker     const std::string& default_group_name,
401*635a8641SAndroid Build Coastguard Worker     double entropy_value) {
402*635a8641SAndroid Build Coastguard Worker   return new FieldTrial(trial_name, total_probability, default_group_name,
403*635a8641SAndroid Build Coastguard Worker                         entropy_value);
404*635a8641SAndroid Build Coastguard Worker }
405*635a8641SAndroid Build Coastguard Worker 
FieldTrial(const std::string & trial_name,const Probability total_probability,const std::string & default_group_name,double entropy_value)406*635a8641SAndroid Build Coastguard Worker FieldTrial::FieldTrial(const std::string& trial_name,
407*635a8641SAndroid Build Coastguard Worker                        const Probability total_probability,
408*635a8641SAndroid Build Coastguard Worker                        const std::string& default_group_name,
409*635a8641SAndroid Build Coastguard Worker                        double entropy_value)
410*635a8641SAndroid Build Coastguard Worker     : trial_name_(trial_name),
411*635a8641SAndroid Build Coastguard Worker       divisor_(total_probability),
412*635a8641SAndroid Build Coastguard Worker       default_group_name_(default_group_name),
413*635a8641SAndroid Build Coastguard Worker       random_(GetGroupBoundaryValue(total_probability, entropy_value)),
414*635a8641SAndroid Build Coastguard Worker       accumulated_group_probability_(0),
415*635a8641SAndroid Build Coastguard Worker       next_group_number_(kDefaultGroupNumber + 1),
416*635a8641SAndroid Build Coastguard Worker       group_(kNotFinalized),
417*635a8641SAndroid Build Coastguard Worker       enable_field_trial_(true),
418*635a8641SAndroid Build Coastguard Worker       forced_(false),
419*635a8641SAndroid Build Coastguard Worker       group_reported_(false),
420*635a8641SAndroid Build Coastguard Worker       trial_registered_(false),
421*635a8641SAndroid Build Coastguard Worker       ref_(FieldTrialList::FieldTrialAllocator::kReferenceNull) {
422*635a8641SAndroid Build Coastguard Worker   DCHECK_GT(total_probability, 0);
423*635a8641SAndroid Build Coastguard Worker   DCHECK(!trial_name_.empty());
424*635a8641SAndroid Build Coastguard Worker   DCHECK(!default_group_name_.empty())
425*635a8641SAndroid Build Coastguard Worker       << "Trial " << trial_name << " is missing a default group name.";
426*635a8641SAndroid Build Coastguard Worker }
427*635a8641SAndroid Build Coastguard Worker 
428*635a8641SAndroid Build Coastguard Worker FieldTrial::~FieldTrial() = default;
429*635a8641SAndroid Build Coastguard Worker 
SetTrialRegistered()430*635a8641SAndroid Build Coastguard Worker void FieldTrial::SetTrialRegistered() {
431*635a8641SAndroid Build Coastguard Worker   DCHECK_EQ(kNotFinalized, group_);
432*635a8641SAndroid Build Coastguard Worker   DCHECK(!trial_registered_);
433*635a8641SAndroid Build Coastguard Worker   trial_registered_ = true;
434*635a8641SAndroid Build Coastguard Worker }
435*635a8641SAndroid Build Coastguard Worker 
SetGroupChoice(const std::string & group_name,int number)436*635a8641SAndroid Build Coastguard Worker void FieldTrial::SetGroupChoice(const std::string& group_name, int number) {
437*635a8641SAndroid Build Coastguard Worker   group_ = number;
438*635a8641SAndroid Build Coastguard Worker   if (group_name.empty())
439*635a8641SAndroid Build Coastguard Worker     StringAppendF(&group_name_, "%d", group_);
440*635a8641SAndroid Build Coastguard Worker   else
441*635a8641SAndroid Build Coastguard Worker     group_name_ = group_name;
442*635a8641SAndroid Build Coastguard Worker   DVLOG(1) << "Field trial: " << trial_name_ << " Group choice:" << group_name_;
443*635a8641SAndroid Build Coastguard Worker }
444*635a8641SAndroid Build Coastguard Worker 
FinalizeGroupChoice()445*635a8641SAndroid Build Coastguard Worker void FieldTrial::FinalizeGroupChoice() {
446*635a8641SAndroid Build Coastguard Worker   FinalizeGroupChoiceImpl(false);
447*635a8641SAndroid Build Coastguard Worker }
448*635a8641SAndroid Build Coastguard Worker 
FinalizeGroupChoiceImpl(bool is_locked)449*635a8641SAndroid Build Coastguard Worker void FieldTrial::FinalizeGroupChoiceImpl(bool is_locked) {
450*635a8641SAndroid Build Coastguard Worker   if (group_ != kNotFinalized)
451*635a8641SAndroid Build Coastguard Worker     return;
452*635a8641SAndroid Build Coastguard Worker   accumulated_group_probability_ = divisor_;
453*635a8641SAndroid Build Coastguard Worker   // Here it's OK to use |kDefaultGroupNumber| since we can't be forced and not
454*635a8641SAndroid Build Coastguard Worker   // finalized.
455*635a8641SAndroid Build Coastguard Worker   DCHECK(!forced_);
456*635a8641SAndroid Build Coastguard Worker   SetGroupChoice(default_group_name_, kDefaultGroupNumber);
457*635a8641SAndroid Build Coastguard Worker 
458*635a8641SAndroid Build Coastguard Worker   // Add the field trial to shared memory.
459*635a8641SAndroid Build Coastguard Worker   if (kUseSharedMemoryForFieldTrials && trial_registered_)
460*635a8641SAndroid Build Coastguard Worker     FieldTrialList::OnGroupFinalized(is_locked, this);
461*635a8641SAndroid Build Coastguard Worker }
462*635a8641SAndroid Build Coastguard Worker 
GetActiveGroup(ActiveGroup * active_group) const463*635a8641SAndroid Build Coastguard Worker bool FieldTrial::GetActiveGroup(ActiveGroup* active_group) const {
464*635a8641SAndroid Build Coastguard Worker   if (!group_reported_ || !enable_field_trial_)
465*635a8641SAndroid Build Coastguard Worker     return false;
466*635a8641SAndroid Build Coastguard Worker   DCHECK_NE(group_, kNotFinalized);
467*635a8641SAndroid Build Coastguard Worker   active_group->trial_name = trial_name_;
468*635a8641SAndroid Build Coastguard Worker   active_group->group_name = group_name_;
469*635a8641SAndroid Build Coastguard Worker   return true;
470*635a8641SAndroid Build Coastguard Worker }
471*635a8641SAndroid Build Coastguard Worker 
GetStateWhileLocked(State * field_trial_state,bool include_expired)472*635a8641SAndroid Build Coastguard Worker bool FieldTrial::GetStateWhileLocked(State* field_trial_state,
473*635a8641SAndroid Build Coastguard Worker                                      bool include_expired) {
474*635a8641SAndroid Build Coastguard Worker   if (!include_expired && !enable_field_trial_)
475*635a8641SAndroid Build Coastguard Worker     return false;
476*635a8641SAndroid Build Coastguard Worker   FinalizeGroupChoiceImpl(true);
477*635a8641SAndroid Build Coastguard Worker   field_trial_state->trial_name = &trial_name_;
478*635a8641SAndroid Build Coastguard Worker   field_trial_state->group_name = &group_name_;
479*635a8641SAndroid Build Coastguard Worker   field_trial_state->activated = group_reported_;
480*635a8641SAndroid Build Coastguard Worker   return true;
481*635a8641SAndroid Build Coastguard Worker }
482*635a8641SAndroid Build Coastguard Worker 
483*635a8641SAndroid Build Coastguard Worker //------------------------------------------------------------------------------
484*635a8641SAndroid Build Coastguard Worker // FieldTrialList methods and members.
485*635a8641SAndroid Build Coastguard Worker 
486*635a8641SAndroid Build Coastguard Worker // static
487*635a8641SAndroid Build Coastguard Worker FieldTrialList* FieldTrialList::global_ = nullptr;
488*635a8641SAndroid Build Coastguard Worker 
489*635a8641SAndroid Build Coastguard Worker // static
490*635a8641SAndroid Build Coastguard Worker bool FieldTrialList::used_without_global_ = false;
491*635a8641SAndroid Build Coastguard Worker 
492*635a8641SAndroid Build Coastguard Worker FieldTrialList::Observer::~Observer() = default;
493*635a8641SAndroid Build Coastguard Worker 
FieldTrialList(std::unique_ptr<const FieldTrial::EntropyProvider> entropy_provider)494*635a8641SAndroid Build Coastguard Worker FieldTrialList::FieldTrialList(
495*635a8641SAndroid Build Coastguard Worker     std::unique_ptr<const FieldTrial::EntropyProvider> entropy_provider)
496*635a8641SAndroid Build Coastguard Worker     : entropy_provider_(std::move(entropy_provider)),
497*635a8641SAndroid Build Coastguard Worker       observer_list_(new ObserverListThreadSafe<FieldTrialList::Observer>(
498*635a8641SAndroid Build Coastguard Worker           ObserverListPolicy::EXISTING_ONLY)) {
499*635a8641SAndroid Build Coastguard Worker   DCHECK(!global_);
500*635a8641SAndroid Build Coastguard Worker   DCHECK(!used_without_global_);
501*635a8641SAndroid Build Coastguard Worker   global_ = this;
502*635a8641SAndroid Build Coastguard Worker 
503*635a8641SAndroid Build Coastguard Worker   Time two_years_from_build_time = GetBuildTime() + TimeDelta::FromDays(730);
504*635a8641SAndroid Build Coastguard Worker   Time::Exploded exploded;
505*635a8641SAndroid Build Coastguard Worker   two_years_from_build_time.LocalExplode(&exploded);
506*635a8641SAndroid Build Coastguard Worker   kNoExpirationYear = exploded.year;
507*635a8641SAndroid Build Coastguard Worker }
508*635a8641SAndroid Build Coastguard Worker 
~FieldTrialList()509*635a8641SAndroid Build Coastguard Worker FieldTrialList::~FieldTrialList() {
510*635a8641SAndroid Build Coastguard Worker   AutoLock auto_lock(lock_);
511*635a8641SAndroid Build Coastguard Worker   while (!registered_.empty()) {
512*635a8641SAndroid Build Coastguard Worker     RegistrationMap::iterator it = registered_.begin();
513*635a8641SAndroid Build Coastguard Worker     it->second->Release();
514*635a8641SAndroid Build Coastguard Worker     registered_.erase(it->first);
515*635a8641SAndroid Build Coastguard Worker   }
516*635a8641SAndroid Build Coastguard Worker   DCHECK_EQ(this, global_);
517*635a8641SAndroid Build Coastguard Worker   global_ = nullptr;
518*635a8641SAndroid Build Coastguard Worker }
519*635a8641SAndroid Build Coastguard Worker 
520*635a8641SAndroid Build Coastguard Worker // static
FactoryGetFieldTrial(const std::string & trial_name,FieldTrial::Probability total_probability,const std::string & default_group_name,const int year,const int month,const int day_of_month,FieldTrial::RandomizationType randomization_type,int * default_group_number)521*635a8641SAndroid Build Coastguard Worker FieldTrial* FieldTrialList::FactoryGetFieldTrial(
522*635a8641SAndroid Build Coastguard Worker     const std::string& trial_name,
523*635a8641SAndroid Build Coastguard Worker     FieldTrial::Probability total_probability,
524*635a8641SAndroid Build Coastguard Worker     const std::string& default_group_name,
525*635a8641SAndroid Build Coastguard Worker     const int year,
526*635a8641SAndroid Build Coastguard Worker     const int month,
527*635a8641SAndroid Build Coastguard Worker     const int day_of_month,
528*635a8641SAndroid Build Coastguard Worker     FieldTrial::RandomizationType randomization_type,
529*635a8641SAndroid Build Coastguard Worker     int* default_group_number) {
530*635a8641SAndroid Build Coastguard Worker   return FactoryGetFieldTrialWithRandomizationSeed(
531*635a8641SAndroid Build Coastguard Worker       trial_name, total_probability, default_group_name, year, month,
532*635a8641SAndroid Build Coastguard Worker       day_of_month, randomization_type, 0, default_group_number, nullptr);
533*635a8641SAndroid Build Coastguard Worker }
534*635a8641SAndroid Build Coastguard Worker 
535*635a8641SAndroid Build Coastguard Worker // static
FactoryGetFieldTrialWithRandomizationSeed(const std::string & trial_name,FieldTrial::Probability total_probability,const std::string & default_group_name,const int year,const int month,const int day_of_month,FieldTrial::RandomizationType randomization_type,uint32_t randomization_seed,int * default_group_number,const FieldTrial::EntropyProvider * override_entropy_provider)536*635a8641SAndroid Build Coastguard Worker FieldTrial* FieldTrialList::FactoryGetFieldTrialWithRandomizationSeed(
537*635a8641SAndroid Build Coastguard Worker     const std::string& trial_name,
538*635a8641SAndroid Build Coastguard Worker     FieldTrial::Probability total_probability,
539*635a8641SAndroid Build Coastguard Worker     const std::string& default_group_name,
540*635a8641SAndroid Build Coastguard Worker     const int year,
541*635a8641SAndroid Build Coastguard Worker     const int month,
542*635a8641SAndroid Build Coastguard Worker     const int day_of_month,
543*635a8641SAndroid Build Coastguard Worker     FieldTrial::RandomizationType randomization_type,
544*635a8641SAndroid Build Coastguard Worker     uint32_t randomization_seed,
545*635a8641SAndroid Build Coastguard Worker     int* default_group_number,
546*635a8641SAndroid Build Coastguard Worker     const FieldTrial::EntropyProvider* override_entropy_provider) {
547*635a8641SAndroid Build Coastguard Worker   if (default_group_number)
548*635a8641SAndroid Build Coastguard Worker     *default_group_number = FieldTrial::kDefaultGroupNumber;
549*635a8641SAndroid Build Coastguard Worker   // Check if the field trial has already been created in some other way.
550*635a8641SAndroid Build Coastguard Worker   FieldTrial* existing_trial = Find(trial_name);
551*635a8641SAndroid Build Coastguard Worker   if (existing_trial) {
552*635a8641SAndroid Build Coastguard Worker     CHECK(existing_trial->forced_);
553*635a8641SAndroid Build Coastguard Worker     // If the default group name differs between the existing forced trial
554*635a8641SAndroid Build Coastguard Worker     // and this trial, then use a different value for the default group number.
555*635a8641SAndroid Build Coastguard Worker     if (default_group_number &&
556*635a8641SAndroid Build Coastguard Worker         default_group_name != existing_trial->default_group_name()) {
557*635a8641SAndroid Build Coastguard Worker       // If the new default group number corresponds to the group that was
558*635a8641SAndroid Build Coastguard Worker       // chosen for the forced trial (which has been finalized when it was
559*635a8641SAndroid Build Coastguard Worker       // forced), then set the default group number to that.
560*635a8641SAndroid Build Coastguard Worker       if (default_group_name == existing_trial->group_name_internal()) {
561*635a8641SAndroid Build Coastguard Worker         *default_group_number = existing_trial->group_;
562*635a8641SAndroid Build Coastguard Worker       } else {
563*635a8641SAndroid Build Coastguard Worker         // Otherwise, use |kNonConflictingGroupNumber| (-2) for the default
564*635a8641SAndroid Build Coastguard Worker         // group number, so that it does not conflict with the |AppendGroup()|
565*635a8641SAndroid Build Coastguard Worker         // result for the chosen group.
566*635a8641SAndroid Build Coastguard Worker         const int kNonConflictingGroupNumber = -2;
567*635a8641SAndroid Build Coastguard Worker         static_assert(
568*635a8641SAndroid Build Coastguard Worker             kNonConflictingGroupNumber != FieldTrial::kDefaultGroupNumber,
569*635a8641SAndroid Build Coastguard Worker             "The 'non-conflicting' group number conflicts");
570*635a8641SAndroid Build Coastguard Worker         static_assert(kNonConflictingGroupNumber != FieldTrial::kNotFinalized,
571*635a8641SAndroid Build Coastguard Worker                       "The 'non-conflicting' group number conflicts");
572*635a8641SAndroid Build Coastguard Worker         *default_group_number = kNonConflictingGroupNumber;
573*635a8641SAndroid Build Coastguard Worker       }
574*635a8641SAndroid Build Coastguard Worker     }
575*635a8641SAndroid Build Coastguard Worker     return existing_trial;
576*635a8641SAndroid Build Coastguard Worker   }
577*635a8641SAndroid Build Coastguard Worker 
578*635a8641SAndroid Build Coastguard Worker   double entropy_value;
579*635a8641SAndroid Build Coastguard Worker   if (randomization_type == FieldTrial::ONE_TIME_RANDOMIZED) {
580*635a8641SAndroid Build Coastguard Worker     // If an override entropy provider is given, use it.
581*635a8641SAndroid Build Coastguard Worker     const FieldTrial::EntropyProvider* entropy_provider =
582*635a8641SAndroid Build Coastguard Worker         override_entropy_provider ? override_entropy_provider
583*635a8641SAndroid Build Coastguard Worker                                   : GetEntropyProviderForOneTimeRandomization();
584*635a8641SAndroid Build Coastguard Worker     CHECK(entropy_provider);
585*635a8641SAndroid Build Coastguard Worker     entropy_value = entropy_provider->GetEntropyForTrial(trial_name,
586*635a8641SAndroid Build Coastguard Worker                                                          randomization_seed);
587*635a8641SAndroid Build Coastguard Worker   } else {
588*635a8641SAndroid Build Coastguard Worker     DCHECK_EQ(FieldTrial::SESSION_RANDOMIZED, randomization_type);
589*635a8641SAndroid Build Coastguard Worker     DCHECK_EQ(0U, randomization_seed);
590*635a8641SAndroid Build Coastguard Worker     entropy_value = RandDouble();
591*635a8641SAndroid Build Coastguard Worker   }
592*635a8641SAndroid Build Coastguard Worker 
593*635a8641SAndroid Build Coastguard Worker   FieldTrial* field_trial = new FieldTrial(trial_name, total_probability,
594*635a8641SAndroid Build Coastguard Worker                                            default_group_name, entropy_value);
595*635a8641SAndroid Build Coastguard Worker   if (GetBuildTime() > CreateTimeFromParams(year, month, day_of_month))
596*635a8641SAndroid Build Coastguard Worker     field_trial->Disable();
597*635a8641SAndroid Build Coastguard Worker   FieldTrialList::Register(field_trial);
598*635a8641SAndroid Build Coastguard Worker   return field_trial;
599*635a8641SAndroid Build Coastguard Worker }
600*635a8641SAndroid Build Coastguard Worker 
601*635a8641SAndroid Build Coastguard Worker // static
Find(const std::string & trial_name)602*635a8641SAndroid Build Coastguard Worker FieldTrial* FieldTrialList::Find(const std::string& trial_name) {
603*635a8641SAndroid Build Coastguard Worker   if (!global_)
604*635a8641SAndroid Build Coastguard Worker     return nullptr;
605*635a8641SAndroid Build Coastguard Worker   AutoLock auto_lock(global_->lock_);
606*635a8641SAndroid Build Coastguard Worker   return global_->PreLockedFind(trial_name);
607*635a8641SAndroid Build Coastguard Worker }
608*635a8641SAndroid Build Coastguard Worker 
609*635a8641SAndroid Build Coastguard Worker // static
FindValue(const std::string & trial_name)610*635a8641SAndroid Build Coastguard Worker int FieldTrialList::FindValue(const std::string& trial_name) {
611*635a8641SAndroid Build Coastguard Worker   FieldTrial* field_trial = Find(trial_name);
612*635a8641SAndroid Build Coastguard Worker   if (field_trial)
613*635a8641SAndroid Build Coastguard Worker     return field_trial->group();
614*635a8641SAndroid Build Coastguard Worker   return FieldTrial::kNotFinalized;
615*635a8641SAndroid Build Coastguard Worker }
616*635a8641SAndroid Build Coastguard Worker 
617*635a8641SAndroid Build Coastguard Worker // static
FindFullName(const std::string & trial_name)618*635a8641SAndroid Build Coastguard Worker std::string FieldTrialList::FindFullName(const std::string& trial_name) {
619*635a8641SAndroid Build Coastguard Worker   FieldTrial* field_trial = Find(trial_name);
620*635a8641SAndroid Build Coastguard Worker   if (field_trial)
621*635a8641SAndroid Build Coastguard Worker     return field_trial->group_name();
622*635a8641SAndroid Build Coastguard Worker   return std::string();
623*635a8641SAndroid Build Coastguard Worker }
624*635a8641SAndroid Build Coastguard Worker 
625*635a8641SAndroid Build Coastguard Worker // static
TrialExists(const std::string & trial_name)626*635a8641SAndroid Build Coastguard Worker bool FieldTrialList::TrialExists(const std::string& trial_name) {
627*635a8641SAndroid Build Coastguard Worker   return Find(trial_name) != nullptr;
628*635a8641SAndroid Build Coastguard Worker }
629*635a8641SAndroid Build Coastguard Worker 
630*635a8641SAndroid Build Coastguard Worker // static
IsTrialActive(const std::string & trial_name)631*635a8641SAndroid Build Coastguard Worker bool FieldTrialList::IsTrialActive(const std::string& trial_name) {
632*635a8641SAndroid Build Coastguard Worker   FieldTrial* field_trial = Find(trial_name);
633*635a8641SAndroid Build Coastguard Worker   FieldTrial::ActiveGroup active_group;
634*635a8641SAndroid Build Coastguard Worker   return field_trial && field_trial->GetActiveGroup(&active_group);
635*635a8641SAndroid Build Coastguard Worker }
636*635a8641SAndroid Build Coastguard Worker 
637*635a8641SAndroid Build Coastguard Worker // static
StatesToString(std::string * output)638*635a8641SAndroid Build Coastguard Worker void FieldTrialList::StatesToString(std::string* output) {
639*635a8641SAndroid Build Coastguard Worker   FieldTrial::ActiveGroups active_groups;
640*635a8641SAndroid Build Coastguard Worker   GetActiveFieldTrialGroups(&active_groups);
641*635a8641SAndroid Build Coastguard Worker   for (FieldTrial::ActiveGroups::const_iterator it = active_groups.begin();
642*635a8641SAndroid Build Coastguard Worker        it != active_groups.end(); ++it) {
643*635a8641SAndroid Build Coastguard Worker     DCHECK_EQ(std::string::npos,
644*635a8641SAndroid Build Coastguard Worker               it->trial_name.find(kPersistentStringSeparator));
645*635a8641SAndroid Build Coastguard Worker     DCHECK_EQ(std::string::npos,
646*635a8641SAndroid Build Coastguard Worker               it->group_name.find(kPersistentStringSeparator));
647*635a8641SAndroid Build Coastguard Worker     output->append(it->trial_name);
648*635a8641SAndroid Build Coastguard Worker     output->append(1, kPersistentStringSeparator);
649*635a8641SAndroid Build Coastguard Worker     output->append(it->group_name);
650*635a8641SAndroid Build Coastguard Worker     output->append(1, kPersistentStringSeparator);
651*635a8641SAndroid Build Coastguard Worker   }
652*635a8641SAndroid Build Coastguard Worker }
653*635a8641SAndroid Build Coastguard Worker 
654*635a8641SAndroid Build Coastguard Worker // static
AllStatesToString(std::string * output,bool include_expired)655*635a8641SAndroid Build Coastguard Worker void FieldTrialList::AllStatesToString(std::string* output,
656*635a8641SAndroid Build Coastguard Worker                                        bool include_expired) {
657*635a8641SAndroid Build Coastguard Worker   if (!global_)
658*635a8641SAndroid Build Coastguard Worker     return;
659*635a8641SAndroid Build Coastguard Worker   AutoLock auto_lock(global_->lock_);
660*635a8641SAndroid Build Coastguard Worker 
661*635a8641SAndroid Build Coastguard Worker   for (const auto& registered : global_->registered_) {
662*635a8641SAndroid Build Coastguard Worker     FieldTrial::State trial;
663*635a8641SAndroid Build Coastguard Worker     if (!registered.second->GetStateWhileLocked(&trial, include_expired))
664*635a8641SAndroid Build Coastguard Worker       continue;
665*635a8641SAndroid Build Coastguard Worker     DCHECK_EQ(std::string::npos,
666*635a8641SAndroid Build Coastguard Worker               trial.trial_name->find(kPersistentStringSeparator));
667*635a8641SAndroid Build Coastguard Worker     DCHECK_EQ(std::string::npos,
668*635a8641SAndroid Build Coastguard Worker               trial.group_name->find(kPersistentStringSeparator));
669*635a8641SAndroid Build Coastguard Worker     if (trial.activated)
670*635a8641SAndroid Build Coastguard Worker       output->append(1, kActivationMarker);
671*635a8641SAndroid Build Coastguard Worker     output->append(*trial.trial_name);
672*635a8641SAndroid Build Coastguard Worker     output->append(1, kPersistentStringSeparator);
673*635a8641SAndroid Build Coastguard Worker     output->append(*trial.group_name);
674*635a8641SAndroid Build Coastguard Worker     output->append(1, kPersistentStringSeparator);
675*635a8641SAndroid Build Coastguard Worker   }
676*635a8641SAndroid Build Coastguard Worker }
677*635a8641SAndroid Build Coastguard Worker 
678*635a8641SAndroid Build Coastguard Worker // static
AllParamsToString(bool include_expired,EscapeDataFunc encode_data_func)679*635a8641SAndroid Build Coastguard Worker std::string FieldTrialList::AllParamsToString(bool include_expired,
680*635a8641SAndroid Build Coastguard Worker                                               EscapeDataFunc encode_data_func) {
681*635a8641SAndroid Build Coastguard Worker   FieldTrialParamAssociator* params_associator =
682*635a8641SAndroid Build Coastguard Worker       FieldTrialParamAssociator::GetInstance();
683*635a8641SAndroid Build Coastguard Worker   std::string output;
684*635a8641SAndroid Build Coastguard Worker   for (const auto& registered : GetRegisteredTrials()) {
685*635a8641SAndroid Build Coastguard Worker     FieldTrial::State trial;
686*635a8641SAndroid Build Coastguard Worker     if (!registered.second->GetStateWhileLocked(&trial, include_expired))
687*635a8641SAndroid Build Coastguard Worker       continue;
688*635a8641SAndroid Build Coastguard Worker     DCHECK_EQ(std::string::npos,
689*635a8641SAndroid Build Coastguard Worker               trial.trial_name->find(kPersistentStringSeparator));
690*635a8641SAndroid Build Coastguard Worker     DCHECK_EQ(std::string::npos,
691*635a8641SAndroid Build Coastguard Worker               trial.group_name->find(kPersistentStringSeparator));
692*635a8641SAndroid Build Coastguard Worker     std::map<std::string, std::string> params;
693*635a8641SAndroid Build Coastguard Worker     if (params_associator->GetFieldTrialParamsWithoutFallback(
694*635a8641SAndroid Build Coastguard Worker             *trial.trial_name, *trial.group_name, &params)) {
695*635a8641SAndroid Build Coastguard Worker       if (params.size() > 0) {
696*635a8641SAndroid Build Coastguard Worker         // Add comma to seprate from previous entry if it exists.
697*635a8641SAndroid Build Coastguard Worker         if (!output.empty())
698*635a8641SAndroid Build Coastguard Worker           output.append(1, ',');
699*635a8641SAndroid Build Coastguard Worker 
700*635a8641SAndroid Build Coastguard Worker         output.append(encode_data_func(*trial.trial_name));
701*635a8641SAndroid Build Coastguard Worker         output.append(1, '.');
702*635a8641SAndroid Build Coastguard Worker         output.append(encode_data_func(*trial.group_name));
703*635a8641SAndroid Build Coastguard Worker         output.append(1, ':');
704*635a8641SAndroid Build Coastguard Worker 
705*635a8641SAndroid Build Coastguard Worker         std::string param_str;
706*635a8641SAndroid Build Coastguard Worker         for (const auto& param : params) {
707*635a8641SAndroid Build Coastguard Worker           // Add separator from previous param information if it exists.
708*635a8641SAndroid Build Coastguard Worker           if (!param_str.empty())
709*635a8641SAndroid Build Coastguard Worker             param_str.append(1, kPersistentStringSeparator);
710*635a8641SAndroid Build Coastguard Worker           param_str.append(encode_data_func(param.first));
711*635a8641SAndroid Build Coastguard Worker           param_str.append(1, kPersistentStringSeparator);
712*635a8641SAndroid Build Coastguard Worker           param_str.append(encode_data_func(param.second));
713*635a8641SAndroid Build Coastguard Worker         }
714*635a8641SAndroid Build Coastguard Worker 
715*635a8641SAndroid Build Coastguard Worker         output.append(param_str);
716*635a8641SAndroid Build Coastguard Worker       }
717*635a8641SAndroid Build Coastguard Worker     }
718*635a8641SAndroid Build Coastguard Worker   }
719*635a8641SAndroid Build Coastguard Worker   return output;
720*635a8641SAndroid Build Coastguard Worker }
721*635a8641SAndroid Build Coastguard Worker 
722*635a8641SAndroid Build Coastguard Worker // static
GetActiveFieldTrialGroups(FieldTrial::ActiveGroups * active_groups)723*635a8641SAndroid Build Coastguard Worker void FieldTrialList::GetActiveFieldTrialGroups(
724*635a8641SAndroid Build Coastguard Worker     FieldTrial::ActiveGroups* active_groups) {
725*635a8641SAndroid Build Coastguard Worker   DCHECK(active_groups->empty());
726*635a8641SAndroid Build Coastguard Worker   if (!global_)
727*635a8641SAndroid Build Coastguard Worker     return;
728*635a8641SAndroid Build Coastguard Worker   AutoLock auto_lock(global_->lock_);
729*635a8641SAndroid Build Coastguard Worker 
730*635a8641SAndroid Build Coastguard Worker   for (RegistrationMap::iterator it = global_->registered_.begin();
731*635a8641SAndroid Build Coastguard Worker        it != global_->registered_.end(); ++it) {
732*635a8641SAndroid Build Coastguard Worker     FieldTrial::ActiveGroup active_group;
733*635a8641SAndroid Build Coastguard Worker     if (it->second->GetActiveGroup(&active_group))
734*635a8641SAndroid Build Coastguard Worker       active_groups->push_back(active_group);
735*635a8641SAndroid Build Coastguard Worker   }
736*635a8641SAndroid Build Coastguard Worker }
737*635a8641SAndroid Build Coastguard Worker 
738*635a8641SAndroid Build Coastguard Worker // static
GetActiveFieldTrialGroupsFromString(const std::string & trials_string,FieldTrial::ActiveGroups * active_groups)739*635a8641SAndroid Build Coastguard Worker void FieldTrialList::GetActiveFieldTrialGroupsFromString(
740*635a8641SAndroid Build Coastguard Worker     const std::string& trials_string,
741*635a8641SAndroid Build Coastguard Worker     FieldTrial::ActiveGroups* active_groups) {
742*635a8641SAndroid Build Coastguard Worker   std::vector<FieldTrialStringEntry> entries;
743*635a8641SAndroid Build Coastguard Worker   if (!ParseFieldTrialsString(trials_string, &entries))
744*635a8641SAndroid Build Coastguard Worker     return;
745*635a8641SAndroid Build Coastguard Worker 
746*635a8641SAndroid Build Coastguard Worker   for (const auto& entry : entries) {
747*635a8641SAndroid Build Coastguard Worker     if (entry.activated) {
748*635a8641SAndroid Build Coastguard Worker       FieldTrial::ActiveGroup group;
749*635a8641SAndroid Build Coastguard Worker       group.trial_name = entry.trial_name.as_string();
750*635a8641SAndroid Build Coastguard Worker       group.group_name = entry.group_name.as_string();
751*635a8641SAndroid Build Coastguard Worker       active_groups->push_back(group);
752*635a8641SAndroid Build Coastguard Worker     }
753*635a8641SAndroid Build Coastguard Worker   }
754*635a8641SAndroid Build Coastguard Worker }
755*635a8641SAndroid Build Coastguard Worker 
756*635a8641SAndroid Build Coastguard Worker // static
GetInitiallyActiveFieldTrials(const base::CommandLine & command_line,FieldTrial::ActiveGroups * active_groups)757*635a8641SAndroid Build Coastguard Worker void FieldTrialList::GetInitiallyActiveFieldTrials(
758*635a8641SAndroid Build Coastguard Worker     const base::CommandLine& command_line,
759*635a8641SAndroid Build Coastguard Worker     FieldTrial::ActiveGroups* active_groups) {
760*635a8641SAndroid Build Coastguard Worker   DCHECK(global_);
761*635a8641SAndroid Build Coastguard Worker   DCHECK(global_->create_trials_from_command_line_called_);
762*635a8641SAndroid Build Coastguard Worker 
763*635a8641SAndroid Build Coastguard Worker   if (!global_->field_trial_allocator_) {
764*635a8641SAndroid Build Coastguard Worker     GetActiveFieldTrialGroupsFromString(
765*635a8641SAndroid Build Coastguard Worker         command_line.GetSwitchValueASCII(switches::kForceFieldTrials),
766*635a8641SAndroid Build Coastguard Worker         active_groups);
767*635a8641SAndroid Build Coastguard Worker     return;
768*635a8641SAndroid Build Coastguard Worker   }
769*635a8641SAndroid Build Coastguard Worker 
770*635a8641SAndroid Build Coastguard Worker   FieldTrialAllocator* allocator = global_->field_trial_allocator_.get();
771*635a8641SAndroid Build Coastguard Worker   FieldTrialAllocator::Iterator mem_iter(allocator);
772*635a8641SAndroid Build Coastguard Worker   const FieldTrial::FieldTrialEntry* entry;
773*635a8641SAndroid Build Coastguard Worker   while ((entry = mem_iter.GetNextOfObject<FieldTrial::FieldTrialEntry>()) !=
774*635a8641SAndroid Build Coastguard Worker          nullptr) {
775*635a8641SAndroid Build Coastguard Worker     StringPiece trial_name;
776*635a8641SAndroid Build Coastguard Worker     StringPiece group_name;
777*635a8641SAndroid Build Coastguard Worker     if (subtle::NoBarrier_Load(&entry->activated) &&
778*635a8641SAndroid Build Coastguard Worker         entry->GetTrialAndGroupName(&trial_name, &group_name)) {
779*635a8641SAndroid Build Coastguard Worker       FieldTrial::ActiveGroup group;
780*635a8641SAndroid Build Coastguard Worker       group.trial_name = trial_name.as_string();
781*635a8641SAndroid Build Coastguard Worker       group.group_name = group_name.as_string();
782*635a8641SAndroid Build Coastguard Worker       active_groups->push_back(group);
783*635a8641SAndroid Build Coastguard Worker     }
784*635a8641SAndroid Build Coastguard Worker   }
785*635a8641SAndroid Build Coastguard Worker }
786*635a8641SAndroid Build Coastguard Worker 
787*635a8641SAndroid Build Coastguard Worker // static
CreateTrialsFromString(const std::string & trials_string,const std::set<std::string> & ignored_trial_names)788*635a8641SAndroid Build Coastguard Worker bool FieldTrialList::CreateTrialsFromString(
789*635a8641SAndroid Build Coastguard Worker     const std::string& trials_string,
790*635a8641SAndroid Build Coastguard Worker     const std::set<std::string>& ignored_trial_names) {
791*635a8641SAndroid Build Coastguard Worker   DCHECK(global_);
792*635a8641SAndroid Build Coastguard Worker   if (trials_string.empty() || !global_)
793*635a8641SAndroid Build Coastguard Worker     return true;
794*635a8641SAndroid Build Coastguard Worker 
795*635a8641SAndroid Build Coastguard Worker   std::vector<FieldTrialStringEntry> entries;
796*635a8641SAndroid Build Coastguard Worker   if (!ParseFieldTrialsString(trials_string, &entries))
797*635a8641SAndroid Build Coastguard Worker     return false;
798*635a8641SAndroid Build Coastguard Worker 
799*635a8641SAndroid Build Coastguard Worker   for (const auto& entry : entries) {
800*635a8641SAndroid Build Coastguard Worker     const std::string trial_name = entry.trial_name.as_string();
801*635a8641SAndroid Build Coastguard Worker     const std::string group_name = entry.group_name.as_string();
802*635a8641SAndroid Build Coastguard Worker 
803*635a8641SAndroid Build Coastguard Worker     if (ContainsKey(ignored_trial_names, trial_name)) {
804*635a8641SAndroid Build Coastguard Worker       // This is to warn that the field trial forced through command-line
805*635a8641SAndroid Build Coastguard Worker       // input is unforcable.
806*635a8641SAndroid Build Coastguard Worker       // Use --enable-logging or --enable-logging=stderr to see this warning.
807*635a8641SAndroid Build Coastguard Worker       LOG(WARNING) << "Field trial: " << trial_name << " cannot be forced.";
808*635a8641SAndroid Build Coastguard Worker       continue;
809*635a8641SAndroid Build Coastguard Worker     }
810*635a8641SAndroid Build Coastguard Worker 
811*635a8641SAndroid Build Coastguard Worker     FieldTrial* trial = CreateFieldTrial(trial_name, group_name);
812*635a8641SAndroid Build Coastguard Worker     if (!trial)
813*635a8641SAndroid Build Coastguard Worker       return false;
814*635a8641SAndroid Build Coastguard Worker     if (entry.activated) {
815*635a8641SAndroid Build Coastguard Worker       // Call |group()| to mark the trial as "used" and notify observers, if
816*635a8641SAndroid Build Coastguard Worker       // any. This is useful to ensure that field trials created in child
817*635a8641SAndroid Build Coastguard Worker       // processes are properly reported in crash reports.
818*635a8641SAndroid Build Coastguard Worker       trial->group();
819*635a8641SAndroid Build Coastguard Worker     }
820*635a8641SAndroid Build Coastguard Worker   }
821*635a8641SAndroid Build Coastguard Worker   return true;
822*635a8641SAndroid Build Coastguard Worker }
823*635a8641SAndroid Build Coastguard Worker 
824*635a8641SAndroid Build Coastguard Worker // static
CreateTrialsFromCommandLine(const CommandLine & cmd_line,const char * field_trial_handle_switch,int fd_key)825*635a8641SAndroid Build Coastguard Worker void FieldTrialList::CreateTrialsFromCommandLine(
826*635a8641SAndroid Build Coastguard Worker     const CommandLine& cmd_line,
827*635a8641SAndroid Build Coastguard Worker     const char* field_trial_handle_switch,
828*635a8641SAndroid Build Coastguard Worker     int fd_key) {
829*635a8641SAndroid Build Coastguard Worker   global_->create_trials_from_command_line_called_ = true;
830*635a8641SAndroid Build Coastguard Worker 
831*635a8641SAndroid Build Coastguard Worker #if defined(OS_WIN) || defined(OS_FUCHSIA)
832*635a8641SAndroid Build Coastguard Worker   if (cmd_line.HasSwitch(field_trial_handle_switch)) {
833*635a8641SAndroid Build Coastguard Worker     std::string switch_value =
834*635a8641SAndroid Build Coastguard Worker         cmd_line.GetSwitchValueASCII(field_trial_handle_switch);
835*635a8641SAndroid Build Coastguard Worker     bool result = CreateTrialsFromSwitchValue(switch_value);
836*635a8641SAndroid Build Coastguard Worker     DCHECK(result);
837*635a8641SAndroid Build Coastguard Worker   }
838*635a8641SAndroid Build Coastguard Worker #elif defined(OS_POSIX) && !defined(OS_NACL)
839*635a8641SAndroid Build Coastguard Worker   // On POSIX, we check if the handle is valid by seeing if the browser process
840*635a8641SAndroid Build Coastguard Worker   // sent over the switch (we don't care about the value). Invalid handles
841*635a8641SAndroid Build Coastguard Worker   // occur in some browser tests which don't initialize the allocator.
842*635a8641SAndroid Build Coastguard Worker   if (cmd_line.HasSwitch(field_trial_handle_switch)) {
843*635a8641SAndroid Build Coastguard Worker     std::string switch_value =
844*635a8641SAndroid Build Coastguard Worker         cmd_line.GetSwitchValueASCII(field_trial_handle_switch);
845*635a8641SAndroid Build Coastguard Worker     bool result = CreateTrialsFromDescriptor(fd_key, switch_value);
846*635a8641SAndroid Build Coastguard Worker     DCHECK(result);
847*635a8641SAndroid Build Coastguard Worker   }
848*635a8641SAndroid Build Coastguard Worker #endif
849*635a8641SAndroid Build Coastguard Worker 
850*635a8641SAndroid Build Coastguard Worker   if (cmd_line.HasSwitch(switches::kForceFieldTrials)) {
851*635a8641SAndroid Build Coastguard Worker     bool result = FieldTrialList::CreateTrialsFromString(
852*635a8641SAndroid Build Coastguard Worker         cmd_line.GetSwitchValueASCII(switches::kForceFieldTrials),
853*635a8641SAndroid Build Coastguard Worker         std::set<std::string>());
854*635a8641SAndroid Build Coastguard Worker     DCHECK(result);
855*635a8641SAndroid Build Coastguard Worker   }
856*635a8641SAndroid Build Coastguard Worker }
857*635a8641SAndroid Build Coastguard Worker 
858*635a8641SAndroid Build Coastguard Worker // static
CreateFeaturesFromCommandLine(const base::CommandLine & command_line,const char * enable_features_switch,const char * disable_features_switch,FeatureList * feature_list)859*635a8641SAndroid Build Coastguard Worker void FieldTrialList::CreateFeaturesFromCommandLine(
860*635a8641SAndroid Build Coastguard Worker     const base::CommandLine& command_line,
861*635a8641SAndroid Build Coastguard Worker     const char* enable_features_switch,
862*635a8641SAndroid Build Coastguard Worker     const char* disable_features_switch,
863*635a8641SAndroid Build Coastguard Worker     FeatureList* feature_list) {
864*635a8641SAndroid Build Coastguard Worker   // Fallback to command line if not using shared memory.
865*635a8641SAndroid Build Coastguard Worker   if (!kUseSharedMemoryForFieldTrials ||
866*635a8641SAndroid Build Coastguard Worker       !global_->field_trial_allocator_.get()) {
867*635a8641SAndroid Build Coastguard Worker     return feature_list->InitializeFromCommandLine(
868*635a8641SAndroid Build Coastguard Worker         command_line.GetSwitchValueASCII(enable_features_switch),
869*635a8641SAndroid Build Coastguard Worker         command_line.GetSwitchValueASCII(disable_features_switch));
870*635a8641SAndroid Build Coastguard Worker   }
871*635a8641SAndroid Build Coastguard Worker 
872*635a8641SAndroid Build Coastguard Worker   feature_list->InitializeFromSharedMemory(
873*635a8641SAndroid Build Coastguard Worker       global_->field_trial_allocator_.get());
874*635a8641SAndroid Build Coastguard Worker }
875*635a8641SAndroid Build Coastguard Worker 
876*635a8641SAndroid Build Coastguard Worker #if defined(OS_WIN)
877*635a8641SAndroid Build Coastguard Worker // static
AppendFieldTrialHandleIfNeeded(HandlesToInheritVector * handles)878*635a8641SAndroid Build Coastguard Worker void FieldTrialList::AppendFieldTrialHandleIfNeeded(
879*635a8641SAndroid Build Coastguard Worker     HandlesToInheritVector* handles) {
880*635a8641SAndroid Build Coastguard Worker   if (!global_)
881*635a8641SAndroid Build Coastguard Worker     return;
882*635a8641SAndroid Build Coastguard Worker   if (kUseSharedMemoryForFieldTrials) {
883*635a8641SAndroid Build Coastguard Worker     InstantiateFieldTrialAllocatorIfNeeded();
884*635a8641SAndroid Build Coastguard Worker     if (global_->readonly_allocator_handle_.IsValid())
885*635a8641SAndroid Build Coastguard Worker       handles->push_back(global_->readonly_allocator_handle_.GetHandle());
886*635a8641SAndroid Build Coastguard Worker   }
887*635a8641SAndroid Build Coastguard Worker }
888*635a8641SAndroid Build Coastguard Worker #elif defined(OS_FUCHSIA)
889*635a8641SAndroid Build Coastguard Worker // TODO(fuchsia): Implement shared-memory configuration (crbug.com/752368).
890*635a8641SAndroid Build Coastguard Worker #elif defined(OS_POSIX) && !defined(OS_NACL)
891*635a8641SAndroid Build Coastguard Worker // static
GetFieldTrialHandle()892*635a8641SAndroid Build Coastguard Worker SharedMemoryHandle FieldTrialList::GetFieldTrialHandle() {
893*635a8641SAndroid Build Coastguard Worker   if (global_ && kUseSharedMemoryForFieldTrials) {
894*635a8641SAndroid Build Coastguard Worker     InstantiateFieldTrialAllocatorIfNeeded();
895*635a8641SAndroid Build Coastguard Worker     // We check for an invalid handle where this gets called.
896*635a8641SAndroid Build Coastguard Worker     return global_->readonly_allocator_handle_;
897*635a8641SAndroid Build Coastguard Worker   }
898*635a8641SAndroid Build Coastguard Worker   return SharedMemoryHandle();
899*635a8641SAndroid Build Coastguard Worker }
900*635a8641SAndroid Build Coastguard Worker #endif
901*635a8641SAndroid Build Coastguard Worker 
902*635a8641SAndroid Build Coastguard Worker // static
CopyFieldTrialStateToFlags(const char * field_trial_handle_switch,const char * enable_features_switch,const char * disable_features_switch,CommandLine * cmd_line)903*635a8641SAndroid Build Coastguard Worker void FieldTrialList::CopyFieldTrialStateToFlags(
904*635a8641SAndroid Build Coastguard Worker     const char* field_trial_handle_switch,
905*635a8641SAndroid Build Coastguard Worker     const char* enable_features_switch,
906*635a8641SAndroid Build Coastguard Worker     const char* disable_features_switch,
907*635a8641SAndroid Build Coastguard Worker     CommandLine* cmd_line) {
908*635a8641SAndroid Build Coastguard Worker   // TODO(lawrencewu): Ideally, having the global would be guaranteed. However,
909*635a8641SAndroid Build Coastguard Worker   // content browser tests currently don't create a FieldTrialList because they
910*635a8641SAndroid Build Coastguard Worker   // don't run ChromeBrowserMainParts code where it's done for Chrome.
911*635a8641SAndroid Build Coastguard Worker   // Some tests depend on the enable and disable features flag switch, though,
912*635a8641SAndroid Build Coastguard Worker   // so we can still add those even though AllStatesToString() will be a no-op.
913*635a8641SAndroid Build Coastguard Worker   if (!global_) {
914*635a8641SAndroid Build Coastguard Worker     AddFeatureAndFieldTrialFlags(enable_features_switch,
915*635a8641SAndroid Build Coastguard Worker                                  disable_features_switch, cmd_line);
916*635a8641SAndroid Build Coastguard Worker     return;
917*635a8641SAndroid Build Coastguard Worker   }
918*635a8641SAndroid Build Coastguard Worker 
919*635a8641SAndroid Build Coastguard Worker   // Use shared memory to pass the state if the feature is enabled, otherwise
920*635a8641SAndroid Build Coastguard Worker   // fallback to passing it via the command line as a string.
921*635a8641SAndroid Build Coastguard Worker   if (kUseSharedMemoryForFieldTrials) {
922*635a8641SAndroid Build Coastguard Worker     InstantiateFieldTrialAllocatorIfNeeded();
923*635a8641SAndroid Build Coastguard Worker     // If the readonly handle didn't get duplicated properly, then fallback to
924*635a8641SAndroid Build Coastguard Worker     // original behavior.
925*635a8641SAndroid Build Coastguard Worker     if (!global_->readonly_allocator_handle_.IsValid()) {
926*635a8641SAndroid Build Coastguard Worker       AddFeatureAndFieldTrialFlags(enable_features_switch,
927*635a8641SAndroid Build Coastguard Worker                                    disable_features_switch, cmd_line);
928*635a8641SAndroid Build Coastguard Worker       return;
929*635a8641SAndroid Build Coastguard Worker     }
930*635a8641SAndroid Build Coastguard Worker 
931*635a8641SAndroid Build Coastguard Worker     global_->field_trial_allocator_->UpdateTrackingHistograms();
932*635a8641SAndroid Build Coastguard Worker     std::string switch_value = SerializeSharedMemoryHandleMetadata(
933*635a8641SAndroid Build Coastguard Worker         global_->readonly_allocator_handle_);
934*635a8641SAndroid Build Coastguard Worker     cmd_line->AppendSwitchASCII(field_trial_handle_switch, switch_value);
935*635a8641SAndroid Build Coastguard Worker 
936*635a8641SAndroid Build Coastguard Worker     // Append --enable-features and --disable-features switches corresponding
937*635a8641SAndroid Build Coastguard Worker     // to the features enabled on the command-line, so that child and browser
938*635a8641SAndroid Build Coastguard Worker     // process command lines match and clearly show what has been specified
939*635a8641SAndroid Build Coastguard Worker     // explicitly by the user.
940*635a8641SAndroid Build Coastguard Worker     std::string enabled_features;
941*635a8641SAndroid Build Coastguard Worker     std::string disabled_features;
942*635a8641SAndroid Build Coastguard Worker     FeatureList::GetInstance()->GetCommandLineFeatureOverrides(
943*635a8641SAndroid Build Coastguard Worker         &enabled_features, &disabled_features);
944*635a8641SAndroid Build Coastguard Worker 
945*635a8641SAndroid Build Coastguard Worker     if (!enabled_features.empty())
946*635a8641SAndroid Build Coastguard Worker       cmd_line->AppendSwitchASCII(enable_features_switch, enabled_features);
947*635a8641SAndroid Build Coastguard Worker     if (!disabled_features.empty())
948*635a8641SAndroid Build Coastguard Worker       cmd_line->AppendSwitchASCII(disable_features_switch, disabled_features);
949*635a8641SAndroid Build Coastguard Worker 
950*635a8641SAndroid Build Coastguard Worker     return;
951*635a8641SAndroid Build Coastguard Worker   }
952*635a8641SAndroid Build Coastguard Worker 
953*635a8641SAndroid Build Coastguard Worker   AddFeatureAndFieldTrialFlags(enable_features_switch, disable_features_switch,
954*635a8641SAndroid Build Coastguard Worker                                cmd_line);
955*635a8641SAndroid Build Coastguard Worker }
956*635a8641SAndroid Build Coastguard Worker 
957*635a8641SAndroid Build Coastguard Worker // static
CreateFieldTrial(const std::string & name,const std::string & group_name)958*635a8641SAndroid Build Coastguard Worker FieldTrial* FieldTrialList::CreateFieldTrial(
959*635a8641SAndroid Build Coastguard Worker     const std::string& name,
960*635a8641SAndroid Build Coastguard Worker     const std::string& group_name) {
961*635a8641SAndroid Build Coastguard Worker   DCHECK(global_);
962*635a8641SAndroid Build Coastguard Worker   DCHECK_GE(name.size(), 0u);
963*635a8641SAndroid Build Coastguard Worker   DCHECK_GE(group_name.size(), 0u);
964*635a8641SAndroid Build Coastguard Worker   if (name.empty() || group_name.empty() || !global_)
965*635a8641SAndroid Build Coastguard Worker     return nullptr;
966*635a8641SAndroid Build Coastguard Worker 
967*635a8641SAndroid Build Coastguard Worker   FieldTrial* field_trial = FieldTrialList::Find(name);
968*635a8641SAndroid Build Coastguard Worker   if (field_trial) {
969*635a8641SAndroid Build Coastguard Worker     // In single process mode, or when we force them from the command line,
970*635a8641SAndroid Build Coastguard Worker     // we may have already created the field trial.
971*635a8641SAndroid Build Coastguard Worker     if (field_trial->group_name_internal() != group_name)
972*635a8641SAndroid Build Coastguard Worker       return nullptr;
973*635a8641SAndroid Build Coastguard Worker     return field_trial;
974*635a8641SAndroid Build Coastguard Worker   }
975*635a8641SAndroid Build Coastguard Worker   const int kTotalProbability = 100;
976*635a8641SAndroid Build Coastguard Worker   field_trial = new FieldTrial(name, kTotalProbability, group_name, 0);
977*635a8641SAndroid Build Coastguard Worker   FieldTrialList::Register(field_trial);
978*635a8641SAndroid Build Coastguard Worker   // Force the trial, which will also finalize the group choice.
979*635a8641SAndroid Build Coastguard Worker   field_trial->SetForced();
980*635a8641SAndroid Build Coastguard Worker   return field_trial;
981*635a8641SAndroid Build Coastguard Worker }
982*635a8641SAndroid Build Coastguard Worker 
983*635a8641SAndroid Build Coastguard Worker // static
AddObserver(Observer * observer)984*635a8641SAndroid Build Coastguard Worker bool FieldTrialList::AddObserver(Observer* observer) {
985*635a8641SAndroid Build Coastguard Worker   if (!global_)
986*635a8641SAndroid Build Coastguard Worker     return false;
987*635a8641SAndroid Build Coastguard Worker   global_->observer_list_->AddObserver(observer);
988*635a8641SAndroid Build Coastguard Worker   return true;
989*635a8641SAndroid Build Coastguard Worker }
990*635a8641SAndroid Build Coastguard Worker 
991*635a8641SAndroid Build Coastguard Worker // static
RemoveObserver(Observer * observer)992*635a8641SAndroid Build Coastguard Worker void FieldTrialList::RemoveObserver(Observer* observer) {
993*635a8641SAndroid Build Coastguard Worker   if (!global_)
994*635a8641SAndroid Build Coastguard Worker     return;
995*635a8641SAndroid Build Coastguard Worker   global_->observer_list_->RemoveObserver(observer);
996*635a8641SAndroid Build Coastguard Worker }
997*635a8641SAndroid Build Coastguard Worker 
998*635a8641SAndroid Build Coastguard Worker // static
SetSynchronousObserver(Observer * observer)999*635a8641SAndroid Build Coastguard Worker void FieldTrialList::SetSynchronousObserver(Observer* observer) {
1000*635a8641SAndroid Build Coastguard Worker   DCHECK(!global_->synchronous_observer_);
1001*635a8641SAndroid Build Coastguard Worker   global_->synchronous_observer_ = observer;
1002*635a8641SAndroid Build Coastguard Worker }
1003*635a8641SAndroid Build Coastguard Worker 
1004*635a8641SAndroid Build Coastguard Worker // static
RemoveSynchronousObserver(Observer * observer)1005*635a8641SAndroid Build Coastguard Worker void FieldTrialList::RemoveSynchronousObserver(Observer* observer) {
1006*635a8641SAndroid Build Coastguard Worker   DCHECK_EQ(global_->synchronous_observer_, observer);
1007*635a8641SAndroid Build Coastguard Worker   global_->synchronous_observer_ = nullptr;
1008*635a8641SAndroid Build Coastguard Worker }
1009*635a8641SAndroid Build Coastguard Worker 
1010*635a8641SAndroid Build Coastguard Worker // static
OnGroupFinalized(bool is_locked,FieldTrial * field_trial)1011*635a8641SAndroid Build Coastguard Worker void FieldTrialList::OnGroupFinalized(bool is_locked, FieldTrial* field_trial) {
1012*635a8641SAndroid Build Coastguard Worker   if (!global_)
1013*635a8641SAndroid Build Coastguard Worker     return;
1014*635a8641SAndroid Build Coastguard Worker   if (is_locked) {
1015*635a8641SAndroid Build Coastguard Worker     AddToAllocatorWhileLocked(global_->field_trial_allocator_.get(),
1016*635a8641SAndroid Build Coastguard Worker                               field_trial);
1017*635a8641SAndroid Build Coastguard Worker   } else {
1018*635a8641SAndroid Build Coastguard Worker     AutoLock auto_lock(global_->lock_);
1019*635a8641SAndroid Build Coastguard Worker     AddToAllocatorWhileLocked(global_->field_trial_allocator_.get(),
1020*635a8641SAndroid Build Coastguard Worker                               field_trial);
1021*635a8641SAndroid Build Coastguard Worker   }
1022*635a8641SAndroid Build Coastguard Worker }
1023*635a8641SAndroid Build Coastguard Worker 
1024*635a8641SAndroid Build Coastguard Worker // static
NotifyFieldTrialGroupSelection(FieldTrial * field_trial)1025*635a8641SAndroid Build Coastguard Worker void FieldTrialList::NotifyFieldTrialGroupSelection(FieldTrial* field_trial) {
1026*635a8641SAndroid Build Coastguard Worker   if (!global_)
1027*635a8641SAndroid Build Coastguard Worker     return;
1028*635a8641SAndroid Build Coastguard Worker 
1029*635a8641SAndroid Build Coastguard Worker   {
1030*635a8641SAndroid Build Coastguard Worker     AutoLock auto_lock(global_->lock_);
1031*635a8641SAndroid Build Coastguard Worker     if (field_trial->group_reported_)
1032*635a8641SAndroid Build Coastguard Worker       return;
1033*635a8641SAndroid Build Coastguard Worker     field_trial->group_reported_ = true;
1034*635a8641SAndroid Build Coastguard Worker 
1035*635a8641SAndroid Build Coastguard Worker     if (!field_trial->enable_field_trial_)
1036*635a8641SAndroid Build Coastguard Worker       return;
1037*635a8641SAndroid Build Coastguard Worker 
1038*635a8641SAndroid Build Coastguard Worker     if (kUseSharedMemoryForFieldTrials)
1039*635a8641SAndroid Build Coastguard Worker       ActivateFieldTrialEntryWhileLocked(field_trial);
1040*635a8641SAndroid Build Coastguard Worker   }
1041*635a8641SAndroid Build Coastguard Worker 
1042*635a8641SAndroid Build Coastguard Worker   // Recording for stability debugging has to be done inline as a task posted
1043*635a8641SAndroid Build Coastguard Worker   // to an observer may not get executed before a crash.
1044*635a8641SAndroid Build Coastguard Worker   base::debug::GlobalActivityTracker* tracker =
1045*635a8641SAndroid Build Coastguard Worker       base::debug::GlobalActivityTracker::Get();
1046*635a8641SAndroid Build Coastguard Worker   if (tracker) {
1047*635a8641SAndroid Build Coastguard Worker     tracker->RecordFieldTrial(field_trial->trial_name(),
1048*635a8641SAndroid Build Coastguard Worker                               field_trial->group_name_internal());
1049*635a8641SAndroid Build Coastguard Worker   }
1050*635a8641SAndroid Build Coastguard Worker 
1051*635a8641SAndroid Build Coastguard Worker   if (global_->synchronous_observer_) {
1052*635a8641SAndroid Build Coastguard Worker     global_->synchronous_observer_->OnFieldTrialGroupFinalized(
1053*635a8641SAndroid Build Coastguard Worker         field_trial->trial_name(), field_trial->group_name_internal());
1054*635a8641SAndroid Build Coastguard Worker   }
1055*635a8641SAndroid Build Coastguard Worker 
1056*635a8641SAndroid Build Coastguard Worker   global_->observer_list_->Notify(
1057*635a8641SAndroid Build Coastguard Worker       FROM_HERE, &FieldTrialList::Observer::OnFieldTrialGroupFinalized,
1058*635a8641SAndroid Build Coastguard Worker       field_trial->trial_name(), field_trial->group_name_internal());
1059*635a8641SAndroid Build Coastguard Worker }
1060*635a8641SAndroid Build Coastguard Worker 
1061*635a8641SAndroid Build Coastguard Worker // static
GetFieldTrialCount()1062*635a8641SAndroid Build Coastguard Worker size_t FieldTrialList::GetFieldTrialCount() {
1063*635a8641SAndroid Build Coastguard Worker   if (!global_)
1064*635a8641SAndroid Build Coastguard Worker     return 0;
1065*635a8641SAndroid Build Coastguard Worker   AutoLock auto_lock(global_->lock_);
1066*635a8641SAndroid Build Coastguard Worker   return global_->registered_.size();
1067*635a8641SAndroid Build Coastguard Worker }
1068*635a8641SAndroid Build Coastguard Worker 
1069*635a8641SAndroid Build Coastguard Worker // static
GetParamsFromSharedMemory(FieldTrial * field_trial,std::map<std::string,std::string> * params)1070*635a8641SAndroid Build Coastguard Worker bool FieldTrialList::GetParamsFromSharedMemory(
1071*635a8641SAndroid Build Coastguard Worker     FieldTrial* field_trial,
1072*635a8641SAndroid Build Coastguard Worker     std::map<std::string, std::string>* params) {
1073*635a8641SAndroid Build Coastguard Worker   DCHECK(global_);
1074*635a8641SAndroid Build Coastguard Worker   // If the field trial allocator is not set up yet, then there are several
1075*635a8641SAndroid Build Coastguard Worker   // cases:
1076*635a8641SAndroid Build Coastguard Worker   //   - We are in the browser process and the allocator has not been set up
1077*635a8641SAndroid Build Coastguard Worker   //   yet. If we got here, then we couldn't find the params in
1078*635a8641SAndroid Build Coastguard Worker   //   FieldTrialParamAssociator, so it's definitely not here. Return false.
1079*635a8641SAndroid Build Coastguard Worker   //   - Using shared memory for field trials is not enabled. If we got here,
1080*635a8641SAndroid Build Coastguard Worker   //   then there's nothing in shared memory. Return false.
1081*635a8641SAndroid Build Coastguard Worker   //   - We are in the child process and the allocator has not been set up yet.
1082*635a8641SAndroid Build Coastguard Worker   //   If this is the case, then you are calling this too early. The field trial
1083*635a8641SAndroid Build Coastguard Worker   //   allocator should get set up very early in the lifecycle. Try to see if
1084*635a8641SAndroid Build Coastguard Worker   //   you can call it after it's been set up.
1085*635a8641SAndroid Build Coastguard Worker   AutoLock auto_lock(global_->lock_);
1086*635a8641SAndroid Build Coastguard Worker   if (!global_->field_trial_allocator_)
1087*635a8641SAndroid Build Coastguard Worker     return false;
1088*635a8641SAndroid Build Coastguard Worker 
1089*635a8641SAndroid Build Coastguard Worker   // If ref_ isn't set, then the field trial data can't be in shared memory.
1090*635a8641SAndroid Build Coastguard Worker   if (!field_trial->ref_)
1091*635a8641SAndroid Build Coastguard Worker     return false;
1092*635a8641SAndroid Build Coastguard Worker 
1093*635a8641SAndroid Build Coastguard Worker   const FieldTrial::FieldTrialEntry* entry =
1094*635a8641SAndroid Build Coastguard Worker       global_->field_trial_allocator_->GetAsObject<FieldTrial::FieldTrialEntry>(
1095*635a8641SAndroid Build Coastguard Worker           field_trial->ref_);
1096*635a8641SAndroid Build Coastguard Worker 
1097*635a8641SAndroid Build Coastguard Worker   size_t allocated_size =
1098*635a8641SAndroid Build Coastguard Worker       global_->field_trial_allocator_->GetAllocSize(field_trial->ref_);
1099*635a8641SAndroid Build Coastguard Worker   size_t actual_size = sizeof(FieldTrial::FieldTrialEntry) + entry->pickle_size;
1100*635a8641SAndroid Build Coastguard Worker   if (allocated_size < actual_size)
1101*635a8641SAndroid Build Coastguard Worker     return false;
1102*635a8641SAndroid Build Coastguard Worker 
1103*635a8641SAndroid Build Coastguard Worker   return entry->GetParams(params);
1104*635a8641SAndroid Build Coastguard Worker }
1105*635a8641SAndroid Build Coastguard Worker 
1106*635a8641SAndroid Build Coastguard Worker // static
ClearParamsFromSharedMemoryForTesting()1107*635a8641SAndroid Build Coastguard Worker void FieldTrialList::ClearParamsFromSharedMemoryForTesting() {
1108*635a8641SAndroid Build Coastguard Worker   if (!global_)
1109*635a8641SAndroid Build Coastguard Worker     return;
1110*635a8641SAndroid Build Coastguard Worker 
1111*635a8641SAndroid Build Coastguard Worker   AutoLock auto_lock(global_->lock_);
1112*635a8641SAndroid Build Coastguard Worker   if (!global_->field_trial_allocator_)
1113*635a8641SAndroid Build Coastguard Worker     return;
1114*635a8641SAndroid Build Coastguard Worker 
1115*635a8641SAndroid Build Coastguard Worker   // To clear the params, we iterate through every item in the allocator, copy
1116*635a8641SAndroid Build Coastguard Worker   // just the trial and group name into a newly-allocated segment and then clear
1117*635a8641SAndroid Build Coastguard Worker   // the existing item.
1118*635a8641SAndroid Build Coastguard Worker   FieldTrialAllocator* allocator = global_->field_trial_allocator_.get();
1119*635a8641SAndroid Build Coastguard Worker   FieldTrialAllocator::Iterator mem_iter(allocator);
1120*635a8641SAndroid Build Coastguard Worker 
1121*635a8641SAndroid Build Coastguard Worker   // List of refs to eventually be made iterable. We can't make it in the loop,
1122*635a8641SAndroid Build Coastguard Worker   // since it would go on forever.
1123*635a8641SAndroid Build Coastguard Worker   std::vector<FieldTrial::FieldTrialRef> new_refs;
1124*635a8641SAndroid Build Coastguard Worker 
1125*635a8641SAndroid Build Coastguard Worker   FieldTrial::FieldTrialRef prev_ref;
1126*635a8641SAndroid Build Coastguard Worker   while ((prev_ref = mem_iter.GetNextOfType<FieldTrial::FieldTrialEntry>()) !=
1127*635a8641SAndroid Build Coastguard Worker          FieldTrialAllocator::kReferenceNull) {
1128*635a8641SAndroid Build Coastguard Worker     // Get the existing field trial entry in shared memory.
1129*635a8641SAndroid Build Coastguard Worker     const FieldTrial::FieldTrialEntry* prev_entry =
1130*635a8641SAndroid Build Coastguard Worker         allocator->GetAsObject<FieldTrial::FieldTrialEntry>(prev_ref);
1131*635a8641SAndroid Build Coastguard Worker     StringPiece trial_name;
1132*635a8641SAndroid Build Coastguard Worker     StringPiece group_name;
1133*635a8641SAndroid Build Coastguard Worker     if (!prev_entry->GetTrialAndGroupName(&trial_name, &group_name))
1134*635a8641SAndroid Build Coastguard Worker       continue;
1135*635a8641SAndroid Build Coastguard Worker 
1136*635a8641SAndroid Build Coastguard Worker     // Write a new entry, minus the params.
1137*635a8641SAndroid Build Coastguard Worker     Pickle pickle;
1138*635a8641SAndroid Build Coastguard Worker     pickle.WriteString(trial_name);
1139*635a8641SAndroid Build Coastguard Worker     pickle.WriteString(group_name);
1140*635a8641SAndroid Build Coastguard Worker     size_t total_size = sizeof(FieldTrial::FieldTrialEntry) + pickle.size();
1141*635a8641SAndroid Build Coastguard Worker     FieldTrial::FieldTrialEntry* new_entry =
1142*635a8641SAndroid Build Coastguard Worker         allocator->New<FieldTrial::FieldTrialEntry>(total_size);
1143*635a8641SAndroid Build Coastguard Worker     subtle::NoBarrier_Store(&new_entry->activated,
1144*635a8641SAndroid Build Coastguard Worker                             subtle::NoBarrier_Load(&prev_entry->activated));
1145*635a8641SAndroid Build Coastguard Worker     new_entry->pickle_size = pickle.size();
1146*635a8641SAndroid Build Coastguard Worker 
1147*635a8641SAndroid Build Coastguard Worker     // TODO(lawrencewu): Modify base::Pickle to be able to write over a section
1148*635a8641SAndroid Build Coastguard Worker     // in memory, so we can avoid this memcpy.
1149*635a8641SAndroid Build Coastguard Worker     char* dst = reinterpret_cast<char*>(new_entry) +
1150*635a8641SAndroid Build Coastguard Worker                 sizeof(FieldTrial::FieldTrialEntry);
1151*635a8641SAndroid Build Coastguard Worker     memcpy(dst, pickle.data(), pickle.size());
1152*635a8641SAndroid Build Coastguard Worker 
1153*635a8641SAndroid Build Coastguard Worker     // Update the ref on the field trial and add it to the list to be made
1154*635a8641SAndroid Build Coastguard Worker     // iterable.
1155*635a8641SAndroid Build Coastguard Worker     FieldTrial::FieldTrialRef new_ref = allocator->GetAsReference(new_entry);
1156*635a8641SAndroid Build Coastguard Worker     FieldTrial* trial = global_->PreLockedFind(trial_name.as_string());
1157*635a8641SAndroid Build Coastguard Worker     trial->ref_ = new_ref;
1158*635a8641SAndroid Build Coastguard Worker     new_refs.push_back(new_ref);
1159*635a8641SAndroid Build Coastguard Worker 
1160*635a8641SAndroid Build Coastguard Worker     // Mark the existing entry as unused.
1161*635a8641SAndroid Build Coastguard Worker     allocator->ChangeType(prev_ref, 0,
1162*635a8641SAndroid Build Coastguard Worker                           FieldTrial::FieldTrialEntry::kPersistentTypeId,
1163*635a8641SAndroid Build Coastguard Worker                           /*clear=*/false);
1164*635a8641SAndroid Build Coastguard Worker   }
1165*635a8641SAndroid Build Coastguard Worker 
1166*635a8641SAndroid Build Coastguard Worker   for (const auto& ref : new_refs) {
1167*635a8641SAndroid Build Coastguard Worker     allocator->MakeIterable(ref);
1168*635a8641SAndroid Build Coastguard Worker   }
1169*635a8641SAndroid Build Coastguard Worker }
1170*635a8641SAndroid Build Coastguard Worker 
1171*635a8641SAndroid Build Coastguard Worker // static
DumpAllFieldTrialsToPersistentAllocator(PersistentMemoryAllocator * allocator)1172*635a8641SAndroid Build Coastguard Worker void FieldTrialList::DumpAllFieldTrialsToPersistentAllocator(
1173*635a8641SAndroid Build Coastguard Worker     PersistentMemoryAllocator* allocator) {
1174*635a8641SAndroid Build Coastguard Worker   if (!global_)
1175*635a8641SAndroid Build Coastguard Worker     return;
1176*635a8641SAndroid Build Coastguard Worker   AutoLock auto_lock(global_->lock_);
1177*635a8641SAndroid Build Coastguard Worker   for (const auto& registered : global_->registered_) {
1178*635a8641SAndroid Build Coastguard Worker     AddToAllocatorWhileLocked(allocator, registered.second);
1179*635a8641SAndroid Build Coastguard Worker   }
1180*635a8641SAndroid Build Coastguard Worker }
1181*635a8641SAndroid Build Coastguard Worker 
1182*635a8641SAndroid Build Coastguard Worker // static
1183*635a8641SAndroid Build Coastguard Worker std::vector<const FieldTrial::FieldTrialEntry*>
GetAllFieldTrialsFromPersistentAllocator(PersistentMemoryAllocator const & allocator)1184*635a8641SAndroid Build Coastguard Worker FieldTrialList::GetAllFieldTrialsFromPersistentAllocator(
1185*635a8641SAndroid Build Coastguard Worker     PersistentMemoryAllocator const& allocator) {
1186*635a8641SAndroid Build Coastguard Worker   std::vector<const FieldTrial::FieldTrialEntry*> entries;
1187*635a8641SAndroid Build Coastguard Worker   FieldTrialAllocator::Iterator iter(&allocator);
1188*635a8641SAndroid Build Coastguard Worker   const FieldTrial::FieldTrialEntry* entry;
1189*635a8641SAndroid Build Coastguard Worker   while ((entry = iter.GetNextOfObject<FieldTrial::FieldTrialEntry>()) !=
1190*635a8641SAndroid Build Coastguard Worker          nullptr) {
1191*635a8641SAndroid Build Coastguard Worker     entries.push_back(entry);
1192*635a8641SAndroid Build Coastguard Worker   }
1193*635a8641SAndroid Build Coastguard Worker   return entries;
1194*635a8641SAndroid Build Coastguard Worker }
1195*635a8641SAndroid Build Coastguard Worker 
1196*635a8641SAndroid Build Coastguard Worker // static
IsGlobalSetForTesting()1197*635a8641SAndroid Build Coastguard Worker bool FieldTrialList::IsGlobalSetForTesting() {
1198*635a8641SAndroid Build Coastguard Worker   return global_ != nullptr;
1199*635a8641SAndroid Build Coastguard Worker }
1200*635a8641SAndroid Build Coastguard Worker 
1201*635a8641SAndroid Build Coastguard Worker // static
SerializeSharedMemoryHandleMetadata(const SharedMemoryHandle & shm)1202*635a8641SAndroid Build Coastguard Worker std::string FieldTrialList::SerializeSharedMemoryHandleMetadata(
1203*635a8641SAndroid Build Coastguard Worker     const SharedMemoryHandle& shm) {
1204*635a8641SAndroid Build Coastguard Worker   std::stringstream ss;
1205*635a8641SAndroid Build Coastguard Worker #if defined(OS_WIN)
1206*635a8641SAndroid Build Coastguard Worker   // Tell the child process the name of the inherited HANDLE.
1207*635a8641SAndroid Build Coastguard Worker   uintptr_t uintptr_handle = reinterpret_cast<uintptr_t>(shm.GetHandle());
1208*635a8641SAndroid Build Coastguard Worker   ss << uintptr_handle << ",";
1209*635a8641SAndroid Build Coastguard Worker #elif defined(OS_FUCHSIA)
1210*635a8641SAndroid Build Coastguard Worker   ss << shm.GetHandle() << ",";
1211*635a8641SAndroid Build Coastguard Worker #elif !defined(OS_POSIX)
1212*635a8641SAndroid Build Coastguard Worker #error Unsupported OS
1213*635a8641SAndroid Build Coastguard Worker #endif
1214*635a8641SAndroid Build Coastguard Worker 
1215*635a8641SAndroid Build Coastguard Worker   base::UnguessableToken guid = shm.GetGUID();
1216*635a8641SAndroid Build Coastguard Worker   ss << guid.GetHighForSerialization() << "," << guid.GetLowForSerialization();
1217*635a8641SAndroid Build Coastguard Worker   ss << "," << shm.GetSize();
1218*635a8641SAndroid Build Coastguard Worker   return ss.str();
1219*635a8641SAndroid Build Coastguard Worker }
1220*635a8641SAndroid Build Coastguard Worker 
1221*635a8641SAndroid Build Coastguard Worker #if defined(OS_WIN) || defined(OS_FUCHSIA)
1222*635a8641SAndroid Build Coastguard Worker 
1223*635a8641SAndroid Build Coastguard Worker // static
DeserializeSharedMemoryHandleMetadata(const std::string & switch_value)1224*635a8641SAndroid Build Coastguard Worker SharedMemoryHandle FieldTrialList::DeserializeSharedMemoryHandleMetadata(
1225*635a8641SAndroid Build Coastguard Worker     const std::string& switch_value) {
1226*635a8641SAndroid Build Coastguard Worker   std::vector<base::StringPiece> tokens = base::SplitStringPiece(
1227*635a8641SAndroid Build Coastguard Worker       switch_value, ",", base::KEEP_WHITESPACE, base::SPLIT_WANT_ALL);
1228*635a8641SAndroid Build Coastguard Worker 
1229*635a8641SAndroid Build Coastguard Worker   if (tokens.size() != 4)
1230*635a8641SAndroid Build Coastguard Worker     return SharedMemoryHandle();
1231*635a8641SAndroid Build Coastguard Worker 
1232*635a8641SAndroid Build Coastguard Worker   int field_trial_handle = 0;
1233*635a8641SAndroid Build Coastguard Worker   if (!base::StringToInt(tokens[0], &field_trial_handle))
1234*635a8641SAndroid Build Coastguard Worker     return SharedMemoryHandle();
1235*635a8641SAndroid Build Coastguard Worker #if defined(OS_FUCHSIA)
1236*635a8641SAndroid Build Coastguard Worker   zx_handle_t handle = static_cast<zx_handle_t>(field_trial_handle);
1237*635a8641SAndroid Build Coastguard Worker #elif defined(OS_WIN)
1238*635a8641SAndroid Build Coastguard Worker   HANDLE handle = reinterpret_cast<HANDLE>(field_trial_handle);
1239*635a8641SAndroid Build Coastguard Worker   if (base::IsCurrentProcessElevated()) {
1240*635a8641SAndroid Build Coastguard Worker     // base::LaunchElevatedProcess doesn't have a way to duplicate the handle,
1241*635a8641SAndroid Build Coastguard Worker     // but this process can since by definition it's not sandboxed.
1242*635a8641SAndroid Build Coastguard Worker     base::ProcessId parent_pid = base::GetParentProcessId(GetCurrentProcess());
1243*635a8641SAndroid Build Coastguard Worker     HANDLE parent_handle = OpenProcess(PROCESS_ALL_ACCESS, FALSE, parent_pid);
1244*635a8641SAndroid Build Coastguard Worker     DuplicateHandle(parent_handle, handle, GetCurrentProcess(), &handle, 0,
1245*635a8641SAndroid Build Coastguard Worker                     FALSE, DUPLICATE_SAME_ACCESS);
1246*635a8641SAndroid Build Coastguard Worker     CloseHandle(parent_handle);
1247*635a8641SAndroid Build Coastguard Worker   }
1248*635a8641SAndroid Build Coastguard Worker #endif  // defined(OS_WIN)
1249*635a8641SAndroid Build Coastguard Worker 
1250*635a8641SAndroid Build Coastguard Worker   base::UnguessableToken guid;
1251*635a8641SAndroid Build Coastguard Worker   if (!DeserializeGUIDFromStringPieces(tokens[1], tokens[2], &guid))
1252*635a8641SAndroid Build Coastguard Worker     return SharedMemoryHandle();
1253*635a8641SAndroid Build Coastguard Worker 
1254*635a8641SAndroid Build Coastguard Worker   int size;
1255*635a8641SAndroid Build Coastguard Worker   if (!base::StringToInt(tokens[3], &size))
1256*635a8641SAndroid Build Coastguard Worker     return SharedMemoryHandle();
1257*635a8641SAndroid Build Coastguard Worker 
1258*635a8641SAndroid Build Coastguard Worker   return SharedMemoryHandle(handle, static_cast<size_t>(size), guid);
1259*635a8641SAndroid Build Coastguard Worker }
1260*635a8641SAndroid Build Coastguard Worker 
1261*635a8641SAndroid Build Coastguard Worker #elif defined(OS_POSIX) && !defined(OS_NACL)
1262*635a8641SAndroid Build Coastguard Worker 
1263*635a8641SAndroid Build Coastguard Worker // static
DeserializeSharedMemoryHandleMetadata(int fd,const std::string & switch_value)1264*635a8641SAndroid Build Coastguard Worker SharedMemoryHandle FieldTrialList::DeserializeSharedMemoryHandleMetadata(
1265*635a8641SAndroid Build Coastguard Worker     int fd,
1266*635a8641SAndroid Build Coastguard Worker     const std::string& switch_value) {
1267*635a8641SAndroid Build Coastguard Worker   std::vector<base::StringPiece> tokens = base::SplitStringPiece(
1268*635a8641SAndroid Build Coastguard Worker       switch_value, ",", base::KEEP_WHITESPACE, base::SPLIT_WANT_ALL);
1269*635a8641SAndroid Build Coastguard Worker 
1270*635a8641SAndroid Build Coastguard Worker   if (tokens.size() != 3)
1271*635a8641SAndroid Build Coastguard Worker     return SharedMemoryHandle();
1272*635a8641SAndroid Build Coastguard Worker 
1273*635a8641SAndroid Build Coastguard Worker   base::UnguessableToken guid;
1274*635a8641SAndroid Build Coastguard Worker   if (!DeserializeGUIDFromStringPieces(tokens[0], tokens[1], &guid))
1275*635a8641SAndroid Build Coastguard Worker     return SharedMemoryHandle();
1276*635a8641SAndroid Build Coastguard Worker 
1277*635a8641SAndroid Build Coastguard Worker   int size;
1278*635a8641SAndroid Build Coastguard Worker   if (!base::StringToInt(tokens[2], &size))
1279*635a8641SAndroid Build Coastguard Worker     return SharedMemoryHandle();
1280*635a8641SAndroid Build Coastguard Worker 
1281*635a8641SAndroid Build Coastguard Worker   return SharedMemoryHandle(FileDescriptor(fd, true), static_cast<size_t>(size),
1282*635a8641SAndroid Build Coastguard Worker                             guid);
1283*635a8641SAndroid Build Coastguard Worker }
1284*635a8641SAndroid Build Coastguard Worker 
1285*635a8641SAndroid Build Coastguard Worker #endif
1286*635a8641SAndroid Build Coastguard Worker 
1287*635a8641SAndroid Build Coastguard Worker #if defined(OS_WIN) || defined(OS_FUCHSIA)
1288*635a8641SAndroid Build Coastguard Worker // static
CreateTrialsFromSwitchValue(const std::string & switch_value)1289*635a8641SAndroid Build Coastguard Worker bool FieldTrialList::CreateTrialsFromSwitchValue(
1290*635a8641SAndroid Build Coastguard Worker     const std::string& switch_value) {
1291*635a8641SAndroid Build Coastguard Worker   SharedMemoryHandle shm = DeserializeSharedMemoryHandleMetadata(switch_value);
1292*635a8641SAndroid Build Coastguard Worker   if (!shm.IsValid())
1293*635a8641SAndroid Build Coastguard Worker     return false;
1294*635a8641SAndroid Build Coastguard Worker   return FieldTrialList::CreateTrialsFromSharedMemoryHandle(shm);
1295*635a8641SAndroid Build Coastguard Worker }
1296*635a8641SAndroid Build Coastguard Worker #elif defined(OS_POSIX) && !defined(OS_NACL)
1297*635a8641SAndroid Build Coastguard Worker // static
CreateTrialsFromDescriptor(int fd_key,const std::string & switch_value)1298*635a8641SAndroid Build Coastguard Worker bool FieldTrialList::CreateTrialsFromDescriptor(
1299*635a8641SAndroid Build Coastguard Worker     int fd_key,
1300*635a8641SAndroid Build Coastguard Worker     const std::string& switch_value) {
1301*635a8641SAndroid Build Coastguard Worker   if (!kUseSharedMemoryForFieldTrials)
1302*635a8641SAndroid Build Coastguard Worker     return false;
1303*635a8641SAndroid Build Coastguard Worker 
1304*635a8641SAndroid Build Coastguard Worker   if (fd_key == -1)
1305*635a8641SAndroid Build Coastguard Worker     return false;
1306*635a8641SAndroid Build Coastguard Worker 
1307*635a8641SAndroid Build Coastguard Worker   int fd = GlobalDescriptors::GetInstance()->MaybeGet(fd_key);
1308*635a8641SAndroid Build Coastguard Worker   if (fd == -1)
1309*635a8641SAndroid Build Coastguard Worker     return false;
1310*635a8641SAndroid Build Coastguard Worker 
1311*635a8641SAndroid Build Coastguard Worker   SharedMemoryHandle shm =
1312*635a8641SAndroid Build Coastguard Worker       DeserializeSharedMemoryHandleMetadata(fd, switch_value);
1313*635a8641SAndroid Build Coastguard Worker   if (!shm.IsValid())
1314*635a8641SAndroid Build Coastguard Worker     return false;
1315*635a8641SAndroid Build Coastguard Worker 
1316*635a8641SAndroid Build Coastguard Worker   bool result = FieldTrialList::CreateTrialsFromSharedMemoryHandle(shm);
1317*635a8641SAndroid Build Coastguard Worker   DCHECK(result);
1318*635a8641SAndroid Build Coastguard Worker   return true;
1319*635a8641SAndroid Build Coastguard Worker }
1320*635a8641SAndroid Build Coastguard Worker #endif  // defined(OS_POSIX) && !defined(OS_NACL)
1321*635a8641SAndroid Build Coastguard Worker 
1322*635a8641SAndroid Build Coastguard Worker // static
CreateTrialsFromSharedMemoryHandle(SharedMemoryHandle shm_handle)1323*635a8641SAndroid Build Coastguard Worker bool FieldTrialList::CreateTrialsFromSharedMemoryHandle(
1324*635a8641SAndroid Build Coastguard Worker     SharedMemoryHandle shm_handle) {
1325*635a8641SAndroid Build Coastguard Worker   // shm gets deleted when it gets out of scope, but that's OK because we need
1326*635a8641SAndroid Build Coastguard Worker   // it only for the duration of this method.
1327*635a8641SAndroid Build Coastguard Worker   std::unique_ptr<SharedMemory> shm(new SharedMemory(shm_handle, true));
1328*635a8641SAndroid Build Coastguard Worker   if (!shm.get()->Map(kFieldTrialAllocationSize))
1329*635a8641SAndroid Build Coastguard Worker     OnOutOfMemory(kFieldTrialAllocationSize);
1330*635a8641SAndroid Build Coastguard Worker 
1331*635a8641SAndroid Build Coastguard Worker   return FieldTrialList::CreateTrialsFromSharedMemory(std::move(shm));
1332*635a8641SAndroid Build Coastguard Worker }
1333*635a8641SAndroid Build Coastguard Worker 
1334*635a8641SAndroid Build Coastguard Worker // static
CreateTrialsFromSharedMemory(std::unique_ptr<SharedMemory> shm)1335*635a8641SAndroid Build Coastguard Worker bool FieldTrialList::CreateTrialsFromSharedMemory(
1336*635a8641SAndroid Build Coastguard Worker     std::unique_ptr<SharedMemory> shm) {
1337*635a8641SAndroid Build Coastguard Worker   global_->field_trial_allocator_.reset(
1338*635a8641SAndroid Build Coastguard Worker       new FieldTrialAllocator(std::move(shm), 0, kAllocatorName, true));
1339*635a8641SAndroid Build Coastguard Worker   FieldTrialAllocator* shalloc = global_->field_trial_allocator_.get();
1340*635a8641SAndroid Build Coastguard Worker   FieldTrialAllocator::Iterator mem_iter(shalloc);
1341*635a8641SAndroid Build Coastguard Worker 
1342*635a8641SAndroid Build Coastguard Worker   const FieldTrial::FieldTrialEntry* entry;
1343*635a8641SAndroid Build Coastguard Worker   while ((entry = mem_iter.GetNextOfObject<FieldTrial::FieldTrialEntry>()) !=
1344*635a8641SAndroid Build Coastguard Worker          nullptr) {
1345*635a8641SAndroid Build Coastguard Worker     StringPiece trial_name;
1346*635a8641SAndroid Build Coastguard Worker     StringPiece group_name;
1347*635a8641SAndroid Build Coastguard Worker     if (!entry->GetTrialAndGroupName(&trial_name, &group_name))
1348*635a8641SAndroid Build Coastguard Worker       return false;
1349*635a8641SAndroid Build Coastguard Worker 
1350*635a8641SAndroid Build Coastguard Worker     // TODO(lawrencewu): Convert the API for CreateFieldTrial to take
1351*635a8641SAndroid Build Coastguard Worker     // StringPieces.
1352*635a8641SAndroid Build Coastguard Worker     FieldTrial* trial =
1353*635a8641SAndroid Build Coastguard Worker         CreateFieldTrial(trial_name.as_string(), group_name.as_string());
1354*635a8641SAndroid Build Coastguard Worker 
1355*635a8641SAndroid Build Coastguard Worker     trial->ref_ = mem_iter.GetAsReference(entry);
1356*635a8641SAndroid Build Coastguard Worker     if (subtle::NoBarrier_Load(&entry->activated)) {
1357*635a8641SAndroid Build Coastguard Worker       // Call |group()| to mark the trial as "used" and notify observers, if
1358*635a8641SAndroid Build Coastguard Worker       // any. This is useful to ensure that field trials created in child
1359*635a8641SAndroid Build Coastguard Worker       // processes are properly reported in crash reports.
1360*635a8641SAndroid Build Coastguard Worker       trial->group();
1361*635a8641SAndroid Build Coastguard Worker     }
1362*635a8641SAndroid Build Coastguard Worker   }
1363*635a8641SAndroid Build Coastguard Worker   return true;
1364*635a8641SAndroid Build Coastguard Worker }
1365*635a8641SAndroid Build Coastguard Worker 
1366*635a8641SAndroid Build Coastguard Worker // static
InstantiateFieldTrialAllocatorIfNeeded()1367*635a8641SAndroid Build Coastguard Worker void FieldTrialList::InstantiateFieldTrialAllocatorIfNeeded() {
1368*635a8641SAndroid Build Coastguard Worker   if (!global_)
1369*635a8641SAndroid Build Coastguard Worker     return;
1370*635a8641SAndroid Build Coastguard Worker   AutoLock auto_lock(global_->lock_);
1371*635a8641SAndroid Build Coastguard Worker   // Create the allocator if not already created and add all existing trials.
1372*635a8641SAndroid Build Coastguard Worker   if (global_->field_trial_allocator_ != nullptr)
1373*635a8641SAndroid Build Coastguard Worker     return;
1374*635a8641SAndroid Build Coastguard Worker 
1375*635a8641SAndroid Build Coastguard Worker   SharedMemoryCreateOptions options;
1376*635a8641SAndroid Build Coastguard Worker   options.size = kFieldTrialAllocationSize;
1377*635a8641SAndroid Build Coastguard Worker   options.share_read_only = true;
1378*635a8641SAndroid Build Coastguard Worker #if defined(OS_MACOSX) && !defined(OS_IOS)
1379*635a8641SAndroid Build Coastguard Worker   options.type = SharedMemoryHandle::POSIX;
1380*635a8641SAndroid Build Coastguard Worker #endif
1381*635a8641SAndroid Build Coastguard Worker 
1382*635a8641SAndroid Build Coastguard Worker   std::unique_ptr<SharedMemory> shm(new SharedMemory());
1383*635a8641SAndroid Build Coastguard Worker   if (!shm->Create(options))
1384*635a8641SAndroid Build Coastguard Worker     OnOutOfMemory(kFieldTrialAllocationSize);
1385*635a8641SAndroid Build Coastguard Worker 
1386*635a8641SAndroid Build Coastguard Worker   if (!shm->Map(kFieldTrialAllocationSize))
1387*635a8641SAndroid Build Coastguard Worker     OnOutOfMemory(kFieldTrialAllocationSize);
1388*635a8641SAndroid Build Coastguard Worker 
1389*635a8641SAndroid Build Coastguard Worker   global_->field_trial_allocator_.reset(
1390*635a8641SAndroid Build Coastguard Worker       new FieldTrialAllocator(std::move(shm), 0, kAllocatorName, false));
1391*635a8641SAndroid Build Coastguard Worker   global_->field_trial_allocator_->CreateTrackingHistograms(kAllocatorName);
1392*635a8641SAndroid Build Coastguard Worker 
1393*635a8641SAndroid Build Coastguard Worker   // Add all existing field trials.
1394*635a8641SAndroid Build Coastguard Worker   for (const auto& registered : global_->registered_) {
1395*635a8641SAndroid Build Coastguard Worker     AddToAllocatorWhileLocked(global_->field_trial_allocator_.get(),
1396*635a8641SAndroid Build Coastguard Worker                               registered.second);
1397*635a8641SAndroid Build Coastguard Worker   }
1398*635a8641SAndroid Build Coastguard Worker 
1399*635a8641SAndroid Build Coastguard Worker   // Add all existing features.
1400*635a8641SAndroid Build Coastguard Worker   FeatureList::GetInstance()->AddFeaturesToAllocator(
1401*635a8641SAndroid Build Coastguard Worker       global_->field_trial_allocator_.get());
1402*635a8641SAndroid Build Coastguard Worker 
1403*635a8641SAndroid Build Coastguard Worker #if !defined(OS_NACL)
1404*635a8641SAndroid Build Coastguard Worker   global_->readonly_allocator_handle_ = GetSharedMemoryReadOnlyHandle(
1405*635a8641SAndroid Build Coastguard Worker       global_->field_trial_allocator_->shared_memory());
1406*635a8641SAndroid Build Coastguard Worker #endif
1407*635a8641SAndroid Build Coastguard Worker }
1408*635a8641SAndroid Build Coastguard Worker 
1409*635a8641SAndroid Build Coastguard Worker // static
AddToAllocatorWhileLocked(PersistentMemoryAllocator * allocator,FieldTrial * field_trial)1410*635a8641SAndroid Build Coastguard Worker void FieldTrialList::AddToAllocatorWhileLocked(
1411*635a8641SAndroid Build Coastguard Worker     PersistentMemoryAllocator* allocator,
1412*635a8641SAndroid Build Coastguard Worker     FieldTrial* field_trial) {
1413*635a8641SAndroid Build Coastguard Worker   // Don't do anything if the allocator hasn't been instantiated yet.
1414*635a8641SAndroid Build Coastguard Worker   if (allocator == nullptr)
1415*635a8641SAndroid Build Coastguard Worker     return;
1416*635a8641SAndroid Build Coastguard Worker 
1417*635a8641SAndroid Build Coastguard Worker   // Or if the allocator is read only, which means we are in a child process and
1418*635a8641SAndroid Build Coastguard Worker   // shouldn't be writing to it.
1419*635a8641SAndroid Build Coastguard Worker   if (allocator->IsReadonly())
1420*635a8641SAndroid Build Coastguard Worker     return;
1421*635a8641SAndroid Build Coastguard Worker 
1422*635a8641SAndroid Build Coastguard Worker   FieldTrial::State trial_state;
1423*635a8641SAndroid Build Coastguard Worker   if (!field_trial->GetStateWhileLocked(&trial_state, false))
1424*635a8641SAndroid Build Coastguard Worker     return;
1425*635a8641SAndroid Build Coastguard Worker 
1426*635a8641SAndroid Build Coastguard Worker   // Or if we've already added it. We must check after GetState since it can
1427*635a8641SAndroid Build Coastguard Worker   // also add to the allocator.
1428*635a8641SAndroid Build Coastguard Worker   if (field_trial->ref_)
1429*635a8641SAndroid Build Coastguard Worker     return;
1430*635a8641SAndroid Build Coastguard Worker 
1431*635a8641SAndroid Build Coastguard Worker   Pickle pickle;
1432*635a8641SAndroid Build Coastguard Worker   PickleFieldTrial(trial_state, &pickle);
1433*635a8641SAndroid Build Coastguard Worker 
1434*635a8641SAndroid Build Coastguard Worker   size_t total_size = sizeof(FieldTrial::FieldTrialEntry) + pickle.size();
1435*635a8641SAndroid Build Coastguard Worker   FieldTrial::FieldTrialRef ref = allocator->Allocate(
1436*635a8641SAndroid Build Coastguard Worker       total_size, FieldTrial::FieldTrialEntry::kPersistentTypeId);
1437*635a8641SAndroid Build Coastguard Worker   if (ref == FieldTrialAllocator::kReferenceNull) {
1438*635a8641SAndroid Build Coastguard Worker     NOTREACHED();
1439*635a8641SAndroid Build Coastguard Worker     return;
1440*635a8641SAndroid Build Coastguard Worker   }
1441*635a8641SAndroid Build Coastguard Worker 
1442*635a8641SAndroid Build Coastguard Worker   FieldTrial::FieldTrialEntry* entry =
1443*635a8641SAndroid Build Coastguard Worker       allocator->GetAsObject<FieldTrial::FieldTrialEntry>(ref);
1444*635a8641SAndroid Build Coastguard Worker   subtle::NoBarrier_Store(&entry->activated, trial_state.activated);
1445*635a8641SAndroid Build Coastguard Worker   entry->pickle_size = pickle.size();
1446*635a8641SAndroid Build Coastguard Worker 
1447*635a8641SAndroid Build Coastguard Worker   // TODO(lawrencewu): Modify base::Pickle to be able to write over a section in
1448*635a8641SAndroid Build Coastguard Worker   // memory, so we can avoid this memcpy.
1449*635a8641SAndroid Build Coastguard Worker   char* dst =
1450*635a8641SAndroid Build Coastguard Worker       reinterpret_cast<char*>(entry) + sizeof(FieldTrial::FieldTrialEntry);
1451*635a8641SAndroid Build Coastguard Worker   memcpy(dst, pickle.data(), pickle.size());
1452*635a8641SAndroid Build Coastguard Worker 
1453*635a8641SAndroid Build Coastguard Worker   allocator->MakeIterable(ref);
1454*635a8641SAndroid Build Coastguard Worker   field_trial->ref_ = ref;
1455*635a8641SAndroid Build Coastguard Worker }
1456*635a8641SAndroid Build Coastguard Worker 
1457*635a8641SAndroid Build Coastguard Worker // static
ActivateFieldTrialEntryWhileLocked(FieldTrial * field_trial)1458*635a8641SAndroid Build Coastguard Worker void FieldTrialList::ActivateFieldTrialEntryWhileLocked(
1459*635a8641SAndroid Build Coastguard Worker     FieldTrial* field_trial) {
1460*635a8641SAndroid Build Coastguard Worker   FieldTrialAllocator* allocator = global_->field_trial_allocator_.get();
1461*635a8641SAndroid Build Coastguard Worker 
1462*635a8641SAndroid Build Coastguard Worker   // Check if we're in the child process and return early if so.
1463*635a8641SAndroid Build Coastguard Worker   if (!allocator || allocator->IsReadonly())
1464*635a8641SAndroid Build Coastguard Worker     return;
1465*635a8641SAndroid Build Coastguard Worker 
1466*635a8641SAndroid Build Coastguard Worker   FieldTrial::FieldTrialRef ref = field_trial->ref_;
1467*635a8641SAndroid Build Coastguard Worker   if (ref == FieldTrialAllocator::kReferenceNull) {
1468*635a8641SAndroid Build Coastguard Worker     // It's fine to do this even if the allocator hasn't been instantiated
1469*635a8641SAndroid Build Coastguard Worker     // yet -- it'll just return early.
1470*635a8641SAndroid Build Coastguard Worker     AddToAllocatorWhileLocked(allocator, field_trial);
1471*635a8641SAndroid Build Coastguard Worker   } else {
1472*635a8641SAndroid Build Coastguard Worker     // It's also okay to do this even though the callee doesn't have a lock --
1473*635a8641SAndroid Build Coastguard Worker     // the only thing that happens on a stale read here is a slight performance
1474*635a8641SAndroid Build Coastguard Worker     // hit from the child re-synchronizing activation state.
1475*635a8641SAndroid Build Coastguard Worker     FieldTrial::FieldTrialEntry* entry =
1476*635a8641SAndroid Build Coastguard Worker         allocator->GetAsObject<FieldTrial::FieldTrialEntry>(ref);
1477*635a8641SAndroid Build Coastguard Worker     subtle::NoBarrier_Store(&entry->activated, 1);
1478*635a8641SAndroid Build Coastguard Worker   }
1479*635a8641SAndroid Build Coastguard Worker }
1480*635a8641SAndroid Build Coastguard Worker 
1481*635a8641SAndroid Build Coastguard Worker // static
1482*635a8641SAndroid Build Coastguard Worker const FieldTrial::EntropyProvider*
GetEntropyProviderForOneTimeRandomization()1483*635a8641SAndroid Build Coastguard Worker     FieldTrialList::GetEntropyProviderForOneTimeRandomization() {
1484*635a8641SAndroid Build Coastguard Worker   if (!global_) {
1485*635a8641SAndroid Build Coastguard Worker     used_without_global_ = true;
1486*635a8641SAndroid Build Coastguard Worker     return nullptr;
1487*635a8641SAndroid Build Coastguard Worker   }
1488*635a8641SAndroid Build Coastguard Worker 
1489*635a8641SAndroid Build Coastguard Worker   return global_->entropy_provider_.get();
1490*635a8641SAndroid Build Coastguard Worker }
1491*635a8641SAndroid Build Coastguard Worker 
PreLockedFind(const std::string & name)1492*635a8641SAndroid Build Coastguard Worker FieldTrial* FieldTrialList::PreLockedFind(const std::string& name) {
1493*635a8641SAndroid Build Coastguard Worker   RegistrationMap::iterator it = registered_.find(name);
1494*635a8641SAndroid Build Coastguard Worker   if (registered_.end() == it)
1495*635a8641SAndroid Build Coastguard Worker     return nullptr;
1496*635a8641SAndroid Build Coastguard Worker   return it->second;
1497*635a8641SAndroid Build Coastguard Worker }
1498*635a8641SAndroid Build Coastguard Worker 
1499*635a8641SAndroid Build Coastguard Worker // static
Register(FieldTrial * trial)1500*635a8641SAndroid Build Coastguard Worker void FieldTrialList::Register(FieldTrial* trial) {
1501*635a8641SAndroid Build Coastguard Worker   if (!global_) {
1502*635a8641SAndroid Build Coastguard Worker     used_without_global_ = true;
1503*635a8641SAndroid Build Coastguard Worker     return;
1504*635a8641SAndroid Build Coastguard Worker   }
1505*635a8641SAndroid Build Coastguard Worker   AutoLock auto_lock(global_->lock_);
1506*635a8641SAndroid Build Coastguard Worker   CHECK(!global_->PreLockedFind(trial->trial_name())) << trial->trial_name();
1507*635a8641SAndroid Build Coastguard Worker   trial->AddRef();
1508*635a8641SAndroid Build Coastguard Worker   trial->SetTrialRegistered();
1509*635a8641SAndroid Build Coastguard Worker   global_->registered_[trial->trial_name()] = trial;
1510*635a8641SAndroid Build Coastguard Worker }
1511*635a8641SAndroid Build Coastguard Worker 
1512*635a8641SAndroid Build Coastguard Worker // static
GetRegisteredTrials()1513*635a8641SAndroid Build Coastguard Worker FieldTrialList::RegistrationMap FieldTrialList::GetRegisteredTrials() {
1514*635a8641SAndroid Build Coastguard Worker   RegistrationMap output;
1515*635a8641SAndroid Build Coastguard Worker   if (global_) {
1516*635a8641SAndroid Build Coastguard Worker     AutoLock auto_lock(global_->lock_);
1517*635a8641SAndroid Build Coastguard Worker     output = global_->registered_;
1518*635a8641SAndroid Build Coastguard Worker   }
1519*635a8641SAndroid Build Coastguard Worker   return output;
1520*635a8641SAndroid Build Coastguard Worker }
1521*635a8641SAndroid Build Coastguard Worker 
1522*635a8641SAndroid Build Coastguard Worker }  // namespace base
1523