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