blob: 8d04e74ed06100218bcec710d9b5023cffdfd6eb [file] [log] [blame] [view]
Ming-Ying Chungc23505d62022-09-22 10:07:331# Integrating a feature with the Origin Trials framework
chasejc74a4c9c2017-02-10 20:38:092
Ming-Ying Chungc23505d62022-09-22 10:07:333To expose your feature via the [Origin Trials framework], there are a few code
chasejc74a4c9c2017-02-10 20:38:094changes required.
5
Ming-Ying Chungc23505d62022-09-22 10:07:336*** note
7**WARNING:** This is only available for features implemented in Blink.
8***
9
chasejc74a4c9c2017-02-10 20:38:0910[TOC]
11
12## Code Changes
13
Ming-Ying Chungc23505d62022-09-22 10:07:3314*** promo
15**NOTE:** You can land these code changes before requesting to run an origin
16trial.
Jason Chasedbd8b9732020-11-26 17:18:4317These code changes make it possible to control a feature via an origin trial,
18but don't require an origin trial to be approved. For more on the process, see
19[Running an Origin Trial].
Ming-Ying Chungc23505d62022-09-22 10:07:3320***
Jason Chasedbd8b9732020-11-26 17:18:4321
Ming-Ying Chungc23505d62022-09-22 10:07:3322### Step 1: Add Runtime Enabled Feature in Blink for Origin Trial
chasejc74a4c9c2017-02-10 20:38:0923
Ming-Ying Chungc23505d62022-09-22 10:07:3324First, you’ll need to configure [runtime\_enabled\_features.json5]. If you don't
25have a Blink's [Runtime Enabled Feature] flag yet, you will need to add an entry
26in this file.
chasejc74a4c9c2017-02-10 20:38:0927
Ming-Ying Chungc23505d62022-09-22 10:07:3328The following fields of an entry are relevant:
Christian Biesinger0651e8252022-01-25 17:18:0829
Ming-Ying Chungc23505d62022-09-22 10:07:3330- `name`: The name of your runtime enabled feature, e.g. `"MyFeature"`.
31- `origin_trial_feature_name`: The name of your runtime enabled feature in the
32 origin trial. This can be the same as your runtime feature flag (i.e. `name`
33 field), or different. Eventually, this configured name will be used in the
34 origin trials developer console.
35- `origin_trial_os`: Specifies a `[list]` of platforms where they will allow the
36 trial to be enabled. The list values are case-insensitive, but must match one
37 of the defined `OS_<platform>` macros (see [build_config.h]).
38- `base_feature`: Generates a `base::Feature` in the `blink::features`
Kent Tamura0bc0a4532023-02-17 04:18:3839 namespace if the value is not `"none"`. It helps to control the Origin Trial
40 remotely. See also [Generate a `base::Feature` instance from a Blink Feature]
41 [from blink].
Ming-Ying Chungc23505d62022-09-22 10:07:3342
43Not specific to Origin Trial:
44
45- `status`: Controls when the runtime enabled feature is enabled in Blink. See
46 also [the Status table].
47- `base_feature_status`: Controls when the `base::Feature` defined by
48 `base_feature` is enabled.
49
50More details are explained in the json5 file and in the above linked doc.
51
52If the runtime enabled feature flag is [used in C++](#1-in-c), you will have to
53change all callers of the no-argument overload of
54`RuntimeEnabledFeatures::MyFeatureEnabled()` to the overload that takes a
55`const FeatureContext*`. You can pass an `ExecutionContext` here, e.g. using
56`ExecutionContext::From(ScriptState*)`.
chasejc74a4c9c2017-02-10 20:38:0957
58#### Examples
59
Ming-Ying Chungc23505d62022-09-22 10:07:3360RuntimeEnabledFeature flag name, trial name and `base::Feature` are all the
61same:
62
63```json
chasejc74a4c9c2017-02-10 20:38:0964{
Ming-Ying Chungc23505d62022-09-22 10:07:3365 name: "MyFeature", // Generates `RuntimeEnabledFeatures::MyFeatureEnabled()`
chasejc74a4c9c2017-02-10 20:38:0966 origin_trial_feature_name: "MyFeature",
67 status: "experimental",
Kent Tamura0bc0a4532023-02-17 04:18:3868 // No need to specify base_feature.
chasejc74a4c9c2017-02-10 20:38:0969},
70```
Ming-Ying Chungc23505d62022-09-22 10:07:3371
Kent Tamura0bc0a4532023-02-17 04:18:3872RuntimeEnabledFeature flag name, trial name, and `base::Feature` name are
73different:
Ming-Ying Chungc23505d62022-09-22 10:07:3374
75```json
chasejc74a4c9c2017-02-10 20:38:0976{
77 name: "MyFeature",
78 origin_trial_feature_name: "MyFeatureTrial",
Kent Tamura0bc0a4532023-02-17 04:18:3879 base_feature: "MyBaseFeature", // Generates blink::features::kMyBaseFeature
chasejc74a4c9c2017-02-10 20:38:0980 status: "experimental",
81},
82```
Ming-Ying Chungc23505d62022-09-22 10:07:3383
chasejc74a4c9c2017-02-10 20:38:0984Trial limited to specific platform:
Ming-Ying Chungc23505d62022-09-22 10:07:3385
86```json
chasejc74a4c9c2017-02-10 20:38:0987{
88 name: "MyFeature",
89 origin_trial_feature_name: "MyFeature",
90 origin_trial_os: ["android"],
91 status: "experimental",
92},
93```
94
Peter Birk Pakkenbergf6ca5252022-09-05 08:54:0595#### WebView considerations
Ming-Ying Chungc23505d62022-09-22 10:07:3396
97Because WebView is built as part of the `"android"` os target, it is not
98possible to exclude a trial from WebView if it is enabled on Android.
Peter Birk Pakkenbergf6ca5252022-09-05 08:54:0599
100If the feature under trial can be enabled on WebView alongside other Android
101platforms, this is preferred.
102
103In situations where this is not feasible, the recommended solution is to
104explicitly disable the origin trial in
105`AwMainDelegate::BasicStartupComplete()` in [aw\_main\_delegate.cc] by
106appending the `embedder_support::kOriginTrialDisabledFeatures` switch with the
107disabled trial names as values.
108
109See http://crrev.com/c/3733267 for an example of how this can be done.
110
Ming-Ying Chungc23505d62022-09-22 10:07:33111### Step 2: Gating Access
chasejc74a4c9c2017-02-10 20:38:09112
113Once configured, there are two mechanisms to gate access to your feature behind
114an origin trial. You can use either mechanism, or both, as appropriate to your
115feature implementation.
116
Ming-Ying Chungc23505d62022-09-22 10:07:33117#### 1) In C++
118
119A native C++ method that you can call in Blink code at runtime to expose your
120feature:
121
122```cpp
123bool RuntimeEnabledFeatures::MyFeatureEnabled(ExecutionContext*)
chasejc74a4c9c2017-02-10 20:38:09124```
Ming-Ying Chungc23505d62022-09-22 10:07:33125
126*** note
127**WARNING:** Your feature implementation must not persist the result of the
128enabled check. Your code should simply call
129`RuntimeEnabledFeatures::MyFeatureEnabled(ExecutionContext*)` as often as
130necessary to gate access to your feature.
131***
132
133#### 2-1) In Web IDL
134
135An IDL attribute \[[RuntimeEnabled]\] that you can use to automatically generate
136code to expose and hide JavaScript methods/attributes/objects.
137
138```cpp
Allen Robinsonb0efcfa2019-06-25 13:24:04139[RuntimeEnabled=MyFeature]
chasejc74a4c9c2017-02-10 20:38:09140partial interface Navigator {
141 readonly attribute MyFeatureManager myFeature;
142}
143```
144
Ming-Ying Chungc23505d62022-09-22 10:07:33145#### 2-2) CSS Properties
Allen Robinsonb0efcfa2019-06-25 13:24:04146
Ming-Ying Chungc23505d62022-09-22 10:07:33147*** promo
148**NOTE:** For CSS properties, you do not need to edit the IDL files, as the
149exposure on the [CSSStyleDeclaration] is handled at runtime.
150***
Rodney Ding533e41a2020-01-15 20:17:18151
Ming-Ying Chungc23505d62022-09-22 10:07:33152You can also run experiment for new CSS properties with origin trial. After you
153have configured your feature in [runtime\_enabled\_features.json5] as above,
154head to [css\_properties.json5]. As explained in the file, you use
155`runtime_flag` to associate the CSS property with the feature you just defined.
156This will automatically link the CSS property to the origin trial defined in the
157runtime feature. It will be available in both JavaScript (`Element.style`) and
158CSS (including `@supports`) when the trial is enabled.
Rodney Ding533e41a2020-01-15 20:17:18159
Ming-Ying Chungc23505d62022-09-22 10:07:33160*** promo
161**EXAMPLE:** [origin-trial-test-property] defines a test css property controlled
162via runtime feature `OriginTrialsSampleAPI` and subsequently an origin trial
163named `Frobulate`.
164***
165
166*** note
167**ISSUE:** In the rare cases where the origin trial token is added via script
168after the css style declaration, the css property will be enabled and is fully
169functional, however it will not appear on the [CSSStyleDeclaration] interface,
170i.e. not accessible in `Element.style`. This issue is tracked in crbug/1041993.
171***
172
173### Step 3: Mapping Runtime Enabled Feature to `base::Feature` (optional)
174
175Given the following example:
176
177```json
178{
179 name: "MyFeature",
180 origin_trial_feature_name: "MyFeature",
181 base_feature: "MyFeature",
182 status: "experimental",
183},
184```
185
186```cpp
187[RuntimeEnabled=MyFeature]
188interface MyFeatureAPI {
189 readonly attribute bool dummy;
190}
191```
192
193```cpp
194// third_party/blink/.../my_feature_api.cc
195bool MyFeatureAPI::ConnectToBrowser() {
196 if (base::FeatureList::IsEnabled(blink::features::kMyFeature) {
197 // Do something
198 }
199 return false;
200}
201```
202
203The above example shows a new feature relies on a `base::Feature` generated from
204the `base_feature` definition in json file, e.g. `blink::features::kMyFeature`,
205in addition to the runtime enabled feature flag `MyFeature`.
206However, their values are not associated.
207
208In addition, due to the [limitation](#limitations), the runtime enabled feature
209flag is not available in the browser process **by default**:
210
211> if you need to know in the browser process whether a feature should
212> be enabled, then you will have to either have the renderer inform it at
213> runtime, or else just assume that it's always enabled, and gate access to the
214> feature from the renderer.
215
216*** note
217**TLDR:** Turning on `MyFeature` doesn't automatically turning on
218`blink::features::kMyFeature`, and vice versa.
219***
220
221To mitigate the issue, there are several options:
222
223#### Option 1: Fully Enabling `base::Feature`, e.g. `kMyFeature`
224
225And letting Origin Trial decides when your feature (via runtime enabled feature
226flag `blink::features::MyFeature`) is available, as suggested in the above
227quote. The `base::Feature` can be enabled via a remote Finch config, or by
228updating the default value in C++.
229
230However, after the Origin Trial ends, it will be impossible to ramp up the
231feature by Finch if the part controlled by `MyFeature` cannot be enabled
232independently. For example, if you have a new Web API `MyFeatureAPI`, enabling
233`MyFeature` will just make the IDL available to everyone without the
234Blink/browser implementation.
235
236*** note
237**Example Bug:** https://crbug.com/1360678.
238***
239
240#### Option 2: Setting Up a Custom Mapping
241
2421. Make `MyFeature` depend on `blink::features::kMyFeature` so that the feature
243 is not enabled if `features::kMyFeatures` is not enabled. In
244 [third_party/blink/renderer/core/origin_trials/origin_trial_context.cc](../third_party/blink/renderer/core/origin_trials/origin_trial_context.cc):
245
246 ```cpp
247 bool OriginTrialContext::CanEnableTrialFromName(const StringView& trial_name) {
248 ...
249 if (trial_name == "MyFeature") {
250 return base::FeatureList::IsEnabled(blink::features::kMyFeatures);
251 }
252 }
253 ```
254
2552. Add custom relationship for `MyFeature` and `blink::features::kMyFeature` to
256 handle your use case.
257
258 Read
259 [**Determine how your feature is initialized: Depends on the status of a base::Feature**](initialize_blink_features.md#step-2_determine-how-your-feature-is-initialized)
260 first. If the mappings described there don't meet your use case, refer to
261 the following examples.
262
263 In [content/child/runtime_features.cc](https://source.chromium.org/chromium/chromium/src/+/main:content/child/runtime_features.cc):
264
265 ```cpp
266 void SetCustomizedRuntimeFeaturesFromCombinedArgs(
267 const base::CommandLine& command_line) {
268 // Example 1: https://bit.ly/configuring-trust-tokens
269 // Example 2: https://crrev.com/c/3878922/14/content/child/runtime_features.cc
270 }
271 ```
272
273### Step 4: Web Feature Counting
Ruslan Burakov53cefa72019-05-09 08:22:25274
275Once the feature is created, in order to run the origin trial you need to track
276how often users use your feature. You can do it in two ways.
277
Ming-Ying Chungc23505d62022-09-22 10:07:33278#### Increment counter in your c++ code
Ruslan Burakov53cefa72019-05-09 08:22:25279
2801. Add your feature counter to end of [web\_feature.mojom]:
281
Ming-Ying Chungc23505d62022-09-22 10:07:33282 ```cpp
283 enum WebFeature {
284 // ...
285 kLastFeatureBeforeYours = 1235,
286 // Here, increment the last feature count before yours by 1.
287 kMyFeature = 1236,
Ruslan Burakov53cefa72019-05-09 08:22:25288
Ming-Ying Chungc23505d62022-09-22 10:07:33289 kNumberOfFeatures, // This enum value must be last.
290 };
291 ```
292
Ruslan Burakov53cefa72019-05-09 08:22:252932. Run [update\_use\_counter\_feature\_enum.py] to update the UMA mapping.
294
2953. Increment your feature counter in c++ code.
Ruslan Burakov53cefa72019-05-09 08:22:25296
Ming-Ying Chungc23505d62022-09-22 10:07:33297 ```c++
298 #include "third_party/blink/renderer/platform/instrumentation/use_counter.h"
Ruslan Burakov53cefa72019-05-09 08:22:25299
Ming-Ying Chungc23505d62022-09-22 10:07:33300 // ...
301
302 if (RuntimeEnabledFeatures::MyFeatureEnabled(context)) {
303 UseCounter::Count(context, WebFeature::kMyFeature);
304 }
305 ```
Ruslan Burakov53cefa72019-05-09 08:22:25306
307#### Update counter with \[Measure\] IDL attribute
308
3091. Add \[[Measure]\] IDL attribute
Ming-Ying Chungc23505d62022-09-22 10:07:33310
311 ```cpp
312 partial interface Navigator {
313 [RuntimeEnabled=MyFeature, Measure]
314 readonly attribute MyFeatureManager myFeature;
315 ```
Ruslan Burakov53cefa72019-05-09 08:22:25316
3172. The code to increment your feature counter will be generated in V8
318 automatically. But it requires you to follow \[[Measure]\] IDL attribute
319 naming convention when you will add your feature counter to
320 [web\_feature.mojom].
Ruslan Burakov53cefa72019-05-09 08:22:25321
Ming-Ying Chungc23505d62022-09-22 10:07:33322 ```cpp
323 enum WebFeature {
324 // ...
325 kLastFeatureBeforeYours = 1235,
326 // Here, increment the last feature count before yours by 1.
327 kV8Navigator_MyFeature_AttributeGetter = 1236,
328
329 kNumberOfFeatures, // This enum value must be last.
330 };
331 ```
332
333### Step 5: Add Web Tests
334
335When using the \[[RuntimeEnabled]\] IDL attribute, you should add web tests
336to verify that the V8 bindings code is working as expected. Depending on how
337your feature is exposed, you'll want tests for the exposed interfaces, as well
338as tests for script-added tokens. For examples, refer to the existing tests in
339[origin_trials/webexposed].
Ruslan Burakov53cefa72019-05-09 08:22:25340
chasejc74a4c9c2017-02-10 20:38:09341## Limitations
342
Allen Robinsonb0efcfa2019-06-25 13:24:04343What you can't do, because of the nature of these origin trials, is know at
chasejc74a4c9c2017-02-10 20:38:09344either browser or renderer startup time whether your feature is going to be used
345in the current page/context. This means that if you require lots of expensive
346processing to begin (say you index the user's hard drive, or scan an entire city
347for interesting weather patterns,) that you will have to either do it on browser
348startup for *all* users, just in case it's used, or do it on first access. (If
349you go with first access, then only people trying the experiment will notice the
350delay, and hopefully only the first time they use it.). We are investigating
351providing a method like `OriginTrials::myFeatureShouldInitialize()` that will
352hint if you should do startup initialization. For example, this could include
353checks for trials that have been revoked (or throttled) due to usage, if the
354entire origin trials framework has been disabled, etc. The method would be
355conservative and assume initialization is required, but it could avoid expensive
356startup in some known scenarios.
357
358Similarly, if you need to know in the browser process whether a feature should
359be enabled, then you will have to either have the renderer inform it at runtime,
360or else just assume that it's always enabled, and gate access to the feature
361from the renderer.
362
Ming-Ying Chungc23505d62022-09-22 10:07:33363## Manual Testing
chasejc74a4c9c2017-02-10 20:38:09364
Steve Kobes6d752cb2019-01-16 01:37:46365To test an origin trial feature during development, follow these steps:
chasejc74a4c9c2017-02-10 20:38:09366
Steve Kobes6d752cb2019-01-16 01:37:463671. Use [generate_token.py] to generate a token signed with the test private key.
368 You can generate signed tokens for any origin that you need to help you test,
369 including localhost or 127.0.0.1. Example:
chasejc74a4c9c2017-02-10 20:38:09370
Ming-Ying Chungc23505d62022-09-22 10:07:33371 ```bash
372 tools/origin_trials/generate_token.py http://localhost:8000 MyFeature
373 ```
chasejc74a4c9c2017-02-10 20:38:09374
Jason Chasedbd8b9732020-11-26 17:18:43375 There are additional flags to generate third-party tokens, set the expiry
376 date, and control other options. See the command help for details (`--help`).
377 For example, to generate a third-party token, with [user subset exclusion]:
378
Ming-Ying Chungc23505d62022-09-22 10:07:33379 ```bash
380 tools/origin_trials/generate_token.py --is-third-party --usage-restriction=subset http://localhost:8000 MyFeature
381 ```
Jason Chasedbd8b9732020-11-26 17:18:43382
Steve Kobes6d752cb2019-01-16 01:37:463832. Copy the token from the end of the output and use it in a `<meta>` tag or
384 an `Origin-Trial` header as described in the [Developer Guide].
chasejc74a4c9c2017-02-10 20:38:09385
Steve Kobes6d752cb2019-01-16 01:37:463863. Run Chrome with the test public key by passing:
387 `--origin-trial-public-key=dRCs+TocuKkocNKa0AtZ4awrt9XKH2SQCI6o4FY6BNA=`
388
Ming-Ying Chungc23505d62022-09-22 10:07:33389You can also run Chrome with both the test public key and the default public key
390along side by passing:
Andrii Sagaidakdbc6a772019-12-12 03:43:39391`--origin-trial-public-key=dRCs+TocuKkocNKa0AtZ4awrt9XKH2SQCI6o4FY6BNA=,fMS4mpO6buLQ/QMd+zJmxzty/VQ6B1EUZqoCU04zoRU=`
392
Steve Kobes6d752cb2019-01-16 01:37:46393The `--origin-trial-public-key` switch is not needed with `content_shell`, as it
394uses the test public key by default.
395
396The test private key is stored in the repo at `tools/origin_trials/eftest.key`.
397It's also used by Origin Trials unit tests and web tests.
398
399If you cannot set command-line switches (e.g., on Chrome OS), you can also
400directly modify [chrome_origin_trial_policy.cc].
chasejc74a4c9c2017-02-10 20:38:09401
Ming-Ying Chungc23505d62022-09-22 10:07:33402To see additional information about origin trial token parsing (including
403reasons for failures, or token names for successful tokens), you can add these
404switches:
Mason Freed9ee18c762020-08-18 20:57:21405
406 `--vmodule=trial_token=2,origin_trial_context=1`
407
408If you are building with `is_debug=false`, then you will also need to add
409`dcheck_always_on=true` to your build options, and add this to the command line:
410
411 `--enable-logging=stderr`
412
Ming-Ying Chungc23505d62022-09-22 10:07:33413## Related Documents
Mason Freed9ee18c762020-08-18 20:57:21414
Ming-Ying Chungc23505d62022-09-22 10:07:33415- [Chromium Feature API & Finch (Googler-only)](http://go/finch-feature-api)
416- [Configuration: Prefs, Settings, Features, Switches & Flags](configuration.md)
417- [Runtime Enabled Features](../third_party/blink/renderer/platform/RuntimeEnabledFeatures.md)
418- [Initialization of Blink runtime features in content layer](initialize_blink_features.md)
chasej0ac7dd22017-02-23 18:16:17419
Ming-Ying Chungc23505d62022-09-22 10:07:33420[Origin Trials framework]: http://googlechrome.github.io/OriginTrials/developer-guide.html
421[Runtime Enabled Features]: ../third_party/blink/renderer/platform/RuntimeEnabledFeatures.md
422[from blink]: ../third_party/blink/renderer/platform/RuntimeEnabledFeatures.md#generate-a-instance-from-a-blink-feature
423[the Status table]: ../third_party/blink/renderer/platform/RuntimeEnabledFeatures.md#adding-a-runtime-enabled-feature
chasejc74a4c9c2017-02-10 20:38:09424[build_config.h]: /build/build_config.h
425[chrome_origin_trial_policy.cc]: /chrome/common/origin_trials/chrome_origin_trial_policy.cc
chasejc74a4c9c2017-02-10 20:38:09426[generate_token.py]: /tools/origin_trials/generate_token.py
427[Developer Guide]: https://github.com/jpchase/OriginTrials/blob/gh-pages/developer-guide.md
Ming-Ying Chungc23505d62022-09-22 10:07:33428[RuntimeEnabled]: ../third_party/blink/renderer/bindings/IDLExtendedAttributes.md#RuntimeEnabled_i_m_a_c
429[origin_trials/webexposed]: ../third_party/blink/web_tests/http/tests/origin_trials/webexposed/
430[runtime\_enabled\_features.json5]: ../third_party/blink/renderer/platform/runtime_enabled_features.json5
431[trial_token_unittest.cc]: ../third_party/blink/common/origin_trials/trial_token_unittest.cc
432[web\_feature.mojom]: ../third_party/blink/public/mojom/use_counter/metrics/web_feature.mojom
Ruslan Burakov53cefa72019-05-09 08:22:25433[update\_use\_counter\_feature\_enum.py]: /tools/metrics/histograms/update_use_counter_feature_enum.py
Ming-Ying Chungc23505d62022-09-22 10:07:33434[Measure]: ../third_party/blink/renderer/bindings/IDLExtendedAttributes.md#Measure_i_m_a_c
435[css\_properties.json5]: ../third_party/blink/renderer/core/css/css_properties.json5
Rodney Ding533e41a2020-01-15 20:17:18436[origin-trial-test-property]: https://chromium.googlesource.com/chromium/src/+/ff2ab8b89745602c8300322c2a0158e210178c7e/third_party/blink/renderer/core/css/css_properties.json5#2635
Ming-Ying Chungc23505d62022-09-22 10:07:33437[CSSStyleDeclaration]: ../third_party/blink/renderer/core/css/css_style_declaration.idl
Jason Chasedbd8b9732020-11-26 17:18:43438[Running an Origin Trial]: https://www.chromium.org/blink/origin-trials/running-an-origin-trial
439[user subset exclusion]: https://docs.google.com/document/d/1xALH9W7rWmX0FpjudhDeS2TNTEOXuPn4Tlc9VmuPdHA/edit#heading=h.myaz1twlipw