xref: /aosp_15_r20/external/cronet/base/metrics/field_trial.cc (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1*6777b538SAndroid Build Coastguard Worker // Copyright 2012 The Chromium Authors
2*6777b538SAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be
3*6777b538SAndroid Build Coastguard Worker // found in the LICENSE file.
4*6777b538SAndroid Build Coastguard Worker 
5*6777b538SAndroid Build Coastguard Worker #include "base/metrics/field_trial.h"
6*6777b538SAndroid Build Coastguard Worker 
7*6777b538SAndroid Build Coastguard Worker #include <algorithm>
8*6777b538SAndroid Build Coastguard Worker #include <string_view>
9*6777b538SAndroid Build Coastguard Worker #include <utility>
10*6777b538SAndroid Build Coastguard Worker 
11*6777b538SAndroid Build Coastguard Worker #include "base/auto_reset.h"
12*6777b538SAndroid Build Coastguard Worker #include "base/base_switches.h"
13*6777b538SAndroid Build Coastguard Worker #include "base/command_line.h"
14*6777b538SAndroid Build Coastguard Worker #include "base/containers/span.h"
15*6777b538SAndroid Build Coastguard Worker #include "base/debug/crash_logging.h"
16*6777b538SAndroid Build Coastguard Worker #include "base/logging.h"
17*6777b538SAndroid Build Coastguard Worker #include "base/memory/raw_ptr.h"
18*6777b538SAndroid Build Coastguard Worker #include "base/metrics/field_trial_param_associator.h"
19*6777b538SAndroid Build Coastguard Worker #include "base/metrics/histogram_functions.h"
20*6777b538SAndroid Build Coastguard Worker #include "base/metrics/histogram_macros.h"
21*6777b538SAndroid Build Coastguard Worker #include "base/no_destructor.h"
22*6777b538SAndroid Build Coastguard Worker #include "base/notreached.h"
23*6777b538SAndroid Build Coastguard Worker #include "base/numerics/safe_conversions.h"
24*6777b538SAndroid Build Coastguard Worker #include "base/process/memory.h"
25*6777b538SAndroid Build Coastguard Worker #include "base/process/process_handle.h"
26*6777b538SAndroid Build Coastguard Worker #include "base/process/process_info.h"
27*6777b538SAndroid Build Coastguard Worker #include "base/rand_util.h"
28*6777b538SAndroid Build Coastguard Worker #include "base/strings/strcat.h"
29*6777b538SAndroid Build Coastguard Worker #include "base/strings/string_number_conversions.h"
30*6777b538SAndroid Build Coastguard Worker 
31*6777b538SAndroid Build Coastguard Worker #include "base/strings/string_split.h"
32*6777b538SAndroid Build Coastguard Worker #include "base/strings/string_util.h"
33*6777b538SAndroid Build Coastguard Worker #include "base/strings/stringprintf.h"
34*6777b538SAndroid Build Coastguard Worker #include "base/strings/utf_string_conversions.h"
35*6777b538SAndroid Build Coastguard Worker #include "base/unguessable_token.h"
36*6777b538SAndroid Build Coastguard Worker #include "build/build_config.h"
37*6777b538SAndroid Build Coastguard Worker 
38*6777b538SAndroid Build Coastguard Worker #if BUILDFLAG(USE_BLINK)
39*6777b538SAndroid Build Coastguard Worker #include "base/memory/shared_memory_switch.h"
40*6777b538SAndroid Build Coastguard Worker #include "base/process/launch.h"
41*6777b538SAndroid Build Coastguard Worker #endif
42*6777b538SAndroid Build Coastguard Worker 
43*6777b538SAndroid Build Coastguard Worker #if BUILDFLAG(IS_APPLE) && BUILDFLAG(USE_BLINK)
44*6777b538SAndroid Build Coastguard Worker #include "base/mac/mach_port_rendezvous.h"
45*6777b538SAndroid Build Coastguard Worker #endif
46*6777b538SAndroid Build Coastguard Worker 
47*6777b538SAndroid Build Coastguard Worker #if BUILDFLAG(IS_POSIX) && BUILDFLAG(USE_BLINK)
48*6777b538SAndroid Build Coastguard Worker #include <unistd.h>  // For getppid().
49*6777b538SAndroid Build Coastguard Worker #include "base/threading/platform_thread.h"
50*6777b538SAndroid Build Coastguard Worker // On POSIX, the fd is shared using the mapping in GlobalDescriptors.
51*6777b538SAndroid Build Coastguard Worker #include "base/posix/global_descriptors.h"
52*6777b538SAndroid Build Coastguard Worker #endif
53*6777b538SAndroid Build Coastguard Worker 
54*6777b538SAndroid Build Coastguard Worker #if BUILDFLAG(IS_WIN)
55*6777b538SAndroid Build Coastguard Worker #include <windows.h>
56*6777b538SAndroid Build Coastguard Worker #endif
57*6777b538SAndroid Build Coastguard Worker 
58*6777b538SAndroid Build Coastguard Worker #if BUILDFLAG(IS_FUCHSIA)
59*6777b538SAndroid Build Coastguard Worker #include <lib/zx/vmo.h>
60*6777b538SAndroid Build Coastguard Worker #include <zircon/process.h>
61*6777b538SAndroid Build Coastguard Worker 
62*6777b538SAndroid Build Coastguard Worker #include "base/fuchsia/fuchsia_logging.h"
63*6777b538SAndroid Build Coastguard Worker #endif
64*6777b538SAndroid Build Coastguard Worker 
65*6777b538SAndroid Build Coastguard Worker namespace base {
66*6777b538SAndroid Build Coastguard Worker 
67*6777b538SAndroid Build Coastguard Worker namespace {
68*6777b538SAndroid Build Coastguard Worker 
69*6777b538SAndroid Build Coastguard Worker #if BUILDFLAG(USE_BLINK)
70*6777b538SAndroid Build Coastguard Worker using shared_memory::SharedMemoryError;
71*6777b538SAndroid Build Coastguard Worker #endif
72*6777b538SAndroid Build Coastguard Worker 
73*6777b538SAndroid Build Coastguard Worker // Define a separator character to use when creating a persistent form of an
74*6777b538SAndroid Build Coastguard Worker // instance.  This is intended for use as a command line argument, passed to a
75*6777b538SAndroid Build Coastguard Worker // second process to mimic our state (i.e., provide the same group name).
76*6777b538SAndroid Build Coastguard Worker const char kPersistentStringSeparator = '/';  // Currently a slash.
77*6777b538SAndroid Build Coastguard Worker 
78*6777b538SAndroid Build Coastguard Worker // Define a marker character to be used as a prefix to a trial name on the
79*6777b538SAndroid Build Coastguard Worker // command line which forces its activation.
80*6777b538SAndroid Build Coastguard Worker const char kActivationMarker = '*';
81*6777b538SAndroid Build Coastguard Worker 
82*6777b538SAndroid Build Coastguard Worker // Constants for the field trial allocator.
83*6777b538SAndroid Build Coastguard Worker const char kAllocatorName[] = "FieldTrialAllocator";
84*6777b538SAndroid Build Coastguard Worker 
85*6777b538SAndroid Build Coastguard Worker // We allocate 256 KiB to hold all the field trial data. This should be enough,
86*6777b538SAndroid Build Coastguard Worker // as most people use 3 - 25 KiB for field trials (as of 11/25/2016).
87*6777b538SAndroid Build Coastguard Worker // This also doesn't allocate all 256 KiB at once -- the pages only get mapped
88*6777b538SAndroid Build Coastguard Worker // to physical memory when they are touched. If the size of the allocated field
89*6777b538SAndroid Build Coastguard Worker // trials does get larger than 256 KiB, then we will drop some field trials in
90*6777b538SAndroid Build Coastguard Worker // child processes, leading to an inconsistent view between browser and child
91*6777b538SAndroid Build Coastguard Worker // processes and possibly causing crashes (see crbug.com/661617).
92*6777b538SAndroid Build Coastguard Worker const size_t kFieldTrialAllocationSize = 256 << 10;  // 256 KiB
93*6777b538SAndroid Build Coastguard Worker 
94*6777b538SAndroid Build Coastguard Worker #if BUILDFLAG(IS_APPLE) && BUILDFLAG(USE_BLINK)
95*6777b538SAndroid Build Coastguard Worker constexpr MachPortsForRendezvous::key_type kFieldTrialRendezvousKey = 'fldt';
96*6777b538SAndroid Build Coastguard Worker #endif
97*6777b538SAndroid Build Coastguard Worker 
98*6777b538SAndroid Build Coastguard Worker // Writes out string1 and then string2 to pickle.
WriteStringPair(Pickle * pickle,std::string_view string1,std::string_view string2)99*6777b538SAndroid Build Coastguard Worker void WriteStringPair(Pickle* pickle,
100*6777b538SAndroid Build Coastguard Worker                      std::string_view string1,
101*6777b538SAndroid Build Coastguard Worker                      std::string_view string2) {
102*6777b538SAndroid Build Coastguard Worker   pickle->WriteString(string1);
103*6777b538SAndroid Build Coastguard Worker   pickle->WriteString(string2);
104*6777b538SAndroid Build Coastguard Worker }
105*6777b538SAndroid Build Coastguard Worker 
106*6777b538SAndroid Build Coastguard Worker // Writes out the field trial's contents (via trial_state) to the pickle. The
107*6777b538SAndroid Build Coastguard Worker // format of the pickle looks like:
108*6777b538SAndroid Build Coastguard Worker // TrialName, GroupName, is_overridden, ParamKey1, ParamValue1, ParamKey2,
109*6777b538SAndroid Build Coastguard Worker // ParamValue2, ... If there are no parameters, then it just ends at
110*6777b538SAndroid Build Coastguard Worker // is_overridden.
PickleFieldTrial(const FieldTrial::PickleState & trial_state,Pickle * pickle)111*6777b538SAndroid Build Coastguard Worker void PickleFieldTrial(const FieldTrial::PickleState& trial_state,
112*6777b538SAndroid Build Coastguard Worker                       Pickle* pickle) {
113*6777b538SAndroid Build Coastguard Worker   WriteStringPair(pickle, *trial_state.trial_name, *trial_state.group_name);
114*6777b538SAndroid Build Coastguard Worker   pickle->WriteBool(trial_state.is_overridden);
115*6777b538SAndroid Build Coastguard Worker 
116*6777b538SAndroid Build Coastguard Worker   // Get field trial params.
117*6777b538SAndroid Build Coastguard Worker   std::map<std::string, std::string> params;
118*6777b538SAndroid Build Coastguard Worker   FieldTrialParamAssociator::GetInstance()->GetFieldTrialParamsWithoutFallback(
119*6777b538SAndroid Build Coastguard Worker       *trial_state.trial_name, *trial_state.group_name, &params);
120*6777b538SAndroid Build Coastguard Worker 
121*6777b538SAndroid Build Coastguard Worker   // Write params to pickle.
122*6777b538SAndroid Build Coastguard Worker   for (const auto& param : params)
123*6777b538SAndroid Build Coastguard Worker     WriteStringPair(pickle, param.first, param.second);
124*6777b538SAndroid Build Coastguard Worker }
125*6777b538SAndroid Build Coastguard Worker 
126*6777b538SAndroid Build Coastguard Worker // Returns the boundary value for comparing against the FieldTrial's added
127*6777b538SAndroid Build Coastguard Worker // groups for a given |divisor| (total probability) and |entropy_value|.
GetGroupBoundaryValue(FieldTrial::Probability divisor,double entropy_value)128*6777b538SAndroid Build Coastguard Worker FieldTrial::Probability GetGroupBoundaryValue(
129*6777b538SAndroid Build Coastguard Worker     FieldTrial::Probability divisor,
130*6777b538SAndroid Build Coastguard Worker     double entropy_value) {
131*6777b538SAndroid Build Coastguard Worker   // Add a tiny epsilon value to get consistent results when converting floating
132*6777b538SAndroid Build Coastguard Worker   // points to int. Without it, boundary values have inconsistent results, e.g.:
133*6777b538SAndroid Build Coastguard Worker   //
134*6777b538SAndroid Build Coastguard Worker   //   static_cast<FieldTrial::Probability>(100 * 0.56) == 56
135*6777b538SAndroid Build Coastguard Worker   //   static_cast<FieldTrial::Probability>(100 * 0.57) == 56
136*6777b538SAndroid Build Coastguard Worker   //   static_cast<FieldTrial::Probability>(100 * 0.58) == 57
137*6777b538SAndroid Build Coastguard Worker   //   static_cast<FieldTrial::Probability>(100 * 0.59) == 59
138*6777b538SAndroid Build Coastguard Worker   const double kEpsilon = 1e-8;
139*6777b538SAndroid Build Coastguard Worker   const FieldTrial::Probability result =
140*6777b538SAndroid Build Coastguard Worker       static_cast<FieldTrial::Probability>(divisor * entropy_value + kEpsilon);
141*6777b538SAndroid Build Coastguard Worker   // Ensure that adding the epsilon still results in a value < |divisor|.
142*6777b538SAndroid Build Coastguard Worker   return std::min(result, divisor - 1);
143*6777b538SAndroid Build Coastguard Worker }
144*6777b538SAndroid Build Coastguard Worker 
OnOutOfMemory(size_t size)145*6777b538SAndroid Build Coastguard Worker void OnOutOfMemory(size_t size) {
146*6777b538SAndroid Build Coastguard Worker   TerminateBecauseOutOfMemory(size);
147*6777b538SAndroid Build Coastguard Worker }
148*6777b538SAndroid Build Coastguard Worker 
AppendFieldTrialGroupToString(bool activated,std::string_view trial_name,std::string_view group_name,std::string & field_trials_string)149*6777b538SAndroid Build Coastguard Worker void AppendFieldTrialGroupToString(bool activated,
150*6777b538SAndroid Build Coastguard Worker                                    std::string_view trial_name,
151*6777b538SAndroid Build Coastguard Worker                                    std::string_view group_name,
152*6777b538SAndroid Build Coastguard Worker                                    std::string& field_trials_string) {
153*6777b538SAndroid Build Coastguard Worker   DCHECK_EQ(std::string::npos, trial_name.find(kPersistentStringSeparator))
154*6777b538SAndroid Build Coastguard Worker       << " in name " << trial_name;
155*6777b538SAndroid Build Coastguard Worker   DCHECK_EQ(std::string::npos, group_name.find(kPersistentStringSeparator))
156*6777b538SAndroid Build Coastguard Worker       << " in name " << group_name;
157*6777b538SAndroid Build Coastguard Worker 
158*6777b538SAndroid Build Coastguard Worker   if (!field_trials_string.empty()) {
159*6777b538SAndroid Build Coastguard Worker     // Add a '/' in-between field trial groups.
160*6777b538SAndroid Build Coastguard Worker     field_trials_string.push_back(kPersistentStringSeparator);
161*6777b538SAndroid Build Coastguard Worker   }
162*6777b538SAndroid Build Coastguard Worker   if (activated) {
163*6777b538SAndroid Build Coastguard Worker     field_trials_string.push_back(kActivationMarker);
164*6777b538SAndroid Build Coastguard Worker   }
165*6777b538SAndroid Build Coastguard Worker 
166*6777b538SAndroid Build Coastguard Worker   base::StrAppend(&field_trials_string,
167*6777b538SAndroid Build Coastguard Worker                   {trial_name, std::string_view(&kPersistentStringSeparator, 1),
168*6777b538SAndroid Build Coastguard Worker                    group_name});
169*6777b538SAndroid Build Coastguard Worker }
170*6777b538SAndroid Build Coastguard Worker 
171*6777b538SAndroid Build Coastguard Worker }  // namespace
172*6777b538SAndroid Build Coastguard Worker 
173*6777b538SAndroid Build Coastguard Worker // statics
174*6777b538SAndroid Build Coastguard Worker const int FieldTrial::kNotFinalized = -1;
175*6777b538SAndroid Build Coastguard Worker const int FieldTrial::kDefaultGroupNumber = 0;
176*6777b538SAndroid Build Coastguard Worker bool FieldTrial::enable_benchmarking_ = false;
177*6777b538SAndroid Build Coastguard Worker 
178*6777b538SAndroid Build Coastguard Worker //------------------------------------------------------------------------------
179*6777b538SAndroid Build Coastguard Worker // FieldTrial methods and members.
180*6777b538SAndroid Build Coastguard Worker 
181*6777b538SAndroid Build Coastguard Worker FieldTrial::EntropyProvider::~EntropyProvider() = default;
182*6777b538SAndroid Build Coastguard Worker 
GetPseudorandomValue(uint32_t salt,uint32_t output_range) const183*6777b538SAndroid Build Coastguard Worker uint32_t FieldTrial::EntropyProvider::GetPseudorandomValue(
184*6777b538SAndroid Build Coastguard Worker     uint32_t salt,
185*6777b538SAndroid Build Coastguard Worker     uint32_t output_range) const {
186*6777b538SAndroid Build Coastguard Worker   // Passing a different salt is sufficient to get a "different" result from
187*6777b538SAndroid Build Coastguard Worker   // GetEntropyForTrial (ignoring collisions).
188*6777b538SAndroid Build Coastguard Worker   double entropy_value = GetEntropyForTrial(/*trial_name=*/"", salt);
189*6777b538SAndroid Build Coastguard Worker 
190*6777b538SAndroid Build Coastguard Worker   // Convert the [0,1) double to an [0, output_range) integer.
191*6777b538SAndroid Build Coastguard Worker   return static_cast<uint32_t>(GetGroupBoundaryValue(
192*6777b538SAndroid Build Coastguard Worker       static_cast<FieldTrial::Probability>(output_range), entropy_value));
193*6777b538SAndroid Build Coastguard Worker }
194*6777b538SAndroid Build Coastguard Worker 
195*6777b538SAndroid Build Coastguard Worker FieldTrial::PickleState::PickleState() = default;
196*6777b538SAndroid Build Coastguard Worker 
197*6777b538SAndroid Build Coastguard Worker FieldTrial::PickleState::PickleState(const PickleState& other) = default;
198*6777b538SAndroid Build Coastguard Worker 
199*6777b538SAndroid Build Coastguard Worker FieldTrial::PickleState::~PickleState() = default;
200*6777b538SAndroid Build Coastguard Worker 
GetState(std::string_view & trial_name,std::string_view & group_name,bool & overridden) const201*6777b538SAndroid Build Coastguard Worker bool FieldTrial::FieldTrialEntry::GetState(std::string_view& trial_name,
202*6777b538SAndroid Build Coastguard Worker                                            std::string_view& group_name,
203*6777b538SAndroid Build Coastguard Worker                                            bool& overridden) const {
204*6777b538SAndroid Build Coastguard Worker   PickleIterator iter = GetPickleIterator();
205*6777b538SAndroid Build Coastguard Worker   return ReadHeader(iter, trial_name, group_name, overridden);
206*6777b538SAndroid Build Coastguard Worker }
207*6777b538SAndroid Build Coastguard Worker 
GetParams(std::map<std::string,std::string> * params) const208*6777b538SAndroid Build Coastguard Worker bool FieldTrial::FieldTrialEntry::GetParams(
209*6777b538SAndroid Build Coastguard Worker     std::map<std::string, std::string>* params) const {
210*6777b538SAndroid Build Coastguard Worker   PickleIterator iter = GetPickleIterator();
211*6777b538SAndroid Build Coastguard Worker   std::string_view tmp_string;
212*6777b538SAndroid Build Coastguard Worker   bool tmp_bool;
213*6777b538SAndroid Build Coastguard Worker   // Skip reading trial and group name, and overridden bit.
214*6777b538SAndroid Build Coastguard Worker   if (!ReadHeader(iter, tmp_string, tmp_string, tmp_bool)) {
215*6777b538SAndroid Build Coastguard Worker     return false;
216*6777b538SAndroid Build Coastguard Worker   }
217*6777b538SAndroid Build Coastguard Worker 
218*6777b538SAndroid Build Coastguard Worker   while (true) {
219*6777b538SAndroid Build Coastguard Worker     std::string_view key;
220*6777b538SAndroid Build Coastguard Worker     std::string_view value;
221*6777b538SAndroid Build Coastguard Worker     if (!ReadStringPair(&iter, &key, &value))
222*6777b538SAndroid Build Coastguard Worker       return key.empty();  // Non-empty is bad: got one of a pair.
223*6777b538SAndroid Build Coastguard Worker     (*params)[std::string(key)] = std::string(value);
224*6777b538SAndroid Build Coastguard Worker   }
225*6777b538SAndroid Build Coastguard Worker }
226*6777b538SAndroid Build Coastguard Worker 
GetPickleIterator() const227*6777b538SAndroid Build Coastguard Worker PickleIterator FieldTrial::FieldTrialEntry::GetPickleIterator() const {
228*6777b538SAndroid Build Coastguard Worker   Pickle pickle = Pickle::WithUnownedBuffer(
229*6777b538SAndroid Build Coastguard Worker       span(GetPickledDataPtr(), checked_cast<size_t>(pickle_size)));
230*6777b538SAndroid Build Coastguard Worker   return PickleIterator(pickle);
231*6777b538SAndroid Build Coastguard Worker }
232*6777b538SAndroid Build Coastguard Worker 
ReadHeader(PickleIterator & iter,std::string_view & trial_name,std::string_view & group_name,bool & overridden) const233*6777b538SAndroid Build Coastguard Worker bool FieldTrial::FieldTrialEntry::ReadHeader(PickleIterator& iter,
234*6777b538SAndroid Build Coastguard Worker                                              std::string_view& trial_name,
235*6777b538SAndroid Build Coastguard Worker                                              std::string_view& group_name,
236*6777b538SAndroid Build Coastguard Worker                                              bool& overridden) const {
237*6777b538SAndroid Build Coastguard Worker   return ReadStringPair(&iter, &trial_name, &group_name) &&
238*6777b538SAndroid Build Coastguard Worker          iter.ReadBool(&overridden);
239*6777b538SAndroid Build Coastguard Worker }
240*6777b538SAndroid Build Coastguard Worker 
ReadStringPair(PickleIterator * iter,std::string_view * trial_name,std::string_view * group_name) const241*6777b538SAndroid Build Coastguard Worker bool FieldTrial::FieldTrialEntry::ReadStringPair(
242*6777b538SAndroid Build Coastguard Worker     PickleIterator* iter,
243*6777b538SAndroid Build Coastguard Worker     std::string_view* trial_name,
244*6777b538SAndroid Build Coastguard Worker     std::string_view* group_name) const {
245*6777b538SAndroid Build Coastguard Worker   if (!iter->ReadStringPiece(trial_name))
246*6777b538SAndroid Build Coastguard Worker     return false;
247*6777b538SAndroid Build Coastguard Worker   if (!iter->ReadStringPiece(group_name))
248*6777b538SAndroid Build Coastguard Worker     return false;
249*6777b538SAndroid Build Coastguard Worker   return true;
250*6777b538SAndroid Build Coastguard Worker }
251*6777b538SAndroid Build Coastguard Worker 
AppendGroup(const std::string & name,Probability group_probability)252*6777b538SAndroid Build Coastguard Worker void FieldTrial::AppendGroup(const std::string& name,
253*6777b538SAndroid Build Coastguard Worker                              Probability group_probability) {
254*6777b538SAndroid Build Coastguard Worker   // When the group choice was previously forced, we only need to return the
255*6777b538SAndroid Build Coastguard Worker   // the id of the chosen group, and anything can be returned for the others.
256*6777b538SAndroid Build Coastguard Worker   if (forced_) {
257*6777b538SAndroid Build Coastguard Worker     DCHECK(!group_name_.empty());
258*6777b538SAndroid Build Coastguard Worker     if (name == group_name_) {
259*6777b538SAndroid Build Coastguard Worker       // Note that while |group_| may be equal to |kDefaultGroupNumber| on the
260*6777b538SAndroid Build Coastguard Worker       // forced trial, it will not have the same value as the default group
261*6777b538SAndroid Build Coastguard Worker       // number returned from the non-forced |FactoryGetFieldTrial()| call,
262*6777b538SAndroid Build Coastguard Worker       // which takes care to ensure that this does not happen.
263*6777b538SAndroid Build Coastguard Worker       return;
264*6777b538SAndroid Build Coastguard Worker     }
265*6777b538SAndroid Build Coastguard Worker     DCHECK_NE(next_group_number_, group_);
266*6777b538SAndroid Build Coastguard Worker     // We still return different numbers each time, in case some caller need
267*6777b538SAndroid Build Coastguard Worker     // them to be different.
268*6777b538SAndroid Build Coastguard Worker     next_group_number_++;
269*6777b538SAndroid Build Coastguard Worker     return;
270*6777b538SAndroid Build Coastguard Worker   }
271*6777b538SAndroid Build Coastguard Worker 
272*6777b538SAndroid Build Coastguard Worker   DCHECK_LE(group_probability, divisor_);
273*6777b538SAndroid Build Coastguard Worker   DCHECK_GE(group_probability, 0);
274*6777b538SAndroid Build Coastguard Worker 
275*6777b538SAndroid Build Coastguard Worker   if (enable_benchmarking_)
276*6777b538SAndroid Build Coastguard Worker     group_probability = 0;
277*6777b538SAndroid Build Coastguard Worker 
278*6777b538SAndroid Build Coastguard Worker   accumulated_group_probability_ += group_probability;
279*6777b538SAndroid Build Coastguard Worker 
280*6777b538SAndroid Build Coastguard Worker   DCHECK_LE(accumulated_group_probability_, divisor_);
281*6777b538SAndroid Build Coastguard Worker   if (group_ == kNotFinalized && accumulated_group_probability_ > random_) {
282*6777b538SAndroid Build Coastguard Worker     // This is the group that crossed the random line, so we do the assignment.
283*6777b538SAndroid Build Coastguard Worker     SetGroupChoice(name, next_group_number_);
284*6777b538SAndroid Build Coastguard Worker   }
285*6777b538SAndroid Build Coastguard Worker   next_group_number_++;
286*6777b538SAndroid Build Coastguard Worker   return;
287*6777b538SAndroid Build Coastguard Worker }
288*6777b538SAndroid Build Coastguard Worker 
Activate()289*6777b538SAndroid Build Coastguard Worker void FieldTrial::Activate() {
290*6777b538SAndroid Build Coastguard Worker   FinalizeGroupChoice();
291*6777b538SAndroid Build Coastguard Worker   if (trial_registered_)
292*6777b538SAndroid Build Coastguard Worker     FieldTrialList::NotifyFieldTrialGroupSelection(this);
293*6777b538SAndroid Build Coastguard Worker }
294*6777b538SAndroid Build Coastguard Worker 
group_name()295*6777b538SAndroid Build Coastguard Worker const std::string& FieldTrial::group_name() {
296*6777b538SAndroid Build Coastguard Worker   // Call |Activate()| to ensure group gets assigned and observers are notified.
297*6777b538SAndroid Build Coastguard Worker   Activate();
298*6777b538SAndroid Build Coastguard Worker   DCHECK(!group_name_.empty());
299*6777b538SAndroid Build Coastguard Worker   return group_name_;
300*6777b538SAndroid Build Coastguard Worker }
301*6777b538SAndroid Build Coastguard Worker 
GetGroupNameWithoutActivation()302*6777b538SAndroid Build Coastguard Worker const std::string& FieldTrial::GetGroupNameWithoutActivation() {
303*6777b538SAndroid Build Coastguard Worker   FinalizeGroupChoice();
304*6777b538SAndroid Build Coastguard Worker   return group_name_;
305*6777b538SAndroid Build Coastguard Worker }
306*6777b538SAndroid Build Coastguard Worker 
SetForced()307*6777b538SAndroid Build Coastguard Worker void FieldTrial::SetForced() {
308*6777b538SAndroid Build Coastguard Worker   // We might have been forced before (e.g., by CreateFieldTrial) and it's
309*6777b538SAndroid Build Coastguard Worker   // first come first served, e.g., command line switch has precedence.
310*6777b538SAndroid Build Coastguard Worker   if (forced_)
311*6777b538SAndroid Build Coastguard Worker     return;
312*6777b538SAndroid Build Coastguard Worker 
313*6777b538SAndroid Build Coastguard Worker   // And we must finalize the group choice before we mark ourselves as forced.
314*6777b538SAndroid Build Coastguard Worker   FinalizeGroupChoice();
315*6777b538SAndroid Build Coastguard Worker   forced_ = true;
316*6777b538SAndroid Build Coastguard Worker }
317*6777b538SAndroid Build Coastguard Worker 
IsOverridden() const318*6777b538SAndroid Build Coastguard Worker bool FieldTrial::IsOverridden() const {
319*6777b538SAndroid Build Coastguard Worker   return is_overridden_;
320*6777b538SAndroid Build Coastguard Worker }
321*6777b538SAndroid Build Coastguard Worker 
322*6777b538SAndroid Build Coastguard Worker // static
EnableBenchmarking()323*6777b538SAndroid Build Coastguard Worker void FieldTrial::EnableBenchmarking() {
324*6777b538SAndroid Build Coastguard Worker   // We don't need to see field trials created via CreateFieldTrial() for
325*6777b538SAndroid Build Coastguard Worker   // benchmarking, because such field trials have only a single group and are
326*6777b538SAndroid Build Coastguard Worker   // not affected by randomization that |enable_benchmarking_| would disable.
327*6777b538SAndroid Build Coastguard Worker   DCHECK_EQ(0u, FieldTrialList::GetRandomizedFieldTrialCount());
328*6777b538SAndroid Build Coastguard Worker   enable_benchmarking_ = true;
329*6777b538SAndroid Build Coastguard Worker }
330*6777b538SAndroid Build Coastguard Worker 
331*6777b538SAndroid Build Coastguard Worker // static
CreateSimulatedFieldTrial(std::string_view trial_name,Probability total_probability,std::string_view default_group_name,double entropy_value)332*6777b538SAndroid Build Coastguard Worker FieldTrial* FieldTrial::CreateSimulatedFieldTrial(
333*6777b538SAndroid Build Coastguard Worker     std::string_view trial_name,
334*6777b538SAndroid Build Coastguard Worker     Probability total_probability,
335*6777b538SAndroid Build Coastguard Worker     std::string_view default_group_name,
336*6777b538SAndroid Build Coastguard Worker     double entropy_value) {
337*6777b538SAndroid Build Coastguard Worker   return new FieldTrial(trial_name, total_probability, default_group_name,
338*6777b538SAndroid Build Coastguard Worker                         entropy_value, /*is_low_anonymity=*/false,
339*6777b538SAndroid Build Coastguard Worker                         /*is_overridden=*/false);
340*6777b538SAndroid Build Coastguard Worker }
341*6777b538SAndroid Build Coastguard Worker 
342*6777b538SAndroid Build Coastguard Worker // static
ParseFieldTrialsString(std::string_view trials_string,bool override_trials,std::vector<State> & entries)343*6777b538SAndroid Build Coastguard Worker bool FieldTrial::ParseFieldTrialsString(std::string_view trials_string,
344*6777b538SAndroid Build Coastguard Worker                                         bool override_trials,
345*6777b538SAndroid Build Coastguard Worker                                         std::vector<State>& entries) {
346*6777b538SAndroid Build Coastguard Worker   size_t next_item = 0;
347*6777b538SAndroid Build Coastguard Worker   while (next_item < trials_string.length()) {
348*6777b538SAndroid Build Coastguard Worker     // Parse one entry. Entries have the format
349*6777b538SAndroid Build Coastguard Worker     // TrialName1/GroupName1/TrialName2/GroupName2. Each loop parses one trial
350*6777b538SAndroid Build Coastguard Worker     // and group name.
351*6777b538SAndroid Build Coastguard Worker 
352*6777b538SAndroid Build Coastguard Worker     // Find the first delimiter starting at next_item, or quit.
353*6777b538SAndroid Build Coastguard Worker     size_t trial_name_end =
354*6777b538SAndroid Build Coastguard Worker         trials_string.find(kPersistentStringSeparator, next_item);
355*6777b538SAndroid Build Coastguard Worker     if (trial_name_end == trials_string.npos || next_item == trial_name_end) {
356*6777b538SAndroid Build Coastguard Worker       return false;
357*6777b538SAndroid Build Coastguard Worker     }
358*6777b538SAndroid Build Coastguard Worker     // Find the second delimiter, or end of string.
359*6777b538SAndroid Build Coastguard Worker     size_t group_name_end =
360*6777b538SAndroid Build Coastguard Worker         trials_string.find(kPersistentStringSeparator, trial_name_end + 1);
361*6777b538SAndroid Build Coastguard Worker     if (group_name_end == trials_string.npos) {
362*6777b538SAndroid Build Coastguard Worker       group_name_end = trials_string.length();
363*6777b538SAndroid Build Coastguard Worker     }
364*6777b538SAndroid Build Coastguard Worker     // Group names should not be empty, so quit if it is.
365*6777b538SAndroid Build Coastguard Worker     if (trial_name_end + 1 == group_name_end) {
366*6777b538SAndroid Build Coastguard Worker       return false;
367*6777b538SAndroid Build Coastguard Worker     }
368*6777b538SAndroid Build Coastguard Worker 
369*6777b538SAndroid Build Coastguard Worker     FieldTrial::State entry;
370*6777b538SAndroid Build Coastguard Worker     // Verify if the trial should be activated or not.
371*6777b538SAndroid Build Coastguard Worker     if (trials_string[next_item] == kActivationMarker) {
372*6777b538SAndroid Build Coastguard Worker       // Name cannot be only the indicator.
373*6777b538SAndroid Build Coastguard Worker       if (trial_name_end - next_item == 1) {
374*6777b538SAndroid Build Coastguard Worker         return false;
375*6777b538SAndroid Build Coastguard Worker       }
376*6777b538SAndroid Build Coastguard Worker       next_item++;
377*6777b538SAndroid Build Coastguard Worker       entry.activated = true;
378*6777b538SAndroid Build Coastguard Worker     }
379*6777b538SAndroid Build Coastguard Worker     entry.trial_name =
380*6777b538SAndroid Build Coastguard Worker         trials_string.substr(next_item, trial_name_end - next_item);
381*6777b538SAndroid Build Coastguard Worker     entry.group_name = trials_string.substr(
382*6777b538SAndroid Build Coastguard Worker         trial_name_end + 1, group_name_end - trial_name_end - 1);
383*6777b538SAndroid Build Coastguard Worker     entry.is_overridden = override_trials;
384*6777b538SAndroid Build Coastguard Worker     // The next item starts after the delimiter, if it exists.
385*6777b538SAndroid Build Coastguard Worker     next_item = group_name_end + 1;
386*6777b538SAndroid Build Coastguard Worker 
387*6777b538SAndroid Build Coastguard Worker     entries.push_back(std::move(entry));
388*6777b538SAndroid Build Coastguard Worker   }
389*6777b538SAndroid Build Coastguard Worker   return true;
390*6777b538SAndroid Build Coastguard Worker }
391*6777b538SAndroid Build Coastguard Worker 
392*6777b538SAndroid Build Coastguard Worker // static
BuildFieldTrialStateString(const std::vector<State> & states)393*6777b538SAndroid Build Coastguard Worker std::string FieldTrial::BuildFieldTrialStateString(
394*6777b538SAndroid Build Coastguard Worker     const std::vector<State>& states) {
395*6777b538SAndroid Build Coastguard Worker   std::string result;
396*6777b538SAndroid Build Coastguard Worker   for (const State& state : states) {
397*6777b538SAndroid Build Coastguard Worker     AppendFieldTrialGroupToString(state.activated, state.trial_name,
398*6777b538SAndroid Build Coastguard Worker                                   state.group_name, result);
399*6777b538SAndroid Build Coastguard Worker   }
400*6777b538SAndroid Build Coastguard Worker   return result;
401*6777b538SAndroid Build Coastguard Worker }
402*6777b538SAndroid Build Coastguard Worker 
FieldTrial(std::string_view trial_name,const Probability total_probability,std::string_view default_group_name,double entropy_value,bool is_low_anonymity,bool is_overridden)403*6777b538SAndroid Build Coastguard Worker FieldTrial::FieldTrial(std::string_view trial_name,
404*6777b538SAndroid Build Coastguard Worker                        const Probability total_probability,
405*6777b538SAndroid Build Coastguard Worker                        std::string_view default_group_name,
406*6777b538SAndroid Build Coastguard Worker                        double entropy_value,
407*6777b538SAndroid Build Coastguard Worker                        bool is_low_anonymity,
408*6777b538SAndroid Build Coastguard Worker                        bool is_overridden)
409*6777b538SAndroid Build Coastguard Worker     : trial_name_(trial_name),
410*6777b538SAndroid Build Coastguard Worker       divisor_(total_probability),
411*6777b538SAndroid Build Coastguard Worker       default_group_name_(default_group_name),
412*6777b538SAndroid Build Coastguard Worker       random_(GetGroupBoundaryValue(total_probability, entropy_value)),
413*6777b538SAndroid Build Coastguard Worker       accumulated_group_probability_(0),
414*6777b538SAndroid Build Coastguard Worker       next_group_number_(kDefaultGroupNumber + 1),
415*6777b538SAndroid Build Coastguard Worker       group_(kNotFinalized),
416*6777b538SAndroid Build Coastguard Worker       forced_(false),
417*6777b538SAndroid Build Coastguard Worker       is_overridden_(is_overridden),
418*6777b538SAndroid Build Coastguard Worker       group_reported_(false),
419*6777b538SAndroid Build Coastguard Worker       trial_registered_(false),
420*6777b538SAndroid Build Coastguard Worker       ref_(FieldTrialList::FieldTrialAllocator::kReferenceNull),
421*6777b538SAndroid Build Coastguard Worker       is_low_anonymity_(is_low_anonymity) {
422*6777b538SAndroid Build Coastguard Worker   DCHECK_GT(total_probability, 0);
423*6777b538SAndroid Build Coastguard Worker   DCHECK(!trial_name_.empty());
424*6777b538SAndroid Build Coastguard Worker   DCHECK(!default_group_name_.empty())
425*6777b538SAndroid Build Coastguard Worker       << "Trial " << trial_name << " is missing a default group name.";
426*6777b538SAndroid Build Coastguard Worker }
427*6777b538SAndroid Build Coastguard Worker 
428*6777b538SAndroid Build Coastguard Worker FieldTrial::~FieldTrial() = default;
429*6777b538SAndroid Build Coastguard Worker 
SetTrialRegistered()430*6777b538SAndroid Build Coastguard Worker void FieldTrial::SetTrialRegistered() {
431*6777b538SAndroid Build Coastguard Worker   DCHECK_EQ(kNotFinalized, group_);
432*6777b538SAndroid Build Coastguard Worker   DCHECK(!trial_registered_);
433*6777b538SAndroid Build Coastguard Worker   trial_registered_ = true;
434*6777b538SAndroid Build Coastguard Worker }
435*6777b538SAndroid Build Coastguard Worker 
SetGroupChoice(const std::string & group_name,int number)436*6777b538SAndroid Build Coastguard Worker void FieldTrial::SetGroupChoice(const std::string& group_name, int number) {
437*6777b538SAndroid Build Coastguard Worker   group_ = number;
438*6777b538SAndroid Build Coastguard Worker   if (group_name.empty())
439*6777b538SAndroid Build Coastguard Worker     StringAppendF(&group_name_, "%d", group_);
440*6777b538SAndroid Build Coastguard Worker   else
441*6777b538SAndroid Build Coastguard Worker     group_name_ = group_name;
442*6777b538SAndroid Build Coastguard Worker   DVLOG(1) << "Field trial: " << trial_name_ << " Group choice:" << group_name_;
443*6777b538SAndroid Build Coastguard Worker }
444*6777b538SAndroid Build Coastguard Worker 
FinalizeGroupChoice()445*6777b538SAndroid Build Coastguard Worker void FieldTrial::FinalizeGroupChoice() {
446*6777b538SAndroid Build Coastguard Worker   if (group_ != kNotFinalized)
447*6777b538SAndroid Build Coastguard Worker     return;
448*6777b538SAndroid Build Coastguard Worker   accumulated_group_probability_ = divisor_;
449*6777b538SAndroid Build Coastguard Worker   // Here it's OK to use |kDefaultGroupNumber| since we can't be forced and not
450*6777b538SAndroid Build Coastguard Worker   // finalized.
451*6777b538SAndroid Build Coastguard Worker   DCHECK(!forced_);
452*6777b538SAndroid Build Coastguard Worker   SetGroupChoice(default_group_name_, kDefaultGroupNumber);
453*6777b538SAndroid Build Coastguard Worker }
454*6777b538SAndroid Build Coastguard Worker 
GetActiveGroup(ActiveGroup * active_group) const455*6777b538SAndroid Build Coastguard Worker bool FieldTrial::GetActiveGroup(ActiveGroup* active_group) const {
456*6777b538SAndroid Build Coastguard Worker   if (!group_reported_)
457*6777b538SAndroid Build Coastguard Worker     return false;
458*6777b538SAndroid Build Coastguard Worker   DCHECK_NE(group_, kNotFinalized);
459*6777b538SAndroid Build Coastguard Worker   active_group->trial_name = trial_name_;
460*6777b538SAndroid Build Coastguard Worker   active_group->group_name = group_name_;
461*6777b538SAndroid Build Coastguard Worker   active_group->is_overridden = is_overridden_;
462*6777b538SAndroid Build Coastguard Worker   return true;
463*6777b538SAndroid Build Coastguard Worker }
464*6777b538SAndroid Build Coastguard Worker 
GetStateWhileLocked(PickleState * field_trial_state)465*6777b538SAndroid Build Coastguard Worker void FieldTrial::GetStateWhileLocked(PickleState* field_trial_state) {
466*6777b538SAndroid Build Coastguard Worker   FinalizeGroupChoice();
467*6777b538SAndroid Build Coastguard Worker   field_trial_state->trial_name = &trial_name_;
468*6777b538SAndroid Build Coastguard Worker   field_trial_state->group_name = &group_name_;
469*6777b538SAndroid Build Coastguard Worker   field_trial_state->activated = group_reported_;
470*6777b538SAndroid Build Coastguard Worker   field_trial_state->is_overridden = is_overridden_;
471*6777b538SAndroid Build Coastguard Worker }
472*6777b538SAndroid Build Coastguard Worker 
473*6777b538SAndroid Build Coastguard Worker //------------------------------------------------------------------------------
474*6777b538SAndroid Build Coastguard Worker // FieldTrialList methods and members.
475*6777b538SAndroid Build Coastguard Worker 
476*6777b538SAndroid Build Coastguard Worker // static
477*6777b538SAndroid Build Coastguard Worker FieldTrialList* FieldTrialList::global_ = nullptr;
478*6777b538SAndroid Build Coastguard Worker 
479*6777b538SAndroid Build Coastguard Worker FieldTrialList::Observer::~Observer() = default;
480*6777b538SAndroid Build Coastguard Worker 
FieldTrialList()481*6777b538SAndroid Build Coastguard Worker FieldTrialList::FieldTrialList() {
482*6777b538SAndroid Build Coastguard Worker   DCHECK(!global_);
483*6777b538SAndroid Build Coastguard Worker   global_ = this;
484*6777b538SAndroid Build Coastguard Worker }
485*6777b538SAndroid Build Coastguard Worker 
~FieldTrialList()486*6777b538SAndroid Build Coastguard Worker FieldTrialList::~FieldTrialList() {
487*6777b538SAndroid Build Coastguard Worker   AutoLock auto_lock(lock_);
488*6777b538SAndroid Build Coastguard Worker   while (!registered_.empty()) {
489*6777b538SAndroid Build Coastguard Worker     auto it = registered_.begin();
490*6777b538SAndroid Build Coastguard Worker     it->second->Release();
491*6777b538SAndroid Build Coastguard Worker     registered_.erase(it->first);
492*6777b538SAndroid Build Coastguard Worker   }
493*6777b538SAndroid Build Coastguard Worker   // Note: If this DCHECK fires in a test that uses ScopedFeatureList, it is
494*6777b538SAndroid Build Coastguard Worker   // likely caused by nested ScopedFeatureLists being destroyed in a different
495*6777b538SAndroid Build Coastguard Worker   // order than they are initialized.
496*6777b538SAndroid Build Coastguard Worker   if (!was_reset_) {
497*6777b538SAndroid Build Coastguard Worker     DCHECK_EQ(this, global_);
498*6777b538SAndroid Build Coastguard Worker     global_ = nullptr;
499*6777b538SAndroid Build Coastguard Worker   }
500*6777b538SAndroid Build Coastguard Worker }
501*6777b538SAndroid Build Coastguard Worker 
502*6777b538SAndroid Build Coastguard Worker // static
FactoryGetFieldTrial(std::string_view trial_name,FieldTrial::Probability total_probability,std::string_view default_group_name,const FieldTrial::EntropyProvider & entropy_provider,uint32_t randomization_seed,bool is_low_anonymity,bool is_overridden)503*6777b538SAndroid Build Coastguard Worker FieldTrial* FieldTrialList::FactoryGetFieldTrial(
504*6777b538SAndroid Build Coastguard Worker     std::string_view trial_name,
505*6777b538SAndroid Build Coastguard Worker     FieldTrial::Probability total_probability,
506*6777b538SAndroid Build Coastguard Worker     std::string_view default_group_name,
507*6777b538SAndroid Build Coastguard Worker     const FieldTrial::EntropyProvider& entropy_provider,
508*6777b538SAndroid Build Coastguard Worker     uint32_t randomization_seed,
509*6777b538SAndroid Build Coastguard Worker     bool is_low_anonymity,
510*6777b538SAndroid Build Coastguard Worker     bool is_overridden) {
511*6777b538SAndroid Build Coastguard Worker   // Check if the field trial has already been created in some other way.
512*6777b538SAndroid Build Coastguard Worker   FieldTrial* existing_trial = Find(trial_name);
513*6777b538SAndroid Build Coastguard Worker   if (existing_trial) {
514*6777b538SAndroid Build Coastguard Worker     CHECK(existing_trial->forced_);
515*6777b538SAndroid Build Coastguard Worker     return existing_trial;
516*6777b538SAndroid Build Coastguard Worker   }
517*6777b538SAndroid Build Coastguard Worker 
518*6777b538SAndroid Build Coastguard Worker   double entropy_value =
519*6777b538SAndroid Build Coastguard Worker       entropy_provider.GetEntropyForTrial(trial_name, randomization_seed);
520*6777b538SAndroid Build Coastguard Worker 
521*6777b538SAndroid Build Coastguard Worker   FieldTrial* field_trial =
522*6777b538SAndroid Build Coastguard Worker       new FieldTrial(trial_name, total_probability, default_group_name,
523*6777b538SAndroid Build Coastguard Worker                      entropy_value, is_low_anonymity, is_overridden);
524*6777b538SAndroid Build Coastguard Worker   FieldTrialList::Register(field_trial, /*is_randomized_trial=*/true);
525*6777b538SAndroid Build Coastguard Worker   return field_trial;
526*6777b538SAndroid Build Coastguard Worker }
527*6777b538SAndroid Build Coastguard Worker 
528*6777b538SAndroid Build Coastguard Worker // static
Find(std::string_view trial_name)529*6777b538SAndroid Build Coastguard Worker FieldTrial* FieldTrialList::Find(std::string_view trial_name) {
530*6777b538SAndroid Build Coastguard Worker   if (!global_)
531*6777b538SAndroid Build Coastguard Worker     return nullptr;
532*6777b538SAndroid Build Coastguard Worker   AutoLock auto_lock(global_->lock_);
533*6777b538SAndroid Build Coastguard Worker   return global_->PreLockedFind(trial_name);
534*6777b538SAndroid Build Coastguard Worker }
535*6777b538SAndroid Build Coastguard Worker 
536*6777b538SAndroid Build Coastguard Worker // static
FindFullName(std::string_view trial_name)537*6777b538SAndroid Build Coastguard Worker std::string FieldTrialList::FindFullName(std::string_view trial_name) {
538*6777b538SAndroid Build Coastguard Worker   FieldTrial* field_trial = Find(trial_name);
539*6777b538SAndroid Build Coastguard Worker   if (field_trial)
540*6777b538SAndroid Build Coastguard Worker     return field_trial->group_name();
541*6777b538SAndroid Build Coastguard Worker   return std::string();
542*6777b538SAndroid Build Coastguard Worker }
543*6777b538SAndroid Build Coastguard Worker 
544*6777b538SAndroid Build Coastguard Worker // static
TrialExists(std::string_view trial_name)545*6777b538SAndroid Build Coastguard Worker bool FieldTrialList::TrialExists(std::string_view trial_name) {
546*6777b538SAndroid Build Coastguard Worker   return Find(trial_name) != nullptr;
547*6777b538SAndroid Build Coastguard Worker }
548*6777b538SAndroid Build Coastguard Worker 
549*6777b538SAndroid Build Coastguard Worker // static
IsTrialActive(std::string_view trial_name)550*6777b538SAndroid Build Coastguard Worker bool FieldTrialList::IsTrialActive(std::string_view trial_name) {
551*6777b538SAndroid Build Coastguard Worker   FieldTrial* field_trial = Find(trial_name);
552*6777b538SAndroid Build Coastguard Worker   return field_trial && field_trial->group_reported_;
553*6777b538SAndroid Build Coastguard Worker }
554*6777b538SAndroid Build Coastguard Worker 
555*6777b538SAndroid Build Coastguard Worker // static
GetAllFieldTrialStates(PassKey<test::ScopedFeatureList>)556*6777b538SAndroid Build Coastguard Worker std::vector<FieldTrial::State> FieldTrialList::GetAllFieldTrialStates(
557*6777b538SAndroid Build Coastguard Worker     PassKey<test::ScopedFeatureList>) {
558*6777b538SAndroid Build Coastguard Worker   std::vector<FieldTrial::State> states;
559*6777b538SAndroid Build Coastguard Worker 
560*6777b538SAndroid Build Coastguard Worker   if (!global_)
561*6777b538SAndroid Build Coastguard Worker     return states;
562*6777b538SAndroid Build Coastguard Worker 
563*6777b538SAndroid Build Coastguard Worker   AutoLock auto_lock(global_->lock_);
564*6777b538SAndroid Build Coastguard Worker   for (const auto& registered : global_->registered_) {
565*6777b538SAndroid Build Coastguard Worker     FieldTrial::PickleState trial;
566*6777b538SAndroid Build Coastguard Worker     registered.second->GetStateWhileLocked(&trial);
567*6777b538SAndroid Build Coastguard Worker     DCHECK_EQ(std::string::npos,
568*6777b538SAndroid Build Coastguard Worker               trial.trial_name->find(kPersistentStringSeparator));
569*6777b538SAndroid Build Coastguard Worker     DCHECK_EQ(std::string::npos,
570*6777b538SAndroid Build Coastguard Worker               trial.group_name->find(kPersistentStringSeparator));
571*6777b538SAndroid Build Coastguard Worker     FieldTrial::State entry;
572*6777b538SAndroid Build Coastguard Worker     entry.activated = trial.activated;
573*6777b538SAndroid Build Coastguard Worker     entry.trial_name = *trial.trial_name;
574*6777b538SAndroid Build Coastguard Worker     entry.group_name = *trial.group_name;
575*6777b538SAndroid Build Coastguard Worker     states.push_back(std::move(entry));
576*6777b538SAndroid Build Coastguard Worker   }
577*6777b538SAndroid Build Coastguard Worker   return states;
578*6777b538SAndroid Build Coastguard Worker }
579*6777b538SAndroid Build Coastguard Worker 
580*6777b538SAndroid Build Coastguard Worker // static
AllStatesToString(std::string * output)581*6777b538SAndroid Build Coastguard Worker void FieldTrialList::AllStatesToString(std::string* output) {
582*6777b538SAndroid Build Coastguard Worker   if (!global_)
583*6777b538SAndroid Build Coastguard Worker     return;
584*6777b538SAndroid Build Coastguard Worker   AutoLock auto_lock(global_->lock_);
585*6777b538SAndroid Build Coastguard Worker 
586*6777b538SAndroid Build Coastguard Worker   for (const auto& registered : global_->registered_) {
587*6777b538SAndroid Build Coastguard Worker     FieldTrial::PickleState trial;
588*6777b538SAndroid Build Coastguard Worker     registered.second->GetStateWhileLocked(&trial);
589*6777b538SAndroid Build Coastguard Worker     AppendFieldTrialGroupToString(trial.activated, *trial.trial_name,
590*6777b538SAndroid Build Coastguard Worker                                   *trial.group_name, *output);
591*6777b538SAndroid Build Coastguard Worker   }
592*6777b538SAndroid Build Coastguard Worker }
593*6777b538SAndroid Build Coastguard Worker 
594*6777b538SAndroid Build Coastguard Worker // static
AllParamsToString(EscapeDataFunc encode_data_func)595*6777b538SAndroid Build Coastguard Worker std::string FieldTrialList::AllParamsToString(EscapeDataFunc encode_data_func) {
596*6777b538SAndroid Build Coastguard Worker   FieldTrialParamAssociator* params_associator =
597*6777b538SAndroid Build Coastguard Worker       FieldTrialParamAssociator::GetInstance();
598*6777b538SAndroid Build Coastguard Worker   std::string output;
599*6777b538SAndroid Build Coastguard Worker   for (const auto& registered : GetRegisteredTrials()) {
600*6777b538SAndroid Build Coastguard Worker     FieldTrial::PickleState trial;
601*6777b538SAndroid Build Coastguard Worker     registered.second->GetStateWhileLocked(&trial);
602*6777b538SAndroid Build Coastguard Worker     DCHECK_EQ(std::string::npos,
603*6777b538SAndroid Build Coastguard Worker               trial.trial_name->find(kPersistentStringSeparator));
604*6777b538SAndroid Build Coastguard Worker     DCHECK_EQ(std::string::npos,
605*6777b538SAndroid Build Coastguard Worker               trial.group_name->find(kPersistentStringSeparator));
606*6777b538SAndroid Build Coastguard Worker     std::map<std::string, std::string> params;
607*6777b538SAndroid Build Coastguard Worker     if (params_associator->GetFieldTrialParamsWithoutFallback(
608*6777b538SAndroid Build Coastguard Worker             *trial.trial_name, *trial.group_name, &params)) {
609*6777b538SAndroid Build Coastguard Worker       if (params.size() > 0) {
610*6777b538SAndroid Build Coastguard Worker         // Add comma to seprate from previous entry if it exists.
611*6777b538SAndroid Build Coastguard Worker         if (!output.empty())
612*6777b538SAndroid Build Coastguard Worker           output.append(1, ',');
613*6777b538SAndroid Build Coastguard Worker 
614*6777b538SAndroid Build Coastguard Worker         output.append(encode_data_func(*trial.trial_name));
615*6777b538SAndroid Build Coastguard Worker         output.append(1, '.');
616*6777b538SAndroid Build Coastguard Worker         output.append(encode_data_func(*trial.group_name));
617*6777b538SAndroid Build Coastguard Worker         output.append(1, ':');
618*6777b538SAndroid Build Coastguard Worker 
619*6777b538SAndroid Build Coastguard Worker         std::string param_str;
620*6777b538SAndroid Build Coastguard Worker         for (const auto& param : params) {
621*6777b538SAndroid Build Coastguard Worker           // Add separator from previous param information if it exists.
622*6777b538SAndroid Build Coastguard Worker           if (!param_str.empty()) {
623*6777b538SAndroid Build Coastguard Worker             param_str.append(1, kPersistentStringSeparator);
624*6777b538SAndroid Build Coastguard Worker           }
625*6777b538SAndroid Build Coastguard Worker           param_str.append(encode_data_func(param.first));
626*6777b538SAndroid Build Coastguard Worker           param_str.append(1, kPersistentStringSeparator);
627*6777b538SAndroid Build Coastguard Worker           param_str.append(encode_data_func(param.second));
628*6777b538SAndroid Build Coastguard Worker         }
629*6777b538SAndroid Build Coastguard Worker 
630*6777b538SAndroid Build Coastguard Worker         output.append(param_str);
631*6777b538SAndroid Build Coastguard Worker       }
632*6777b538SAndroid Build Coastguard Worker     }
633*6777b538SAndroid Build Coastguard Worker   }
634*6777b538SAndroid Build Coastguard Worker   return output;
635*6777b538SAndroid Build Coastguard Worker }
636*6777b538SAndroid Build Coastguard Worker 
637*6777b538SAndroid Build Coastguard Worker // static
GetActiveFieldTrialGroups(FieldTrial::ActiveGroups * active_groups)638*6777b538SAndroid Build Coastguard Worker void FieldTrialList::GetActiveFieldTrialGroups(
639*6777b538SAndroid Build Coastguard Worker     FieldTrial::ActiveGroups* active_groups) {
640*6777b538SAndroid Build Coastguard Worker   GetActiveFieldTrialGroupsInternal(active_groups,
641*6777b538SAndroid Build Coastguard Worker                                     /*include_low_anonymity=*/false);
642*6777b538SAndroid Build Coastguard Worker }
643*6777b538SAndroid Build Coastguard Worker 
644*6777b538SAndroid Build Coastguard Worker // static
GetActiveTrialsOfParentProcess()645*6777b538SAndroid Build Coastguard Worker std::set<std::string> FieldTrialList::GetActiveTrialsOfParentProcess() {
646*6777b538SAndroid Build Coastguard Worker   CHECK(global_);
647*6777b538SAndroid Build Coastguard Worker   CHECK(global_->create_trials_in_child_process_called_);
648*6777b538SAndroid Build Coastguard Worker 
649*6777b538SAndroid Build Coastguard Worker   std::set<std::string> result;
650*6777b538SAndroid Build Coastguard Worker   // CreateTrialsInChildProcess() may not have created the allocator if
651*6777b538SAndroid Build Coastguard Worker   // kFieldTrialHandle was not passed on the command line.
652*6777b538SAndroid Build Coastguard Worker   if (!global_->field_trial_allocator_) {
653*6777b538SAndroid Build Coastguard Worker     return result;
654*6777b538SAndroid Build Coastguard Worker   }
655*6777b538SAndroid Build Coastguard Worker 
656*6777b538SAndroid Build Coastguard Worker   FieldTrialAllocator* allocator = global_->field_trial_allocator_.get();
657*6777b538SAndroid Build Coastguard Worker   FieldTrialAllocator::Iterator mem_iter(allocator);
658*6777b538SAndroid Build Coastguard Worker   const FieldTrial::FieldTrialEntry* entry;
659*6777b538SAndroid Build Coastguard Worker   while ((entry = mem_iter.GetNextOfObject<FieldTrial::FieldTrialEntry>()) !=
660*6777b538SAndroid Build Coastguard Worker          nullptr) {
661*6777b538SAndroid Build Coastguard Worker     std::string_view trial_name;
662*6777b538SAndroid Build Coastguard Worker     std::string_view group_name;
663*6777b538SAndroid Build Coastguard Worker     bool is_overridden;
664*6777b538SAndroid Build Coastguard Worker     if (subtle::NoBarrier_Load(&entry->activated) &&
665*6777b538SAndroid Build Coastguard Worker         entry->GetState(trial_name, group_name, is_overridden)) {
666*6777b538SAndroid Build Coastguard Worker       result.emplace(trial_name);
667*6777b538SAndroid Build Coastguard Worker     }
668*6777b538SAndroid Build Coastguard Worker   }
669*6777b538SAndroid Build Coastguard Worker   return result;
670*6777b538SAndroid Build Coastguard Worker }
671*6777b538SAndroid Build Coastguard Worker 
672*6777b538SAndroid Build Coastguard Worker // static
CreateTrialsFromString(const std::string & trials_string,bool override_trials)673*6777b538SAndroid Build Coastguard Worker bool FieldTrialList::CreateTrialsFromString(const std::string& trials_string,
674*6777b538SAndroid Build Coastguard Worker                                             bool override_trials) {
675*6777b538SAndroid Build Coastguard Worker   DCHECK(global_);
676*6777b538SAndroid Build Coastguard Worker   if (trials_string.empty() || !global_)
677*6777b538SAndroid Build Coastguard Worker     return true;
678*6777b538SAndroid Build Coastguard Worker 
679*6777b538SAndroid Build Coastguard Worker   std::vector<FieldTrial::State> entries;
680*6777b538SAndroid Build Coastguard Worker   if (!FieldTrial::ParseFieldTrialsString(trials_string, override_trials,
681*6777b538SAndroid Build Coastguard Worker                                           entries)) {
682*6777b538SAndroid Build Coastguard Worker     return false;
683*6777b538SAndroid Build Coastguard Worker   }
684*6777b538SAndroid Build Coastguard Worker 
685*6777b538SAndroid Build Coastguard Worker   return CreateTrialsFromFieldTrialStatesInternal(entries);
686*6777b538SAndroid Build Coastguard Worker }
687*6777b538SAndroid Build Coastguard Worker 
688*6777b538SAndroid Build Coastguard Worker // static
CreateTrialsFromFieldTrialStates(PassKey<test::ScopedFeatureList>,const std::vector<FieldTrial::State> & entries)689*6777b538SAndroid Build Coastguard Worker bool FieldTrialList::CreateTrialsFromFieldTrialStates(
690*6777b538SAndroid Build Coastguard Worker     PassKey<test::ScopedFeatureList>,
691*6777b538SAndroid Build Coastguard Worker     const std::vector<FieldTrial::State>& entries) {
692*6777b538SAndroid Build Coastguard Worker   return CreateTrialsFromFieldTrialStatesInternal(entries);
693*6777b538SAndroid Build Coastguard Worker }
694*6777b538SAndroid Build Coastguard Worker 
695*6777b538SAndroid Build Coastguard Worker // static
CreateTrialsInChildProcess(const CommandLine & cmd_line)696*6777b538SAndroid Build Coastguard Worker void FieldTrialList::CreateTrialsInChildProcess(const CommandLine& cmd_line) {
697*6777b538SAndroid Build Coastguard Worker   CHECK(!global_->create_trials_in_child_process_called_);
698*6777b538SAndroid Build Coastguard Worker   global_->create_trials_in_child_process_called_ = true;
699*6777b538SAndroid Build Coastguard Worker 
700*6777b538SAndroid Build Coastguard Worker #if BUILDFLAG(USE_BLINK)
701*6777b538SAndroid Build Coastguard Worker   // TODO(crbug.com/867558): Change to a CHECK.
702*6777b538SAndroid Build Coastguard Worker   if (cmd_line.HasSwitch(switches::kFieldTrialHandle)) {
703*6777b538SAndroid Build Coastguard Worker     std::string switch_value =
704*6777b538SAndroid Build Coastguard Worker         cmd_line.GetSwitchValueASCII(switches::kFieldTrialHandle);
705*6777b538SAndroid Build Coastguard Worker     SharedMemoryError result = CreateTrialsFromSwitchValue(switch_value);
706*6777b538SAndroid Build Coastguard Worker     SCOPED_CRASH_KEY_NUMBER("FieldTrialList", "SharedMemoryError",
707*6777b538SAndroid Build Coastguard Worker                             static_cast<int>(result));
708*6777b538SAndroid Build Coastguard Worker     CHECK_EQ(result, SharedMemoryError::kNoError);
709*6777b538SAndroid Build Coastguard Worker   }
710*6777b538SAndroid Build Coastguard Worker #endif  // BUILDFLAG(USE_BLINK)
711*6777b538SAndroid Build Coastguard Worker }
712*6777b538SAndroid Build Coastguard Worker 
713*6777b538SAndroid Build Coastguard Worker // static
ApplyFeatureOverridesInChildProcess(FeatureList * feature_list)714*6777b538SAndroid Build Coastguard Worker void FieldTrialList::ApplyFeatureOverridesInChildProcess(
715*6777b538SAndroid Build Coastguard Worker     FeatureList* feature_list) {
716*6777b538SAndroid Build Coastguard Worker   CHECK(global_->create_trials_in_child_process_called_);
717*6777b538SAndroid Build Coastguard Worker   // TODO(crbug.com/867558): Change to a CHECK.
718*6777b538SAndroid Build Coastguard Worker   if (global_->field_trial_allocator_) {
719*6777b538SAndroid Build Coastguard Worker     feature_list->InitFromSharedMemory(global_->field_trial_allocator_.get());
720*6777b538SAndroid Build Coastguard Worker   }
721*6777b538SAndroid Build Coastguard Worker }
722*6777b538SAndroid Build Coastguard Worker 
723*6777b538SAndroid Build Coastguard Worker #if BUILDFLAG(USE_BLINK)
724*6777b538SAndroid Build Coastguard Worker // static
PopulateLaunchOptionsWithFieldTrialState(GlobalDescriptors::Key descriptor_key,ScopedFD & descriptor_to_share,CommandLine * command_line,LaunchOptions * launch_options)725*6777b538SAndroid Build Coastguard Worker void FieldTrialList::PopulateLaunchOptionsWithFieldTrialState(
726*6777b538SAndroid Build Coastguard Worker #if BUILDFLAG(IS_POSIX) && !BUILDFLAG(IS_APPLE)
727*6777b538SAndroid Build Coastguard Worker     GlobalDescriptors::Key descriptor_key,
728*6777b538SAndroid Build Coastguard Worker     ScopedFD& descriptor_to_share,
729*6777b538SAndroid Build Coastguard Worker #endif
730*6777b538SAndroid Build Coastguard Worker     CommandLine* command_line,
731*6777b538SAndroid Build Coastguard Worker     LaunchOptions* launch_options) {
732*6777b538SAndroid Build Coastguard Worker   CHECK(command_line);
733*6777b538SAndroid Build Coastguard Worker 
734*6777b538SAndroid Build Coastguard Worker   // Use shared memory to communicate field trial state to child processes.
735*6777b538SAndroid Build Coastguard Worker   // The browser is the only process that has write access to the shared memory.
736*6777b538SAndroid Build Coastguard Worker   InstantiateFieldTrialAllocatorIfNeeded();
737*6777b538SAndroid Build Coastguard Worker   CHECK(global_);
738*6777b538SAndroid Build Coastguard Worker   CHECK(global_->readonly_allocator_region_.IsValid());
739*6777b538SAndroid Build Coastguard Worker 
740*6777b538SAndroid Build Coastguard Worker   global_->field_trial_allocator_->UpdateTrackingHistograms();
741*6777b538SAndroid Build Coastguard Worker   shared_memory::AddToLaunchParameters(
742*6777b538SAndroid Build Coastguard Worker       switches::kFieldTrialHandle,
743*6777b538SAndroid Build Coastguard Worker       global_->readonly_allocator_region_.Duplicate(),
744*6777b538SAndroid Build Coastguard Worker #if BUILDFLAG(IS_APPLE)
745*6777b538SAndroid Build Coastguard Worker       kFieldTrialRendezvousKey,
746*6777b538SAndroid Build Coastguard Worker #elif BUILDFLAG(IS_POSIX)
747*6777b538SAndroid Build Coastguard Worker       descriptor_key, descriptor_to_share,
748*6777b538SAndroid Build Coastguard Worker #endif
749*6777b538SAndroid Build Coastguard Worker       command_line, launch_options);
750*6777b538SAndroid Build Coastguard Worker 
751*6777b538SAndroid Build Coastguard Worker   // Append --enable-features and --disable-features switches corresponding
752*6777b538SAndroid Build Coastguard Worker   // to the features enabled on the command-line, so that child and browser
753*6777b538SAndroid Build Coastguard Worker   // process command lines match and clearly show what has been specified
754*6777b538SAndroid Build Coastguard Worker   // explicitly by the user.
755*6777b538SAndroid Build Coastguard Worker   std::string enabled_features;
756*6777b538SAndroid Build Coastguard Worker   std::string disabled_features;
757*6777b538SAndroid Build Coastguard Worker   FeatureList::GetInstance()->GetCommandLineFeatureOverrides(
758*6777b538SAndroid Build Coastguard Worker       &enabled_features, &disabled_features);
759*6777b538SAndroid Build Coastguard Worker 
760*6777b538SAndroid Build Coastguard Worker   if (!enabled_features.empty()) {
761*6777b538SAndroid Build Coastguard Worker     command_line->AppendSwitchASCII(switches::kEnableFeatures,
762*6777b538SAndroid Build Coastguard Worker                                     enabled_features);
763*6777b538SAndroid Build Coastguard Worker   }
764*6777b538SAndroid Build Coastguard Worker   if (!disabled_features.empty()) {
765*6777b538SAndroid Build Coastguard Worker     command_line->AppendSwitchASCII(switches::kDisableFeatures,
766*6777b538SAndroid Build Coastguard Worker                                     disabled_features);
767*6777b538SAndroid Build Coastguard Worker   }
768*6777b538SAndroid Build Coastguard Worker }
769*6777b538SAndroid Build Coastguard Worker #endif  // BUILDFLAG(USE_BLINK)
770*6777b538SAndroid Build Coastguard Worker 
771*6777b538SAndroid Build Coastguard Worker // static
772*6777b538SAndroid Build Coastguard Worker ReadOnlySharedMemoryRegion
DuplicateFieldTrialSharedMemoryForTesting()773*6777b538SAndroid Build Coastguard Worker FieldTrialList::DuplicateFieldTrialSharedMemoryForTesting() {
774*6777b538SAndroid Build Coastguard Worker   if (!global_)
775*6777b538SAndroid Build Coastguard Worker     return ReadOnlySharedMemoryRegion();
776*6777b538SAndroid Build Coastguard Worker 
777*6777b538SAndroid Build Coastguard Worker   return global_->readonly_allocator_region_.Duplicate();
778*6777b538SAndroid Build Coastguard Worker }
779*6777b538SAndroid Build Coastguard Worker 
780*6777b538SAndroid Build Coastguard Worker // static
CreateFieldTrial(std::string_view name,std::string_view group_name,bool is_low_anonymity,bool is_overridden)781*6777b538SAndroid Build Coastguard Worker FieldTrial* FieldTrialList::CreateFieldTrial(std::string_view name,
782*6777b538SAndroid Build Coastguard Worker                                              std::string_view group_name,
783*6777b538SAndroid Build Coastguard Worker                                              bool is_low_anonymity,
784*6777b538SAndroid Build Coastguard Worker                                              bool is_overridden) {
785*6777b538SAndroid Build Coastguard Worker   DCHECK(global_);
786*6777b538SAndroid Build Coastguard Worker   DCHECK_GE(name.size(), 0u);
787*6777b538SAndroid Build Coastguard Worker   DCHECK_GE(group_name.size(), 0u);
788*6777b538SAndroid Build Coastguard Worker   if (name.empty() || group_name.empty() || !global_)
789*6777b538SAndroid Build Coastguard Worker     return nullptr;
790*6777b538SAndroid Build Coastguard Worker 
791*6777b538SAndroid Build Coastguard Worker   FieldTrial* field_trial = FieldTrialList::Find(name);
792*6777b538SAndroid Build Coastguard Worker   if (field_trial) {
793*6777b538SAndroid Build Coastguard Worker     // In single process mode, or when we force them from the command line,
794*6777b538SAndroid Build Coastguard Worker     // we may have already created the field trial.
795*6777b538SAndroid Build Coastguard Worker     if (field_trial->group_name_internal() != group_name)
796*6777b538SAndroid Build Coastguard Worker       return nullptr;
797*6777b538SAndroid Build Coastguard Worker     return field_trial;
798*6777b538SAndroid Build Coastguard Worker   }
799*6777b538SAndroid Build Coastguard Worker   const int kTotalProbability = 100;
800*6777b538SAndroid Build Coastguard Worker   field_trial = new FieldTrial(name, kTotalProbability, group_name, 0,
801*6777b538SAndroid Build Coastguard Worker                                is_low_anonymity, is_overridden);
802*6777b538SAndroid Build Coastguard Worker   // The group choice will be finalized in this method. So
803*6777b538SAndroid Build Coastguard Worker   // |is_randomized_trial| should be false.
804*6777b538SAndroid Build Coastguard Worker   FieldTrialList::Register(field_trial, /*is_randomized_trial=*/false);
805*6777b538SAndroid Build Coastguard Worker   // Force the trial, which will also finalize the group choice.
806*6777b538SAndroid Build Coastguard Worker   field_trial->SetForced();
807*6777b538SAndroid Build Coastguard Worker   return field_trial;
808*6777b538SAndroid Build Coastguard Worker }
809*6777b538SAndroid Build Coastguard Worker 
810*6777b538SAndroid Build Coastguard Worker // static
AddObserver(Observer * observer)811*6777b538SAndroid Build Coastguard Worker bool FieldTrialList::AddObserver(Observer* observer) {
812*6777b538SAndroid Build Coastguard Worker   return FieldTrialList::AddObserverInternal(observer,
813*6777b538SAndroid Build Coastguard Worker                                              /*include_low_anonymity=*/false);
814*6777b538SAndroid Build Coastguard Worker }
815*6777b538SAndroid Build Coastguard Worker 
816*6777b538SAndroid Build Coastguard Worker // static
RemoveObserver(Observer * observer)817*6777b538SAndroid Build Coastguard Worker void FieldTrialList::RemoveObserver(Observer* observer) {
818*6777b538SAndroid Build Coastguard Worker   FieldTrialList::RemoveObserverInternal(observer,
819*6777b538SAndroid Build Coastguard Worker                                          /*include_low_anonymity=*/false);
820*6777b538SAndroid Build Coastguard Worker }
821*6777b538SAndroid Build Coastguard Worker 
822*6777b538SAndroid Build Coastguard Worker // static
NotifyFieldTrialGroupSelection(FieldTrial * field_trial)823*6777b538SAndroid Build Coastguard Worker void FieldTrialList::NotifyFieldTrialGroupSelection(FieldTrial* field_trial) {
824*6777b538SAndroid Build Coastguard Worker   if (!global_)
825*6777b538SAndroid Build Coastguard Worker     return;
826*6777b538SAndroid Build Coastguard Worker 
827*6777b538SAndroid Build Coastguard Worker   std::vector<raw_ptr<Observer, VectorExperimental>> local_observers;
828*6777b538SAndroid Build Coastguard Worker   std::vector<raw_ptr<Observer, VectorExperimental>>
829*6777b538SAndroid Build Coastguard Worker       local_observers_including_low_anonymity;
830*6777b538SAndroid Build Coastguard Worker 
831*6777b538SAndroid Build Coastguard Worker   {
832*6777b538SAndroid Build Coastguard Worker     AutoLock auto_lock(global_->lock_);
833*6777b538SAndroid Build Coastguard Worker     if (field_trial->group_reported_)
834*6777b538SAndroid Build Coastguard Worker       return;
835*6777b538SAndroid Build Coastguard Worker     field_trial->group_reported_ = true;
836*6777b538SAndroid Build Coastguard Worker 
837*6777b538SAndroid Build Coastguard Worker     ++global_->num_ongoing_notify_field_trial_group_selection_calls_;
838*6777b538SAndroid Build Coastguard Worker 
839*6777b538SAndroid Build Coastguard Worker     ActivateFieldTrialEntryWhileLocked(field_trial);
840*6777b538SAndroid Build Coastguard Worker 
841*6777b538SAndroid Build Coastguard Worker     // Copy observers to a local variable to access outside the scope of the
842*6777b538SAndroid Build Coastguard Worker     // lock. Since removing observers concurrently with this method is
843*6777b538SAndroid Build Coastguard Worker     // disallowed, pointers should remain valid while observers are notified.
844*6777b538SAndroid Build Coastguard Worker     local_observers = global_->observers_;
845*6777b538SAndroid Build Coastguard Worker     local_observers_including_low_anonymity =
846*6777b538SAndroid Build Coastguard Worker         global_->observers_including_low_anonymity_;
847*6777b538SAndroid Build Coastguard Worker   }
848*6777b538SAndroid Build Coastguard Worker 
849*6777b538SAndroid Build Coastguard Worker   if (!field_trial->is_low_anonymity_) {
850*6777b538SAndroid Build Coastguard Worker     for (Observer* observer : local_observers) {
851*6777b538SAndroid Build Coastguard Worker       observer->OnFieldTrialGroupFinalized(*field_trial,
852*6777b538SAndroid Build Coastguard Worker                                            field_trial->group_name_internal());
853*6777b538SAndroid Build Coastguard Worker     }
854*6777b538SAndroid Build Coastguard Worker   }
855*6777b538SAndroid Build Coastguard Worker 
856*6777b538SAndroid Build Coastguard Worker   for (Observer* observer : local_observers_including_low_anonymity) {
857*6777b538SAndroid Build Coastguard Worker     observer->OnFieldTrialGroupFinalized(*field_trial,
858*6777b538SAndroid Build Coastguard Worker                                          field_trial->group_name_internal());
859*6777b538SAndroid Build Coastguard Worker   }
860*6777b538SAndroid Build Coastguard Worker 
861*6777b538SAndroid Build Coastguard Worker   int previous_num_ongoing_notify_field_trial_group_selection_calls =
862*6777b538SAndroid Build Coastguard Worker       global_->num_ongoing_notify_field_trial_group_selection_calls_--;
863*6777b538SAndroid Build Coastguard Worker   DCHECK_GT(previous_num_ongoing_notify_field_trial_group_selection_calls, 0);
864*6777b538SAndroid Build Coastguard Worker }
865*6777b538SAndroid Build Coastguard Worker 
866*6777b538SAndroid Build Coastguard Worker // static
GetFieldTrialCount()867*6777b538SAndroid Build Coastguard Worker size_t FieldTrialList::GetFieldTrialCount() {
868*6777b538SAndroid Build Coastguard Worker   if (!global_)
869*6777b538SAndroid Build Coastguard Worker     return 0;
870*6777b538SAndroid Build Coastguard Worker   AutoLock auto_lock(global_->lock_);
871*6777b538SAndroid Build Coastguard Worker   return global_->registered_.size();
872*6777b538SAndroid Build Coastguard Worker }
873*6777b538SAndroid Build Coastguard Worker 
874*6777b538SAndroid Build Coastguard Worker // static
GetRandomizedFieldTrialCount()875*6777b538SAndroid Build Coastguard Worker size_t FieldTrialList::GetRandomizedFieldTrialCount() {
876*6777b538SAndroid Build Coastguard Worker   if (!global_)
877*6777b538SAndroid Build Coastguard Worker     return 0;
878*6777b538SAndroid Build Coastguard Worker   AutoLock auto_lock(global_->lock_);
879*6777b538SAndroid Build Coastguard Worker   return global_->num_registered_randomized_trials_;
880*6777b538SAndroid Build Coastguard Worker }
881*6777b538SAndroid Build Coastguard Worker 
882*6777b538SAndroid Build Coastguard Worker // static
GetParamsFromSharedMemory(FieldTrial * field_trial,std::map<std::string,std::string> * params)883*6777b538SAndroid Build Coastguard Worker bool FieldTrialList::GetParamsFromSharedMemory(
884*6777b538SAndroid Build Coastguard Worker     FieldTrial* field_trial,
885*6777b538SAndroid Build Coastguard Worker     std::map<std::string, std::string>* params) {
886*6777b538SAndroid Build Coastguard Worker   DCHECK(global_);
887*6777b538SAndroid Build Coastguard Worker   // If the field trial allocator is not set up yet, then there are several
888*6777b538SAndroid Build Coastguard Worker   // cases:
889*6777b538SAndroid Build Coastguard Worker   //   - We are in the browser process and the allocator has not been set up
890*6777b538SAndroid Build Coastguard Worker   //   yet. If we got here, then we couldn't find the params in
891*6777b538SAndroid Build Coastguard Worker   //   FieldTrialParamAssociator, so it's definitely not here. Return false.
892*6777b538SAndroid Build Coastguard Worker   //   - Using shared memory for field trials is not enabled. If we got here,
893*6777b538SAndroid Build Coastguard Worker   //   then there's nothing in shared memory. Return false.
894*6777b538SAndroid Build Coastguard Worker   //   - We are in the child process and the allocator has not been set up yet.
895*6777b538SAndroid Build Coastguard Worker   //   If this is the case, then you are calling this too early. The field trial
896*6777b538SAndroid Build Coastguard Worker   //   allocator should get set up very early in the lifecycle. Try to see if
897*6777b538SAndroid Build Coastguard Worker   //   you can call it after it's been set up.
898*6777b538SAndroid Build Coastguard Worker   AutoLock auto_lock(global_->lock_);
899*6777b538SAndroid Build Coastguard Worker   if (!global_->field_trial_allocator_)
900*6777b538SAndroid Build Coastguard Worker     return false;
901*6777b538SAndroid Build Coastguard Worker 
902*6777b538SAndroid Build Coastguard Worker   // If ref_ isn't set, then the field trial data can't be in shared memory.
903*6777b538SAndroid Build Coastguard Worker   if (!field_trial->ref_)
904*6777b538SAndroid Build Coastguard Worker     return false;
905*6777b538SAndroid Build Coastguard Worker 
906*6777b538SAndroid Build Coastguard Worker   const FieldTrial::FieldTrialEntry* entry =
907*6777b538SAndroid Build Coastguard Worker       global_->field_trial_allocator_->GetAsObject<FieldTrial::FieldTrialEntry>(
908*6777b538SAndroid Build Coastguard Worker           field_trial->ref_);
909*6777b538SAndroid Build Coastguard Worker 
910*6777b538SAndroid Build Coastguard Worker   size_t allocated_size =
911*6777b538SAndroid Build Coastguard Worker       global_->field_trial_allocator_->GetAllocSize(field_trial->ref_);
912*6777b538SAndroid Build Coastguard Worker   uint64_t actual_size =
913*6777b538SAndroid Build Coastguard Worker       sizeof(FieldTrial::FieldTrialEntry) + entry->pickle_size;
914*6777b538SAndroid Build Coastguard Worker   if (allocated_size < actual_size)
915*6777b538SAndroid Build Coastguard Worker     return false;
916*6777b538SAndroid Build Coastguard Worker 
917*6777b538SAndroid Build Coastguard Worker   return entry->GetParams(params);
918*6777b538SAndroid Build Coastguard Worker }
919*6777b538SAndroid Build Coastguard Worker 
920*6777b538SAndroid Build Coastguard Worker // static
ClearParamsFromSharedMemoryForTesting()921*6777b538SAndroid Build Coastguard Worker void FieldTrialList::ClearParamsFromSharedMemoryForTesting() {
922*6777b538SAndroid Build Coastguard Worker   if (!global_)
923*6777b538SAndroid Build Coastguard Worker     return;
924*6777b538SAndroid Build Coastguard Worker 
925*6777b538SAndroid Build Coastguard Worker   AutoLock auto_lock(global_->lock_);
926*6777b538SAndroid Build Coastguard Worker   if (!global_->field_trial_allocator_)
927*6777b538SAndroid Build Coastguard Worker     return;
928*6777b538SAndroid Build Coastguard Worker 
929*6777b538SAndroid Build Coastguard Worker   // To clear the params, we iterate through every item in the allocator, copy
930*6777b538SAndroid Build Coastguard Worker   // just the trial and group name into a newly-allocated segment and then clear
931*6777b538SAndroid Build Coastguard Worker   // the existing item.
932*6777b538SAndroid Build Coastguard Worker   FieldTrialAllocator* allocator = global_->field_trial_allocator_.get();
933*6777b538SAndroid Build Coastguard Worker   FieldTrialAllocator::Iterator mem_iter(allocator);
934*6777b538SAndroid Build Coastguard Worker 
935*6777b538SAndroid Build Coastguard Worker   // List of refs to eventually be made iterable. We can't make it in the loop,
936*6777b538SAndroid Build Coastguard Worker   // since it would go on forever.
937*6777b538SAndroid Build Coastguard Worker   std::vector<FieldTrial::FieldTrialRef> new_refs;
938*6777b538SAndroid Build Coastguard Worker 
939*6777b538SAndroid Build Coastguard Worker   FieldTrial::FieldTrialRef prev_ref;
940*6777b538SAndroid Build Coastguard Worker   while ((prev_ref = mem_iter.GetNextOfType<FieldTrial::FieldTrialEntry>()) !=
941*6777b538SAndroid Build Coastguard Worker          FieldTrialAllocator::kReferenceNull) {
942*6777b538SAndroid Build Coastguard Worker     // Get the existing field trial entry in shared memory.
943*6777b538SAndroid Build Coastguard Worker     const FieldTrial::FieldTrialEntry* prev_entry =
944*6777b538SAndroid Build Coastguard Worker         allocator->GetAsObject<FieldTrial::FieldTrialEntry>(prev_ref);
945*6777b538SAndroid Build Coastguard Worker     std::string_view trial_name;
946*6777b538SAndroid Build Coastguard Worker     std::string_view group_name;
947*6777b538SAndroid Build Coastguard Worker     bool is_overridden;
948*6777b538SAndroid Build Coastguard Worker     if (!prev_entry->GetState(trial_name, group_name, is_overridden)) {
949*6777b538SAndroid Build Coastguard Worker       continue;
950*6777b538SAndroid Build Coastguard Worker     }
951*6777b538SAndroid Build Coastguard Worker 
952*6777b538SAndroid Build Coastguard Worker     // Write a new entry, minus the params.
953*6777b538SAndroid Build Coastguard Worker     Pickle pickle;
954*6777b538SAndroid Build Coastguard Worker     pickle.WriteString(trial_name);
955*6777b538SAndroid Build Coastguard Worker     pickle.WriteString(group_name);
956*6777b538SAndroid Build Coastguard Worker     pickle.WriteBool(is_overridden);
957*6777b538SAndroid Build Coastguard Worker 
958*6777b538SAndroid Build Coastguard Worker     if (prev_entry->pickle_size == pickle.size() &&
959*6777b538SAndroid Build Coastguard Worker         memcmp(prev_entry->GetPickledDataPtr(), pickle.data(), pickle.size()) ==
960*6777b538SAndroid Build Coastguard Worker             0) {
961*6777b538SAndroid Build Coastguard Worker       // If the new entry is going to be the exact same as the existing one,
962*6777b538SAndroid Build Coastguard Worker       // then simply keep the existing one to avoid taking extra space in the
963*6777b538SAndroid Build Coastguard Worker       // allocator. This should mean that this trial has no params.
964*6777b538SAndroid Build Coastguard Worker       std::map<std::string, std::string> params;
965*6777b538SAndroid Build Coastguard Worker       CHECK(prev_entry->GetParams(&params));
966*6777b538SAndroid Build Coastguard Worker       CHECK(params.empty());
967*6777b538SAndroid Build Coastguard Worker       continue;
968*6777b538SAndroid Build Coastguard Worker     }
969*6777b538SAndroid Build Coastguard Worker 
970*6777b538SAndroid Build Coastguard Worker     size_t total_size = sizeof(FieldTrial::FieldTrialEntry) + pickle.size();
971*6777b538SAndroid Build Coastguard Worker     FieldTrial::FieldTrialEntry* new_entry =
972*6777b538SAndroid Build Coastguard Worker         allocator->New<FieldTrial::FieldTrialEntry>(total_size);
973*6777b538SAndroid Build Coastguard Worker     DCHECK(new_entry)
974*6777b538SAndroid Build Coastguard Worker         << "Failed to allocate a new entry, likely because the allocator is "
975*6777b538SAndroid Build Coastguard Worker            "full. Consider increasing kFieldTrialAllocationSize.";
976*6777b538SAndroid Build Coastguard Worker     subtle::NoBarrier_Store(&new_entry->activated,
977*6777b538SAndroid Build Coastguard Worker                             subtle::NoBarrier_Load(&prev_entry->activated));
978*6777b538SAndroid Build Coastguard Worker     new_entry->pickle_size = pickle.size();
979*6777b538SAndroid Build Coastguard Worker 
980*6777b538SAndroid Build Coastguard Worker     // TODO(lawrencewu): Modify base::Pickle to be able to write over a section
981*6777b538SAndroid Build Coastguard Worker     // in memory, so we can avoid this memcpy.
982*6777b538SAndroid Build Coastguard Worker     memcpy(new_entry->GetPickledDataPtr(), pickle.data(), pickle.size());
983*6777b538SAndroid Build Coastguard Worker 
984*6777b538SAndroid Build Coastguard Worker     // Update the ref on the field trial and add it to the list to be made
985*6777b538SAndroid Build Coastguard Worker     // iterable.
986*6777b538SAndroid Build Coastguard Worker     FieldTrial::FieldTrialRef new_ref = allocator->GetAsReference(new_entry);
987*6777b538SAndroid Build Coastguard Worker     FieldTrial* trial = global_->PreLockedFind(trial_name);
988*6777b538SAndroid Build Coastguard Worker     trial->ref_ = new_ref;
989*6777b538SAndroid Build Coastguard Worker     new_refs.push_back(new_ref);
990*6777b538SAndroid Build Coastguard Worker 
991*6777b538SAndroid Build Coastguard Worker     // Mark the existing entry as unused.
992*6777b538SAndroid Build Coastguard Worker     allocator->ChangeType(prev_ref, 0,
993*6777b538SAndroid Build Coastguard Worker                           FieldTrial::FieldTrialEntry::kPersistentTypeId,
994*6777b538SAndroid Build Coastguard Worker                           /*clear=*/false);
995*6777b538SAndroid Build Coastguard Worker   }
996*6777b538SAndroid Build Coastguard Worker 
997*6777b538SAndroid Build Coastguard Worker   for (const auto& ref : new_refs) {
998*6777b538SAndroid Build Coastguard Worker     allocator->MakeIterable(ref);
999*6777b538SAndroid Build Coastguard Worker   }
1000*6777b538SAndroid Build Coastguard Worker }
1001*6777b538SAndroid Build Coastguard Worker 
1002*6777b538SAndroid Build Coastguard Worker // static
DumpAllFieldTrialsToPersistentAllocator(PersistentMemoryAllocator * allocator)1003*6777b538SAndroid Build Coastguard Worker void FieldTrialList::DumpAllFieldTrialsToPersistentAllocator(
1004*6777b538SAndroid Build Coastguard Worker     PersistentMemoryAllocator* allocator) {
1005*6777b538SAndroid Build Coastguard Worker   if (!global_)
1006*6777b538SAndroid Build Coastguard Worker     return;
1007*6777b538SAndroid Build Coastguard Worker   AutoLock auto_lock(global_->lock_);
1008*6777b538SAndroid Build Coastguard Worker   for (const auto& registered : global_->registered_) {
1009*6777b538SAndroid Build Coastguard Worker     AddToAllocatorWhileLocked(allocator, registered.second);
1010*6777b538SAndroid Build Coastguard Worker   }
1011*6777b538SAndroid Build Coastguard Worker }
1012*6777b538SAndroid Build Coastguard Worker 
1013*6777b538SAndroid Build Coastguard Worker // static
1014*6777b538SAndroid Build Coastguard Worker std::vector<const FieldTrial::FieldTrialEntry*>
GetAllFieldTrialsFromPersistentAllocator(PersistentMemoryAllocator const & allocator)1015*6777b538SAndroid Build Coastguard Worker FieldTrialList::GetAllFieldTrialsFromPersistentAllocator(
1016*6777b538SAndroid Build Coastguard Worker     PersistentMemoryAllocator const& allocator) {
1017*6777b538SAndroid Build Coastguard Worker   std::vector<const FieldTrial::FieldTrialEntry*> entries;
1018*6777b538SAndroid Build Coastguard Worker   FieldTrialAllocator::Iterator iter(&allocator);
1019*6777b538SAndroid Build Coastguard Worker   const FieldTrial::FieldTrialEntry* entry;
1020*6777b538SAndroid Build Coastguard Worker   while ((entry = iter.GetNextOfObject<FieldTrial::FieldTrialEntry>()) !=
1021*6777b538SAndroid Build Coastguard Worker          nullptr) {
1022*6777b538SAndroid Build Coastguard Worker     entries.push_back(entry);
1023*6777b538SAndroid Build Coastguard Worker   }
1024*6777b538SAndroid Build Coastguard Worker   return entries;
1025*6777b538SAndroid Build Coastguard Worker }
1026*6777b538SAndroid Build Coastguard Worker 
1027*6777b538SAndroid Build Coastguard Worker // static
GetInstance()1028*6777b538SAndroid Build Coastguard Worker FieldTrialList* FieldTrialList::GetInstance() {
1029*6777b538SAndroid Build Coastguard Worker   return global_;
1030*6777b538SAndroid Build Coastguard Worker }
1031*6777b538SAndroid Build Coastguard Worker 
1032*6777b538SAndroid Build Coastguard Worker // static
ResetInstance()1033*6777b538SAndroid Build Coastguard Worker FieldTrialList* FieldTrialList::ResetInstance() {
1034*6777b538SAndroid Build Coastguard Worker   FieldTrialList* instance = global_;
1035*6777b538SAndroid Build Coastguard Worker   instance->was_reset_ = true;
1036*6777b538SAndroid Build Coastguard Worker   global_ = nullptr;
1037*6777b538SAndroid Build Coastguard Worker   return instance;
1038*6777b538SAndroid Build Coastguard Worker }
1039*6777b538SAndroid Build Coastguard Worker 
1040*6777b538SAndroid Build Coastguard Worker // static
BackupInstanceForTesting()1041*6777b538SAndroid Build Coastguard Worker FieldTrialList* FieldTrialList::BackupInstanceForTesting() {
1042*6777b538SAndroid Build Coastguard Worker   FieldTrialList* instance = global_;
1043*6777b538SAndroid Build Coastguard Worker   global_ = nullptr;
1044*6777b538SAndroid Build Coastguard Worker   return instance;
1045*6777b538SAndroid Build Coastguard Worker }
1046*6777b538SAndroid Build Coastguard Worker 
1047*6777b538SAndroid Build Coastguard Worker // static
RestoreInstanceForTesting(FieldTrialList * instance)1048*6777b538SAndroid Build Coastguard Worker void FieldTrialList::RestoreInstanceForTesting(FieldTrialList* instance) {
1049*6777b538SAndroid Build Coastguard Worker   global_ = instance;
1050*6777b538SAndroid Build Coastguard Worker }
1051*6777b538SAndroid Build Coastguard Worker 
1052*6777b538SAndroid Build Coastguard Worker #if BUILDFLAG(USE_BLINK)
1053*6777b538SAndroid Build Coastguard Worker 
1054*6777b538SAndroid Build Coastguard Worker // static
CreateTrialsFromSwitchValue(const std::string & switch_value)1055*6777b538SAndroid Build Coastguard Worker SharedMemoryError FieldTrialList::CreateTrialsFromSwitchValue(
1056*6777b538SAndroid Build Coastguard Worker     const std::string& switch_value) {
1057*6777b538SAndroid Build Coastguard Worker   auto shm = shared_memory::ReadOnlySharedMemoryRegionFrom(switch_value);
1058*6777b538SAndroid Build Coastguard Worker   if (!shm.has_value()) {
1059*6777b538SAndroid Build Coastguard Worker     return shm.error();
1060*6777b538SAndroid Build Coastguard Worker   }
1061*6777b538SAndroid Build Coastguard Worker   if (!FieldTrialList::CreateTrialsFromSharedMemoryRegion(shm.value())) {
1062*6777b538SAndroid Build Coastguard Worker     return SharedMemoryError::kCreateTrialsFailed;
1063*6777b538SAndroid Build Coastguard Worker   }
1064*6777b538SAndroid Build Coastguard Worker   return SharedMemoryError::kNoError;
1065*6777b538SAndroid Build Coastguard Worker }
1066*6777b538SAndroid Build Coastguard Worker 
1067*6777b538SAndroid Build Coastguard Worker #endif  // BUILDFLAG(USE_BLINK)
1068*6777b538SAndroid Build Coastguard Worker 
1069*6777b538SAndroid Build Coastguard Worker // static
CreateTrialsFromSharedMemoryRegion(const ReadOnlySharedMemoryRegion & shm_region)1070*6777b538SAndroid Build Coastguard Worker bool FieldTrialList::CreateTrialsFromSharedMemoryRegion(
1071*6777b538SAndroid Build Coastguard Worker     const ReadOnlySharedMemoryRegion& shm_region) {
1072*6777b538SAndroid Build Coastguard Worker   ReadOnlySharedMemoryMapping shm_mapping =
1073*6777b538SAndroid Build Coastguard Worker       shm_region.MapAt(0, kFieldTrialAllocationSize);
1074*6777b538SAndroid Build Coastguard Worker   if (!shm_mapping.IsValid())
1075*6777b538SAndroid Build Coastguard Worker     OnOutOfMemory(kFieldTrialAllocationSize);
1076*6777b538SAndroid Build Coastguard Worker 
1077*6777b538SAndroid Build Coastguard Worker   return FieldTrialList::CreateTrialsFromSharedMemoryMapping(
1078*6777b538SAndroid Build Coastguard Worker       std::move(shm_mapping));
1079*6777b538SAndroid Build Coastguard Worker }
1080*6777b538SAndroid Build Coastguard Worker 
1081*6777b538SAndroid Build Coastguard Worker // static
CreateTrialsFromSharedMemoryMapping(ReadOnlySharedMemoryMapping shm_mapping)1082*6777b538SAndroid Build Coastguard Worker bool FieldTrialList::CreateTrialsFromSharedMemoryMapping(
1083*6777b538SAndroid Build Coastguard Worker     ReadOnlySharedMemoryMapping shm_mapping) {
1084*6777b538SAndroid Build Coastguard Worker   global_->field_trial_allocator_ =
1085*6777b538SAndroid Build Coastguard Worker       std::make_unique<ReadOnlySharedPersistentMemoryAllocator>(
1086*6777b538SAndroid Build Coastguard Worker           std::move(shm_mapping), 0, kAllocatorName);
1087*6777b538SAndroid Build Coastguard Worker   FieldTrialAllocator* shalloc = global_->field_trial_allocator_.get();
1088*6777b538SAndroid Build Coastguard Worker   FieldTrialAllocator::Iterator mem_iter(shalloc);
1089*6777b538SAndroid Build Coastguard Worker 
1090*6777b538SAndroid Build Coastguard Worker   const FieldTrial::FieldTrialEntry* entry;
1091*6777b538SAndroid Build Coastguard Worker   while ((entry = mem_iter.GetNextOfObject<FieldTrial::FieldTrialEntry>()) !=
1092*6777b538SAndroid Build Coastguard Worker          nullptr) {
1093*6777b538SAndroid Build Coastguard Worker     std::string_view trial_name;
1094*6777b538SAndroid Build Coastguard Worker     std::string_view group_name;
1095*6777b538SAndroid Build Coastguard Worker     bool is_overridden;
1096*6777b538SAndroid Build Coastguard Worker     if (!entry->GetState(trial_name, group_name, is_overridden)) {
1097*6777b538SAndroid Build Coastguard Worker       return false;
1098*6777b538SAndroid Build Coastguard Worker     }
1099*6777b538SAndroid Build Coastguard Worker     // TODO(crbug.com/1431156): Don't set is_low_anonymity=false, but instead
1100*6777b538SAndroid Build Coastguard Worker     // propagate the is_low_anonymity state to the child process.
1101*6777b538SAndroid Build Coastguard Worker     FieldTrial* trial = CreateFieldTrial(
1102*6777b538SAndroid Build Coastguard Worker         trial_name, group_name, /*is_low_anonymity=*/false, is_overridden);
1103*6777b538SAndroid Build Coastguard Worker     trial->ref_ = mem_iter.GetAsReference(entry);
1104*6777b538SAndroid Build Coastguard Worker     if (subtle::NoBarrier_Load(&entry->activated)) {
1105*6777b538SAndroid Build Coastguard Worker       // Mark the trial as "used" and notify observers, if any.
1106*6777b538SAndroid Build Coastguard Worker       // This is useful to ensure that field trials created in child
1107*6777b538SAndroid Build Coastguard Worker       // processes are properly reported in crash reports.
1108*6777b538SAndroid Build Coastguard Worker       trial->Activate();
1109*6777b538SAndroid Build Coastguard Worker     }
1110*6777b538SAndroid Build Coastguard Worker   }
1111*6777b538SAndroid Build Coastguard Worker   return true;
1112*6777b538SAndroid Build Coastguard Worker }
1113*6777b538SAndroid Build Coastguard Worker 
1114*6777b538SAndroid Build Coastguard Worker // static
InstantiateFieldTrialAllocatorIfNeeded()1115*6777b538SAndroid Build Coastguard Worker void FieldTrialList::InstantiateFieldTrialAllocatorIfNeeded() {
1116*6777b538SAndroid Build Coastguard Worker   if (!global_)
1117*6777b538SAndroid Build Coastguard Worker     return;
1118*6777b538SAndroid Build Coastguard Worker 
1119*6777b538SAndroid Build Coastguard Worker   AutoLock auto_lock(global_->lock_);
1120*6777b538SAndroid Build Coastguard Worker   // Create the allocator if not already created and add all existing trials.
1121*6777b538SAndroid Build Coastguard Worker   if (global_->field_trial_allocator_ != nullptr)
1122*6777b538SAndroid Build Coastguard Worker     return;
1123*6777b538SAndroid Build Coastguard Worker 
1124*6777b538SAndroid Build Coastguard Worker   MappedReadOnlyRegion shm =
1125*6777b538SAndroid Build Coastguard Worker       ReadOnlySharedMemoryRegion::Create(kFieldTrialAllocationSize);
1126*6777b538SAndroid Build Coastguard Worker 
1127*6777b538SAndroid Build Coastguard Worker   if (!shm.IsValid())
1128*6777b538SAndroid Build Coastguard Worker     OnOutOfMemory(kFieldTrialAllocationSize);
1129*6777b538SAndroid Build Coastguard Worker 
1130*6777b538SAndroid Build Coastguard Worker   global_->field_trial_allocator_ =
1131*6777b538SAndroid Build Coastguard Worker       std::make_unique<WritableSharedPersistentMemoryAllocator>(
1132*6777b538SAndroid Build Coastguard Worker           std::move(shm.mapping), 0, kAllocatorName);
1133*6777b538SAndroid Build Coastguard Worker   global_->field_trial_allocator_->CreateTrackingHistograms(kAllocatorName);
1134*6777b538SAndroid Build Coastguard Worker 
1135*6777b538SAndroid Build Coastguard Worker   // Add all existing field trials.
1136*6777b538SAndroid Build Coastguard Worker   for (const auto& registered : global_->registered_) {
1137*6777b538SAndroid Build Coastguard Worker     AddToAllocatorWhileLocked(global_->field_trial_allocator_.get(),
1138*6777b538SAndroid Build Coastguard Worker                               registered.second);
1139*6777b538SAndroid Build Coastguard Worker   }
1140*6777b538SAndroid Build Coastguard Worker 
1141*6777b538SAndroid Build Coastguard Worker   // Add all existing features.
1142*6777b538SAndroid Build Coastguard Worker   FeatureList::GetInstance()->AddFeaturesToAllocator(
1143*6777b538SAndroid Build Coastguard Worker       global_->field_trial_allocator_.get());
1144*6777b538SAndroid Build Coastguard Worker 
1145*6777b538SAndroid Build Coastguard Worker   global_->readonly_allocator_region_ = std::move(shm.region);
1146*6777b538SAndroid Build Coastguard Worker }
1147*6777b538SAndroid Build Coastguard Worker 
1148*6777b538SAndroid Build Coastguard Worker // static
AddToAllocatorWhileLocked(PersistentMemoryAllocator * allocator,FieldTrial * field_trial)1149*6777b538SAndroid Build Coastguard Worker void FieldTrialList::AddToAllocatorWhileLocked(
1150*6777b538SAndroid Build Coastguard Worker     PersistentMemoryAllocator* allocator,
1151*6777b538SAndroid Build Coastguard Worker     FieldTrial* field_trial) {
1152*6777b538SAndroid Build Coastguard Worker   // Don't do anything if the allocator hasn't been instantiated yet.
1153*6777b538SAndroid Build Coastguard Worker   if (allocator == nullptr)
1154*6777b538SAndroid Build Coastguard Worker     return;
1155*6777b538SAndroid Build Coastguard Worker 
1156*6777b538SAndroid Build Coastguard Worker   // Or if the allocator is read only, which means we are in a child process and
1157*6777b538SAndroid Build Coastguard Worker   // shouldn't be writing to it.
1158*6777b538SAndroid Build Coastguard Worker   if (allocator->IsReadonly())
1159*6777b538SAndroid Build Coastguard Worker     return;
1160*6777b538SAndroid Build Coastguard Worker 
1161*6777b538SAndroid Build Coastguard Worker   FieldTrial::PickleState trial_state;
1162*6777b538SAndroid Build Coastguard Worker   field_trial->GetStateWhileLocked(&trial_state);
1163*6777b538SAndroid Build Coastguard Worker 
1164*6777b538SAndroid Build Coastguard Worker   // Or if we've already added it. We must check after GetState since it can
1165*6777b538SAndroid Build Coastguard Worker   // also add to the allocator.
1166*6777b538SAndroid Build Coastguard Worker   if (field_trial->ref_)
1167*6777b538SAndroid Build Coastguard Worker     return;
1168*6777b538SAndroid Build Coastguard Worker 
1169*6777b538SAndroid Build Coastguard Worker   Pickle pickle;
1170*6777b538SAndroid Build Coastguard Worker   PickleFieldTrial(trial_state, &pickle);
1171*6777b538SAndroid Build Coastguard Worker 
1172*6777b538SAndroid Build Coastguard Worker   size_t total_size = sizeof(FieldTrial::FieldTrialEntry) + pickle.size();
1173*6777b538SAndroid Build Coastguard Worker   FieldTrial::FieldTrialRef ref = allocator->Allocate(
1174*6777b538SAndroid Build Coastguard Worker       total_size, FieldTrial::FieldTrialEntry::kPersistentTypeId);
1175*6777b538SAndroid Build Coastguard Worker   if (ref == FieldTrialAllocator::kReferenceNull) {
1176*6777b538SAndroid Build Coastguard Worker     NOTREACHED();
1177*6777b538SAndroid Build Coastguard Worker     return;
1178*6777b538SAndroid Build Coastguard Worker   }
1179*6777b538SAndroid Build Coastguard Worker 
1180*6777b538SAndroid Build Coastguard Worker   FieldTrial::FieldTrialEntry* entry =
1181*6777b538SAndroid Build Coastguard Worker       allocator->GetAsObject<FieldTrial::FieldTrialEntry>(ref);
1182*6777b538SAndroid Build Coastguard Worker   subtle::NoBarrier_Store(&entry->activated, trial_state.activated);
1183*6777b538SAndroid Build Coastguard Worker   entry->pickle_size = pickle.size();
1184*6777b538SAndroid Build Coastguard Worker 
1185*6777b538SAndroid Build Coastguard Worker   // TODO(lawrencewu): Modify base::Pickle to be able to write over a section in
1186*6777b538SAndroid Build Coastguard Worker   // memory, so we can avoid this memcpy.
1187*6777b538SAndroid Build Coastguard Worker   memcpy(entry->GetPickledDataPtr(), pickle.data(), pickle.size());
1188*6777b538SAndroid Build Coastguard Worker 
1189*6777b538SAndroid Build Coastguard Worker   allocator->MakeIterable(ref);
1190*6777b538SAndroid Build Coastguard Worker   field_trial->ref_ = ref;
1191*6777b538SAndroid Build Coastguard Worker }
1192*6777b538SAndroid Build Coastguard Worker 
1193*6777b538SAndroid Build Coastguard Worker // static
ActivateFieldTrialEntryWhileLocked(FieldTrial * field_trial)1194*6777b538SAndroid Build Coastguard Worker void FieldTrialList::ActivateFieldTrialEntryWhileLocked(
1195*6777b538SAndroid Build Coastguard Worker     FieldTrial* field_trial) {
1196*6777b538SAndroid Build Coastguard Worker   FieldTrialAllocator* allocator = global_->field_trial_allocator_.get();
1197*6777b538SAndroid Build Coastguard Worker 
1198*6777b538SAndroid Build Coastguard Worker   // Check if we're in the child process and return early if so.
1199*6777b538SAndroid Build Coastguard Worker   if (!allocator || allocator->IsReadonly())
1200*6777b538SAndroid Build Coastguard Worker     return;
1201*6777b538SAndroid Build Coastguard Worker 
1202*6777b538SAndroid Build Coastguard Worker   FieldTrial::FieldTrialRef ref = field_trial->ref_;
1203*6777b538SAndroid Build Coastguard Worker   if (ref == FieldTrialAllocator::kReferenceNull) {
1204*6777b538SAndroid Build Coastguard Worker     // It's fine to do this even if the allocator hasn't been instantiated
1205*6777b538SAndroid Build Coastguard Worker     // yet -- it'll just return early.
1206*6777b538SAndroid Build Coastguard Worker     AddToAllocatorWhileLocked(allocator, field_trial);
1207*6777b538SAndroid Build Coastguard Worker   } else {
1208*6777b538SAndroid Build Coastguard Worker     // It's also okay to do this even though the callee doesn't have a lock --
1209*6777b538SAndroid Build Coastguard Worker     // the only thing that happens on a stale read here is a slight performance
1210*6777b538SAndroid Build Coastguard Worker     // hit from the child re-synchronizing activation state.
1211*6777b538SAndroid Build Coastguard Worker     FieldTrial::FieldTrialEntry* entry =
1212*6777b538SAndroid Build Coastguard Worker         allocator->GetAsObject<FieldTrial::FieldTrialEntry>(ref);
1213*6777b538SAndroid Build Coastguard Worker     subtle::NoBarrier_Store(&entry->activated, 1);
1214*6777b538SAndroid Build Coastguard Worker   }
1215*6777b538SAndroid Build Coastguard Worker }
1216*6777b538SAndroid Build Coastguard Worker 
PreLockedFind(std::string_view name)1217*6777b538SAndroid Build Coastguard Worker FieldTrial* FieldTrialList::PreLockedFind(std::string_view name) {
1218*6777b538SAndroid Build Coastguard Worker   auto it = registered_.find(name);
1219*6777b538SAndroid Build Coastguard Worker   if (registered_.end() == it)
1220*6777b538SAndroid Build Coastguard Worker     return nullptr;
1221*6777b538SAndroid Build Coastguard Worker   return it->second;
1222*6777b538SAndroid Build Coastguard Worker }
1223*6777b538SAndroid Build Coastguard Worker 
1224*6777b538SAndroid Build Coastguard Worker // static
Register(FieldTrial * trial,bool is_randomized_trial)1225*6777b538SAndroid Build Coastguard Worker void FieldTrialList::Register(FieldTrial* trial, bool is_randomized_trial) {
1226*6777b538SAndroid Build Coastguard Worker   DCHECK(global_);
1227*6777b538SAndroid Build Coastguard Worker 
1228*6777b538SAndroid Build Coastguard Worker   AutoLock auto_lock(global_->lock_);
1229*6777b538SAndroid Build Coastguard Worker   CHECK(!global_->PreLockedFind(trial->trial_name())) << trial->trial_name();
1230*6777b538SAndroid Build Coastguard Worker   trial->AddRef();
1231*6777b538SAndroid Build Coastguard Worker   trial->SetTrialRegistered();
1232*6777b538SAndroid Build Coastguard Worker   global_->registered_[trial->trial_name()] = trial;
1233*6777b538SAndroid Build Coastguard Worker 
1234*6777b538SAndroid Build Coastguard Worker   if (is_randomized_trial)
1235*6777b538SAndroid Build Coastguard Worker     ++global_->num_registered_randomized_trials_;
1236*6777b538SAndroid Build Coastguard Worker }
1237*6777b538SAndroid Build Coastguard Worker 
1238*6777b538SAndroid Build Coastguard Worker // static
GetRegisteredTrials()1239*6777b538SAndroid Build Coastguard Worker FieldTrialList::RegistrationMap FieldTrialList::GetRegisteredTrials() {
1240*6777b538SAndroid Build Coastguard Worker   RegistrationMap output;
1241*6777b538SAndroid Build Coastguard Worker   if (global_) {
1242*6777b538SAndroid Build Coastguard Worker     AutoLock auto_lock(global_->lock_);
1243*6777b538SAndroid Build Coastguard Worker     output = global_->registered_;
1244*6777b538SAndroid Build Coastguard Worker   }
1245*6777b538SAndroid Build Coastguard Worker   return output;
1246*6777b538SAndroid Build Coastguard Worker }
1247*6777b538SAndroid Build Coastguard Worker 
1248*6777b538SAndroid Build Coastguard Worker // static
CreateTrialsFromFieldTrialStatesInternal(const std::vector<FieldTrial::State> & entries)1249*6777b538SAndroid Build Coastguard Worker bool FieldTrialList::CreateTrialsFromFieldTrialStatesInternal(
1250*6777b538SAndroid Build Coastguard Worker     const std::vector<FieldTrial::State>& entries) {
1251*6777b538SAndroid Build Coastguard Worker   DCHECK(global_);
1252*6777b538SAndroid Build Coastguard Worker 
1253*6777b538SAndroid Build Coastguard Worker   for (const auto& entry : entries) {
1254*6777b538SAndroid Build Coastguard Worker     FieldTrial* trial =
1255*6777b538SAndroid Build Coastguard Worker         CreateFieldTrial(entry.trial_name, entry.group_name,
1256*6777b538SAndroid Build Coastguard Worker                          /*is_low_anonymity=*/false, entry.is_overridden);
1257*6777b538SAndroid Build Coastguard Worker     if (!trial)
1258*6777b538SAndroid Build Coastguard Worker       return false;
1259*6777b538SAndroid Build Coastguard Worker     if (entry.activated) {
1260*6777b538SAndroid Build Coastguard Worker       // Mark the trial as "used" and notify observers, if any.
1261*6777b538SAndroid Build Coastguard Worker       // This is useful to ensure that field trials created in child
1262*6777b538SAndroid Build Coastguard Worker       // processes are properly reported in crash reports.
1263*6777b538SAndroid Build Coastguard Worker       trial->Activate();
1264*6777b538SAndroid Build Coastguard Worker     }
1265*6777b538SAndroid Build Coastguard Worker   }
1266*6777b538SAndroid Build Coastguard Worker   return true;
1267*6777b538SAndroid Build Coastguard Worker }
1268*6777b538SAndroid Build Coastguard Worker 
1269*6777b538SAndroid Build Coastguard Worker // static
GetActiveFieldTrialGroupsInternal(FieldTrial::ActiveGroups * active_groups,bool include_low_anonymity)1270*6777b538SAndroid Build Coastguard Worker void FieldTrialList::GetActiveFieldTrialGroupsInternal(
1271*6777b538SAndroid Build Coastguard Worker     FieldTrial::ActiveGroups* active_groups,
1272*6777b538SAndroid Build Coastguard Worker     bool include_low_anonymity) {
1273*6777b538SAndroid Build Coastguard Worker   DCHECK(active_groups->empty());
1274*6777b538SAndroid Build Coastguard Worker   if (!global_) {
1275*6777b538SAndroid Build Coastguard Worker     return;
1276*6777b538SAndroid Build Coastguard Worker   }
1277*6777b538SAndroid Build Coastguard Worker   AutoLock auto_lock(global_->lock_);
1278*6777b538SAndroid Build Coastguard Worker 
1279*6777b538SAndroid Build Coastguard Worker   for (const auto& registered : global_->registered_) {
1280*6777b538SAndroid Build Coastguard Worker     const FieldTrial& trial = *registered.second;
1281*6777b538SAndroid Build Coastguard Worker     FieldTrial::ActiveGroup active_group;
1282*6777b538SAndroid Build Coastguard Worker     if ((include_low_anonymity || !trial.is_low_anonymity_) &&
1283*6777b538SAndroid Build Coastguard Worker         trial.GetActiveGroup(&active_group)) {
1284*6777b538SAndroid Build Coastguard Worker       active_groups->push_back(active_group);
1285*6777b538SAndroid Build Coastguard Worker     }
1286*6777b538SAndroid Build Coastguard Worker   }
1287*6777b538SAndroid Build Coastguard Worker }
1288*6777b538SAndroid Build Coastguard Worker 
1289*6777b538SAndroid Build Coastguard Worker // static
AddObserverInternal(Observer * observer,bool include_low_anonymity)1290*6777b538SAndroid Build Coastguard Worker bool FieldTrialList::AddObserverInternal(Observer* observer,
1291*6777b538SAndroid Build Coastguard Worker                                          bool include_low_anonymity) {
1292*6777b538SAndroid Build Coastguard Worker   if (!global_) {
1293*6777b538SAndroid Build Coastguard Worker     return false;
1294*6777b538SAndroid Build Coastguard Worker   }
1295*6777b538SAndroid Build Coastguard Worker   AutoLock auto_lock(global_->lock_);
1296*6777b538SAndroid Build Coastguard Worker   if (include_low_anonymity) {
1297*6777b538SAndroid Build Coastguard Worker     global_->observers_including_low_anonymity_.push_back(observer);
1298*6777b538SAndroid Build Coastguard Worker   } else {
1299*6777b538SAndroid Build Coastguard Worker     global_->observers_.push_back(observer);
1300*6777b538SAndroid Build Coastguard Worker   }
1301*6777b538SAndroid Build Coastguard Worker   return true;
1302*6777b538SAndroid Build Coastguard Worker }
1303*6777b538SAndroid Build Coastguard Worker 
1304*6777b538SAndroid Build Coastguard Worker // static
RemoveObserverInternal(Observer * observer,bool include_low_anonymity)1305*6777b538SAndroid Build Coastguard Worker void FieldTrialList::RemoveObserverInternal(Observer* observer,
1306*6777b538SAndroid Build Coastguard Worker                                             bool include_low_anonymity) {
1307*6777b538SAndroid Build Coastguard Worker   if (!global_) {
1308*6777b538SAndroid Build Coastguard Worker     return;
1309*6777b538SAndroid Build Coastguard Worker   }
1310*6777b538SAndroid Build Coastguard Worker   AutoLock auto_lock(global_->lock_);
1311*6777b538SAndroid Build Coastguard Worker   std::erase(include_low_anonymity ? global_->observers_including_low_anonymity_
1312*6777b538SAndroid Build Coastguard Worker                                    : global_->observers_,
1313*6777b538SAndroid Build Coastguard Worker              observer);
1314*6777b538SAndroid Build Coastguard Worker   DCHECK_EQ(global_->num_ongoing_notify_field_trial_group_selection_calls_, 0)
1315*6777b538SAndroid Build Coastguard Worker       << "Cannot call RemoveObserver while accessing FieldTrial::group_name().";
1316*6777b538SAndroid Build Coastguard Worker }
1317*6777b538SAndroid Build Coastguard Worker 
1318*6777b538SAndroid Build Coastguard Worker }  // namespace base
1319