xref: /aosp_15_r20/external/cronet/base/feature_list.cc (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1*6777b538SAndroid Build Coastguard Worker // Copyright 2015 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/feature_list.h"
6*6777b538SAndroid Build Coastguard Worker 
7*6777b538SAndroid Build Coastguard Worker #include <stddef.h>
8*6777b538SAndroid Build Coastguard Worker 
9*6777b538SAndroid Build Coastguard Worker #include <string>
10*6777b538SAndroid Build Coastguard Worker #include <string_view>
11*6777b538SAndroid Build Coastguard Worker #include <tuple>
12*6777b538SAndroid Build Coastguard Worker 
13*6777b538SAndroid Build Coastguard Worker #include "base/base_switches.h"
14*6777b538SAndroid Build Coastguard Worker #include "base/containers/contains.h"
15*6777b538SAndroid Build Coastguard Worker #include "base/containers/span.h"
16*6777b538SAndroid Build Coastguard Worker #include "base/debug/crash_logging.h"
17*6777b538SAndroid Build Coastguard Worker #include "base/debug/dump_without_crashing.h"
18*6777b538SAndroid Build Coastguard Worker #include "base/logging.h"
19*6777b538SAndroid Build Coastguard Worker #include "base/memory/ptr_util.h"
20*6777b538SAndroid Build Coastguard Worker #include "base/memory/raw_ptr.h"
21*6777b538SAndroid Build Coastguard Worker #include "base/metrics/field_trial.h"
22*6777b538SAndroid Build Coastguard Worker #include "base/metrics/field_trial_param_associator.h"
23*6777b538SAndroid Build Coastguard Worker #include "base/metrics/field_trial_params.h"
24*6777b538SAndroid Build Coastguard Worker #include "base/metrics/persistent_memory_allocator.h"
25*6777b538SAndroid Build Coastguard Worker #include "base/no_destructor.h"
26*6777b538SAndroid Build Coastguard Worker #include "base/notreached.h"
27*6777b538SAndroid Build Coastguard Worker #include "base/pickle.h"
28*6777b538SAndroid Build Coastguard Worker #include "base/rand_util.h"
29*6777b538SAndroid Build Coastguard Worker #include "base/strings/string_split.h"
30*6777b538SAndroid Build Coastguard Worker #include "base/strings/string_util.h"
31*6777b538SAndroid Build Coastguard Worker #include "base/strings/stringprintf.h"
32*6777b538SAndroid Build Coastguard Worker #include "build/build_config.h"
33*6777b538SAndroid Build Coastguard Worker #include "build/chromeos_buildflags.h"
34*6777b538SAndroid Build Coastguard Worker 
35*6777b538SAndroid Build Coastguard Worker #if BUILDFLAG(IS_CHROMEOS_ASH)
36*6777b538SAndroid Build Coastguard Worker #include "base/feature_visitor.h"
37*6777b538SAndroid Build Coastguard Worker #endif  // BUILDFLAG(IS_CHROMEOS_ASH)
38*6777b538SAndroid Build Coastguard Worker 
39*6777b538SAndroid Build Coastguard Worker namespace base {
40*6777b538SAndroid Build Coastguard Worker 
41*6777b538SAndroid Build Coastguard Worker namespace {
42*6777b538SAndroid Build Coastguard Worker 
43*6777b538SAndroid Build Coastguard Worker // Pointer to the FeatureList instance singleton that was set via
44*6777b538SAndroid Build Coastguard Worker // FeatureList::SetInstance(). Does not use base/memory/singleton.h in order to
45*6777b538SAndroid Build Coastguard Worker // have more control over initialization timing. Leaky.
46*6777b538SAndroid Build Coastguard Worker FeatureList* g_feature_list_instance = nullptr;
47*6777b538SAndroid Build Coastguard Worker 
48*6777b538SAndroid Build Coastguard Worker // Tracks access to Feature state before FeatureList registration.
49*6777b538SAndroid Build Coastguard Worker class EarlyFeatureAccessTracker {
50*6777b538SAndroid Build Coastguard Worker  public:
GetInstance()51*6777b538SAndroid Build Coastguard Worker   static EarlyFeatureAccessTracker* GetInstance() {
52*6777b538SAndroid Build Coastguard Worker     static NoDestructor<EarlyFeatureAccessTracker> instance;
53*6777b538SAndroid Build Coastguard Worker     return instance.get();
54*6777b538SAndroid Build Coastguard Worker   }
55*6777b538SAndroid Build Coastguard Worker 
56*6777b538SAndroid Build Coastguard Worker   // Invoked when `feature` is accessed before FeatureList registration.
AccessedFeature(const Feature & feature,bool with_feature_allow_list=false)57*6777b538SAndroid Build Coastguard Worker   void AccessedFeature(const Feature& feature,
58*6777b538SAndroid Build Coastguard Worker                        bool with_feature_allow_list = false) {
59*6777b538SAndroid Build Coastguard Worker     AutoLock lock(lock_);
60*6777b538SAndroid Build Coastguard Worker     if (fail_instantly_) {
61*6777b538SAndroid Build Coastguard Worker       Fail(&feature, with_feature_allow_list);
62*6777b538SAndroid Build Coastguard Worker     } else if (!feature_) {
63*6777b538SAndroid Build Coastguard Worker       feature_ = &feature;
64*6777b538SAndroid Build Coastguard Worker       feature_had_feature_allow_list_ = with_feature_allow_list;
65*6777b538SAndroid Build Coastguard Worker     }
66*6777b538SAndroid Build Coastguard Worker   }
67*6777b538SAndroid Build Coastguard Worker 
68*6777b538SAndroid Build Coastguard Worker   // Asserts that no feature was accessed before FeatureList registration.
AssertNoAccess()69*6777b538SAndroid Build Coastguard Worker   void AssertNoAccess() {
70*6777b538SAndroid Build Coastguard Worker     AutoLock lock(lock_);
71*6777b538SAndroid Build Coastguard Worker     if (feature_) {
72*6777b538SAndroid Build Coastguard Worker       Fail(feature_, feature_had_feature_allow_list_);
73*6777b538SAndroid Build Coastguard Worker     }
74*6777b538SAndroid Build Coastguard Worker   }
75*6777b538SAndroid Build Coastguard Worker 
76*6777b538SAndroid Build Coastguard Worker   // Makes calls to AccessedFeature() fail instantly.
FailOnFeatureAccessWithoutFeatureList()77*6777b538SAndroid Build Coastguard Worker   void FailOnFeatureAccessWithoutFeatureList() {
78*6777b538SAndroid Build Coastguard Worker     AutoLock lock(lock_);
79*6777b538SAndroid Build Coastguard Worker     if (feature_) {
80*6777b538SAndroid Build Coastguard Worker       Fail(feature_, feature_had_feature_allow_list_);
81*6777b538SAndroid Build Coastguard Worker     }
82*6777b538SAndroid Build Coastguard Worker     fail_instantly_ = true;
83*6777b538SAndroid Build Coastguard Worker   }
84*6777b538SAndroid Build Coastguard Worker 
85*6777b538SAndroid Build Coastguard Worker   // Resets the state of this tracker.
Reset()86*6777b538SAndroid Build Coastguard Worker   void Reset() {
87*6777b538SAndroid Build Coastguard Worker     AutoLock lock(lock_);
88*6777b538SAndroid Build Coastguard Worker     feature_ = nullptr;
89*6777b538SAndroid Build Coastguard Worker     fail_instantly_ = false;
90*6777b538SAndroid Build Coastguard Worker   }
91*6777b538SAndroid Build Coastguard Worker 
GetFeature()92*6777b538SAndroid Build Coastguard Worker   const Feature* GetFeature() {
93*6777b538SAndroid Build Coastguard Worker     AutoLock lock(lock_);
94*6777b538SAndroid Build Coastguard Worker     return feature_.get();
95*6777b538SAndroid Build Coastguard Worker   }
96*6777b538SAndroid Build Coastguard Worker 
97*6777b538SAndroid Build Coastguard Worker  private:
Fail(const Feature * feature,bool with_feature_allow_list)98*6777b538SAndroid Build Coastguard Worker   void Fail(const Feature* feature, bool with_feature_allow_list) {
99*6777b538SAndroid Build Coastguard Worker     // TODO(crbug.com/1358639): Enable this check on all platforms.
100*6777b538SAndroid Build Coastguard Worker #if !BUILDFLAG(IS_IOS) && !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_CHROMEOS)
101*6777b538SAndroid Build Coastguard Worker #if !BUILDFLAG(IS_NACL)
102*6777b538SAndroid Build Coastguard Worker     // Create a crash key with the name of the feature accessed too early, to
103*6777b538SAndroid Build Coastguard Worker     // facilitate crash triage.
104*6777b538SAndroid Build Coastguard Worker     SCOPED_CRASH_KEY_STRING256("FeatureList", "feature-accessed-too-early",
105*6777b538SAndroid Build Coastguard Worker                                feature->name);
106*6777b538SAndroid Build Coastguard Worker     SCOPED_CRASH_KEY_BOOL("FeatureList", "early-access-allow-list",
107*6777b538SAndroid Build Coastguard Worker                           with_feature_allow_list);
108*6777b538SAndroid Build Coastguard Worker #endif  // !BUILDFLAG(IS_NACL)
109*6777b538SAndroid Build Coastguard Worker     CHECK(!feature) << "Accessed feature " << feature->name
110*6777b538SAndroid Build Coastguard Worker                     << (with_feature_allow_list
111*6777b538SAndroid Build Coastguard Worker                             ? " which is not on the allow list passed to "
112*6777b538SAndroid Build Coastguard Worker                               "SetEarlyAccessInstance()."
113*6777b538SAndroid Build Coastguard Worker                             : " before FeatureList registration.");
114*6777b538SAndroid Build Coastguard Worker #endif  // !BUILDFLAG(IS_IOS) && !BUILDFLAG(IS_ANDROID) &&
115*6777b538SAndroid Build Coastguard Worker         // !BUILDFLAG(IS_CHROMEOS)
116*6777b538SAndroid Build Coastguard Worker   }
117*6777b538SAndroid Build Coastguard Worker 
118*6777b538SAndroid Build Coastguard Worker   friend class NoDestructor<EarlyFeatureAccessTracker>;
119*6777b538SAndroid Build Coastguard Worker 
120*6777b538SAndroid Build Coastguard Worker   EarlyFeatureAccessTracker() = default;
121*6777b538SAndroid Build Coastguard Worker   ~EarlyFeatureAccessTracker() = default;
122*6777b538SAndroid Build Coastguard Worker 
123*6777b538SAndroid Build Coastguard Worker   Lock lock_;
124*6777b538SAndroid Build Coastguard Worker 
125*6777b538SAndroid Build Coastguard Worker   // First feature to be accessed before FeatureList registration.
126*6777b538SAndroid Build Coastguard Worker   raw_ptr<const Feature> feature_ GUARDED_BY(lock_) = nullptr;
127*6777b538SAndroid Build Coastguard Worker   bool feature_had_feature_allow_list_ GUARDED_BY(lock_) = false;
128*6777b538SAndroid Build Coastguard Worker 
129*6777b538SAndroid Build Coastguard Worker   // Whether AccessedFeature() should fail instantly.
130*6777b538SAndroid Build Coastguard Worker   bool fail_instantly_ GUARDED_BY(lock_) = false;
131*6777b538SAndroid Build Coastguard Worker };
132*6777b538SAndroid Build Coastguard Worker 
133*6777b538SAndroid Build Coastguard Worker #if DCHECK_IS_ON()
134*6777b538SAndroid Build Coastguard Worker const char* g_reason_overrides_disallowed = nullptr;
135*6777b538SAndroid Build Coastguard Worker 
DCheckOverridesAllowed()136*6777b538SAndroid Build Coastguard Worker void DCheckOverridesAllowed() {
137*6777b538SAndroid Build Coastguard Worker   const bool feature_overrides_allowed = !g_reason_overrides_disallowed;
138*6777b538SAndroid Build Coastguard Worker   DCHECK(feature_overrides_allowed) << g_reason_overrides_disallowed;
139*6777b538SAndroid Build Coastguard Worker }
140*6777b538SAndroid Build Coastguard Worker #else
DCheckOverridesAllowed()141*6777b538SAndroid Build Coastguard Worker void DCheckOverridesAllowed() {}
142*6777b538SAndroid Build Coastguard Worker #endif
143*6777b538SAndroid Build Coastguard Worker 
144*6777b538SAndroid Build Coastguard Worker // An allocator entry for a feature in shared memory. The FeatureEntry is
145*6777b538SAndroid Build Coastguard Worker // followed by a base::Pickle object that contains the feature and trial name.
146*6777b538SAndroid Build Coastguard Worker struct FeatureEntry {
147*6777b538SAndroid Build Coastguard Worker   // SHA1(FeatureEntry): Increment this if structure changes!
148*6777b538SAndroid Build Coastguard Worker   static constexpr uint32_t kPersistentTypeId = 0x06567CA6 + 2;
149*6777b538SAndroid Build Coastguard Worker 
150*6777b538SAndroid Build Coastguard Worker   // Expected size for 32/64-bit check.
151*6777b538SAndroid Build Coastguard Worker   static constexpr size_t kExpectedInstanceSize = 16;
152*6777b538SAndroid Build Coastguard Worker 
153*6777b538SAndroid Build Coastguard Worker   // Specifies whether a feature override enables or disables the feature. Same
154*6777b538SAndroid Build Coastguard Worker   // values as the OverrideState enum in feature_list.h
155*6777b538SAndroid Build Coastguard Worker   uint32_t override_state;
156*6777b538SAndroid Build Coastguard Worker 
157*6777b538SAndroid Build Coastguard Worker   // On e.g. x86, alignof(uint64_t) is 4.  Ensure consistent size and alignment
158*6777b538SAndroid Build Coastguard Worker   // of `pickle_size` across platforms.
159*6777b538SAndroid Build Coastguard Worker   uint32_t padding;
160*6777b538SAndroid Build Coastguard Worker 
161*6777b538SAndroid Build Coastguard Worker   // Size of the pickled structure, NOT the total size of this entry.
162*6777b538SAndroid Build Coastguard Worker   uint64_t pickle_size;
163*6777b538SAndroid Build Coastguard Worker 
164*6777b538SAndroid Build Coastguard Worker   // Return a pointer to the pickled data area immediately following the entry.
GetPickledDataPtrbase::__anon54ff85260111::FeatureEntry165*6777b538SAndroid Build Coastguard Worker   uint8_t* GetPickledDataPtr() { return reinterpret_cast<uint8_t*>(this + 1); }
GetPickledDataPtrbase::__anon54ff85260111::FeatureEntry166*6777b538SAndroid Build Coastguard Worker   const uint8_t* GetPickledDataPtr() const {
167*6777b538SAndroid Build Coastguard Worker     return reinterpret_cast<const uint8_t*>(this + 1);
168*6777b538SAndroid Build Coastguard Worker   }
169*6777b538SAndroid Build Coastguard Worker 
170*6777b538SAndroid Build Coastguard Worker   // Reads the feature and trial name from the pickle. Calling this is only
171*6777b538SAndroid Build Coastguard Worker   // valid on an initialized entry that's in shared memory.
GetFeatureAndTrialNamebase::__anon54ff85260111::FeatureEntry172*6777b538SAndroid Build Coastguard Worker   bool GetFeatureAndTrialName(std::string_view* feature_name,
173*6777b538SAndroid Build Coastguard Worker                               std::string_view* trial_name) const {
174*6777b538SAndroid Build Coastguard Worker     Pickle pickle = Pickle::WithUnownedBuffer(
175*6777b538SAndroid Build Coastguard Worker         span(GetPickledDataPtr(), checked_cast<size_t>(pickle_size)));
176*6777b538SAndroid Build Coastguard Worker     PickleIterator pickle_iter(pickle);
177*6777b538SAndroid Build Coastguard Worker     if (!pickle_iter.ReadStringPiece(feature_name)) {
178*6777b538SAndroid Build Coastguard Worker       return false;
179*6777b538SAndroid Build Coastguard Worker     }
180*6777b538SAndroid Build Coastguard Worker     // Return true because we are not guaranteed to have a trial name anyways.
181*6777b538SAndroid Build Coastguard Worker     std::ignore = pickle_iter.ReadStringPiece(trial_name);
182*6777b538SAndroid Build Coastguard Worker     return true;
183*6777b538SAndroid Build Coastguard Worker   }
184*6777b538SAndroid Build Coastguard Worker };
185*6777b538SAndroid Build Coastguard Worker 
186*6777b538SAndroid Build Coastguard Worker // Splits |text| into two parts by the |separator| where the first part will be
187*6777b538SAndroid Build Coastguard Worker // returned updated in |first| and the second part will be returned as |second|.
188*6777b538SAndroid Build Coastguard Worker // This function returns false if there is more than one |separator| in |first|.
189*6777b538SAndroid Build Coastguard Worker // If there is no |separator| presented in |first|, this function will not
190*6777b538SAndroid Build Coastguard Worker // modify |first| and |second|. It's used for splitting the |enable_features|
191*6777b538SAndroid Build Coastguard Worker // flag into feature name, field trial name and feature parameters.
SplitIntoTwo(std::string_view text,std::string_view separator,std::string_view * first,std::string * second)192*6777b538SAndroid Build Coastguard Worker bool SplitIntoTwo(std::string_view text,
193*6777b538SAndroid Build Coastguard Worker                   std::string_view separator,
194*6777b538SAndroid Build Coastguard Worker                   std::string_view* first,
195*6777b538SAndroid Build Coastguard Worker                   std::string* second) {
196*6777b538SAndroid Build Coastguard Worker   std::vector<std::string_view> parts =
197*6777b538SAndroid Build Coastguard Worker       SplitStringPiece(text, separator, TRIM_WHITESPACE, SPLIT_WANT_ALL);
198*6777b538SAndroid Build Coastguard Worker   if (parts.size() == 2) {
199*6777b538SAndroid Build Coastguard Worker     *second = std::string(parts[1]);
200*6777b538SAndroid Build Coastguard Worker   } else if (parts.size() > 2) {
201*6777b538SAndroid Build Coastguard Worker     DLOG(ERROR) << "Only one '" << separator
202*6777b538SAndroid Build Coastguard Worker                 << "' is allowed but got: " << *first;
203*6777b538SAndroid Build Coastguard Worker     return false;
204*6777b538SAndroid Build Coastguard Worker   }
205*6777b538SAndroid Build Coastguard Worker   *first = parts[0];
206*6777b538SAndroid Build Coastguard Worker   return true;
207*6777b538SAndroid Build Coastguard Worker }
208*6777b538SAndroid Build Coastguard Worker 
209*6777b538SAndroid Build Coastguard Worker // Checks and parses the |enable_features| flag and sets
210*6777b538SAndroid Build Coastguard Worker // |parsed_enable_features| to be a comma-separated list of features,
211*6777b538SAndroid Build Coastguard Worker // |force_fieldtrials| to be a comma-separated list of field trials that each
212*6777b538SAndroid Build Coastguard Worker // feature want to associate with and |force_fieldtrial_params| to be the field
213*6777b538SAndroid Build Coastguard Worker // trial parameters for each field trial.
214*6777b538SAndroid Build Coastguard Worker // Returns true if |enable_features| is parsable, otherwise false.
ParseEnableFeatures(const std::string & enable_features,std::string * parsed_enable_features,std::string * force_fieldtrials,std::string * force_fieldtrial_params)215*6777b538SAndroid Build Coastguard Worker bool ParseEnableFeatures(const std::string& enable_features,
216*6777b538SAndroid Build Coastguard Worker                          std::string* parsed_enable_features,
217*6777b538SAndroid Build Coastguard Worker                          std::string* force_fieldtrials,
218*6777b538SAndroid Build Coastguard Worker                          std::string* force_fieldtrial_params) {
219*6777b538SAndroid Build Coastguard Worker   std::vector<std::string> enable_features_list;
220*6777b538SAndroid Build Coastguard Worker   std::vector<std::string> force_fieldtrials_list;
221*6777b538SAndroid Build Coastguard Worker   std::vector<std::string> force_fieldtrial_params_list;
222*6777b538SAndroid Build Coastguard Worker   for (const auto& enable_feature :
223*6777b538SAndroid Build Coastguard Worker        FeatureList::SplitFeatureListString(enable_features)) {
224*6777b538SAndroid Build Coastguard Worker     std::string feature_name;
225*6777b538SAndroid Build Coastguard Worker     std::string study;
226*6777b538SAndroid Build Coastguard Worker     std::string group;
227*6777b538SAndroid Build Coastguard Worker     std::string feature_params;
228*6777b538SAndroid Build Coastguard Worker     if (!FeatureList::ParseEnableFeatureString(
229*6777b538SAndroid Build Coastguard Worker             enable_feature, &feature_name, &study, &group, &feature_params)) {
230*6777b538SAndroid Build Coastguard Worker       return false;
231*6777b538SAndroid Build Coastguard Worker     }
232*6777b538SAndroid Build Coastguard Worker 
233*6777b538SAndroid Build Coastguard Worker     // If feature params were set but group and study weren't, associate the
234*6777b538SAndroid Build Coastguard Worker     // feature and its feature params to a synthetic field trial as the
235*6777b538SAndroid Build Coastguard Worker     // feature params only make sense when it's combined with a field trial.
236*6777b538SAndroid Build Coastguard Worker     if (!feature_params.empty()) {
237*6777b538SAndroid Build Coastguard Worker       force_fieldtrials_list.push_back(study + "/" + group);
238*6777b538SAndroid Build Coastguard Worker       force_fieldtrial_params_list.push_back(study + "." + group + ":" +
239*6777b538SAndroid Build Coastguard Worker                                              feature_params);
240*6777b538SAndroid Build Coastguard Worker     }
241*6777b538SAndroid Build Coastguard Worker     enable_features_list.push_back(
242*6777b538SAndroid Build Coastguard Worker         study.empty() ? feature_name : (feature_name + "<" + study));
243*6777b538SAndroid Build Coastguard Worker   }
244*6777b538SAndroid Build Coastguard Worker 
245*6777b538SAndroid Build Coastguard Worker   *parsed_enable_features = JoinString(enable_features_list, ",");
246*6777b538SAndroid Build Coastguard Worker   // Field trial separator is currently a slash. See
247*6777b538SAndroid Build Coastguard Worker   // |kPersistentStringSeparator| in base/metrics/field_trial.cc.
248*6777b538SAndroid Build Coastguard Worker   *force_fieldtrials = JoinString(force_fieldtrials_list, "/");
249*6777b538SAndroid Build Coastguard Worker   *force_fieldtrial_params = JoinString(force_fieldtrial_params_list, ",");
250*6777b538SAndroid Build Coastguard Worker   return true;
251*6777b538SAndroid Build Coastguard Worker }
252*6777b538SAndroid Build Coastguard Worker 
UnpackFeatureCache(uint32_t packed_cache_value)253*6777b538SAndroid Build Coastguard Worker std::pair<FeatureList::OverrideState, uint16_t> UnpackFeatureCache(
254*6777b538SAndroid Build Coastguard Worker     uint32_t packed_cache_value) {
255*6777b538SAndroid Build Coastguard Worker   return std::make_pair(
256*6777b538SAndroid Build Coastguard Worker       static_cast<FeatureList::OverrideState>(packed_cache_value >> 24),
257*6777b538SAndroid Build Coastguard Worker       packed_cache_value & 0xFFFF);
258*6777b538SAndroid Build Coastguard Worker }
259*6777b538SAndroid Build Coastguard Worker 
PackFeatureCache(FeatureList::OverrideState override_state,uint32_t caching_context)260*6777b538SAndroid Build Coastguard Worker uint32_t PackFeatureCache(FeatureList::OverrideState override_state,
261*6777b538SAndroid Build Coastguard Worker                           uint32_t caching_context) {
262*6777b538SAndroid Build Coastguard Worker   return (static_cast<uint32_t>(override_state) << 24) |
263*6777b538SAndroid Build Coastguard Worker          (caching_context & 0xFFFF);
264*6777b538SAndroid Build Coastguard Worker }
265*6777b538SAndroid Build Coastguard Worker 
266*6777b538SAndroid Build Coastguard Worker // A monotonically increasing id, passed to `FeatureList`s as they are created
267*6777b538SAndroid Build Coastguard Worker // to invalidate the cache member of `base::Feature` objects that were queried
268*6777b538SAndroid Build Coastguard Worker // with a different `FeatureList` installed.
269*6777b538SAndroid Build Coastguard Worker uint16_t g_current_caching_context = 1;
270*6777b538SAndroid Build Coastguard Worker 
271*6777b538SAndroid Build Coastguard Worker }  // namespace
272*6777b538SAndroid Build Coastguard Worker 
273*6777b538SAndroid Build Coastguard Worker #if BUILDFLAG(DCHECK_IS_CONFIGURABLE)
274*6777b538SAndroid Build Coastguard Worker BASE_FEATURE(kDCheckIsFatalFeature,
275*6777b538SAndroid Build Coastguard Worker              "DcheckIsFatal",
276*6777b538SAndroid Build Coastguard Worker              FEATURE_DISABLED_BY_DEFAULT);
277*6777b538SAndroid Build Coastguard Worker #endif  // BUILDFLAG(DCHECK_IS_CONFIGURABLE)
278*6777b538SAndroid Build Coastguard Worker 
FeatureList()279*6777b538SAndroid Build Coastguard Worker FeatureList::FeatureList() : caching_context_(g_current_caching_context++) {}
280*6777b538SAndroid Build Coastguard Worker 
281*6777b538SAndroid Build Coastguard Worker FeatureList::~FeatureList() = default;
282*6777b538SAndroid Build Coastguard Worker 
ScopedDisallowOverrides(const char * reason)283*6777b538SAndroid Build Coastguard Worker FeatureList::ScopedDisallowOverrides::ScopedDisallowOverrides(
284*6777b538SAndroid Build Coastguard Worker     const char* reason)
285*6777b538SAndroid Build Coastguard Worker #if DCHECK_IS_ON()
286*6777b538SAndroid Build Coastguard Worker     : previous_reason_(g_reason_overrides_disallowed) {
287*6777b538SAndroid Build Coastguard Worker   g_reason_overrides_disallowed = reason;
288*6777b538SAndroid Build Coastguard Worker }
289*6777b538SAndroid Build Coastguard Worker #else
290*6777b538SAndroid Build Coastguard Worker {
291*6777b538SAndroid Build Coastguard Worker }
292*6777b538SAndroid Build Coastguard Worker #endif
293*6777b538SAndroid Build Coastguard Worker 
~ScopedDisallowOverrides()294*6777b538SAndroid Build Coastguard Worker FeatureList::ScopedDisallowOverrides::~ScopedDisallowOverrides() {
295*6777b538SAndroid Build Coastguard Worker #if DCHECK_IS_ON()
296*6777b538SAndroid Build Coastguard Worker   g_reason_overrides_disallowed = previous_reason_;
297*6777b538SAndroid Build Coastguard Worker #endif
298*6777b538SAndroid Build Coastguard Worker }
299*6777b538SAndroid Build Coastguard Worker 
InitFromCommandLine(const std::string & enable_features,const std::string & disable_features)300*6777b538SAndroid Build Coastguard Worker void FeatureList::InitFromCommandLine(const std::string& enable_features,
301*6777b538SAndroid Build Coastguard Worker                                       const std::string& disable_features) {
302*6777b538SAndroid Build Coastguard Worker   DCHECK(!initialized_);
303*6777b538SAndroid Build Coastguard Worker 
304*6777b538SAndroid Build Coastguard Worker   std::string parsed_enable_features;
305*6777b538SAndroid Build Coastguard Worker   std::string force_fieldtrials;
306*6777b538SAndroid Build Coastguard Worker   std::string force_fieldtrial_params;
307*6777b538SAndroid Build Coastguard Worker   bool parse_enable_features_result =
308*6777b538SAndroid Build Coastguard Worker       ParseEnableFeatures(enable_features, &parsed_enable_features,
309*6777b538SAndroid Build Coastguard Worker                           &force_fieldtrials, &force_fieldtrial_params);
310*6777b538SAndroid Build Coastguard Worker   DCHECK(parse_enable_features_result) << StringPrintf(
311*6777b538SAndroid Build Coastguard Worker       "The --%s list is unparsable or invalid, please check the format.",
312*6777b538SAndroid Build Coastguard Worker       ::switches::kEnableFeatures);
313*6777b538SAndroid Build Coastguard Worker 
314*6777b538SAndroid Build Coastguard Worker   // Only create field trials when field_trial_list is available. Some tests
315*6777b538SAndroid Build Coastguard Worker   // don't have field trial list available.
316*6777b538SAndroid Build Coastguard Worker   if (FieldTrialList::GetInstance()) {
317*6777b538SAndroid Build Coastguard Worker     bool associate_params_result = AssociateFieldTrialParamsFromString(
318*6777b538SAndroid Build Coastguard Worker         force_fieldtrial_params, &UnescapeValue);
319*6777b538SAndroid Build Coastguard Worker     DCHECK(associate_params_result) << StringPrintf(
320*6777b538SAndroid Build Coastguard Worker         "The field trial parameters part of the --%s list is invalid. Make "
321*6777b538SAndroid Build Coastguard Worker         "sure "
322*6777b538SAndroid Build Coastguard Worker         "you %%-encode the following characters in param values: %%:/.,",
323*6777b538SAndroid Build Coastguard Worker         ::switches::kEnableFeatures);
324*6777b538SAndroid Build Coastguard Worker 
325*6777b538SAndroid Build Coastguard Worker     bool create_trials_result =
326*6777b538SAndroid Build Coastguard Worker         FieldTrialList::CreateTrialsFromString(force_fieldtrials);
327*6777b538SAndroid Build Coastguard Worker     DCHECK(create_trials_result)
328*6777b538SAndroid Build Coastguard Worker         << StringPrintf("Invalid field trials are specified in --%s.",
329*6777b538SAndroid Build Coastguard Worker                         ::switches::kEnableFeatures);
330*6777b538SAndroid Build Coastguard Worker   }
331*6777b538SAndroid Build Coastguard Worker 
332*6777b538SAndroid Build Coastguard Worker   // Process disabled features first, so that disabled ones take precedence over
333*6777b538SAndroid Build Coastguard Worker   // enabled ones (since RegisterOverride() uses insert()).
334*6777b538SAndroid Build Coastguard Worker   RegisterOverridesFromCommandLine(disable_features, OVERRIDE_DISABLE_FEATURE);
335*6777b538SAndroid Build Coastguard Worker   RegisterOverridesFromCommandLine(parsed_enable_features,
336*6777b538SAndroid Build Coastguard Worker                                    OVERRIDE_ENABLE_FEATURE);
337*6777b538SAndroid Build Coastguard Worker 
338*6777b538SAndroid Build Coastguard Worker   initialized_from_command_line_ = true;
339*6777b538SAndroid Build Coastguard Worker }
340*6777b538SAndroid Build Coastguard Worker 
InitFromSharedMemory(PersistentMemoryAllocator * allocator)341*6777b538SAndroid Build Coastguard Worker void FeatureList::InitFromSharedMemory(PersistentMemoryAllocator* allocator) {
342*6777b538SAndroid Build Coastguard Worker   DCHECK(!initialized_);
343*6777b538SAndroid Build Coastguard Worker 
344*6777b538SAndroid Build Coastguard Worker   PersistentMemoryAllocator::Iterator iter(allocator);
345*6777b538SAndroid Build Coastguard Worker   const FeatureEntry* entry;
346*6777b538SAndroid Build Coastguard Worker   while ((entry = iter.GetNextOfObject<FeatureEntry>()) != nullptr) {
347*6777b538SAndroid Build Coastguard Worker     OverrideState override_state =
348*6777b538SAndroid Build Coastguard Worker         static_cast<OverrideState>(entry->override_state);
349*6777b538SAndroid Build Coastguard Worker 
350*6777b538SAndroid Build Coastguard Worker     std::string_view feature_name;
351*6777b538SAndroid Build Coastguard Worker     std::string_view trial_name;
352*6777b538SAndroid Build Coastguard Worker     if (!entry->GetFeatureAndTrialName(&feature_name, &trial_name))
353*6777b538SAndroid Build Coastguard Worker       continue;
354*6777b538SAndroid Build Coastguard Worker 
355*6777b538SAndroid Build Coastguard Worker     FieldTrial* trial = FieldTrialList::Find(trial_name);
356*6777b538SAndroid Build Coastguard Worker     RegisterOverride(feature_name, override_state, trial);
357*6777b538SAndroid Build Coastguard Worker   }
358*6777b538SAndroid Build Coastguard Worker }
359*6777b538SAndroid Build Coastguard Worker 
IsFeatureOverridden(const std::string & feature_name) const360*6777b538SAndroid Build Coastguard Worker bool FeatureList::IsFeatureOverridden(const std::string& feature_name) const {
361*6777b538SAndroid Build Coastguard Worker   return overrides_.count(feature_name);
362*6777b538SAndroid Build Coastguard Worker }
363*6777b538SAndroid Build Coastguard Worker 
IsFeatureOverriddenFromCommandLine(const std::string & feature_name) const364*6777b538SAndroid Build Coastguard Worker bool FeatureList::IsFeatureOverriddenFromCommandLine(
365*6777b538SAndroid Build Coastguard Worker     const std::string& feature_name) const {
366*6777b538SAndroid Build Coastguard Worker   auto it = overrides_.find(feature_name);
367*6777b538SAndroid Build Coastguard Worker   return it != overrides_.end() && !it->second.overridden_by_field_trial;
368*6777b538SAndroid Build Coastguard Worker }
369*6777b538SAndroid Build Coastguard Worker 
IsFeatureOverriddenFromCommandLine(const std::string & feature_name,OverrideState state) const370*6777b538SAndroid Build Coastguard Worker bool FeatureList::IsFeatureOverriddenFromCommandLine(
371*6777b538SAndroid Build Coastguard Worker     const std::string& feature_name,
372*6777b538SAndroid Build Coastguard Worker     OverrideState state) const {
373*6777b538SAndroid Build Coastguard Worker   auto it = overrides_.find(feature_name);
374*6777b538SAndroid Build Coastguard Worker   return it != overrides_.end() && !it->second.overridden_by_field_trial &&
375*6777b538SAndroid Build Coastguard Worker          it->second.overridden_state == state;
376*6777b538SAndroid Build Coastguard Worker }
377*6777b538SAndroid Build Coastguard Worker 
AssociateReportingFieldTrial(const std::string & feature_name,OverrideState for_overridden_state,FieldTrial * field_trial)378*6777b538SAndroid Build Coastguard Worker void FeatureList::AssociateReportingFieldTrial(
379*6777b538SAndroid Build Coastguard Worker     const std::string& feature_name,
380*6777b538SAndroid Build Coastguard Worker     OverrideState for_overridden_state,
381*6777b538SAndroid Build Coastguard Worker     FieldTrial* field_trial) {
382*6777b538SAndroid Build Coastguard Worker   DCHECK(
383*6777b538SAndroid Build Coastguard Worker       IsFeatureOverriddenFromCommandLine(feature_name, for_overridden_state));
384*6777b538SAndroid Build Coastguard Worker 
385*6777b538SAndroid Build Coastguard Worker   // Only one associated field trial is supported per feature. This is generally
386*6777b538SAndroid Build Coastguard Worker   // enforced server-side.
387*6777b538SAndroid Build Coastguard Worker   OverrideEntry* entry = &overrides_.find(feature_name)->second;
388*6777b538SAndroid Build Coastguard Worker   if (entry->field_trial) {
389*6777b538SAndroid Build Coastguard Worker     NOTREACHED() << "Feature " << feature_name
390*6777b538SAndroid Build Coastguard Worker                  << " already has trial: " << entry->field_trial->trial_name()
391*6777b538SAndroid Build Coastguard Worker                  << ", associating trial: " << field_trial->trial_name();
392*6777b538SAndroid Build Coastguard Worker     return;
393*6777b538SAndroid Build Coastguard Worker   }
394*6777b538SAndroid Build Coastguard Worker 
395*6777b538SAndroid Build Coastguard Worker   entry->field_trial = field_trial;
396*6777b538SAndroid Build Coastguard Worker }
397*6777b538SAndroid Build Coastguard Worker 
RegisterFieldTrialOverride(const std::string & feature_name,OverrideState override_state,FieldTrial * field_trial)398*6777b538SAndroid Build Coastguard Worker void FeatureList::RegisterFieldTrialOverride(const std::string& feature_name,
399*6777b538SAndroid Build Coastguard Worker                                              OverrideState override_state,
400*6777b538SAndroid Build Coastguard Worker                                              FieldTrial* field_trial) {
401*6777b538SAndroid Build Coastguard Worker   DCHECK(field_trial);
402*6777b538SAndroid Build Coastguard Worker   DCHECK(!HasAssociatedFieldTrialByFeatureName(feature_name))
403*6777b538SAndroid Build Coastguard Worker       << "Feature " << feature_name << " is overriden multiple times in these "
404*6777b538SAndroid Build Coastguard Worker       << "trials: "
405*6777b538SAndroid Build Coastguard Worker       << overrides_.find(feature_name)->second.field_trial->trial_name()
406*6777b538SAndroid Build Coastguard Worker       << " and " << field_trial->trial_name() << ". "
407*6777b538SAndroid Build Coastguard Worker       << "Check the trial (study) in (1) the server config, "
408*6777b538SAndroid Build Coastguard Worker       << "(2) fieldtrial_testing_config.json, (3) about_flags.cc, and "
409*6777b538SAndroid Build Coastguard Worker       << "(4) client-side field trials.";
410*6777b538SAndroid Build Coastguard Worker 
411*6777b538SAndroid Build Coastguard Worker   RegisterOverride(feature_name, override_state, field_trial);
412*6777b538SAndroid Build Coastguard Worker }
413*6777b538SAndroid Build Coastguard Worker 
RegisterExtraFeatureOverrides(const std::vector<FeatureOverrideInfo> & extra_overrides)414*6777b538SAndroid Build Coastguard Worker void FeatureList::RegisterExtraFeatureOverrides(
415*6777b538SAndroid Build Coastguard Worker     const std::vector<FeatureOverrideInfo>& extra_overrides) {
416*6777b538SAndroid Build Coastguard Worker   for (const FeatureOverrideInfo& override_info : extra_overrides) {
417*6777b538SAndroid Build Coastguard Worker     RegisterOverride(override_info.first.get().name, override_info.second,
418*6777b538SAndroid Build Coastguard Worker                      /* field_trial = */ nullptr);
419*6777b538SAndroid Build Coastguard Worker   }
420*6777b538SAndroid Build Coastguard Worker }
421*6777b538SAndroid Build Coastguard Worker 
AddFeaturesToAllocator(PersistentMemoryAllocator * allocator)422*6777b538SAndroid Build Coastguard Worker void FeatureList::AddFeaturesToAllocator(PersistentMemoryAllocator* allocator) {
423*6777b538SAndroid Build Coastguard Worker   DCHECK(initialized_);
424*6777b538SAndroid Build Coastguard Worker 
425*6777b538SAndroid Build Coastguard Worker   for (const auto& override : overrides_) {
426*6777b538SAndroid Build Coastguard Worker     Pickle pickle;
427*6777b538SAndroid Build Coastguard Worker     pickle.WriteString(override.first);
428*6777b538SAndroid Build Coastguard Worker     if (override.second.field_trial)
429*6777b538SAndroid Build Coastguard Worker       pickle.WriteString(override.second.field_trial->trial_name());
430*6777b538SAndroid Build Coastguard Worker 
431*6777b538SAndroid Build Coastguard Worker     size_t total_size = sizeof(FeatureEntry) + pickle.size();
432*6777b538SAndroid Build Coastguard Worker     FeatureEntry* entry = allocator->New<FeatureEntry>(total_size);
433*6777b538SAndroid Build Coastguard Worker     if (!entry)
434*6777b538SAndroid Build Coastguard Worker       return;
435*6777b538SAndroid Build Coastguard Worker 
436*6777b538SAndroid Build Coastguard Worker     entry->override_state = override.second.overridden_state;
437*6777b538SAndroid Build Coastguard Worker     entry->pickle_size = pickle.size();
438*6777b538SAndroid Build Coastguard Worker     memcpy(entry->GetPickledDataPtr(), pickle.data(), pickle.size());
439*6777b538SAndroid Build Coastguard Worker 
440*6777b538SAndroid Build Coastguard Worker     allocator->MakeIterable(entry);
441*6777b538SAndroid Build Coastguard Worker   }
442*6777b538SAndroid Build Coastguard Worker }
443*6777b538SAndroid Build Coastguard Worker 
GetFeatureOverrides(std::string * enable_overrides,std::string * disable_overrides,bool include_group_name) const444*6777b538SAndroid Build Coastguard Worker void FeatureList::GetFeatureOverrides(std::string* enable_overrides,
445*6777b538SAndroid Build Coastguard Worker                                       std::string* disable_overrides,
446*6777b538SAndroid Build Coastguard Worker                                       bool include_group_name) const {
447*6777b538SAndroid Build Coastguard Worker   GetFeatureOverridesImpl(enable_overrides, disable_overrides, false,
448*6777b538SAndroid Build Coastguard Worker                           include_group_name);
449*6777b538SAndroid Build Coastguard Worker }
450*6777b538SAndroid Build Coastguard Worker 
GetCommandLineFeatureOverrides(std::string * enable_overrides,std::string * disable_overrides) const451*6777b538SAndroid Build Coastguard Worker void FeatureList::GetCommandLineFeatureOverrides(
452*6777b538SAndroid Build Coastguard Worker     std::string* enable_overrides,
453*6777b538SAndroid Build Coastguard Worker     std::string* disable_overrides) const {
454*6777b538SAndroid Build Coastguard Worker   GetFeatureOverridesImpl(enable_overrides, disable_overrides, true);
455*6777b538SAndroid Build Coastguard Worker }
456*6777b538SAndroid Build Coastguard Worker 
457*6777b538SAndroid Build Coastguard Worker // static
IsEnabled(const Feature & feature)458*6777b538SAndroid Build Coastguard Worker bool FeatureList::IsEnabled(const Feature& feature) {
459*6777b538SAndroid Build Coastguard Worker   if (!g_feature_list_instance ||
460*6777b538SAndroid Build Coastguard Worker       !g_feature_list_instance->AllowFeatureAccess(feature)) {
461*6777b538SAndroid Build Coastguard Worker     EarlyFeatureAccessTracker::GetInstance()->AccessedFeature(
462*6777b538SAndroid Build Coastguard Worker         feature, g_feature_list_instance &&
463*6777b538SAndroid Build Coastguard Worker                      g_feature_list_instance->IsEarlyAccessInstance());
464*6777b538SAndroid Build Coastguard Worker     return feature.default_state == FEATURE_ENABLED_BY_DEFAULT;
465*6777b538SAndroid Build Coastguard Worker   }
466*6777b538SAndroid Build Coastguard Worker   return g_feature_list_instance->IsFeatureEnabled(feature);
467*6777b538SAndroid Build Coastguard Worker }
468*6777b538SAndroid Build Coastguard Worker 
469*6777b538SAndroid Build Coastguard Worker // static
IsValidFeatureOrFieldTrialName(std::string_view name)470*6777b538SAndroid Build Coastguard Worker bool FeatureList::IsValidFeatureOrFieldTrialName(std::string_view name) {
471*6777b538SAndroid Build Coastguard Worker   return IsStringASCII(name) && name.find_first_of(",<*") == std::string::npos;
472*6777b538SAndroid Build Coastguard Worker }
473*6777b538SAndroid Build Coastguard Worker 
474*6777b538SAndroid Build Coastguard Worker // static
GetStateIfOverridden(const Feature & feature)475*6777b538SAndroid Build Coastguard Worker std::optional<bool> FeatureList::GetStateIfOverridden(const Feature& feature) {
476*6777b538SAndroid Build Coastguard Worker   if (!g_feature_list_instance ||
477*6777b538SAndroid Build Coastguard Worker       !g_feature_list_instance->AllowFeatureAccess(feature)) {
478*6777b538SAndroid Build Coastguard Worker     EarlyFeatureAccessTracker::GetInstance()->AccessedFeature(
479*6777b538SAndroid Build Coastguard Worker         feature, g_feature_list_instance &&
480*6777b538SAndroid Build Coastguard Worker                      g_feature_list_instance->IsEarlyAccessInstance());
481*6777b538SAndroid Build Coastguard Worker     // If there is no feature list, there can be no overrides.
482*6777b538SAndroid Build Coastguard Worker     return std::nullopt;
483*6777b538SAndroid Build Coastguard Worker   }
484*6777b538SAndroid Build Coastguard Worker   return g_feature_list_instance->IsFeatureEnabledIfOverridden(feature);
485*6777b538SAndroid Build Coastguard Worker }
486*6777b538SAndroid Build Coastguard Worker 
487*6777b538SAndroid Build Coastguard Worker // static
GetFieldTrial(const Feature & feature)488*6777b538SAndroid Build Coastguard Worker FieldTrial* FeatureList::GetFieldTrial(const Feature& feature) {
489*6777b538SAndroid Build Coastguard Worker   if (!g_feature_list_instance ||
490*6777b538SAndroid Build Coastguard Worker       !g_feature_list_instance->AllowFeatureAccess(feature)) {
491*6777b538SAndroid Build Coastguard Worker     EarlyFeatureAccessTracker::GetInstance()->AccessedFeature(
492*6777b538SAndroid Build Coastguard Worker         feature, g_feature_list_instance &&
493*6777b538SAndroid Build Coastguard Worker                      g_feature_list_instance->IsEarlyAccessInstance());
494*6777b538SAndroid Build Coastguard Worker     return nullptr;
495*6777b538SAndroid Build Coastguard Worker   }
496*6777b538SAndroid Build Coastguard Worker   return g_feature_list_instance->GetAssociatedFieldTrial(feature);
497*6777b538SAndroid Build Coastguard Worker }
498*6777b538SAndroid Build Coastguard Worker 
499*6777b538SAndroid Build Coastguard Worker // static
SplitFeatureListString(std::string_view input)500*6777b538SAndroid Build Coastguard Worker std::vector<std::string_view> FeatureList::SplitFeatureListString(
501*6777b538SAndroid Build Coastguard Worker     std::string_view input) {
502*6777b538SAndroid Build Coastguard Worker   return SplitStringPiece(input, ",", TRIM_WHITESPACE, SPLIT_WANT_NONEMPTY);
503*6777b538SAndroid Build Coastguard Worker }
504*6777b538SAndroid Build Coastguard Worker 
505*6777b538SAndroid Build Coastguard Worker // static
ParseEnableFeatureString(std::string_view enable_feature,std::string * feature_name,std::string * study_name,std::string * group_name,std::string * params)506*6777b538SAndroid Build Coastguard Worker bool FeatureList::ParseEnableFeatureString(std::string_view enable_feature,
507*6777b538SAndroid Build Coastguard Worker                                            std::string* feature_name,
508*6777b538SAndroid Build Coastguard Worker                                            std::string* study_name,
509*6777b538SAndroid Build Coastguard Worker                                            std::string* group_name,
510*6777b538SAndroid Build Coastguard Worker                                            std::string* params) {
511*6777b538SAndroid Build Coastguard Worker   std::string_view first;
512*6777b538SAndroid Build Coastguard Worker   // First, check whether ":" is present. If true, feature parameters were
513*6777b538SAndroid Build Coastguard Worker   // set for this feature.
514*6777b538SAndroid Build Coastguard Worker   std::string feature_params;
515*6777b538SAndroid Build Coastguard Worker   if (!SplitIntoTwo(enable_feature, ":", &first, &feature_params))
516*6777b538SAndroid Build Coastguard Worker     return false;
517*6777b538SAndroid Build Coastguard Worker   // Then, check whether "." is present. If true, a group was specified for
518*6777b538SAndroid Build Coastguard Worker   // this feature.
519*6777b538SAndroid Build Coastguard Worker   std::string group;
520*6777b538SAndroid Build Coastguard Worker   if (!SplitIntoTwo(first, ".", &first, &group))
521*6777b538SAndroid Build Coastguard Worker     return false;
522*6777b538SAndroid Build Coastguard Worker   // Finally, check whether "<" is present. If true, a study was specified for
523*6777b538SAndroid Build Coastguard Worker   // this feature.
524*6777b538SAndroid Build Coastguard Worker   std::string study;
525*6777b538SAndroid Build Coastguard Worker   if (!SplitIntoTwo(first, "<", &first, &study))
526*6777b538SAndroid Build Coastguard Worker     return false;
527*6777b538SAndroid Build Coastguard Worker 
528*6777b538SAndroid Build Coastguard Worker   std::string enable_feature_name(first);
529*6777b538SAndroid Build Coastguard Worker   // If feature params were set but group and study weren't, associate the
530*6777b538SAndroid Build Coastguard Worker   // feature and its feature params to a synthetic field trial as the
531*6777b538SAndroid Build Coastguard Worker   // feature params only make sense when it's combined with a field trial.
532*6777b538SAndroid Build Coastguard Worker   if (!feature_params.empty()) {
533*6777b538SAndroid Build Coastguard Worker     study = study.empty() ? "Study" + enable_feature_name : study;
534*6777b538SAndroid Build Coastguard Worker     group = group.empty() ? "Group" + enable_feature_name : group;
535*6777b538SAndroid Build Coastguard Worker   }
536*6777b538SAndroid Build Coastguard Worker 
537*6777b538SAndroid Build Coastguard Worker   feature_name->swap(enable_feature_name);
538*6777b538SAndroid Build Coastguard Worker   study_name->swap(study);
539*6777b538SAndroid Build Coastguard Worker   group_name->swap(group);
540*6777b538SAndroid Build Coastguard Worker   params->swap(feature_params);
541*6777b538SAndroid Build Coastguard Worker   return true;
542*6777b538SAndroid Build Coastguard Worker }
543*6777b538SAndroid Build Coastguard Worker 
544*6777b538SAndroid Build Coastguard Worker // static
InitInstance(const std::string & enable_features,const std::string & disable_features)545*6777b538SAndroid Build Coastguard Worker bool FeatureList::InitInstance(const std::string& enable_features,
546*6777b538SAndroid Build Coastguard Worker                                const std::string& disable_features) {
547*6777b538SAndroid Build Coastguard Worker   return InitInstance(enable_features, disable_features,
548*6777b538SAndroid Build Coastguard Worker                       std::vector<FeatureOverrideInfo>());
549*6777b538SAndroid Build Coastguard Worker }
550*6777b538SAndroid Build Coastguard Worker 
551*6777b538SAndroid Build Coastguard Worker // static
InitInstance(const std::string & enable_features,const std::string & disable_features,const std::vector<FeatureOverrideInfo> & extra_overrides)552*6777b538SAndroid Build Coastguard Worker bool FeatureList::InitInstance(
553*6777b538SAndroid Build Coastguard Worker     const std::string& enable_features,
554*6777b538SAndroid Build Coastguard Worker     const std::string& disable_features,
555*6777b538SAndroid Build Coastguard Worker     const std::vector<FeatureOverrideInfo>& extra_overrides) {
556*6777b538SAndroid Build Coastguard Worker   // We want to initialize a new instance here to support command-line features
557*6777b538SAndroid Build Coastguard Worker   // in testing better. For example, we initialize a dummy instance in
558*6777b538SAndroid Build Coastguard Worker   // base/test/test_suite.cc, and override it in content/browser/
559*6777b538SAndroid Build Coastguard Worker   // browser_main_loop.cc.
560*6777b538SAndroid Build Coastguard Worker   // On the other hand, we want to avoid re-initialization from command line.
561*6777b538SAndroid Build Coastguard Worker   // For example, we initialize an instance in chrome/browser/
562*6777b538SAndroid Build Coastguard Worker   // chrome_browser_main.cc and do not override it in content/browser/
563*6777b538SAndroid Build Coastguard Worker   // browser_main_loop.cc.
564*6777b538SAndroid Build Coastguard Worker   // If the singleton was previously initialized from within an accessor, we
565*6777b538SAndroid Build Coastguard Worker   // want to prevent callers from reinitializing the singleton and masking the
566*6777b538SAndroid Build Coastguard Worker   // accessor call(s) which likely returned incorrect information.
567*6777b538SAndroid Build Coastguard Worker   EarlyFeatureAccessTracker::GetInstance()->AssertNoAccess();
568*6777b538SAndroid Build Coastguard Worker   bool instance_existed_before = false;
569*6777b538SAndroid Build Coastguard Worker   if (g_feature_list_instance) {
570*6777b538SAndroid Build Coastguard Worker     if (g_feature_list_instance->initialized_from_command_line_)
571*6777b538SAndroid Build Coastguard Worker       return false;
572*6777b538SAndroid Build Coastguard Worker 
573*6777b538SAndroid Build Coastguard Worker     delete g_feature_list_instance;
574*6777b538SAndroid Build Coastguard Worker     g_feature_list_instance = nullptr;
575*6777b538SAndroid Build Coastguard Worker     instance_existed_before = true;
576*6777b538SAndroid Build Coastguard Worker   }
577*6777b538SAndroid Build Coastguard Worker 
578*6777b538SAndroid Build Coastguard Worker   std::unique_ptr<FeatureList> feature_list(new FeatureList);
579*6777b538SAndroid Build Coastguard Worker   feature_list->InitFromCommandLine(enable_features, disable_features);
580*6777b538SAndroid Build Coastguard Worker   feature_list->RegisterExtraFeatureOverrides(extra_overrides);
581*6777b538SAndroid Build Coastguard Worker   FeatureList::SetInstance(std::move(feature_list));
582*6777b538SAndroid Build Coastguard Worker   return !instance_existed_before;
583*6777b538SAndroid Build Coastguard Worker }
584*6777b538SAndroid Build Coastguard Worker 
585*6777b538SAndroid Build Coastguard Worker // static
GetInstance()586*6777b538SAndroid Build Coastguard Worker FeatureList* FeatureList::GetInstance() {
587*6777b538SAndroid Build Coastguard Worker   return g_feature_list_instance;
588*6777b538SAndroid Build Coastguard Worker }
589*6777b538SAndroid Build Coastguard Worker 
590*6777b538SAndroid Build Coastguard Worker // static
SetInstance(std::unique_ptr<FeatureList> instance)591*6777b538SAndroid Build Coastguard Worker void FeatureList::SetInstance(std::unique_ptr<FeatureList> instance) {
592*6777b538SAndroid Build Coastguard Worker   DCHECK(!g_feature_list_instance ||
593*6777b538SAndroid Build Coastguard Worker          g_feature_list_instance->IsEarlyAccessInstance());
594*6777b538SAndroid Build Coastguard Worker   // If there is an existing early-access instance, release it.
595*6777b538SAndroid Build Coastguard Worker   if (g_feature_list_instance) {
596*6777b538SAndroid Build Coastguard Worker     std::unique_ptr<FeatureList> old_instance =
597*6777b538SAndroid Build Coastguard Worker         WrapUnique(g_feature_list_instance);
598*6777b538SAndroid Build Coastguard Worker     g_feature_list_instance = nullptr;
599*6777b538SAndroid Build Coastguard Worker   }
600*6777b538SAndroid Build Coastguard Worker   instance->FinalizeInitialization();
601*6777b538SAndroid Build Coastguard Worker 
602*6777b538SAndroid Build Coastguard Worker   // Note: Intentional leak of global singleton.
603*6777b538SAndroid Build Coastguard Worker   g_feature_list_instance = instance.release();
604*6777b538SAndroid Build Coastguard Worker 
605*6777b538SAndroid Build Coastguard Worker   EarlyFeatureAccessTracker::GetInstance()->AssertNoAccess();
606*6777b538SAndroid Build Coastguard Worker 
607*6777b538SAndroid Build Coastguard Worker   // Don't configure random bytes field trials for a possibly early access
608*6777b538SAndroid Build Coastguard Worker   // FeatureList instance, as the state of the involved Features might change
609*6777b538SAndroid Build Coastguard Worker   // with the final FeatureList for this process.
610*6777b538SAndroid Build Coastguard Worker   if (!g_feature_list_instance->IsEarlyAccessInstance()) {
611*6777b538SAndroid Build Coastguard Worker #if !BUILDFLAG(IS_NACL)
612*6777b538SAndroid Build Coastguard Worker     // Configured first because it takes precedence over the getrandom() trial.
613*6777b538SAndroid Build Coastguard Worker     internal::ConfigureBoringSSLBackedRandBytesFieldTrial();
614*6777b538SAndroid Build Coastguard Worker #endif
615*6777b538SAndroid Build Coastguard Worker 
616*6777b538SAndroid Build Coastguard Worker #if BUILDFLAG(IS_ANDROID)
617*6777b538SAndroid Build Coastguard Worker     internal::ConfigureRandBytesFieldTrial();
618*6777b538SAndroid Build Coastguard Worker #endif
619*6777b538SAndroid Build Coastguard Worker   }
620*6777b538SAndroid Build Coastguard Worker 
621*6777b538SAndroid Build Coastguard Worker #if BUILDFLAG(DCHECK_IS_CONFIGURABLE)
622*6777b538SAndroid Build Coastguard Worker   // Update the behaviour of LOGGING_DCHECK to match the Feature configuration.
623*6777b538SAndroid Build Coastguard Worker   // DCHECK is also forced to be FATAL if we are running a death-test.
624*6777b538SAndroid Build Coastguard Worker   // TODO(crbug.com/1057995#c11): --gtest_internal_run_death_test doesn't
625*6777b538SAndroid Build Coastguard Worker   // currently run through this codepath, mitigated in
626*6777b538SAndroid Build Coastguard Worker   // base::TestSuite::Initialize() for now.
627*6777b538SAndroid Build Coastguard Worker   // TODO(asvitkine): If we find other use-cases that need integrating here
628*6777b538SAndroid Build Coastguard Worker   // then define a proper API/hook for the purpose.
629*6777b538SAndroid Build Coastguard Worker   if (FeatureList::IsEnabled(kDCheckIsFatalFeature) ||
630*6777b538SAndroid Build Coastguard Worker       CommandLine::ForCurrentProcess()->HasSwitch(
631*6777b538SAndroid Build Coastguard Worker           "gtest_internal_run_death_test")) {
632*6777b538SAndroid Build Coastguard Worker     logging::LOGGING_DCHECK = logging::LOGGING_FATAL;
633*6777b538SAndroid Build Coastguard Worker   } else {
634*6777b538SAndroid Build Coastguard Worker     logging::LOGGING_DCHECK = logging::LOGGING_ERROR;
635*6777b538SAndroid Build Coastguard Worker   }
636*6777b538SAndroid Build Coastguard Worker #endif  // BUILDFLAG(DCHECK_IS_CONFIGURABLE)
637*6777b538SAndroid Build Coastguard Worker }
638*6777b538SAndroid Build Coastguard Worker 
639*6777b538SAndroid Build Coastguard Worker // static
SetEarlyAccessInstance(std::unique_ptr<FeatureList> instance,base::flat_set<std::string> allowed_feature_names)640*6777b538SAndroid Build Coastguard Worker void FeatureList::SetEarlyAccessInstance(
641*6777b538SAndroid Build Coastguard Worker     std::unique_ptr<FeatureList> instance,
642*6777b538SAndroid Build Coastguard Worker     base::flat_set<std::string> allowed_feature_names) {
643*6777b538SAndroid Build Coastguard Worker   CHECK(!g_feature_list_instance);
644*6777b538SAndroid Build Coastguard Worker   CHECK(!allowed_feature_names.empty());
645*6777b538SAndroid Build Coastguard Worker   instance->allowed_feature_names_ = std::move(allowed_feature_names);
646*6777b538SAndroid Build Coastguard Worker   SetInstance(std::move(instance));
647*6777b538SAndroid Build Coastguard Worker }
648*6777b538SAndroid Build Coastguard Worker 
649*6777b538SAndroid Build Coastguard Worker // static
ClearInstanceForTesting()650*6777b538SAndroid Build Coastguard Worker std::unique_ptr<FeatureList> FeatureList::ClearInstanceForTesting() {
651*6777b538SAndroid Build Coastguard Worker   FeatureList* old_instance = g_feature_list_instance;
652*6777b538SAndroid Build Coastguard Worker   g_feature_list_instance = nullptr;
653*6777b538SAndroid Build Coastguard Worker   EarlyFeatureAccessTracker::GetInstance()->Reset();
654*6777b538SAndroid Build Coastguard Worker   return WrapUnique(old_instance);
655*6777b538SAndroid Build Coastguard Worker }
656*6777b538SAndroid Build Coastguard Worker 
657*6777b538SAndroid Build Coastguard Worker // static
RestoreInstanceForTesting(std::unique_ptr<FeatureList> instance)658*6777b538SAndroid Build Coastguard Worker void FeatureList::RestoreInstanceForTesting(
659*6777b538SAndroid Build Coastguard Worker     std::unique_ptr<FeatureList> instance) {
660*6777b538SAndroid Build Coastguard Worker   DCHECK(!g_feature_list_instance);
661*6777b538SAndroid Build Coastguard Worker   // Note: Intentional leak of global singleton.
662*6777b538SAndroid Build Coastguard Worker   g_feature_list_instance = instance.release();
663*6777b538SAndroid Build Coastguard Worker }
664*6777b538SAndroid Build Coastguard Worker 
665*6777b538SAndroid Build Coastguard Worker // static
FailOnFeatureAccessWithoutFeatureList()666*6777b538SAndroid Build Coastguard Worker void FeatureList::FailOnFeatureAccessWithoutFeatureList() {
667*6777b538SAndroid Build Coastguard Worker   EarlyFeatureAccessTracker::GetInstance()
668*6777b538SAndroid Build Coastguard Worker       ->FailOnFeatureAccessWithoutFeatureList();
669*6777b538SAndroid Build Coastguard Worker }
670*6777b538SAndroid Build Coastguard Worker 
671*6777b538SAndroid Build Coastguard Worker // static
GetEarlyAccessedFeatureForTesting()672*6777b538SAndroid Build Coastguard Worker const Feature* FeatureList::GetEarlyAccessedFeatureForTesting() {
673*6777b538SAndroid Build Coastguard Worker   return EarlyFeatureAccessTracker::GetInstance()->GetFeature();
674*6777b538SAndroid Build Coastguard Worker }
675*6777b538SAndroid Build Coastguard Worker 
676*6777b538SAndroid Build Coastguard Worker // static
ResetEarlyFeatureAccessTrackerForTesting()677*6777b538SAndroid Build Coastguard Worker void FeatureList::ResetEarlyFeatureAccessTrackerForTesting() {
678*6777b538SAndroid Build Coastguard Worker   EarlyFeatureAccessTracker::GetInstance()->Reset();
679*6777b538SAndroid Build Coastguard Worker }
680*6777b538SAndroid Build Coastguard Worker 
AddEarlyAllowedFeatureForTesting(std::string feature_name)681*6777b538SAndroid Build Coastguard Worker void FeatureList::AddEarlyAllowedFeatureForTesting(std::string feature_name) {
682*6777b538SAndroid Build Coastguard Worker   CHECK(IsEarlyAccessInstance());
683*6777b538SAndroid Build Coastguard Worker   allowed_feature_names_.insert(std::move(feature_name));
684*6777b538SAndroid Build Coastguard Worker }
685*6777b538SAndroid Build Coastguard Worker 
686*6777b538SAndroid Build Coastguard Worker #if BUILDFLAG(IS_CHROMEOS_ASH)
687*6777b538SAndroid Build Coastguard Worker // static
VisitFeaturesAndParams(FeatureVisitor & visitor)688*6777b538SAndroid Build Coastguard Worker void FeatureList::VisitFeaturesAndParams(FeatureVisitor& visitor) {
689*6777b538SAndroid Build Coastguard Worker   CHECK(g_feature_list_instance);
690*6777b538SAndroid Build Coastguard Worker   FieldTrialParamAssociator* params_associator =
691*6777b538SAndroid Build Coastguard Worker       FieldTrialParamAssociator::GetInstance();
692*6777b538SAndroid Build Coastguard Worker 
693*6777b538SAndroid Build Coastguard Worker   for (auto& feature_override : g_feature_list_instance->overrides_) {
694*6777b538SAndroid Build Coastguard Worker     FieldTrial* field_trial = feature_override.second.field_trial;
695*6777b538SAndroid Build Coastguard Worker 
696*6777b538SAndroid Build Coastguard Worker     std::string trial_name;
697*6777b538SAndroid Build Coastguard Worker     std::string group_name;
698*6777b538SAndroid Build Coastguard Worker     FieldTrialParams params;
699*6777b538SAndroid Build Coastguard Worker     if (field_trial) {
700*6777b538SAndroid Build Coastguard Worker       trial_name = field_trial->trial_name();
701*6777b538SAndroid Build Coastguard Worker       group_name = field_trial->group_name();
702*6777b538SAndroid Build Coastguard Worker       params_associator->GetFieldTrialParamsWithoutFallback(
703*6777b538SAndroid Build Coastguard Worker           trial_name, group_name, &params);
704*6777b538SAndroid Build Coastguard Worker     }
705*6777b538SAndroid Build Coastguard Worker 
706*6777b538SAndroid Build Coastguard Worker     visitor.Visit(feature_override.first,
707*6777b538SAndroid Build Coastguard Worker                   feature_override.second.overridden_state, params, trial_name,
708*6777b538SAndroid Build Coastguard Worker                   group_name);
709*6777b538SAndroid Build Coastguard Worker   }
710*6777b538SAndroid Build Coastguard Worker }
711*6777b538SAndroid Build Coastguard Worker #endif  // BULDFLAG(IS_CHROMEOS_ASH)
712*6777b538SAndroid Build Coastguard Worker 
FinalizeInitialization()713*6777b538SAndroid Build Coastguard Worker void FeatureList::FinalizeInitialization() {
714*6777b538SAndroid Build Coastguard Worker   DCHECK(!initialized_);
715*6777b538SAndroid Build Coastguard Worker   // Store the field trial list pointer for DCHECKing.
716*6777b538SAndroid Build Coastguard Worker   field_trial_list_ = FieldTrialList::GetInstance();
717*6777b538SAndroid Build Coastguard Worker   initialized_ = true;
718*6777b538SAndroid Build Coastguard Worker }
719*6777b538SAndroid Build Coastguard Worker 
IsFeatureEnabled(const Feature & feature) const720*6777b538SAndroid Build Coastguard Worker bool FeatureList::IsFeatureEnabled(const Feature& feature) const {
721*6777b538SAndroid Build Coastguard Worker   OverrideState overridden_state = GetOverrideState(feature);
722*6777b538SAndroid Build Coastguard Worker 
723*6777b538SAndroid Build Coastguard Worker   // If marked as OVERRIDE_USE_DEFAULT, simply return the default state below.
724*6777b538SAndroid Build Coastguard Worker   if (overridden_state != OVERRIDE_USE_DEFAULT)
725*6777b538SAndroid Build Coastguard Worker     return overridden_state == OVERRIDE_ENABLE_FEATURE;
726*6777b538SAndroid Build Coastguard Worker 
727*6777b538SAndroid Build Coastguard Worker   return feature.default_state == FEATURE_ENABLED_BY_DEFAULT;
728*6777b538SAndroid Build Coastguard Worker }
729*6777b538SAndroid Build Coastguard Worker 
IsFeatureEnabledIfOverridden(const Feature & feature) const730*6777b538SAndroid Build Coastguard Worker std::optional<bool> FeatureList::IsFeatureEnabledIfOverridden(
731*6777b538SAndroid Build Coastguard Worker     const Feature& feature) const {
732*6777b538SAndroid Build Coastguard Worker   OverrideState overridden_state = GetOverrideState(feature);
733*6777b538SAndroid Build Coastguard Worker 
734*6777b538SAndroid Build Coastguard Worker   // If marked as OVERRIDE_USE_DEFAULT, fall through to returning empty.
735*6777b538SAndroid Build Coastguard Worker   if (overridden_state != OVERRIDE_USE_DEFAULT)
736*6777b538SAndroid Build Coastguard Worker     return overridden_state == OVERRIDE_ENABLE_FEATURE;
737*6777b538SAndroid Build Coastguard Worker 
738*6777b538SAndroid Build Coastguard Worker   return std::nullopt;
739*6777b538SAndroid Build Coastguard Worker }
740*6777b538SAndroid Build Coastguard Worker 
GetOverrideState(const Feature & feature) const741*6777b538SAndroid Build Coastguard Worker FeatureList::OverrideState FeatureList::GetOverrideState(
742*6777b538SAndroid Build Coastguard Worker     const Feature& feature) const {
743*6777b538SAndroid Build Coastguard Worker   DCHECK(initialized_);
744*6777b538SAndroid Build Coastguard Worker   DCHECK(IsValidFeatureOrFieldTrialName(feature.name)) << feature.name;
745*6777b538SAndroid Build Coastguard Worker   DCHECK(CheckFeatureIdentity(feature))
746*6777b538SAndroid Build Coastguard Worker       << feature.name
747*6777b538SAndroid Build Coastguard Worker       << " has multiple definitions. Either it is defined more than once in "
748*6777b538SAndroid Build Coastguard Worker          "code or (for component builds) the code is built into multiple "
749*6777b538SAndroid Build Coastguard Worker          "components (shared libraries) without a corresponding export "
750*6777b538SAndroid Build Coastguard Worker          "statement";
751*6777b538SAndroid Build Coastguard Worker 
752*6777b538SAndroid Build Coastguard Worker   uint32_t current_cache_value =
753*6777b538SAndroid Build Coastguard Worker       feature.cached_value.load(std::memory_order_relaxed);
754*6777b538SAndroid Build Coastguard Worker 
755*6777b538SAndroid Build Coastguard Worker   auto unpacked = UnpackFeatureCache(current_cache_value);
756*6777b538SAndroid Build Coastguard Worker 
757*6777b538SAndroid Build Coastguard Worker   if (unpacked.second == caching_context_)
758*6777b538SAndroid Build Coastguard Worker     return unpacked.first;
759*6777b538SAndroid Build Coastguard Worker 
760*6777b538SAndroid Build Coastguard Worker   OverrideState state = GetOverrideStateByFeatureName(feature.name);
761*6777b538SAndroid Build Coastguard Worker   uint32_t new_cache_value = PackFeatureCache(state, caching_context_);
762*6777b538SAndroid Build Coastguard Worker 
763*6777b538SAndroid Build Coastguard Worker   // Update the cache with the new value.
764*6777b538SAndroid Build Coastguard Worker   // In non-test code, this value can be in one of 2 states: either it's unset,
765*6777b538SAndroid Build Coastguard Worker   // or another thread has updated it to the same value we're about to write.
766*6777b538SAndroid Build Coastguard Worker   // Because of this, a plain `store` yields the correct result in all cases.
767*6777b538SAndroid Build Coastguard Worker   // In test code, it's possible for a different thread to have installed a new
768*6777b538SAndroid Build Coastguard Worker   // `ScopedFeatureList` and written a value that's different than the one we're
769*6777b538SAndroid Build Coastguard Worker   // about to write, although that would be a thread safety violation already
770*6777b538SAndroid Build Coastguard Worker   // and such tests should be fixed.
771*6777b538SAndroid Build Coastguard Worker   feature.cached_value.store(new_cache_value, std::memory_order_relaxed);
772*6777b538SAndroid Build Coastguard Worker 
773*6777b538SAndroid Build Coastguard Worker   return state;
774*6777b538SAndroid Build Coastguard Worker }
775*6777b538SAndroid Build Coastguard Worker 
GetOverrideStateByFeatureName(std::string_view feature_name) const776*6777b538SAndroid Build Coastguard Worker FeatureList::OverrideState FeatureList::GetOverrideStateByFeatureName(
777*6777b538SAndroid Build Coastguard Worker     std::string_view feature_name) const {
778*6777b538SAndroid Build Coastguard Worker   DCHECK(initialized_);
779*6777b538SAndroid Build Coastguard Worker   DCHECK(IsValidFeatureOrFieldTrialName(feature_name)) << feature_name;
780*6777b538SAndroid Build Coastguard Worker 
781*6777b538SAndroid Build Coastguard Worker   auto it = overrides_.find(feature_name);
782*6777b538SAndroid Build Coastguard Worker   if (it != overrides_.end()) {
783*6777b538SAndroid Build Coastguard Worker     const OverrideEntry& entry = it->second;
784*6777b538SAndroid Build Coastguard Worker 
785*6777b538SAndroid Build Coastguard Worker     // Activate the corresponding field trial, if necessary.
786*6777b538SAndroid Build Coastguard Worker     if (entry.field_trial)
787*6777b538SAndroid Build Coastguard Worker       entry.field_trial->Activate();
788*6777b538SAndroid Build Coastguard Worker 
789*6777b538SAndroid Build Coastguard Worker     // TODO(asvitkine) Expand this section as more support is added.
790*6777b538SAndroid Build Coastguard Worker 
791*6777b538SAndroid Build Coastguard Worker     return entry.overridden_state;
792*6777b538SAndroid Build Coastguard Worker   }
793*6777b538SAndroid Build Coastguard Worker   // Otherwise, report that we want to use the default state.
794*6777b538SAndroid Build Coastguard Worker   return OVERRIDE_USE_DEFAULT;
795*6777b538SAndroid Build Coastguard Worker }
796*6777b538SAndroid Build Coastguard Worker 
GetAssociatedFieldTrial(const Feature & feature) const797*6777b538SAndroid Build Coastguard Worker FieldTrial* FeatureList::GetAssociatedFieldTrial(const Feature& feature) const {
798*6777b538SAndroid Build Coastguard Worker   DCHECK(initialized_);
799*6777b538SAndroid Build Coastguard Worker   DCHECK(CheckFeatureIdentity(feature)) << feature.name;
800*6777b538SAndroid Build Coastguard Worker 
801*6777b538SAndroid Build Coastguard Worker   return GetAssociatedFieldTrialByFeatureName(feature.name);
802*6777b538SAndroid Build Coastguard Worker }
803*6777b538SAndroid Build Coastguard Worker 
804*6777b538SAndroid Build Coastguard Worker const base::FeatureList::OverrideEntry*
GetOverrideEntryByFeatureName(std::string_view name) const805*6777b538SAndroid Build Coastguard Worker FeatureList::GetOverrideEntryByFeatureName(std::string_view name) const {
806*6777b538SAndroid Build Coastguard Worker   DCHECK(initialized_);
807*6777b538SAndroid Build Coastguard Worker   DCHECK(IsValidFeatureOrFieldTrialName(name)) << name;
808*6777b538SAndroid Build Coastguard Worker 
809*6777b538SAndroid Build Coastguard Worker   auto it = overrides_.find(name);
810*6777b538SAndroid Build Coastguard Worker   if (it != overrides_.end()) {
811*6777b538SAndroid Build Coastguard Worker     const OverrideEntry& entry = it->second;
812*6777b538SAndroid Build Coastguard Worker     return &entry;
813*6777b538SAndroid Build Coastguard Worker   }
814*6777b538SAndroid Build Coastguard Worker   return nullptr;
815*6777b538SAndroid Build Coastguard Worker }
816*6777b538SAndroid Build Coastguard Worker 
GetAssociatedFieldTrialByFeatureName(std::string_view name) const817*6777b538SAndroid Build Coastguard Worker FieldTrial* FeatureList::GetAssociatedFieldTrialByFeatureName(
818*6777b538SAndroid Build Coastguard Worker     std::string_view name) const {
819*6777b538SAndroid Build Coastguard Worker   DCHECK(initialized_);
820*6777b538SAndroid Build Coastguard Worker 
821*6777b538SAndroid Build Coastguard Worker   const base::FeatureList::OverrideEntry* entry =
822*6777b538SAndroid Build Coastguard Worker       GetOverrideEntryByFeatureName(name);
823*6777b538SAndroid Build Coastguard Worker   if (entry) {
824*6777b538SAndroid Build Coastguard Worker     return entry->field_trial;
825*6777b538SAndroid Build Coastguard Worker   }
826*6777b538SAndroid Build Coastguard Worker   return nullptr;
827*6777b538SAndroid Build Coastguard Worker }
828*6777b538SAndroid Build Coastguard Worker 
HasAssociatedFieldTrialByFeatureName(std::string_view name) const829*6777b538SAndroid Build Coastguard Worker bool FeatureList::HasAssociatedFieldTrialByFeatureName(
830*6777b538SAndroid Build Coastguard Worker     std::string_view name) const {
831*6777b538SAndroid Build Coastguard Worker   DCHECK(!initialized_);
832*6777b538SAndroid Build Coastguard Worker   auto entry = overrides_.find(name);
833*6777b538SAndroid Build Coastguard Worker   return entry != overrides_.end() && entry->second.field_trial != nullptr;
834*6777b538SAndroid Build Coastguard Worker }
835*6777b538SAndroid Build Coastguard Worker 
GetEnabledFieldTrialByFeatureName(std::string_view name) const836*6777b538SAndroid Build Coastguard Worker FieldTrial* FeatureList::GetEnabledFieldTrialByFeatureName(
837*6777b538SAndroid Build Coastguard Worker     std::string_view name) const {
838*6777b538SAndroid Build Coastguard Worker   DCHECK(initialized_);
839*6777b538SAndroid Build Coastguard Worker 
840*6777b538SAndroid Build Coastguard Worker   const base::FeatureList::OverrideEntry* entry =
841*6777b538SAndroid Build Coastguard Worker       GetOverrideEntryByFeatureName(name);
842*6777b538SAndroid Build Coastguard Worker   if (entry &&
843*6777b538SAndroid Build Coastguard Worker       entry->overridden_state == base::FeatureList::OVERRIDE_ENABLE_FEATURE) {
844*6777b538SAndroid Build Coastguard Worker     return entry->field_trial;
845*6777b538SAndroid Build Coastguard Worker   }
846*6777b538SAndroid Build Coastguard Worker   return nullptr;
847*6777b538SAndroid Build Coastguard Worker }
848*6777b538SAndroid Build Coastguard Worker 
ConstructAccessor()849*6777b538SAndroid Build Coastguard Worker std::unique_ptr<FeatureList::Accessor> FeatureList::ConstructAccessor() {
850*6777b538SAndroid Build Coastguard Worker   if (initialized_) {
851*6777b538SAndroid Build Coastguard Worker     // This function shouldn't be called after initialization.
852*6777b538SAndroid Build Coastguard Worker     NOTREACHED();
853*6777b538SAndroid Build Coastguard Worker     return nullptr;
854*6777b538SAndroid Build Coastguard Worker   }
855*6777b538SAndroid Build Coastguard Worker   // Use new and WrapUnique because we want to restrict access to the Accessor's
856*6777b538SAndroid Build Coastguard Worker   // constructor.
857*6777b538SAndroid Build Coastguard Worker   return base::WrapUnique(new Accessor(this));
858*6777b538SAndroid Build Coastguard Worker }
859*6777b538SAndroid Build Coastguard Worker 
RegisterOverridesFromCommandLine(const std::string & feature_list,OverrideState overridden_state)860*6777b538SAndroid Build Coastguard Worker void FeatureList::RegisterOverridesFromCommandLine(
861*6777b538SAndroid Build Coastguard Worker     const std::string& feature_list,
862*6777b538SAndroid Build Coastguard Worker     OverrideState overridden_state) {
863*6777b538SAndroid Build Coastguard Worker   for (const auto& value : SplitFeatureListString(feature_list)) {
864*6777b538SAndroid Build Coastguard Worker     std::string_view feature_name = value;
865*6777b538SAndroid Build Coastguard Worker     FieldTrial* trial = nullptr;
866*6777b538SAndroid Build Coastguard Worker 
867*6777b538SAndroid Build Coastguard Worker     // The entry may be of the form FeatureName<FieldTrialName - in which case,
868*6777b538SAndroid Build Coastguard Worker     // this splits off the field trial name and associates it with the override.
869*6777b538SAndroid Build Coastguard Worker     std::string::size_type pos = feature_name.find('<');
870*6777b538SAndroid Build Coastguard Worker     if (pos != std::string::npos) {
871*6777b538SAndroid Build Coastguard Worker       feature_name = std::string_view(value.data(), pos);
872*6777b538SAndroid Build Coastguard Worker       trial = FieldTrialList::Find(value.substr(pos + 1));
873*6777b538SAndroid Build Coastguard Worker #if !BUILDFLAG(IS_NACL)
874*6777b538SAndroid Build Coastguard Worker       // If the below DCHECK fires, it means a non-existent trial name was
875*6777b538SAndroid Build Coastguard Worker       // specified via the "Feature<Trial" command-line syntax.
876*6777b538SAndroid Build Coastguard Worker       DCHECK(trial) << "trial='" << value.substr(pos + 1) << "' does not exist";
877*6777b538SAndroid Build Coastguard Worker #endif  // !BUILDFLAG(IS_NACL)
878*6777b538SAndroid Build Coastguard Worker     }
879*6777b538SAndroid Build Coastguard Worker 
880*6777b538SAndroid Build Coastguard Worker     RegisterOverride(feature_name, overridden_state, trial);
881*6777b538SAndroid Build Coastguard Worker   }
882*6777b538SAndroid Build Coastguard Worker }
883*6777b538SAndroid Build Coastguard Worker 
RegisterOverride(std::string_view feature_name,OverrideState overridden_state,FieldTrial * field_trial)884*6777b538SAndroid Build Coastguard Worker void FeatureList::RegisterOverride(std::string_view feature_name,
885*6777b538SAndroid Build Coastguard Worker                                    OverrideState overridden_state,
886*6777b538SAndroid Build Coastguard Worker                                    FieldTrial* field_trial) {
887*6777b538SAndroid Build Coastguard Worker   DCHECK(!initialized_);
888*6777b538SAndroid Build Coastguard Worker   DCheckOverridesAllowed();
889*6777b538SAndroid Build Coastguard Worker   if (field_trial) {
890*6777b538SAndroid Build Coastguard Worker     DCHECK(IsValidFeatureOrFieldTrialName(field_trial->trial_name()))
891*6777b538SAndroid Build Coastguard Worker         << field_trial->trial_name();
892*6777b538SAndroid Build Coastguard Worker   }
893*6777b538SAndroid Build Coastguard Worker   if (StartsWith(feature_name, "*")) {
894*6777b538SAndroid Build Coastguard Worker     feature_name = feature_name.substr(1);
895*6777b538SAndroid Build Coastguard Worker     overridden_state = OVERRIDE_USE_DEFAULT;
896*6777b538SAndroid Build Coastguard Worker   }
897*6777b538SAndroid Build Coastguard Worker 
898*6777b538SAndroid Build Coastguard Worker   // Note: The semantics of emplace() is that it does not overwrite the entry if
899*6777b538SAndroid Build Coastguard Worker   // one already exists for the key. Thus, only the first override for a given
900*6777b538SAndroid Build Coastguard Worker   // feature name takes effect.
901*6777b538SAndroid Build Coastguard Worker   overrides_.emplace(std::string(feature_name),
902*6777b538SAndroid Build Coastguard Worker                      OverrideEntry(overridden_state, field_trial));
903*6777b538SAndroid Build Coastguard Worker }
904*6777b538SAndroid Build Coastguard Worker 
GetFeatureOverridesImpl(std::string * enable_overrides,std::string * disable_overrides,bool command_line_only,bool include_group_name) const905*6777b538SAndroid Build Coastguard Worker void FeatureList::GetFeatureOverridesImpl(std::string* enable_overrides,
906*6777b538SAndroid Build Coastguard Worker                                           std::string* disable_overrides,
907*6777b538SAndroid Build Coastguard Worker                                           bool command_line_only,
908*6777b538SAndroid Build Coastguard Worker                                           bool include_group_name) const {
909*6777b538SAndroid Build Coastguard Worker   DCHECK(initialized_);
910*6777b538SAndroid Build Coastguard Worker 
911*6777b538SAndroid Build Coastguard Worker   // Check that the FieldTrialList this is associated with, if any, is the
912*6777b538SAndroid Build Coastguard Worker   // active one. If not, it likely indicates that this FeatureList has override
913*6777b538SAndroid Build Coastguard Worker   // entries from a freed FieldTrial, which may be caused by an incorrect test
914*6777b538SAndroid Build Coastguard Worker   // set up.
915*6777b538SAndroid Build Coastguard Worker   if (field_trial_list_)
916*6777b538SAndroid Build Coastguard Worker     DCHECK_EQ(field_trial_list_, FieldTrialList::GetInstance());
917*6777b538SAndroid Build Coastguard Worker 
918*6777b538SAndroid Build Coastguard Worker   enable_overrides->clear();
919*6777b538SAndroid Build Coastguard Worker   disable_overrides->clear();
920*6777b538SAndroid Build Coastguard Worker 
921*6777b538SAndroid Build Coastguard Worker   // Note: Since |overrides_| is a std::map, iteration will be in alphabetical
922*6777b538SAndroid Build Coastguard Worker   // order. This is not guaranteed to users of this function, but is useful for
923*6777b538SAndroid Build Coastguard Worker   // tests to assume the order.
924*6777b538SAndroid Build Coastguard Worker   for (const auto& entry : overrides_) {
925*6777b538SAndroid Build Coastguard Worker     if (command_line_only &&
926*6777b538SAndroid Build Coastguard Worker         (entry.second.field_trial != nullptr ||
927*6777b538SAndroid Build Coastguard Worker          entry.second.overridden_state == OVERRIDE_USE_DEFAULT)) {
928*6777b538SAndroid Build Coastguard Worker       continue;
929*6777b538SAndroid Build Coastguard Worker     }
930*6777b538SAndroid Build Coastguard Worker 
931*6777b538SAndroid Build Coastguard Worker     std::string* target_list = nullptr;
932*6777b538SAndroid Build Coastguard Worker     switch (entry.second.overridden_state) {
933*6777b538SAndroid Build Coastguard Worker       case OVERRIDE_USE_DEFAULT:
934*6777b538SAndroid Build Coastguard Worker       case OVERRIDE_ENABLE_FEATURE:
935*6777b538SAndroid Build Coastguard Worker         target_list = enable_overrides;
936*6777b538SAndroid Build Coastguard Worker         break;
937*6777b538SAndroid Build Coastguard Worker       case OVERRIDE_DISABLE_FEATURE:
938*6777b538SAndroid Build Coastguard Worker         target_list = disable_overrides;
939*6777b538SAndroid Build Coastguard Worker         break;
940*6777b538SAndroid Build Coastguard Worker     }
941*6777b538SAndroid Build Coastguard Worker 
942*6777b538SAndroid Build Coastguard Worker     if (!target_list->empty())
943*6777b538SAndroid Build Coastguard Worker       target_list->push_back(',');
944*6777b538SAndroid Build Coastguard Worker     if (entry.second.overridden_state == OVERRIDE_USE_DEFAULT)
945*6777b538SAndroid Build Coastguard Worker       target_list->push_back('*');
946*6777b538SAndroid Build Coastguard Worker     target_list->append(entry.first);
947*6777b538SAndroid Build Coastguard Worker     if (entry.second.field_trial) {
948*6777b538SAndroid Build Coastguard Worker       auto* const field_trial = entry.second.field_trial.get();
949*6777b538SAndroid Build Coastguard Worker       target_list->push_back('<');
950*6777b538SAndroid Build Coastguard Worker       target_list->append(field_trial->trial_name());
951*6777b538SAndroid Build Coastguard Worker       if (include_group_name) {
952*6777b538SAndroid Build Coastguard Worker         target_list->push_back('.');
953*6777b538SAndroid Build Coastguard Worker         target_list->append(field_trial->GetGroupNameWithoutActivation());
954*6777b538SAndroid Build Coastguard Worker       }
955*6777b538SAndroid Build Coastguard Worker     }
956*6777b538SAndroid Build Coastguard Worker   }
957*6777b538SAndroid Build Coastguard Worker }
958*6777b538SAndroid Build Coastguard Worker 
CheckFeatureIdentity(const Feature & feature) const959*6777b538SAndroid Build Coastguard Worker bool FeatureList::CheckFeatureIdentity(const Feature& feature) const {
960*6777b538SAndroid Build Coastguard Worker   AutoLock auto_lock(feature_identity_tracker_lock_);
961*6777b538SAndroid Build Coastguard Worker 
962*6777b538SAndroid Build Coastguard Worker   auto it = feature_identity_tracker_.find(feature.name);
963*6777b538SAndroid Build Coastguard Worker   if (it == feature_identity_tracker_.end()) {
964*6777b538SAndroid Build Coastguard Worker     // If it's not tracked yet, register it.
965*6777b538SAndroid Build Coastguard Worker     feature_identity_tracker_[feature.name] = &feature;
966*6777b538SAndroid Build Coastguard Worker     return true;
967*6777b538SAndroid Build Coastguard Worker   }
968*6777b538SAndroid Build Coastguard Worker   // Compare address of |feature| to the existing tracked entry.
969*6777b538SAndroid Build Coastguard Worker   return it->second == &feature;
970*6777b538SAndroid Build Coastguard Worker }
971*6777b538SAndroid Build Coastguard Worker 
IsEarlyAccessInstance() const972*6777b538SAndroid Build Coastguard Worker bool FeatureList::IsEarlyAccessInstance() const {
973*6777b538SAndroid Build Coastguard Worker   return !allowed_feature_names_.empty();
974*6777b538SAndroid Build Coastguard Worker }
975*6777b538SAndroid Build Coastguard Worker 
AllowFeatureAccess(const Feature & feature) const976*6777b538SAndroid Build Coastguard Worker bool FeatureList::AllowFeatureAccess(const Feature& feature) const {
977*6777b538SAndroid Build Coastguard Worker   DCHECK(initialized_);
978*6777b538SAndroid Build Coastguard Worker   // If this isn't an instance set with SetEarlyAccessInstance all features are
979*6777b538SAndroid Build Coastguard Worker   // allowed to be checked.
980*6777b538SAndroid Build Coastguard Worker   if (!IsEarlyAccessInstance()) {
981*6777b538SAndroid Build Coastguard Worker     return true;
982*6777b538SAndroid Build Coastguard Worker   }
983*6777b538SAndroid Build Coastguard Worker   return base::Contains(allowed_feature_names_, feature.name);
984*6777b538SAndroid Build Coastguard Worker }
985*6777b538SAndroid Build Coastguard Worker 
OverrideEntry(OverrideState overridden_state,FieldTrial * field_trial)986*6777b538SAndroid Build Coastguard Worker FeatureList::OverrideEntry::OverrideEntry(OverrideState overridden_state,
987*6777b538SAndroid Build Coastguard Worker                                           FieldTrial* field_trial)
988*6777b538SAndroid Build Coastguard Worker     : overridden_state(overridden_state),
989*6777b538SAndroid Build Coastguard Worker       field_trial(field_trial),
990*6777b538SAndroid Build Coastguard Worker       overridden_by_field_trial(field_trial != nullptr) {}
991*6777b538SAndroid Build Coastguard Worker 
Accessor(FeatureList * feature_list)992*6777b538SAndroid Build Coastguard Worker FeatureList::Accessor::Accessor(FeatureList* feature_list)
993*6777b538SAndroid Build Coastguard Worker     : feature_list_(feature_list) {}
994*6777b538SAndroid Build Coastguard Worker 
GetOverrideStateByFeatureName(std::string_view feature_name)995*6777b538SAndroid Build Coastguard Worker FeatureList::OverrideState FeatureList::Accessor::GetOverrideStateByFeatureName(
996*6777b538SAndroid Build Coastguard Worker     std::string_view feature_name) {
997*6777b538SAndroid Build Coastguard Worker   return feature_list_->GetOverrideStateByFeatureName(feature_name);
998*6777b538SAndroid Build Coastguard Worker }
999*6777b538SAndroid Build Coastguard Worker 
GetParamsByFeatureName(std::string_view feature_name,std::map<std::string,std::string> * params)1000*6777b538SAndroid Build Coastguard Worker bool FeatureList::Accessor::GetParamsByFeatureName(
1001*6777b538SAndroid Build Coastguard Worker     std::string_view feature_name,
1002*6777b538SAndroid Build Coastguard Worker     std::map<std::string, std::string>* params) {
1003*6777b538SAndroid Build Coastguard Worker   base::FieldTrial* trial =
1004*6777b538SAndroid Build Coastguard Worker       feature_list_->GetAssociatedFieldTrialByFeatureName(feature_name);
1005*6777b538SAndroid Build Coastguard Worker   return FieldTrialParamAssociator::GetInstance()->GetFieldTrialParams(trial,
1006*6777b538SAndroid Build Coastguard Worker                                                                        params);
1007*6777b538SAndroid Build Coastguard Worker }
1008*6777b538SAndroid Build Coastguard Worker 
1009*6777b538SAndroid Build Coastguard Worker }  // namespace base
1010