1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
docs / configuration.md [blame]
# Configuration: Prefs, Settings, Features, Switches & Flags
This document outlines all the runtime configuration surfaces of Chromium,
and discusses appropriate uses and standard patterns for each of them. Some of
these are intended for use by users, some by developers, and some by system
administrators.
[TOC]
## Prefs
Example: prefs::kAllowDinosaurEasterEgg aka "allow_dinosaur_easter_egg"
Prefs are implemented by registering them with a central pref service, usually
via [Profile::RegisterProfilePrefs][profile-register]. They store typed values,
which persist across restarts and may be synced between browser instances via
the Sync service. There are several pref stores, which are documented in detail
in the [prefs docs][prefs]. They can be directly configured via enterprise
policy.
Prefs:
* *Are not* directly surfaced to the user
* *Are not* localized into the user's language
* *Are* configurable via enterprise policy if a policy exists for the pref
(there is no catch-all policy that allows setting arbitrary prefs)
* *Are not* reported via UMA when in use
* *Are not* included in chrome://version
* *Are* automatically persistent across restarts (usually)
## Features
Example: base::kDCheckIsFatalFeature
These are implemented via creating a [base::Feature][base-feature] anywhere.
These can be enabled via server-side experimentation or via the command-line
using "--enable-features". Which features are in use is tracked by UMA metrics,
and is visible in chrome://version as the "Variations" field. Do note that in
release builds, only a series of hashes show up in chrome://version rather than
the string names of the variations, but these hashes can be turned back into
string names if needed. This is done by consulting [the testing
config][fieldtrial-config] for Chromium builds, or a Google-internal tool for
Chrome builds.
*Features are the best way to add runtime conditional behavior.*
Features:
* *Are not* directly surfaced to the user
* *Are not* localized into the user's language
* *Are not* configurable via enterprise policy
* *Are* reported via UMA/crash when in use
* *Are* included in chrome://version
* *Are not* automatically persistent across restarts
## Switches
Example: switches::kIncognito aka "--incognito"
These are implemented by testing anywhere in the codebase for the presence or
value of a switch in [base::CommandLine::ForCurrentProcess][base-commandline].
There is no centralized registry of switches and they can be used for
essentially any purpose.
Switches:
* *Are not* directly surfaced to the user
* *Are not* localized into the user's language
* *Are not* configurable via enterprise policy (except on Chrome OS, via FeatureFlagsProto)
* *Are not* reported via UMA when in use
* *Are* included in chrome://version
* *Are not* automatically persistent across restarts
In general, switches are inferior to use of base::Feature, which has the same
capabilities and low engineering overhead but ties into UMA reporting. New code
should use base::Feature instead of switches. An exception to this is when the
configuration value is a string, since features can't take an arbitrary string
value.
## Flags
Example: chrome://flags/#ignore-gpu-blocklist
These are implemented by adding an entry in [about_flags.cc][about-flags]
describing the flag, as well as metadata in [flag-metadata][flag-metadata].
Flags have a name and description, and show up in chrome://flags. Flags also
have an expiration milestone, after which they will be hidden from that UI and
disabled, then later removed. Flags are backed by either a feature or a set of
switches, which they enable at browser startup depending on the value of the
flag.
Flags should usually be temporary, to allow for pre-launch testing of a feature.
Permanent flags (those with expiration -1) should only be used when either:
* The flag is regularly used for support/debugging purposes, by asking users to
flip it to eliminate a possible problem (such as ignore-gpu-blocklist)
* The flag is used for ongoing QA/test purposes in environments where command-line
switches can't be used (e.g. on mobile)
"Users might need to turn the feature on/off" is not a sufficient justification
for a permanent flag. If at all possible, we should design features such that
users don't want or need to turn them off, but if we need to retain that choice,
we should promote it to a full setting (see below) with translations and
support. "Developers/QA might need to turn the feature on/off", on the other
hand, is justification for a permanent flag.
Flags:
* *Are* directly surfaced to the user
* *Are not* localized into the user's language
* *Are not* configurable via enterprise policy
* *Are* reported via UMA when in use (via Launch.FlagsAtStartup)
* *Are not* included in chrome://version
* *Are* automatically persistent across restarts
## Settings
Example: "Show home button"
Settings are implemented in WebUI, and show up in chrome://settings or one of
its subpages. They generally are bound to a pref which stores the value of that
setting. These are comparatively expensive to add, since they require
localization and some amount of UX involvement to figure out how to fit them
into chrome://settings, plus documentation and support material. Many settings
are implemented via prefs, but not all prefs correspond to settings; some are
used for tracking internal browser state across restarts.
Settings:
* *Are* directly surfaced to the user
* *Are* localized into the user's language
* *Are not* configurable via enterprise policy (but their backing prefs may be)
* *Are not* reported via UMA when in use
* *Are not* included in chrome://version
* *Are* automatically persistent across restarts (via their backing prefs)
You should add a setting if end-users might want to change this behavior. A
decent litmus test for whether something should be a flag or a setting is: "will
someone who can't read or write code want to change this?"
## Summary Table
| | Prefs | Features | Switches | Flags | Settings |
| :- | :- | :- | :--: | :--: | :- |
| Directly surfaced to the user | ❌ | ❌ | ❌ | ✅ | ✅ |
| Localized into the user's language | ❌ | ❌ | ❌ | ❌ | ✅ |
| Configurable via enterprise policy | ✅ if a policy<br>maps to the pref | ❌ | ❌ except on ChromeOS | ❌ | ❌ but their backing prefs may be |
| Reported when in use | ❌ | via UMA/crash | ❌ | via UMA<br> `Launch.FlagsAtStartup` | ❌ |
| Included in chrome://version | ❌ | ✅ | ✅ | ❌ | ❌ |
| Automatically persistent<br> across restarts | ✅ usually | ❌ | ❌ | ✅ | ✅ via backing prefs |
## Related Documents
* [Chromium Feature API & Finch (Googler-only)](http://go/finch-feature-api)
* [Adding a new feature flag in chrome://flags](how_to_add_your_feature_flag.md)
* [Runtime Enabled Features](../third_party/blink/renderer/platform/RuntimeEnabledFeatures.md)
* [Initialization of Blink runtime features in content layer](initialize_blink_features.md)
* [Integrating a feature with the origin trials framework](origin_trials_integration.md)
[base-commandline]: https://cs.chromium.org/chromium/src/base/command_line.h?type=cs&l=98
[base-feature]: https://cs.chromium.org/chromium/src/base/feature_list.h?sq=package:chromium&g=0&l=53
[about-flags]: https://cs.chromium.org/chromium/src/chrome/browser/about_flags.cc
[fieldtrial-config]: https://cs.chromium.org/chromium/src/testing/variations/fieldtrial_testing_config.json
[flag-metadata]: https://cs.chromium.org/chromium/src/chrome/browser/flag-metadata.json
[prefs]: https://www.chromium.org/developers/design-documents/preferences
[profile-register]: https://source.chromium.org/chromium/chromium/src/+/main:chrome/browser/profiles/profile.h;l=189;drc=b0378e4b67a5dbdb15acf0341ccd51acda81c8e0