chasej | c74a4c9c | 2017-02-10 20:38:09 | [diff] [blame] | 1 | # Integrating a feature with the Origin Trials framework |
| 2 | |
| 3 | To expose your feature via the origin trials framework, there are a few code |
| 4 | changes required. |
| 5 | |
| 6 | [TOC] |
| 7 | |
| 8 | ## Code Changes |
| 9 | |
| 10 | ### Runtime Enabled Features |
| 11 | |
Kent Tamura | b10f7eda | 2017-09-15 06:45:20 | [diff] [blame] | 12 | First, you’ll need to configure [runtime\_enabled\_features.json5]. This is |
chasej | c74a4c9c | 2017-02-10 20:38:09 | [diff] [blame] | 13 | explained in the file, but you use `origin_trial_feature_name` to associate your |
| 14 | runtime feature flag with a name for your origin trial. The name can be the |
| 15 | same as your runtime feature flag, or different. Eventually, this configured |
| 16 | name will be used in the Origin Trials developer console (still under |
| 17 | development). You can have both `status: experimental` and |
| 18 | `origin_trial_feature_name` if you want your feature to be enabled either by |
| 19 | using the `--enable-experimental-web-platform-features` flag **or** the origin |
| 20 | trial. |
| 21 | |
| 22 | You may have a feature that is not available on all platforms, or need to limit |
| 23 | the trial to specific platforms. Use `origin_trial_os: [list]` to specify which |
| 24 | platforms will allow the trial to be enabled. The list values are case- |
| 25 | insensitive, but must match one of the defined `OS_<platform>` macros (see |
| 26 | [build_config.h]). |
| 27 | |
| 28 | #### Examples |
| 29 | |
| 30 | Flag name and trial name are the same: |
| 31 | ``` |
| 32 | { |
| 33 | name: "MyFeature", |
| 34 | origin_trial_feature_name: "MyFeature", |
| 35 | status: "experimental", |
| 36 | }, |
| 37 | ``` |
| 38 | Flag name and trial name are different: |
| 39 | ``` |
| 40 | { |
| 41 | name: "MyFeature", |
| 42 | origin_trial_feature_name: "MyFeatureTrial", |
| 43 | status: "experimental", |
| 44 | }, |
| 45 | ``` |
| 46 | Trial limited to specific platform: |
| 47 | ``` json |
| 48 | { |
| 49 | name: "MyFeature", |
| 50 | origin_trial_feature_name: "MyFeature", |
| 51 | origin_trial_os: ["android"], |
| 52 | status: "experimental", |
| 53 | }, |
| 54 | ``` |
| 55 | |
| 56 | ### Gating Access |
| 57 | |
| 58 | Once configured, there are two mechanisms to gate access to your feature behind |
| 59 | an origin trial. You can use either mechanism, or both, as appropriate to your |
| 60 | feature implementation. |
| 61 | |
| 62 | 1. A native C++ method that you can call in Blink code at runtime to expose your |
| 63 | feature: `bool OriginTrials::myFeatureEnabled()` |
| 64 | 2. An IDL attribute \[[OriginTrialEnabled]\] that you can use to automatically |
Ian Clelland | a94fcfb | 2017-07-20 03:43:48 | [diff] [blame] | 65 | generate code to expose and hide JavaScript methods/attributes/objects. This |
| 66 | attribute works very similarly to \[RuntimeEnabled\]. |
chasej | c74a4c9c | 2017-02-10 20:38:09 | [diff] [blame] | 67 | ``` |
| 68 | [OriginTrialEnabled=MyFeature] |
| 69 | partial interface Navigator { |
| 70 | readonly attribute MyFeatureManager myFeature; |
| 71 | } |
| 72 | ``` |
| 73 | |
Ruslan Burakov | 53cefa7 | 2019-05-09 08:22:25 | [diff] [blame] | 74 | ### Web Feature Counting |
| 75 | |
| 76 | Once the feature is created, in order to run the origin trial you need to track |
| 77 | how often users use your feature. You can do it in two ways. |
| 78 | |
| 79 | #### Increment counter in your c++ code. |
| 80 | |
| 81 | 1. Add your feature counter to end of [web\_feature.mojom]: |
| 82 | |
| 83 | ``` |
| 84 | enum WebFeature { |
| 85 | // ... |
| 86 | kLastFeatureBeforeYours = 1235, |
| 87 | // Here, increment the last feature count before yours by 1. |
| 88 | kMyFeature = 1236, |
| 89 | |
| 90 | kNumberOfFeatures, // This enum value must be last. |
| 91 | }; |
| 92 | ``` |
| 93 | 2. Run [update\_use\_counter\_feature\_enum.py] to update the UMA mapping. |
| 94 | |
| 95 | 3. Increment your feature counter in c++ code. |
| 96 | ```c++ |
| 97 | #include "third_party/blink/renderer/core/frame/use_counter.h" |
| 98 | |
| 99 | // ... |
| 100 | |
| 101 | if (OriginTrials::myFeatureEnabled()) { |
| 102 | UseCounter::Count(context, WebFeature::kMyFeature); |
| 103 | } |
| 104 | ``` |
| 105 | |
| 106 | #### Update counter with \[Measure\] IDL attribute |
| 107 | |
| 108 | 1. Add \[[Measure]\] IDL attribute |
| 109 | ``` |
| 110 | partial interface Navigator { |
| 111 | [OriginTrialEnabled=MyFeature, Measure] |
| 112 | readonly attribute MyFeatureManager myFeature; |
| 113 | ``` |
| 114 | |
| 115 | 2. The code to increment your feature counter will be generated in V8 |
| 116 | automatically. But it requires you to follow \[[Measure]\] IDL attribute |
| 117 | naming convention when you will add your feature counter to |
| 118 | [web\_feature.mojom]. |
| 119 | ``` |
| 120 | enum WebFeature { |
| 121 | // ... |
| 122 | kLastFeatureBeforeYours = 1235, |
| 123 | // Here, increment the last feature count before yours by 1. |
| 124 | kV8Navigator_MyFeature_AttributeGetter = 1236, |
| 125 | |
| 126 | kNumberOfFeatures, // This enum value must be last. |
| 127 | }; |
| 128 | ``` |
| 129 | |
| 130 | |
chasej | c74a4c9c | 2017-02-10 20:38:09 | [diff] [blame] | 131 | **NOTE:** Your feature implementation must not persist the result of the enabled |
| 132 | check. Your code should simply call `OriginTrials::myFeatureEnabled()` as often |
| 133 | as necessary to gate access to your feature. |
| 134 | |
chasej | c74a4c9c | 2017-02-10 20:38:09 | [diff] [blame] | 135 | ## Limitations |
| 136 | |
| 137 | What you can't do, because of the nature of these Origin Trials, is know at |
| 138 | either browser or renderer startup time whether your feature is going to be used |
| 139 | in the current page/context. This means that if you require lots of expensive |
| 140 | processing to begin (say you index the user's hard drive, or scan an entire city |
| 141 | for interesting weather patterns,) that you will have to either do it on browser |
| 142 | startup for *all* users, just in case it's used, or do it on first access. (If |
| 143 | you go with first access, then only people trying the experiment will notice the |
| 144 | delay, and hopefully only the first time they use it.). We are investigating |
| 145 | providing a method like `OriginTrials::myFeatureShouldInitialize()` that will |
| 146 | hint if you should do startup initialization. For example, this could include |
| 147 | checks for trials that have been revoked (or throttled) due to usage, if the |
| 148 | entire origin trials framework has been disabled, etc. The method would be |
| 149 | conservative and assume initialization is required, but it could avoid expensive |
| 150 | startup in some known scenarios. |
| 151 | |
| 152 | Similarly, if you need to know in the browser process whether a feature should |
| 153 | be enabled, then you will have to either have the renderer inform it at runtime, |
| 154 | or else just assume that it's always enabled, and gate access to the feature |
| 155 | from the renderer. |
| 156 | |
| 157 | ## Testing |
| 158 | |
Steve Kobes | 6d752cb | 2019-01-16 01:37:46 | [diff] [blame] | 159 | To test an origin trial feature during development, follow these steps: |
chasej | c74a4c9c | 2017-02-10 20:38:09 | [diff] [blame] | 160 | |
Steve Kobes | 6d752cb | 2019-01-16 01:37:46 | [diff] [blame] | 161 | 1. Use [generate_token.py] to generate a token signed with the test private key. |
| 162 | You can generate signed tokens for any origin that you need to help you test, |
| 163 | including localhost or 127.0.0.1. Example: |
chasej | c74a4c9c | 2017-02-10 20:38:09 | [diff] [blame] | 164 | |
Steve Kobes | 6d752cb | 2019-01-16 01:37:46 | [diff] [blame] | 165 | ``` |
| 166 | tools/origin_trials/generate_token.py http://localhost:8000 MyFeature |
| 167 | ``` |
chasej | c74a4c9c | 2017-02-10 20:38:09 | [diff] [blame] | 168 | |
Steve Kobes | 6d752cb | 2019-01-16 01:37:46 | [diff] [blame] | 169 | 2. Copy the token from the end of the output and use it in a `<meta>` tag or |
| 170 | an `Origin-Trial` header as described in the [Developer Guide]. |
chasej | c74a4c9c | 2017-02-10 20:38:09 | [diff] [blame] | 171 | |
Steve Kobes | 6d752cb | 2019-01-16 01:37:46 | [diff] [blame] | 172 | 3. Run Chrome with the test public key by passing: |
| 173 | `--origin-trial-public-key=dRCs+TocuKkocNKa0AtZ4awrt9XKH2SQCI6o4FY6BNA=` |
| 174 | |
| 175 | The `--origin-trial-public-key` switch is not needed with `content_shell`, as it |
| 176 | uses the test public key by default. |
| 177 | |
| 178 | The test private key is stored in the repo at `tools/origin_trials/eftest.key`. |
| 179 | It's also used by Origin Trials unit tests and web tests. |
| 180 | |
| 181 | If you cannot set command-line switches (e.g., on Chrome OS), you can also |
| 182 | directly modify [chrome_origin_trial_policy.cc]. |
chasej | c74a4c9c | 2017-02-10 20:38:09 | [diff] [blame] | 183 | |
Kent Tamura | 59ffb02 | 2018-11-27 05:30:56 | [diff] [blame] | 184 | ### Web Tests |
| 185 | When using the \[OriginTrialEnabled\] IDL attribute, you should add web tests |
Ian Clelland | a94fcfb | 2017-07-20 03:43:48 | [diff] [blame] | 186 | to verify that the V8 bindings code is working as expected. Depending on how |
chasej | 0ac7dd2 | 2017-02-23 18:16:17 | [diff] [blame] | 187 | your feature is exposed, you'll want tests for the exposed interfaces, as well |
| 188 | as tests for script-added tokens. For examples, refer to the existing tests in |
| 189 | [origin_trials/webexposed]. |
| 190 | |
chasej | c74a4c9c | 2017-02-10 20:38:09 | [diff] [blame] | 191 | [build_config.h]: /build/build_config.h |
| 192 | [chrome_origin_trial_policy.cc]: /chrome/common/origin_trials/chrome_origin_trial_policy.cc |
chasej | c74a4c9c | 2017-02-10 20:38:09 | [diff] [blame] | 193 | [generate_token.py]: /tools/origin_trials/generate_token.py |
| 194 | [Developer Guide]: https://github.com/jpchase/OriginTrials/blob/gh-pages/developer-guide.md |
Kent Tamura | 6943cf79 | 2018-04-09 05:24:54 | [diff] [blame] | 195 | [OriginTrialEnabled]: /third_party/blink/renderer/bindings/IDLExtendedAttributes.md#_OriginTrialEnabled_i_m_a_c_ |
Kent Tamura | 59ffb02 | 2018-11-27 05:30:56 | [diff] [blame] | 196 | [origin_trials/webexposed]: /third_party/blink/web_tests/http/tests/origin_trials/webexposed/ |
Kent Tamura | 6943cf79 | 2018-04-09 05:24:54 | [diff] [blame] | 197 | [runtime\_enabled\_features.json5]: /third_party/blink/renderer/platform/runtime_enabled_features.json5 |
Lucas Furukawa Gadani | 6c24cdae | 2018-04-27 00:28:40 | [diff] [blame] | 198 | [trial_token_unittest.cc]: /third_party/blink/common/origin_trials/trial_token_unittest.cc |
Ruslan Burakov | 53cefa7 | 2019-05-09 08:22:25 | [diff] [blame] | 199 | [web\_feature.mojom]: /third_party/blink/public/mojom/web_feature/web_feature.mojom |
| 200 | [update\_use\_counter\_feature\_enum.py]: /tools/metrics/histograms/update_use_counter_feature_enum.py |
| 201 | [Measure]: /third_party/blink/renderer/bindings/IDLExtendedAttributes.md#Measure_i_m_a_c |