OLD | NEW |
(Empty) | |
| 1 # Extension Bindings |
| 2 |
| 3 [TOC] |
| 4 |
| 5 ## What Is It? |
| 6 |
| 7 The Bindings System is responsible for creating the JS entry points for APIs. |
| 8 It creates the `chrome` object (if it does not exist) and adds the API objects |
| 9 (e.g. `tabs`) that should be accessible to the context. |
| 10 |
| 11 ## Initialization |
| 12 |
| 13 Bindings are initialized by creating an ObjectTemplate from an API specification |
| 14 and stamping out copies of this template. This means that once an API is |
| 15 instantiated once, further instantiations within that same process are |
| 16 significantly faster. The API itself is specified from a .json or .idl file in |
| 17 extensions/common/api or chrome/common/extensions/api. |
| 18 |
| 19 This is slightly complicated because APIs may have features (such as specific |
| 20 methods or events) that are restricted in certain contexts, even if the rest of |
| 21 the API is available. As a result, after object instantiation, there’s a chance |
| 22 we may have to alter the object in order to remove these unavailable features. |
| 23 |
| 24 ## API Features |
| 25 |
| 26 A "feature" of an API is a property on the API object to expose some |
| 27 functionality. There are three main types of features exposed on APIs. |
| 28 |
| 29 * __Functions__: |
| 30 Functions are the main type of feature exposed on APIs. They allow callers to |
| 31 interact with the browser and trigger behavior. |
| 32 |
| 33 * __Events__: |
| 34 Most events are dispatched when something happens to inform an interested party |
| 35 of the instance. Callers subscribe to the events they are interested in, and |
| 36 are notified only for subscribed events. While most events do not influence |
| 37 behavior change in the browser, declarative events may. |
| 38 |
| 39 * __Properties__: |
| 40 Certain APIs have exposed properties that are accessed directly on the API |
| 41 object. These are frequently constants (including enum definitions), but are |
| 42 also sometimes properties relating to the state of the context. |
| 43 |
| 44 ## Restriction |
| 45 |
| 46 Not all APIs are available to all contexts; we restrict which capabilities are |
| 47 exposed based on multiple factors. |
| 48 |
| 49 ### Scope |
| 50 |
| 51 Features may be restricted at multiple scopes. The most common is at the |
| 52 API-scope - where none of the API will be made available if the requirements |
| 53 aren’t met. In this case, the chrome.<apiName> property will simply be |
| 54 undefined. However, we also have the ability to restrict features on a more |
| 55 granular scope, such as at the method or event level. In this case, even though |
| 56 most of an API may be available, a certain function might not be; or, |
| 57 conversely, only a small subset of features may be available while the rest of |
| 58 the API is restricted. |
| 59 |
| 60 ### Restricting Properties |
| 61 Feature restrictions are based on a specific v8::Context. Different |
| 62 contexts within the same frame may have different API availabilities (this is |
| 63 significantly different than the web platform, where features are exposed at the |
| 64 frame-level). The bindings system takes into account context type, associated |
| 65 extensions, URL, and more when evaluating features; for more information, see |
| 66 the [feature documentation](/chrome/common/extensions/api/_features.md). |
| 67 |
| 68 ## Typical Function Flow |
| 69 |
| 70 The typical flow for all API methods is the same. A JS entry point (the method |
| 71 on the API object) leads to a common native implementation. This implementation |
| 72 has the following steps: |
| 73 |
| 74 * __Argument Parsing__: |
| 75 |
| 76 Passed arguments are parsed against an expected signature defined in the API |
| 77 specification. If the passed arguments match the signature, the arguments are |
| 78 normalized and converted to a serialized format (base::Value). |
| 79 * __Request Dispatch__: |
| 80 A request is dispatched with the parsed arguments and other information about |
| 81 the request (such as requesting context and user gesture status). If a callback |
| 82 is included in the arguments, it is stored (along with other information about |
| 83 the request) until the response is received. |
| 84 * __Request Response__: |
| 85 A response is provided asynchronously, indicating success or failure, along with |
| 86 any return values (to pass to a provided callback) or an error message. The |
| 87 pending request is removed. |
| 88 |
| 89 ## Custom Function Hooks |
| 90 |
| 91 Certain APIs need to deviate from this typical flow in order to customize |
| 92 behavior. We provide the following general custom hooks for APIs to modify the |
| 93 typical behavior. |
| 94 |
| 95 * __updateArgumentsPreValidate__: |
| 96 Allows an API implementation to modify passed arguments before the argument |
| 97 signature is validated. This can be useful in the case of undocumented |
| 98 (internal) parameters or properties, such as a generated ID. |
| 99 * __updateArgumentsPostValidate__: |
| 100 Allows an API implementation to modify passed arguments after the argument |
| 101 signature is validated, but before the request is handled. Note: this is |
| 102 usually bad practice, as any modification means that the arguments no longer |
| 103 match the expected signature. This can cause headaches when we attempt to |
| 104 deserialize these values. |
| 105 * __handleRequest__: |
| 106 Allows an API implementation to internally handle a request. This is useful |
| 107 when the request itself should not go through the normal flow, such as when the |
| 108 logic requires a greater level of involvement on the renderer, or is entirely |
| 109 handled without needing to message the browser. |
| 110 * __customCallback__: |
| 111 Allows an API implementation to add a callback that should be called with the |
| 112 result of an API function call before the caller’s callback is invoked. It is |
| 113 the responsibility of the custom callback to invoke the original callback, which |
| 114 is passed as an argument. This is useful when the return results should be |
| 115 mutated before returning to the caller (which can be necessary when the eventual |
| 116 result could be a renderer-specific concept, such as a DOMWindow). |
| 117 |
| 118 An API implementation may use one or more of these hooks. |
| 119 |
| 120 ### Registering Hooks |
| 121 |
| 122 Custom Hooks can be registered through either native or JS bindings. In native |
| 123 bindings, APIs can subclass APIBindingHooksDelegate and register themselves with |
| 124 the bindings system. This typically happens during the bootstrapping of the |
| 125 renderer process. Native binding hooks are the preferred approach for new |
| 126 bindings. |
| 127 |
| 128 We also expose hooks in JS through the APIBindingBridge object, which provides |
| 129 a registerCustomHook method to allow APIs to create hooks in JS. This style of |
| 130 custom hooks is __not preferred__ and will be __deprecated__. These are bad |
| 131 because a) JS is much more susceptible to untrusted code and b) since these run |
| 132 on each object instantiation, the performance cost is significantly higher. |
| 133 |
| 134 ## Events |
| 135 |
| 136 Events are dispatched when the associated action occurs. |
| 137 |
| 138 ### Types |
| 139 |
| 140 There are three types of events. |
| 141 |
| 142 * __Regular__: |
| 143 These events are dispatched to the subscriber when something happens, and merely |
| 144 serve as a notification to allow the subscriber to react. |
| 145 * __Declarative__: |
| 146 Declarative events allow a subscriber to specify some action to be taken when an |
| 147 event occurs. For instance, the declarativeContent API allows a subscriber to |
| 148 indicate that an action should be shown whenever a certain URL pattern or CSS |
| 149 rule is matched. For these events, the subscriber is not notified when the |
| 150 event happens; rather, the browser immediately takes the specified action. By |
| 151 virtue of not notifying the subscriber, we help preserve the user’s privacy; if |
| 152 a subscriber says "do X when the user visits example.com", it does not know |
| 153 whether the user visited example.com. (Note: subsequent actions, such as a user |
| 154 interacting with the action on a given page, can expose this.) |
| 155 * __Imperative__: |
| 156 A few events are designed to be dispatched and to return a response from the |
| 157 subscriber, indicating an action the browser should take. These are |
| 158 predominantly used in the webRequest API, where a subscriber can register events |
| 159 for navigations, receive notifications of those navigations, and return a result |
| 160 of whether the navigation should continue, cancel, or redirect. These events |
| 161 are generally discouraged for performance reasons, and declarative events are |
| 162 preferred. |
| 163 |
| 164 ### Filters |
| 165 |
| 166 Certain events also allow the registration of filters, which allow subscribers |
| 167 to only be notified of a subset of events. For example, the webNavigation and |
| 168 webRequest APIs allow filtering by URL pattern, so that uninteresting |
| 169 navigations are ignored. |
| 170 |
| 171 ## Legacy JavaScript Implementations |
| 172 |
| 173 The prior bindings system was implemented primarily in JavaScript, rather than |
| 174 utilizing native code. There were many reasons for this, but they include ease |
| 175 of coding and more limited interactions with Blink (WebKit at the time) and V8. |
| 176 Unfortunately, this led to numerous security vulnerabilities (because untrusted |
| 177 code can run in the same context) and performance issues (because bindings were |
| 178 set up per context, and could not be cached in any way). |
| 179 |
| 180 While the native bindings system replaces the core functionality with a native |
| 181 implementation, individual APIs may still be implemented in JavaScript custom |
| 182 bindings, or hooks. These should eventually be replaced by native-only |
| 183 implementations. |
| 184 |
| 185 ## Differences Between Web/Blink Bindings |
| 186 |
| 187 There are a number of differences between the Extensions Bindings System and |
| 188 Blink Bindings. |
| 189 |
| 190 ### Common Implementation to Optimize Binary Size |
| 191 |
| 192 Most Extension APIs are implemented in the browser process after a common flow |
| 193 in the renderer. This allows us to optimize the renderer implementation for |
| 194 space and have the majority of APIs lead to a single entry point, which can |
| 195 match an API against an expected schema. This is contrary to Blink Bindings, |
| 196 which set up a distinct separate entry point for each API, and then individually |
| 197 parses the expected results. |
| 198 |
| 199 The Blink implementation provides greater speed, but comes at a larger generated |
| 200 code cost, since each API has its own generated parsing and handling code. |
| 201 Since most Blink/open web APIs are implemented in the renderer, this cost is not |
| 202 as severe - each API would already require specialized code in the renderer. |
| 203 |
| 204 Extension APIs, on the other hand, are predominantly implemented in the browser; |
| 205 this means we can optimize space by having a single parsing/handling point. |
| 206 This is also beneficial because many extension APIs are exposed on a more |
| 207 limited basis, where only a handful of contexts need access to them, and thus |
| 208 the binary size savings is more valuable, and the speed cost less harmful. |
| 209 |
| 210 ### Signature Matching |
| 211 |
| 212 Signature matching differs significantly between WebIDL and Extension APIs. |
| 213 |
| 214 #### Optional Inner Parameters |
| 215 |
| 216 Unlike OWP APIs, Extension APIs allow for optional inner parameters. For |
| 217 instance, if an API has the signature `(integer, optional string, optional |
| 218 function)`, it may be invoked with `(integer, function)` - which would not be |
| 219 valid in the OWP. This also allows for inner parameters to be optional with |
| 220 subsequent required parameters, such as `(integer, optional string, function)` - |
| 221 again, something which would be disallowed on the OWP. |
| 222 |
| 223 #### Unknown Properties |
| 224 |
| 225 Unknown properties on objects are, by default, unallowed. That is, if a |
| 226 function accepts an object that has properties of `foo` and `bar`, passing |
| 227 `{foo: <foo>, bar: <bar>, baz: <baz>}` is invalid. |
OLD | NEW |