feature_list.h 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500
  1. // Copyright 2015 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #ifndef BASE_FEATURE_LIST_H_
  5. #define BASE_FEATURE_LIST_H_
  6. #include <functional>
  7. #include <map>
  8. #include <memory>
  9. #include <string>
  10. #include <utility>
  11. #include <vector>
  12. #include "base/base_export.h"
  13. #include "base/containers/flat_map.h"
  14. #include "base/dcheck_is_on.h"
  15. #include "base/feature_list_buildflags.h"
  16. #include "base/gtest_prod_util.h"
  17. #include "base/logging.h"
  18. #include "base/memory/raw_ptr.h"
  19. #include "base/strings/string_piece.h"
  20. #include "base/synchronization/lock.h"
  21. #include "third_party/abseil-cpp/absl/types/optional.h"
  22. namespace base {
  23. class FieldTrial;
  24. class FieldTrialList;
  25. class PersistentMemoryAllocator;
  26. // Specifies whether a given feature is enabled or disabled by default.
  27. // NOTE: The actual runtime state may be different, due to a field trial or a
  28. // command line switch.
  29. enum FeatureState {
  30. FEATURE_DISABLED_BY_DEFAULT,
  31. FEATURE_ENABLED_BY_DEFAULT,
  32. };
  33. // The Feature struct is used to define the default state for a feature. See
  34. // comment below for more details. There must only ever be one struct instance
  35. // for a given feature name - generally defined as a constant global variable or
  36. // file static. It should never be used as a constexpr as it breaks
  37. // pointer-based identity lookup.
  38. // Note: New code should use CONSTINIT on the base::Feature declaration.
  39. struct BASE_EXPORT Feature {
  40. constexpr Feature(const char* name, FeatureState default_state)
  41. : name(name), default_state(default_state) {
  42. #if BUILDFLAG(ENABLE_BANNED_BASE_FEATURE_PREFIX)
  43. if (StringPiece(name).find(BUILDFLAG(BANNED_BASE_FEATURE_PREFIX)) == 0) {
  44. LOG(FATAL) << "Invalid feature name " << name << " starts with "
  45. << BUILDFLAG(BANNED_BASE_FEATURE_PREFIX);
  46. }
  47. #endif // BUILDFLAG(ENABLE_BANNED_BASE_FEATURE_PREFIX)
  48. }
  49. // The name of the feature. This should be unique to each feature and is used
  50. // for enabling/disabling features via command line flags and experiments.
  51. // It is strongly recommended to use CamelCase style for feature names, e.g.
  52. // "MyGreatFeature".
  53. const char* const name;
  54. // The default state (i.e. enabled or disabled) for this feature.
  55. // NOTE: The actual runtime state may be different, due to a field trial or a
  56. // command line switch.
  57. const FeatureState default_state;
  58. };
  59. #if BUILDFLAG(DCHECK_IS_CONFIGURABLE)
  60. // DCHECKs have been built-in, and are configurable at run-time to be fatal, or
  61. // not, via a DcheckIsFatal feature. We define the Feature here since it is
  62. // checked in FeatureList::SetInstance(). See https://crbug.com/596231.
  63. extern BASE_EXPORT const Feature kDCheckIsFatalFeature;
  64. #endif // BUILDFLAG(DCHECK_IS_CONFIGURABLE)
  65. // The FeatureList class is used to determine whether a given feature is on or
  66. // off. It provides an authoritative answer, taking into account command-line
  67. // overrides and experimental control.
  68. //
  69. // The basic use case is for any feature that can be toggled (e.g. through
  70. // command-line or an experiment) to have a defined Feature struct, e.g.:
  71. //
  72. // const base::Feature kMyGreatFeature {
  73. // "MyGreatFeature", base::FEATURE_ENABLED_BY_DEFAULT
  74. // };
  75. //
  76. // Then, client code that wishes to query the state of the feature would check:
  77. //
  78. // if (base::FeatureList::IsEnabled(kMyGreatFeature)) {
  79. // // Feature code goes here.
  80. // }
  81. //
  82. // Behind the scenes, the above call would take into account any command-line
  83. // flags to enable or disable the feature, any experiments that may control it
  84. // and finally its default state (in that order of priority), to determine
  85. // whether the feature is on.
  86. //
  87. // Features can be explicitly forced on or off by specifying a list of comma-
  88. // separated feature names via the following command-line flags:
  89. //
  90. // --enable-features=Feature5,Feature7
  91. // --disable-features=Feature1,Feature2,Feature3
  92. //
  93. // To enable/disable features in a test, do NOT append --enable-features or
  94. // --disable-features to the command-line directly. Instead, use
  95. // ScopedFeatureList. See base/test/scoped_feature_list.h for details.
  96. //
  97. // After initialization (which should be done single-threaded), the FeatureList
  98. // API is thread safe.
  99. //
  100. // Note: This class is a singleton, but does not use base/memory/singleton.h in
  101. // order to have control over its initialization sequence. Specifically, the
  102. // intended use is to create an instance of this class and fully initialize it,
  103. // before setting it as the singleton for a process, via SetInstance().
  104. class BASE_EXPORT FeatureList {
  105. public:
  106. FeatureList();
  107. FeatureList(const FeatureList&) = delete;
  108. FeatureList& operator=(const FeatureList&) = delete;
  109. ~FeatureList();
  110. // Used by common test fixture classes to prevent abuse of ScopedFeatureList
  111. // after multiple threads have started.
  112. class BASE_EXPORT ScopedDisallowOverrides {
  113. public:
  114. explicit ScopedDisallowOverrides(const char* reason);
  115. ScopedDisallowOverrides(const ScopedDisallowOverrides&) = delete;
  116. ScopedDisallowOverrides& operator=(const ScopedDisallowOverrides&) = delete;
  117. ~ScopedDisallowOverrides();
  118. private:
  119. #if DCHECK_IS_ON()
  120. const char* const previous_reason_;
  121. #endif
  122. };
  123. // Specifies whether a feature override enables or disables the feature.
  124. enum OverrideState {
  125. OVERRIDE_USE_DEFAULT,
  126. OVERRIDE_DISABLE_FEATURE,
  127. OVERRIDE_ENABLE_FEATURE,
  128. };
  129. // Accessor class, used to look up features by _name_ rather than by Feature
  130. // object.
  131. // Should only be used in limited cases. See ConstructAccessor() for details.
  132. class BASE_EXPORT Accessor {
  133. public:
  134. Accessor(const Accessor&) = delete;
  135. Accessor& operator=(const Accessor&) = delete;
  136. // Looks up the feature, returning only its override state, rather than
  137. // falling back on a default value (since there is no default value given).
  138. // Callers of this MUST ensure that there is a consistent, compile-time
  139. // default value associated.
  140. FeatureList::OverrideState GetOverrideStateByFeatureName(
  141. StringPiece feature_name);
  142. // Look up the feature, and, if present, populate |params|.
  143. // See GetFieldTrialParams in field_trial_params.h for more documentation.
  144. bool GetParamsByFeatureName(StringPiece feature_name,
  145. std::map<std::string, std::string>* params);
  146. private:
  147. // Allow FeatureList to construct this class.
  148. friend class FeatureList;
  149. explicit Accessor(FeatureList* feature_list);
  150. // Unowned pointer to the FeatureList object we use to look up feature
  151. // enablement.
  152. raw_ptr<FeatureList> feature_list_;
  153. };
  154. // Describes a feature override. The first member is a Feature that will be
  155. // overridden with the state given by the second member.
  156. using FeatureOverrideInfo =
  157. std::pair<const std::reference_wrapper<const Feature>, OverrideState>;
  158. // Initializes feature overrides via command-line flags `--enable-features=`
  159. // and `--disable-features=`, each of which is a comma-separated list of
  160. // features to enable or disable, respectively. This function also allows
  161. // users to set a feature's field trial params via `--enable-features=`. Must
  162. // only be invoked during the initialization phase (before
  163. // FinalizeInitialization() has been called).
  164. //
  165. // If a feature appears on both lists, then it will be disabled. If
  166. // a list entry has the format "FeatureName<TrialName" then this
  167. // initialization will also associate the feature state override with the
  168. // named field trial, if it exists. If a list entry has the format
  169. // "FeatureName:k1/v1/k2/v2", "FeatureName<TrialName:k1/v1/k2/v2" or
  170. // "FeatureName<TrialName.GroupName:k1/v1/k2/v2" then this initialization will
  171. // also associate the feature state override with the named field trial and
  172. // its params. If the feature params part is provided but trial and/or group
  173. // isn't, this initialization will also create a synthetic trial, named
  174. // "Study" followed by the feature name, i.e. "StudyFeature", and group, named
  175. // "Group" followed by the feature name, i.e. "GroupFeature", for the params.
  176. // If a feature name is prefixed with the '*' character, it will be created
  177. // with OVERRIDE_USE_DEFAULT - which is useful for associating with a trial
  178. // while using the default state.
  179. void InitializeFromCommandLine(const std::string& enable_features,
  180. const std::string& disable_features);
  181. // Initializes feature overrides through the field trial allocator, which
  182. // we're using to store the feature names, their override state, and the name
  183. // of the associated field trial.
  184. void InitializeFromSharedMemory(PersistentMemoryAllocator* allocator);
  185. // Returns true if the state of |feature_name| has been overridden (regardless
  186. // of whether the overridden value is the same as the default value) for any
  187. // reason (e.g. command line or field trial).
  188. bool IsFeatureOverridden(const std::string& feature_name) const;
  189. // Returns true if the state of |feature_name| has been overridden via
  190. // |InitializeFromCommandLine()|. This includes features explicitly
  191. // disabled/enabled with --disable-features and --enable-features, as well as
  192. // any extra feature overrides that depend on command line switches.
  193. bool IsFeatureOverriddenFromCommandLine(
  194. const std::string& feature_name) const;
  195. // Returns true if the state |feature_name| has been overridden by
  196. // |InitializeFromCommandLine()| and the state matches |state|.
  197. bool IsFeatureOverriddenFromCommandLine(const std::string& feature_name,
  198. OverrideState state) const;
  199. // Associates a field trial for reporting purposes corresponding to the
  200. // command-line setting the feature state to |for_overridden_state|. The trial
  201. // will be activated when the state of the feature is first queried. This
  202. // should be called during registration, after InitializeFromCommandLine() has
  203. // been called but before the instance is registered via SetInstance().
  204. void AssociateReportingFieldTrial(const std::string& feature_name,
  205. OverrideState for_overridden_state,
  206. FieldTrial* field_trial);
  207. // Registers a field trial to override the enabled state of the specified
  208. // feature to |override_state|. Command-line overrides still take precedence
  209. // over field trials, so this will have no effect if the feature is being
  210. // overridden from the command-line. The associated field trial will be
  211. // activated when the feature state for this feature is queried. This should
  212. // be called during registration, after InitializeFromCommandLine() has been
  213. // called but before the instance is registered via SetInstance().
  214. void RegisterFieldTrialOverride(const std::string& feature_name,
  215. OverrideState override_state,
  216. FieldTrial* field_trial);
  217. // Adds extra overrides (not associated with a field trial). Should be called
  218. // before SetInstance().
  219. // The ordering of calls with respect to InitializeFromCommandLine(),
  220. // RegisterFieldTrialOverride(), etc. matters. The first call wins out,
  221. // because the |overrides_| map uses insert(), which retains the first
  222. // inserted entry and does not overwrite it on subsequent calls to insert().
  223. void RegisterExtraFeatureOverrides(
  224. const std::vector<FeatureOverrideInfo>& extra_overrides);
  225. // Loops through feature overrides and serializes them all into |allocator|.
  226. void AddFeaturesToAllocator(PersistentMemoryAllocator* allocator);
  227. // Returns comma-separated lists of feature names (in the same format that is
  228. // accepted by InitializeFromCommandLine()) corresponding to features that
  229. // have been overridden - either through command-line or via FieldTrials. For
  230. // those features that have an associated FieldTrial, the output entry will be
  231. // of the format "FeatureName<TrialName" (|include_group_name|=false) or
  232. // "FeatureName<TrialName.GroupName" (if |include_group_name|=true), where
  233. // "TrialName" is the name of the FieldTrial and "GroupName" is the group
  234. // name of the FieldTrial. Features that have overrides with
  235. // OVERRIDE_USE_DEFAULT will be added to |enable_overrides| with a '*'
  236. // character prefix. Must be called only after the instance has been
  237. // initialized and registered.
  238. void GetFeatureOverrides(std::string* enable_overrides,
  239. std::string* disable_overrides,
  240. bool include_group_names = false) const;
  241. // Like GetFeatureOverrides(), but only returns overrides that were specified
  242. // explicitly on the command-line, omitting the ones from field trials.
  243. void GetCommandLineFeatureOverrides(std::string* enable_overrides,
  244. std::string* disable_overrides) const;
  245. // Returns the field trial associated with the given feature |name|. Used for
  246. // getting the FieldTrial without requiring a struct Feature.
  247. base::FieldTrial* GetAssociatedFieldTrialByFeatureName(
  248. StringPiece name) const;
  249. // Get associated field trial for the given feature |name| only if override
  250. // enables it.
  251. FieldTrial* GetEnabledFieldTrialByFeatureName(StringPiece name) const;
  252. // Construct an accessor allowing access to GetOverrideStateByFeatureName().
  253. // This can only be called before the FeatureList is initialized, and is
  254. // intended for very narrow use.
  255. // If you're tempted to use it, do so only in consultation with feature_list
  256. // OWNERS.
  257. std::unique_ptr<Accessor> ConstructAccessor();
  258. // Returns whether the given |feature| is enabled. Must only be called after
  259. // the singleton instance has been registered via SetInstance(). Additionally,
  260. // a feature with a given name must only have a single corresponding Feature
  261. // struct, which is checked in builds with DCHECKs enabled.
  262. static bool IsEnabled(const Feature& feature);
  263. // If the given |feature| is overridden, returns its enabled state; otherwise,
  264. // returns an empty optional. Must only be called after the singleton instance
  265. // has been registered via SetInstance(). Additionally, a feature with a given
  266. // name must only have a single corresponding Feature struct, which is checked
  267. // in builds with DCHECKs enabled.
  268. static absl::optional<bool> GetStateIfOverridden(const Feature& feature);
  269. // Returns the field trial associated with the given |feature|. Must only be
  270. // called after the singleton instance has been registered via SetInstance().
  271. static FieldTrial* GetFieldTrial(const Feature& feature);
  272. // Splits a comma-separated string containing feature names into a vector. The
  273. // resulting pieces point to parts of |input|.
  274. static std::vector<base::StringPiece> SplitFeatureListString(
  275. base::StringPiece input);
  276. // Checks and parses the |enable_feature| (e.g.
  277. // FeatureName<Study.Group:Param1/value1/) obtained by applying
  278. // SplitFeatureListString() to the |enable_features| flag, and sets
  279. // |feature_name| to be the feature's name, |study_name| and |group_name| to
  280. // be the field trial name and its group name if the field trial is specified
  281. // or field trial parameters are given, |params| to be the field trial
  282. // parameters if exists.
  283. static bool ParseEnableFeatureString(StringPiece enable_feature,
  284. std::string* feature_name,
  285. std::string* study_name,
  286. std::string* group_name,
  287. std::string* params);
  288. // Initializes and sets an instance of FeatureList with feature overrides via
  289. // command-line flags |enable_features| and |disable_features| if one has not
  290. // already been set from command-line flags. Returns true if an instance did
  291. // not previously exist. See InitializeFromCommandLine() for more details
  292. // about |enable_features| and |disable_features| parameters.
  293. static bool InitializeInstance(const std::string& enable_features,
  294. const std::string& disable_features);
  295. // Like the above, but also adds extra overrides. If a feature appears in
  296. // |extra_overrides| and also |enable_features| or |disable_features|, the
  297. // disable/enable will supersede the extra overrides.
  298. static bool InitializeInstance(
  299. const std::string& enable_features,
  300. const std::string& disable_features,
  301. const std::vector<FeatureOverrideInfo>& extra_overrides);
  302. // Returns the singleton instance of FeatureList. Will return null until an
  303. // instance is registered via SetInstance().
  304. static FeatureList* GetInstance();
  305. // Registers the given |instance| to be the singleton feature list for this
  306. // process. This should only be called once and |instance| must not be null.
  307. // Note: If you are considering using this for the purposes of testing, take
  308. // a look at using base/test/scoped_feature_list.h instead.
  309. static void SetInstance(std::unique_ptr<FeatureList> instance);
  310. // Clears the previously-registered singleton instance for tests and returns
  311. // the old instance.
  312. // Note: Most tests should never call this directly. Instead consider using
  313. // base::test::ScopedFeatureList.
  314. static std::unique_ptr<FeatureList> ClearInstanceForTesting();
  315. // Sets a given (initialized) |instance| to be the singleton feature list,
  316. // for testing. Existing instance must be null. This is primarily intended
  317. // to support base::test::ScopedFeatureList helper class.
  318. static void RestoreInstanceForTesting(std::unique_ptr<FeatureList> instance);
  319. // On some platforms, the base::FeatureList singleton might be duplicated to
  320. // more than one module. If this function is called, then using base::Feature
  321. // API will result in DCHECK if accessed from the same module as the callee.
  322. // Has no effect if DCHECKs are not enabled.
  323. static void ForbidUseForCurrentModule();
  324. private:
  325. FRIEND_TEST_ALL_PREFIXES(FeatureListTest, CheckFeatureIdentity);
  326. FRIEND_TEST_ALL_PREFIXES(FeatureListTest,
  327. StoreAndRetrieveFeaturesFromSharedMemory);
  328. FRIEND_TEST_ALL_PREFIXES(FeatureListTest,
  329. StoreAndRetrieveAssociatedFeaturesFromSharedMemory);
  330. // Allow Accessor to access GetOverrideStateByFeatureName().
  331. friend class Accessor;
  332. struct OverrideEntry {
  333. // The overridden enable (on/off) state of the feature.
  334. OverrideState overridden_state;
  335. // An optional associated field trial, which will be activated when the
  336. // state of the feature is queried for the first time. Weak pointer to the
  337. // FieldTrial object that is owned by the FieldTrialList singleton.
  338. base::FieldTrial* field_trial;
  339. // Specifies whether the feature's state is overridden by |field_trial|.
  340. // If it's not, and |field_trial| is not null, it means it is simply an
  341. // associated field trial for reporting purposes (and |overridden_state|
  342. // came from the command-line).
  343. bool overridden_by_field_trial;
  344. // TODO(asvitkine): Expand this as more support is added.
  345. // Constructs an OverrideEntry for the given |overridden_state|. If
  346. // |field_trial| is not null, it implies that |overridden_state| comes from
  347. // the trial, so |overridden_by_field_trial| will be set to true.
  348. OverrideEntry(OverrideState overridden_state, FieldTrial* field_trial);
  349. };
  350. // Returns the override for the field trial associated with the given feature
  351. // |name| or null if the feature is not found.
  352. const base::FeatureList::OverrideEntry* GetOverrideEntryByFeatureName(
  353. StringPiece name) const;
  354. // Finalizes the initialization state of the FeatureList, so that no further
  355. // overrides can be registered. This is called by SetInstance() on the
  356. // singleton feature list that is being registered.
  357. void FinalizeInitialization();
  358. // Returns whether the given |feature| is enabled. This is invoked by the
  359. // public FeatureList::IsEnabled() static function on the global singleton.
  360. // Requires the FeatureList to have already been fully initialized.
  361. bool IsFeatureEnabled(const Feature& feature) const;
  362. // Returns whether the given |feature| is enabled. This is invoked by the
  363. // public FeatureList::GetStateIfOverridden() static function on the global
  364. // singleton. Requires the FeatureList to have already been fully initialized.
  365. absl::optional<bool> IsFeatureEnabledIfOverridden(
  366. const Feature& feature) const;
  367. // Returns the override state of a given |feature|. If the feature was not
  368. // overridden, returns OVERRIDE_USE_DEFAULT. Performs any necessary callbacks
  369. // for when the feature state has been observed, e.g. activating field trials.
  370. OverrideState GetOverrideState(const Feature& feature) const;
  371. // Same as GetOverrideState(), but without a default value.
  372. OverrideState GetOverrideStateByFeatureName(StringPiece feature_name) const;
  373. // Returns the field trial associated with the given |feature|. This is
  374. // invoked by the public FeatureList::GetFieldTrial() static function on the
  375. // global singleton. Requires the FeatureList to have already been fully
  376. // initialized.
  377. base::FieldTrial* GetAssociatedFieldTrial(const Feature& feature) const;
  378. // For each feature name in comma-separated list of strings |feature_list|,
  379. // registers an override with the specified |overridden_state|. Also, will
  380. // associate an optional named field trial if the entry is of the format
  381. // "FeatureName<TrialName".
  382. void RegisterOverridesFromCommandLine(const std::string& feature_list,
  383. OverrideState overridden_state);
  384. // Registers an override for feature |feature_name|. The override specifies
  385. // whether the feature should be on or off (via |overridden_state|), which
  386. // will take precedence over the feature's default state. If |field_trial| is
  387. // not null, registers the specified field trial object to be associated with
  388. // the feature, which will activate the field trial when the feature state is
  389. // queried. If an override is already registered for the given feature, it
  390. // will not be changed.
  391. void RegisterOverride(StringPiece feature_name,
  392. OverrideState overridden_state,
  393. FieldTrial* field_trial);
  394. // Implementation of GetFeatureOverrides() with a parameter that specifies
  395. // whether only command-line enabled overrides should be emitted. See that
  396. // function's comments for more details.
  397. void GetFeatureOverridesImpl(std::string* enable_overrides,
  398. std::string* disable_overrides,
  399. bool command_line_only,
  400. bool include_group_name = false) const;
  401. // Verifies that there's only a single definition of a Feature struct for a
  402. // given feature name. Keeps track of the first seen Feature struct for each
  403. // feature. Returns false when called on a Feature struct with a different
  404. // address than the first one it saw for that feature name. Used only from
  405. // DCHECKs and tests. This is const because it's called from const getters and
  406. // doesn't modify externally visible state.
  407. bool CheckFeatureIdentity(const Feature& feature) const;
  408. // Map from feature name to an OverrideEntry struct for the feature, if it
  409. // exists.
  410. base::flat_map<std::string, OverrideEntry> overrides_;
  411. // Locked map that keeps track of seen features, to ensure a single feature is
  412. // only defined once. This verification is only done in builds with DCHECKs
  413. // enabled. This is mutable as it's not externally visible and needs to be
  414. // usable from const getters.
  415. mutable Lock feature_identity_tracker_lock_;
  416. mutable std::map<std::string, const Feature*> feature_identity_tracker_
  417. GUARDED_BY(feature_identity_tracker_lock_);
  418. // Tracks the associated FieldTrialList for DCHECKs. This is used to catch
  419. // the scenario where multiple FieldTrialList are used with the same
  420. // FeatureList - which can lead to overrides pointing to invalid FieldTrial
  421. // objects.
  422. raw_ptr<base::FieldTrialList> field_trial_list_ = nullptr;
  423. // Whether this object has been fully initialized. This gets set to true as a
  424. // result of FinalizeInitialization().
  425. bool initialized_ = false;
  426. // Whether this object has been initialized from command line.
  427. bool initialized_from_command_line_ = false;
  428. };
  429. } // namespace base
  430. #endif // BASE_FEATURE_LIST_H_