• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2015 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #ifndef BASE_FEATURE_LIST_H_
6 #define BASE_FEATURE_LIST_H_
7 
8 #include <atomic>
9 #include <functional>
10 #include <map>
11 #include <memory>
12 #include <optional>
13 #include <string>
14 #include <string_view>
15 #include <utility>
16 #include <vector>
17 
18 #include "base/base_export.h"
19 #include "base/compiler_specific.h"
20 #include "base/containers/flat_map.h"
21 #include "base/containers/flat_set.h"
22 #include "base/dcheck_is_on.h"
23 #include "base/feature_list_buildflags.h"
24 #include "base/gtest_prod_util.h"
25 #include "base/logging.h"
26 #include "base/memory/raw_ptr.h"
27 #include "base/synchronization/lock.h"
28 #include "build/build_config.h"
29 
30 namespace base {
31 
32 class FieldTrial;
33 class FieldTrialList;
34 class PersistentMemoryAllocator;
35 class FeatureVisitor;
36 
37 // Specifies whether a given feature is enabled or disabled by default.
38 // NOTE: The actual runtime state may be different, due to a field trial or a
39 // command line switch.
40 enum FeatureState {
41   FEATURE_DISABLED_BY_DEFAULT,
42   FEATURE_ENABLED_BY_DEFAULT,
43 };
44 
45 // Recommended macros for declaring and defining features and parameters:
46 //
47 // - `kFeature` is the C++ identifier that will be used for the `base::Feature`.
48 // - `name` is the feature name, which must be globally unique. This name is
49 //   used to enable/disable features via experiments and command-line flags.
50 //   Names should use CamelCase-style naming, e.g. "MyGreatFeature".
51 // - `default_state` is the default state to use for the feature, i.e.
52 //   `base::FEATURE_DISABLED_BY_DEFAULT` or `base::FEATURE_ENABLED_BY_DEFAULT`.
53 //   As noted above, the actual runtime state may differ from the default state,
54 //   due to field trials or command-line switches.
55 
56 // Provides a forward declaration for `kFeature` in a header file, e.g.
57 //
58 //   BASE_DECLARE_FEATURE(kMyFeature);
59 //
60 // If the feature needs to be marked as exported, i.e. it is referenced by
61 // multiple components, then write:
62 //
63 //   COMPONENT_EXPORT(MY_COMPONENT) BASE_DECLARE_FEATURE(kMyFeature);
64 #define BASE_DECLARE_FEATURE(kFeature) \
65   extern constinit const base::Feature kFeature
66 
67 // Provides a definition for `kFeature` with `name` and `default_state`, e.g.
68 //
69 //   BASE_FEATURE(kMyFeature, "MyFeature", base::FEATURE_DISABLED_BY_DEFAULT);
70 //
71 // Features should *not* be defined in header files; do not use this macro in
72 // header files.
73 #define BASE_FEATURE(feature, name, default_state) \
74   constinit const base::Feature feature(           \
75       name, default_state, base::internal::FeatureMacroHandshake::kSecret)
76 
77 // Provides a forward declaration for `feature_object_name` in a header file,
78 // e.g.
79 //
80 //   BASE_DECLARE_FEATURE_PARAM(kMyFeatureParam);
81 //
82 // If the feature needs to be marked as exported, i.e. it is referenced by
83 // multiple components, then write:
84 //
85 //   COMPONENT_EXPORT(MY_COMPONENT) BASE_DECLARE_FEATURE_PARAM(kMyFeatureParam);
86 //
87 // This macro enables optimizations to make the second and later calls faster,
88 // but requires additional memory uses. If you obtain the parameter only once,
89 // you can instantiate base::FeatureParam directly, or can call
90 // base::GetFieldTrialParamByFeatureAsInt or equivalent functions for other
91 // types directly.
92 #define BASE_DECLARE_FEATURE_PARAM(T, feature_object_name) \
93   extern constinit const base::FeatureParam<T> feature_object_name
94 
95 // Provides a definition for `feature_object_name` with `T`, `feature`, `name`
96 // and `default_value`, with an internal parsed value cache, e.g.
97 //
98 //   BASE_FEATURE_PARAM(int, kMyFeatureParam, kMyFeature, "MyFeatureParam", 0);
99 //
100 // `T` is a parameter type, one of bool, int, size_t, double, std::string, and
101 // base::TimeDelta. Enum types are not supported for now.
102 //
103 // For now, ScopedFeatureList doesn't work to change the value dynamically when
104 // the cache is used with this macro.
105 //
106 // It should *not* be defined in header files; do not use this macro in header
107 // files.
108 #define BASE_FEATURE_PARAM(T, feature_object_name, feature, name,       \
109                            default_value)                               \
110   namespace field_trial_params_internal {                               \
111   T GetFeatureParamWithCacheFor##feature_object_name(                   \
112       const base::FeatureParam<T>* feature_param) {                     \
113     static const typename base::internal::FeatureParamTraits<           \
114         T>::CacheStorageType storage =                                  \
115         base::internal::FeatureParamTraits<T>::ToCacheStorageType(      \
116             feature_param->GetWithoutCache());                          \
117     return base::internal::FeatureParamTraits<T>::FromCacheStorageType( \
118         storage);                                                       \
119   }                                                                     \
120   } /* field_trial_params_internal */                                   \
121   constinit const base::FeatureParam<T> feature_object_name(            \
122       feature, name, default_value,                                     \
123       &field_trial_params_internal::                                    \
124           GetFeatureParamWithCacheFor##feature_object_name)
125 
126 // Same as BASE_FEATURE_PARAM() but used for enum type parameters with on extra
127 // argument, `options`. See base::FeatureParam<Enum> template declaration in
128 // //base/metrics/field_trial_params.h for `options`' details.
129 #define BASE_FEATURE_ENUM_PARAM(T, feature_object_name, feature, name, \
130                                 default_value, options)                \
131   namespace field_trial_params_internal {                              \
132   T GetFeatureParamWithCacheFor##feature_object_name(                  \
133       const base::FeatureParam<T>* feature_param) {                    \
134     static const T param = feature_param->GetWithoutCache();           \
135     return param;                                                      \
136   }                                                                    \
137   } /* field_trial_params_internal */                                  \
138   constinit const base::FeatureParam<T> feature_object_name(           \
139       feature, name, default_value, options,                           \
140       &field_trial_params_internal::                                   \
141           GetFeatureParamWithCacheFor##feature_object_name)
142 
143 // Secret handshake to (try to) ensure all places that construct a base::Feature
144 // go through the helper `BASE_FEATURE()` macro above.
145 namespace internal {
146 enum class FeatureMacroHandshake { kSecret };
147 }
148 
149 // The Feature struct is used to define the default state for a feature. There
150 // must only ever be one struct instance for a given feature name—generally
151 // defined as a constant global variable or file static. Declare and define
152 // features using the `BASE_DECLARE_FEATURE()` and `BASE_FEATURE()` macros
153 // above, as there are some subtleties involved.
154 //
155 // Feature constants are internally mutable, as this allows them to contain a
156 // mutable member to cache their override state, while still remaining declared
157 // as const. This cache member allows for significantly faster IsEnabled()
158 // checks.
159 //
160 // However, the "Mutable Constants" check [1] detects this as a regression,
161 // because this usually means that a readonly symbol is put in writable memory
162 // when readonly memory would be more efficient.
163 //
164 // The performance gains of the cache are large enough to offset the downsides
165 // to having the symbols in bssdata rather than rodata. Use LOGICALLY_CONST to
166 // suppress the "Mutable Constants" check.
167 //
168 // [1]:
169 // https://crsrc.org/c/docs/speed/binary_size/android_binary_size_trybot.md#Mutable-Constants
170 struct BASE_EXPORT LOGICALLY_CONST Feature {
FeatureFeature171   constexpr Feature(const char* name,
172                     FeatureState default_state,
173                     internal::FeatureMacroHandshake)
174       : name(name), default_state(default_state) {
175 #if BUILDFLAG(ENABLE_BANNED_BASE_FEATURE_PREFIX)
176     if (std::string_view(name).find(BUILDFLAG(BANNED_BASE_FEATURE_PREFIX)) ==
177         0) {
178       LOG(FATAL) << "Invalid feature name " << name << " starts with "
179                  << BUILDFLAG(BANNED_BASE_FEATURE_PREFIX);
180     }
181 #endif  // BUILDFLAG(ENABLE_BANNED_BASE_FEATURE_PREFIX)
182   }
183 
184   // Non-copyable since:
185   // - there should be only one `Feature` instance per unique name.
186   // - a `Feature` contains internal cached state about the override state.
187   Feature(const Feature&) = delete;
188   Feature& operator=(const Feature&) = delete;
189 
190   // The name of the feature. This should be unique to each feature and is used
191   // for enabling/disabling features via command line flags and experiments.
192   // It is strongly recommended to use CamelCase style for feature names, e.g.
193   // "MyGreatFeature".
194   const char* const name;
195 
196   // The default state (i.e. enabled or disabled) for this feature.
197   // NOTE: The actual runtime state may be different, due to a field trial or a
198   // command line switch.
199   const FeatureState default_state;
200 
201  private:
202   friend class FeatureList;
203 
204   // A packed value where the first 8 bits represent the `OverrideState` of this
205   // feature, and the last 16 bits are a caching context ID used to allow
206   // ScopedFeatureLists to invalidate these cached values in testing. A value of
207   // 0 in the caching context ID field indicates that this value has never been
208   // looked up and cached, a value of 1 indicates this value contains the cached
209   // `OverrideState` that was looked up via `base::FeatureList`, and any other
210   // value indicate that this cached value is only valid for a particular
211   // ScopedFeatureList instance.
212   //
213   // Packing these values into a uint32_t makes it so that atomic operations
214   // performed on this fields can be lock free.
215   //
216   // The override state stored in this field is only used if the current
217   // `FeatureList::caching_context_` field is equal to the lower 16 bits of the
218   // packed cached value. Otherwise, the override state is looked up in the
219   // feature list and the cache is updated.
220   mutable std::atomic<uint32_t> cached_value = 0;
221 };
222 
223 #if BUILDFLAG(DCHECK_IS_CONFIGURABLE)
224 // DCHECKs have been built-in, and are configurable at run-time to be fatal, or
225 // not, via a DcheckIsFatal feature. We define the Feature here since it is
226 // checked in FeatureList::SetInstance(). See https://crbug.com/596231.
227 BASE_EXPORT BASE_DECLARE_FEATURE(kDCheckIsFatalFeature);
228 #endif  // BUILDFLAG(DCHECK_IS_CONFIGURABLE)
229 
230 // The FeatureList class is used to determine whether a given feature is on or
231 // off. It provides an authoritative answer, taking into account command-line
232 // overrides and experimental control.
233 //
234 // The basic use case is for any feature that can be toggled (e.g. through
235 // command-line or an experiment) to have a defined Feature struct, e.g.:
236 //
237 //   const base::Feature kMyGreatFeature {
238 //     "MyGreatFeature", base::FEATURE_ENABLED_BY_DEFAULT
239 //   };
240 //
241 // Then, client code that wishes to query the state of the feature would check:
242 //
243 //   if (base::FeatureList::IsEnabled(kMyGreatFeature)) {
244 //     // Feature code goes here.
245 //   }
246 //
247 // Behind the scenes, the above call would take into account any command-line
248 // flags to enable or disable the feature, any experiments that may control it
249 // and finally its default state (in that order of priority), to determine
250 // whether the feature is on.
251 //
252 // Features can be explicitly forced on or off by specifying a list of comma-
253 // separated feature names via the following command-line flags:
254 //
255 //   --enable-features=Feature5,Feature7
256 //   --disable-features=Feature1,Feature2,Feature3
257 //
258 // To enable/disable features in a test, do NOT append --enable-features or
259 // --disable-features to the command-line directly. Instead, use
260 // ScopedFeatureList. See base/test/scoped_feature_list.h for details.
261 //
262 // After initialization (which should be done single-threaded), the FeatureList
263 // API is thread safe.
264 //
265 // Note: This class is a singleton, but does not use base/memory/singleton.h in
266 // order to have control over its initialization sequence. Specifically, the
267 // intended use is to create an instance of this class and fully initialize it,
268 // before setting it as the singleton for a process, via SetInstance().
269 class BASE_EXPORT FeatureList {
270  public:
271   FeatureList();
272   FeatureList(const FeatureList&) = delete;
273   FeatureList& operator=(const FeatureList&) = delete;
274   ~FeatureList();
275 
276   // Used by common test fixture classes to prevent abuse of ScopedFeatureList
277   // after multiple threads have started.
278   class BASE_EXPORT ScopedDisallowOverrides {
279    public:
280     explicit ScopedDisallowOverrides(const char* reason);
281     ScopedDisallowOverrides(const ScopedDisallowOverrides&) = delete;
282     ScopedDisallowOverrides& operator=(const ScopedDisallowOverrides&) = delete;
283     ~ScopedDisallowOverrides();
284 
285    private:
286 #if DCHECK_IS_ON()
287     const char* const previous_reason_;
288 #endif
289   };
290 
291   // Specifies whether a feature override enables or disables the feature.
292   enum OverrideState {
293     OVERRIDE_USE_DEFAULT,
294     OVERRIDE_DISABLE_FEATURE,
295     OVERRIDE_ENABLE_FEATURE,
296   };
297 
298   // Accessor class, used to look up features by _name_ rather than by Feature
299   // object.
300   // Should only be used in limited cases. See ConstructAccessor() for details.
301   class BASE_EXPORT Accessor {
302    public:
303     Accessor(const Accessor&) = delete;
304     Accessor& operator=(const Accessor&) = delete;
305 
306     // Looks up the feature, returning only its override state, rather than
307     // falling back on a default value (since there is no default value given).
308     // Callers of this MUST ensure that there is a consistent, compile-time
309     // default value associated.
310     FeatureList::OverrideState GetOverrideStateByFeatureName(
311         std::string_view feature_name);
312 
313     // Look up the feature, and, if present, populate |params|.
314     // See GetFieldTrialParams in field_trial_params.h for more documentation.
315     bool GetParamsByFeatureName(std::string_view feature_name,
316                                 std::map<std::string, std::string>* params);
317 
318    private:
319     // Allow FeatureList to construct this class.
320     friend class FeatureList;
321 
322     explicit Accessor(FeatureList* feature_list);
323 
324     // Unowned pointer to the FeatureList object we use to look up feature
325     // enablement.
326     raw_ptr<FeatureList, DanglingUntriaged> feature_list_;
327   };
328 
329   // Describes a feature override. The first member is a Feature that will be
330   // overridden with the state given by the second member.
331   using FeatureOverrideInfo =
332       std::pair<const std::reference_wrapper<const Feature>, OverrideState>;
333 
334   // Initializes feature overrides via command-line flags `--enable-features=`
335   // and `--disable-features=`, each of which is a comma-separated list of
336   // features to enable or disable, respectively. This function also allows
337   // users to set a feature's field trial params via `--enable-features=`. Must
338   // only be invoked during the initialization phase (before
339   // FinalizeInitialization() has been called).
340   //
341   // If a feature appears on both lists, then it will be disabled. If
342   // a list entry has the format "FeatureName<TrialName" then this
343   // initialization will also associate the feature state override with the
344   // named field trial, if it exists. If a list entry has the format
345   // "FeatureName:k1/v1/k2/v2", "FeatureName<TrialName:k1/v1/k2/v2" or
346   // "FeatureName<TrialName.GroupName:k1/v1/k2/v2" then this initialization will
347   // also associate the feature state override with the named field trial and
348   // its params. If the feature params part is provided but trial and/or group
349   // isn't, this initialization will also create a synthetic trial, named
350   // "Study" followed by the feature name, i.e. "StudyFeature", and group, named
351   // "Group" followed by the feature name, i.e. "GroupFeature", for the params.
352   // If a feature name is prefixed with the '*' character, it will be created
353   // with OVERRIDE_USE_DEFAULT - which is useful for associating with a trial
354   // while using the default state.
355   void InitFromCommandLine(const std::string& enable_features,
356                            const std::string& disable_features);
357 
358   // Initializes feature overrides through the field trial allocator, which
359   // we're using to store the feature names, their override state, and the name
360   // of the associated field trial.
361   void InitFromSharedMemory(PersistentMemoryAllocator* allocator);
362 
363   // Returns true if the state of |feature_name| has been overridden (regardless
364   // of whether the overridden value is the same as the default value) for any
365   // reason (e.g. command line or field trial).
366   bool IsFeatureOverridden(const std::string& feature_name) const;
367 
368   // Returns true if the state of |feature_name| has been overridden via
369   // |InitFromCommandLine()|. This includes features explicitly
370   // disabled/enabled with --disable-features and --enable-features, as well as
371   // any extra feature overrides that depend on command line switches.
372   bool IsFeatureOverriddenFromCommandLine(
373       const std::string& feature_name) const;
374 
375   // Returns true if the state |feature_name| has been overridden by
376   // |InitFromCommandLine()| and the state matches |state|.
377   bool IsFeatureOverriddenFromCommandLine(const std::string& feature_name,
378                                           OverrideState state) const;
379 
380   // Associates a field trial for reporting purposes corresponding to the
381   // command-line setting the feature state to |for_overridden_state|. The trial
382   // will be activated when the state of the feature is first queried. This
383   // should be called during registration, after InitFromCommandLine() has
384   // been called but before the instance is registered via SetInstance().
385   void AssociateReportingFieldTrial(const std::string& feature_name,
386                                     OverrideState for_overridden_state,
387                                     FieldTrial* field_trial);
388 
389   // Registers a field trial to override the enabled state of the specified
390   // feature to `override_state`. Command-line overrides still take precedence
391   // over field trials, so this will have no effect if the feature is being
392   // overridden from the command-line. The associated field trial will be
393   // activated when the feature state for this feature is queried. This should
394   // be called during registration, after InitFromCommandLine() has been
395   // called but before the instance is registered via SetInstance().
396   void RegisterFieldTrialOverride(const std::string& feature_name,
397                                   OverrideState override_state,
398                                   FieldTrial* field_trial);
399 
400   // Adds extra overrides (not associated with a field trial). Should be called
401   // before SetInstance().
402   // The ordering of calls with respect to InitFromCommandLine(),
403   // RegisterFieldTrialOverride(), etc. matters. The first call wins out,
404   // because the `overrides_` map uses emplace(), which retains the first
405   // inserted entry and does not overwrite it on subsequent calls to emplace().
406   //
407   // If `replace_use_default_overrides` is true, if there is an existing entry
408   // with type OVERRIDE_USE_DEFAULT, that entry will be replaced.
409   void RegisterExtraFeatureOverrides(
410       const std::vector<FeatureOverrideInfo>& extra_overrides,
411       bool replace_use_default_overrides = false);
412 
413   // Loops through feature overrides and serializes them all into |allocator|.
414   void AddFeaturesToAllocator(PersistentMemoryAllocator* allocator);
415 
416   // Returns comma-separated lists of feature names (in the same format that is
417   // accepted by InitFromCommandLine()) corresponding to features that
418   // have been overridden - either through command-line or via FieldTrials. For
419   // those features that have an associated FieldTrial, the output entry will be
420   // of the format "FeatureName<TrialName" (|include_group_name|=false) or
421   // "FeatureName<TrialName.GroupName" (if |include_group_name|=true), where
422   // "TrialName" is the name of the FieldTrial and "GroupName" is the group
423   // name of the FieldTrial. Features that have overrides with
424   // OVERRIDE_USE_DEFAULT will be added to |enable_overrides| with a '*'
425   // character prefix. Must be called only after the instance has been
426   // initialized and registered.
427   void GetFeatureOverrides(std::string* enable_overrides,
428                            std::string* disable_overrides,
429                            bool include_group_names = false) const;
430 
431   // Like GetFeatureOverrides(), but only returns overrides that were specified
432   // explicitly on the command-line, omitting the ones from field trials.
433   void GetCommandLineFeatureOverrides(std::string* enable_overrides,
434                                       std::string* disable_overrides) const;
435 
436   // Returns the field trial associated with the given feature |name|. Used for
437   // getting the FieldTrial without requiring a struct Feature.
438   base::FieldTrial* GetAssociatedFieldTrialByFeatureName(
439       std::string_view name) const;
440 
441   // DO NOT USE outside of internal field trial implementation code. Instead use
442   // GetAssociatedFieldTrialByFeatureName(), which performs some additional
443   // validation.
444   //
445   // Returns whether the given feature |name| is associated with a field trial.
446   // If the given feature |name| does not exist, return false. Unlike
447   // GetAssociatedFieldTrialByFeatureName(), this function must be called during
448   // |FeatureList| initialization; the returned value will report whether the
449   // provided |name| has been used so far.
450   bool HasAssociatedFieldTrialByFeatureName(std::string_view name) const;
451 
452   // Get associated field trial for the given feature |name| only if override
453   // enables it.
454   FieldTrial* GetEnabledFieldTrialByFeatureName(std::string_view name) const;
455 
456   // Construct an accessor allowing access to GetOverrideStateByFeatureName().
457   // This can only be called before the FeatureList is initialized, and is
458   // intended for very narrow use.
459   // If you're tempted to use it, do so only in consultation with feature_list
460   // OWNERS.
461   std::unique_ptr<Accessor> ConstructAccessor();
462 
463   // Returns whether the given `feature` is enabled.
464   //
465   // If no `FeatureList` instance is registered, this will:
466   // - DCHECK(), if FailOnFeatureAccessWithoutFeatureList() was called.
467   //     TODO(crbug.com/40237050): Change the DCHECK to a CHECK when we're
468   //     confident that all early accesses have been fixed. We don't want to
469   //     get many crash reports from the field in the meantime.
470   // - Return the default state, otherwise. Registering a `FeatureList` later
471   //   will fail.
472   //
473   // TODO(crbug.com/40237050): Make early FeatureList access fail on iOS,
474   // Android and ChromeOS. This currently only works on Windows, Mac and Linux.
475   //
476   // A feature with a given name must only have a single corresponding Feature
477   // instance, which is checked in builds with DCHECKs enabled.
478   static bool IsEnabled(const Feature& feature);
479 
480   // Some characters are not allowed to appear in feature names or the
481   // associated field trial names, as they are used as special characters for
482   // command-line serialization. This function checks that the strings are ASCII
483   // (since they are used in command-line API functions that require ASCII) and
484   // whether there are any reserved characters present, returning true if the
485   // string is valid.
486   static bool IsValidFeatureOrFieldTrialName(std::string_view name);
487 
488   // If the given |feature| is overridden, returns its enabled state; otherwise,
489   // returns an empty optional. Must only be called after the singleton instance
490   // has been registered via SetInstance(). Additionally, a feature with a given
491   // name must only have a single corresponding Feature struct, which is checked
492   // in builds with DCHECKs enabled.
493   static std::optional<bool> GetStateIfOverridden(const Feature& feature);
494 
495   // Returns the field trial associated with the given |feature|. Must only be
496   // called after the singleton instance has been registered via SetInstance().
497   static FieldTrial* GetFieldTrial(const Feature& feature);
498 
499   // Splits a comma-separated string containing feature names into a vector. The
500   // resulting pieces point to parts of |input|.
501   static std::vector<std::string_view> SplitFeatureListString(
502       std::string_view input);
503 
504   // Checks and parses the |enable_feature| (e.g.
505   // FeatureName<Study.Group:Param1/value1/) obtained by applying
506   // SplitFeatureListString() to the |enable_features| flag, and sets
507   // |feature_name| to be the feature's name, |study_name| and |group_name| to
508   // be the field trial name and its group name if the field trial is specified
509   // or field trial parameters are given, |params| to be the field trial
510   // parameters if exists.
511   static bool ParseEnableFeatureString(std::string_view enable_feature,
512                                        std::string* feature_name,
513                                        std::string* study_name,
514                                        std::string* group_name,
515                                        std::string* params);
516 
517   // Initializes and sets an instance of FeatureList with feature overrides via
518   // command-line flags |enable_features| and |disable_features| if one has not
519   // already been set from command-line flags. Returns true if an instance did
520   // not previously exist. See InitFromCommandLine() for more details
521   // about |enable_features| and |disable_features| parameters.
522   static bool InitInstance(const std::string& enable_features,
523                            const std::string& disable_features);
524 
525   // Like the above, but also adds extra overrides. If a feature appears in
526   // |extra_overrides| and also |enable_features| or |disable_features|, the
527   // disable/enable will supersede the extra overrides.
528   static bool InitInstance(
529       const std::string& enable_features,
530       const std::string& disable_features,
531       const std::vector<FeatureOverrideInfo>& extra_overrides);
532 
533   // Returns the singleton instance of FeatureList. Will return null until an
534   // instance is registered via SetInstance().
535   static FeatureList* GetInstance();
536 
537   // Registers the given |instance| to be the singleton feature list for this
538   // process. This should only be called once and |instance| must not be null.
539   // Note: If you are considering using this for the purposes of testing, take
540   // a look at using base/test/scoped_feature_list.h instead.
541   static void SetInstance(std::unique_ptr<FeatureList> instance);
542 
543   // Registers the given `instance` to be the temporary singleton feature list
544   // for this process. While the given `instance` is the singleton feature list,
545   // only the state of features matching `allowed_feature_names` can be checked.
546   // Attempting to query other feature will behave as if no feature list was set
547   // at all. It is expected that this instance is replaced using `SetInstance`
548   // with an instance without limitations as soon as practical.
549   static void SetEarlyAccessInstance(
550       std::unique_ptr<FeatureList> instance,
551       base::flat_set<std::string> allowed_feature_names);
552 
553   // Clears the previously-registered singleton instance for tests and returns
554   // the old instance.
555   // Note: Most tests should never call this directly. Instead consider using
556   // base::test::ScopedFeatureList.
557   static std::unique_ptr<FeatureList> ClearInstanceForTesting();
558 
559   // Sets a given (initialized) |instance| to be the singleton feature list,
560   // for testing. Existing instance must be null. This is primarily intended
561   // to support base::test::ScopedFeatureList helper class.
562   static void RestoreInstanceForTesting(std::unique_ptr<FeatureList> instance);
563 
564   // After calling this, an attempt to access feature state when no FeatureList
565   // is registered will DCHECK.
566   //
567   // TODO(crbug.com/40237050): Change the DCHECK to a CHECK when we're confident
568   // that all early accesses have been fixed. We don't want to get many crash
569   // reports from the field in the meantime.
570   //
571   // Note: This isn't the default behavior because accesses are tolerated in
572   // processes that never register a FeatureList.
573   static void FailOnFeatureAccessWithoutFeatureList();
574 
575   // Returns the first feature that was accessed before a FeatureList was
576   // registered that allows accessing the feature.
577   static const Feature* GetEarlyAccessedFeatureForTesting();
578 
579   // Resets the state of the early feature access tracker.
580   static void ResetEarlyFeatureAccessTrackerForTesting();
581 
582   // Adds a feature to the early allowed feature access list for tests. Should
583   // only be called on a FeatureList that was set with SetEarlyAccessInstance().
584   void AddEarlyAllowedFeatureForTesting(std::string feature_name);
585 
586   // Allows a visitor to record override state, parameters, and field trial
587   // associated with each feature. Optionally, provide a prefix which filters
588   // the visited features.
589   //
590   // NOTE: This is intended only for the special case of needing to get all
591   // overrides. This use case is specific to CrOS-Ash and V8. Most users should
592   // call IsEnabled() to query a feature's state.
593   static void VisitFeaturesAndParams(FeatureVisitor& visitor,
594                                      std::string_view filter_prefix = "");
595 
596  private:
597   FRIEND_TEST_ALL_PREFIXES(FeatureListTest, CheckFeatureIdentity);
598   FRIEND_TEST_ALL_PREFIXES(FeatureListTest,
599                            StoreAndRetrieveFeaturesFromSharedMemory);
600   FRIEND_TEST_ALL_PREFIXES(FeatureListTest,
601                            StoreAndRetrieveAssociatedFeaturesFromSharedMemory);
602   // Allow Accessor to access GetOverrideStateByFeatureName().
603   friend class Accessor;
604 
605   struct OverrideEntry {
606     // The overridden enable (on/off) state of the feature.
607     OverrideState overridden_state;
608 
609     // An optional associated field trial, which will be activated when the
610     // state of the feature is queried for the first time. Weak pointer to the
611     // FieldTrial object that is owned by the FieldTrialList singleton.
612     raw_ptr<base::FieldTrial> field_trial;
613 
614     // Specifies whether the feature's state is overridden by |field_trial|.
615     // If it's not, and |field_trial| is not null, it means it is simply an
616     // associated field trial for reporting purposes (and |overridden_state|
617     // came from the command-line).
618     bool overridden_by_field_trial;
619 
620     // TODO(asvitkine): Expand this as more support is added.
621 
622     // Constructs an OverrideEntry for the given |overridden_state|. If
623     // |field_trial| is not null, it implies that |overridden_state| comes from
624     // the trial, so |overridden_by_field_trial| will be set to true.
625     OverrideEntry(OverrideState overridden_state, FieldTrial* field_trial);
626   };
627 
628   // Returns the override for the field trial associated with the given feature
629   // |name| or null if the feature is not found.
630   const base::FeatureList::OverrideEntry* GetOverrideEntryByFeatureName(
631       std::string_view name) const;
632 
633   // Finalizes the initialization state of the FeatureList, so that no further
634   // overrides can be registered. This is called by SetInstance() on the
635   // singleton feature list that is being registered.
636   void FinalizeInitialization();
637 
638   // Returns whether the given |feature| is enabled. This is invoked by the
639   // public FeatureList::IsEnabled() static function on the global singleton.
640   // Requires the FeatureList to have already been fully initialized.
641   bool IsFeatureEnabled(const Feature& feature) const;
642 
643   // Returns whether the given |feature| is enabled. This is invoked by the
644   // public FeatureList::GetStateIfOverridden() static function on the global
645   // singleton. Requires the FeatureList to have already been fully initialized.
646   std::optional<bool> IsFeatureEnabledIfOverridden(
647       const Feature& feature) const;
648 
649   // Returns the override state of a given |feature|. If the feature was not
650   // overridden, returns OVERRIDE_USE_DEFAULT. Performs any necessary callbacks
651   // for when the feature state has been observed, e.g. activating field trials.
652   OverrideState GetOverrideState(const Feature& feature) const;
653 
654   // Same as GetOverrideState(), but without a default value.
655   OverrideState GetOverrideStateByFeatureName(
656       std::string_view feature_name) const;
657 
658   // Returns the field trial associated with the given |feature|. This is
659   // invoked by the public FeatureList::GetFieldTrial() static function on the
660   // global singleton. Requires the FeatureList to have already been fully
661   // initialized.
662   base::FieldTrial* GetAssociatedFieldTrial(const Feature& feature) const;
663 
664   // For each feature name in comma-separated list of strings |feature_list|,
665   // registers an override with the specified |overridden_state|. Also, will
666   // associate an optional named field trial if the entry is of the format
667   // "FeatureName<TrialName".
668   void RegisterOverridesFromCommandLine(const std::string& feature_list,
669                                         OverrideState overridden_state);
670 
671   // Registers an override for feature |feature_name|. The override specifies
672   // whether the feature should be on or off (via |overridden_state|), which
673   // will take precedence over the feature's default state. If |field_trial| is
674   // not null, registers the specified field trial object to be associated with
675   // the feature, which will activate the field trial when the feature state is
676   // queried.
677   //
678   // If an override is already registered for the given feature, it will not be
679   // changed, unless `replace_use_default_overrides` is true and the existing
680   // entry has type OVERRIDE_USE_DEFAULT.
681   void RegisterOverride(std::string_view feature_name,
682                         OverrideState overridden_state,
683                         FieldTrial* field_trial,
684                         bool replace_use_default_overrides = false);
685 
686   // Implementation of GetFeatureOverrides() with a parameter that specifies
687   // whether only command-line enabled overrides should be emitted. See that
688   // function's comments for more details.
689   void GetFeatureOverridesImpl(std::string* enable_overrides,
690                                std::string* disable_overrides,
691                                bool command_line_only,
692                                bool include_group_name = false) const;
693 
694   // Verifies that there's only a single definition of a Feature struct for a
695   // given feature name. Keeps track of the first seen Feature struct for each
696   // feature. Returns false when called on a Feature struct with a different
697   // address than the first one it saw for that feature name. Used only from
698   // DCHECKs and tests. This is const because it's called from const getters and
699   // doesn't modify externally visible state.
700   bool CheckFeatureIdentity(const Feature& feature) const;
701 
702   // Returns true if this feature list was set with SetEarlyAccessInstance().
703   bool IsEarlyAccessInstance() const;
704 
705   // Returns if this feature list instance allows access to the given feature.
706   // If a this feature list was set with SetEarlyAccessInstance(), only the
707   // features in `allowed_feature_names_` can be checked.
708   bool AllowFeatureAccess(const Feature& feature) const;
709 
710   // Map from feature name to an OverrideEntry struct for the feature, if it
711   // exists.
712   base::flat_map<std::string, OverrideEntry> overrides_;
713 
714   // Locked map that keeps track of seen features, to ensure a single feature is
715   // only defined once. This verification is only done in builds with DCHECKs
716   // enabled. This is mutable as it's not externally visible and needs to be
717   // usable from const getters.
718   mutable Lock feature_identity_tracker_lock_;
719   mutable std::map<std::string, const Feature*, std::less<>>
720       feature_identity_tracker_ GUARDED_BY(feature_identity_tracker_lock_);
721 
722   // Tracks the associated FieldTrialList for DCHECKs. This is used to catch
723   // the scenario where multiple FieldTrialList are used with the same
724   // FeatureList - which can lead to overrides pointing to invalid FieldTrial
725   // objects.
726   raw_ptr<base::FieldTrialList> field_trial_list_ = nullptr;
727 
728   // Whether this object has been fully initialized. This gets set to true as a
729   // result of FinalizeInitialization().
730   bool initialized_ = false;
731 
732   // Whether this object has been initialized from command line.
733   bool initialized_from_command_line_ = false;
734 
735   // Used when querying `base::Feature` state to determine if the cached value
736   // in the `Feature` object is populated and valid. See the comment on
737   // `base::Feature::cached_value` for more details.
738   const uint16_t caching_context_;
739 
740   // If this instance was set with SetEarlyAccessInstance(), this set contains
741   // the names of the features whose state is allowed to be checked. Attempting
742   // to check the state of a feature not on this list will behave as if no
743   // feature list was initialized at all.
744   base::flat_set<std::string> allowed_feature_names_;
745 };
746 
747 }  // namespace base
748 
749 #endif  // BASE_FEATURE_LIST_H_
750