Ken Rockot | ab03512 | 2019-02-06 00:35:24 | [diff] [blame] | 1 | # Converting Legacy IPC to Mojo |
| 2 | |
| 3 | [TOC] |
| 4 | |
| 5 | ## Overview |
| 6 | |
| 7 | A number of IPC messages sent (primarily between the browser and renderer |
| 8 | processes) are still defined using Chrome's old IPC system in `//ipc`. This |
| 9 | system uses |
| 10 | [`base::Pickle`](https://cs.chromium.org/chromium/src/base/pickle.h?rcl=8b7842262ee1239b1f3ae20b9c851748ef0b9a8b&l=128) |
| 11 | as the basis for message serialization and is supported by a number if `IPC_*` |
| 12 | preprocessor macros defined in `//ipc` and used around the source tree. |
| 13 | |
| 14 | There is an ongoing, distributed effort to get these messages converted to Mojo |
| 15 | interface messages. Messages that still need to be converted are tracked in two |
| 16 | spreadsheets: |
| 17 | |
| 18 | - [Chrome IPC to Mojo migration](https://docs.google.com/spreadsheets/d/1pGWX_wxGdjAVtQOmlDDfhuIc3Pbwg9FtvFXAXYu7b7c/edit#gid=0) for non-web platform messages |
| 19 | - [Mojoifying Platform Features](https://docs.google.com/spreadsheets/d/1VIINt17Dg2cJjPpoJ_HY3HI0uLpidql-1u8pBJtpbGk/edit#gid=1603373208) for web platform messages |
| 20 | |
| 21 | This document is concerned primarily with rote conversion of legacy IPC messages |
| 22 | to Mojo interface messages. If you are considering more holistic refactoring and |
| 23 | better isolation of an entire subsystem of the browser, you may consider |
| 24 | [servicifying](servicification.md) the feature instead of merely converting its |
| 25 | IPCs. |
| 26 | |
| 27 | See other [Mojo & Services](/docs/README.md#Mojo-Services) documentation |
| 28 | for introductory guides, API references, and more. |
| 29 | |
| 30 | ## Legacy IPC Concepts |
| 31 | |
| 32 | Each Content child process has a single **`IPC::Channel`** implementation going |
| 33 | between it and the browser process, and this is used as the sole two-way FIFO |
| 34 | to send legacy IPC messages between the processes. |
| 35 | |
| 36 | There are two fundamental types of legacy IPC messages: **control** messages, |
| 37 | defined via `IPC_MESSAGE_CONTROLn` macros (where `n` is some small integer) and |
| 38 | **routed** messages defined via `IPC_MESSAGE_ROUTEDn` macros. |
| 39 | |
| 40 | Control messages generally go between a browser-side process host (*e.g.*, |
| 41 | `RenderProcessHost` or `GpuProcessHost`) and the child-side `ChildThreadImpl` |
| 42 | subclass. All of these classes implement `IPC::Sender` and thus have a `Send` |
| 43 | method for sending a control message to their remote counterpart, and they |
| 44 | implement `IPC::Listener` to receive incoming control messages via |
| 45 | `OnMessageReceived`. |
| 46 | |
| 47 | Routed messages are relegated to **routes** which have arbitrary meaning |
| 48 | determined by their use within a given process. For example, renderers use |
| 49 | routes to isolate messages scoped to individual render frames, and so such |
| 50 | routed messages will travel between a `RenderFrameHostImpl` and its |
| 51 | corresponding `RenderFrameImpl`, both of which also implement `IPC::Sender` and |
| 52 | `IPC::Listener`. |
| 53 | |
| 54 | ## Mojo Interfaces as Routes |
| 55 | |
| 56 | Routed messages in the old IPC system always carry a **routing ID** to identify |
| 57 | to the receiving endpoint which routed object (*e.g.* which `RenderFrameImpl` |
| 58 | or `RenderViewImpl` or whatever) the message is targeting. Each endpoint is thus |
| 59 | required to do some additional book-keeping to track what each routing ID means. |
| 60 | |
| 61 | Mojo interfaces obviate the need for routing IDs, as new "routes" can be |
| 62 | established by simply creating a new interface pipe and passing one endpoint to |
| 63 | something which knows how to bind it. |
| 64 | |
| 65 | When thinking about an IPC message conversion to Mojo, it's important to |
| 66 | consider whether the message is a control message or a routed message, as this |
| 67 | determines where you might find an existing Mojo interface to carry your |
| 68 | message, or where you will want to add a new end-to-end Mojo interface for that |
| 69 | purpose. This can mean the difference between a single per-process interface |
| 70 | going between each `RenderProcessHostImpl` and its corresponding |
| 71 | `RenderThreadImpl`, vs a per-frame interface going between each |
| 72 | `RenderFrameHostImpl` and its corresponding `RenderFrameImpl`. |
| 73 | |
| 74 | ## Ordering Considerations |
| 75 | |
| 76 | One **very important** consideration when doing IPC conversions is the relative |
| 77 | ordering of IPC-driven operations. With the old IPC system, because every |
| 78 | message between two processes is globally ordered, it is quite easy for parts |
| 79 | of the system to (intentionally or often unintentionally) rely on strict |
| 80 | ordering guarantees. |
| 81 | |
| 82 | For example, imagine a `WebContentsObserver` in the browser processes observes |
| 83 | a frame navigation and immediately sends an IPC message to the frame to |
| 84 | configure some new behavior. The implementation may be inadvertently relying on |
| 85 | this message arriving *before* some other tangentially related message sent to |
| 86 | the same frame shortly after the same navigation event. |
| 87 | |
| 88 | Mojo does not (and in fact cannot) make any strict ordering guarantees between |
| 89 | separate message pipes, as message pipes may be freely moved across process |
| 90 | boundaries and thus cannot necessarily share a common FIFO at all times. |
| 91 | |
| 92 | If the two messages described above were moved to separate Mojo interfaces on |
| 93 | separate message pipes, renderer behavior could break as the first message may |
| 94 | arrive after the second message. |
| 95 | |
| 96 | The best solution to this problem is to rethink the IPC surface and/or |
| 97 | implementation on either side to eliminate ordering dependencies between two |
| 98 | interfaces that otherwise seem to be logically distinct. Failing that, Mojo's |
| 99 | solution to this problem is to support |
| 100 | [**associated interfaces**](/mojo/public/tools/bindings/README.md#Associated-Interfaces). |
| 101 | In a nutshell, these allow multiple distinct interfaces to be multiplexed over |
| 102 | a shared message pipe. |
| 103 | |
| 104 | ## Channel-Associated Interfaces |
| 105 | |
| 106 | The previous section mentions **associated interfaces** as a general-purpose |
| 107 | solution for establishing a mutual FIFO between multiple logical Mojo interfaces |
| 108 | by having them share a single message pipe. |
| 109 | |
| 110 | In Chrome, the `IPC::Channel` which carries all legacy IPC messages between |
| 111 | two processes is itself a Mojo message pipe. We provide a mechanism for |
| 112 | associating arbitrary Mojo interfaces with this pipe, which means messages can |
| 113 | be converted to Mojo while preserving strict FIFO with respect to other legacy |
| 114 | IPC messages. Such interfaces are designated in Chrome parlance as |
| 115 | **Channel-associated interfaces**. |
| 116 | |
| 117 | *** aside |
| 118 | **NOTE:** Channel-associated interface acquisition is not constrained by the |
| 119 | Service Manager in any way, so security reviewers need to be careful to inspect |
| 120 | new additions and uses of such interfaces. |
| 121 | *** |
| 122 | |
| 123 | Usage of Channel-associated interfaces should be rare but is considered a |
| 124 | reasonable intermediate solution for incremental IPC conversions where it would |
| 125 | be too risky or noisy to convert a large IPC surface all at once, but it would |
| 126 | also be impossible to split the IPC surface between legacy IPC and a dedicated |
| 127 | Mojo interface pipe without introducing timing bugs. |
| 128 | |
| 129 | At this point in Chrome's development, practical usage of Channel-associated |
| 130 | interfaces is restricted to the `IPC::Channel` between the browser process and |
| 131 | a renderer process, as this is the most complex IPC surface with the most |
| 132 | implicit ordering dependencies. A few simple APIs exist to support this. |
| 133 | |
| 134 | `RenderProcessHostImpl` owns an `IPC::Channel` to its corresponding |
| 135 | `RenderThreadImpl` in the render process. This object has a |
| 136 | `GetRemoteAssociatedInterfaces` method which can be used to pass arbitrary |
| 137 | associated interface requests: |
| 138 | |
| 139 | ``` cpp |
Oksana Zhuravlova | 9f3b8ef | 2019-08-26 20:27:40 | [diff] [blame] | 140 | mojo::PendingAssociatedRemote<magic::mojom::GoatTeleporter> teleporter; |
| 141 | channel_->GetRemoteAssociatedInterfaces()->GetInterface(teleporter.BindNewEndpointAndPassReceiver()); |
Ken Rockot | ab03512 | 2019-02-06 00:35:24 | [diff] [blame] | 142 | |
| 143 | // These messages are all guaranteed to arrive in the same order they were sent. |
| 144 | channel_->Send(new FooMsg_SomeLegacyIPC); |
| 145 | teleporter->TeleportAllGoats(); |
| 146 | channel_->Send(new FooMsg_AnotherLegacyIPC); |
| 147 | ``` |
| 148 | |
| 149 | Likewise, `ChildThreadImpl` has an `IPC::Channel` that can be used in the same |
| 150 | way to send such messages back to the browser. |
| 151 | |
| 152 | To receive and bind incoming Channel-associated interface requests, the above |
| 153 | objects also implement `IPC::Listener::OnAssociatedInterfaceRequest`. |
| 154 | |
| 155 | For supplementation of routed messages, both `RenderFrameHostImpl` and |
| 156 | `RenderFrameImpl` define a `GetRemoteAssociatedInterfaces` method which works |
| 157 | like the one on `IPC::Channel`, and both objects also implement |
| 158 | `IPC::Listener::OnAssociatedInterfaceRequest` for processing incoming associated |
| 159 | interface requests specific to their own frame. |
| 160 | |
| 161 | There are some example conversion CLs which use Channel-associated interfaces |
| 162 | [here](https://codereview.chromium.org/2381493003) and |
| 163 | [here](https://codereview.chromium.org/2400313002). |
| 164 | |
| 165 | ## Deciding How to Approach a Conversion |
| 166 | |
| 167 | There are a few questions you should ask before embarking upon any IPC message |
| 168 | conversion journey, and there are many potential approaches to consider. The |
| 169 | right one depends on context. |
| 170 | |
| 171 | Note that this section assumes the message is traveling between the browser |
| 172 | process and a renderer process. Other cases are rare and developers may wish to |
| 173 | consult |
| 174 | [[email protected]](https://groups.google.com/a/chromium.org/forum/#!forum/chromium-mojo) |
| 175 | before proceeding with them. Otherwise, apply the following basic algorithm to |
| 176 | decide how to proceed: |
| 177 | |
| 178 | - General note: If the message is a reply to some other message (typically these |
| 179 | take a "request ID" argument), see the note about message replies at the |
| 180 | bottom of this section. |
| 181 | - Consider whether or not the message makes sense as part of the IPC surface of |
| 182 | a new or existing service somewhere in `//services` or `//chrome/services`, |
| 183 | *etc.* This is less and less likely to be the case as time goes on, as many |
| 184 | remaining IPC conversions are quite narrowly dealing with specific |
| 185 | browser/renderer details rather than the browser's supporting subsystems. If |
| 186 | defining a new service, you may wish to consult some of the other |
| 187 | [Mojo & Services documentation](/docs/README.md#Mojo-Services) first. |
| 188 | - If the message is an `IPC_MESSAGE_CONTROL` message: |
| 189 | - If there are likely to be strict ordering requirements between this |
| 190 | message and other legacy IPC or Channel-associated interface messages, |
| 191 | consider using a new or existing |
| 192 | [Channel-associated interface](#Channel-Associated-Interfaces) between |
| 193 | `RenderProcessHostImpl` and `RenderThreadImpl`. |
| 194 | - If the message is sent from a renderer to the browser: |
| 195 | - If an existing interface is bound by `RenderProcessHostImpl` and |
| 196 | requested through `RenderThread`'s Connector and seems to be a good |
| 197 | fit for the message, add the equivalent Mojo message to that |
| 198 | interface. |
| 199 | - If no such interface exists, consider adding one for this message and |
| 200 | any related messages. |
| 201 | - If the message is sent from the browser to a renderer: |
| 202 | - If an existing interface is bound by `RenderThreadImpl` and requested |
| 203 | through a `BrowserContext` Connector referencing a specific |
| 204 | `RenderProcessHost` [identity](https://cs.chromium.org/chromium/src/content/public/browser/render_process_host.h?rcl=1497b88b7d6400a2a5cced258df03d53800d7848&l=327), |
| 205 | and the interface seems to be a good fit for the message, add the |
| 206 | equivalent Mojo message to that interface. |
| 207 | - If no such interface exists, consider adding one for this message and |
| 208 | any related messages. |
| 209 | - If the message is an `IPC_MESSAGE_ROUTED` message: |
| 210 | - Determine what the routing endpoints are. If they are |
| 211 | `RenderFrameHostImpl` and `RenderFrameImpl`: |
| 212 | - If there are likely to be strict ordering requirements between this |
| 213 | message and other legacy IPC or Channel-associated interface messages, |
| 214 | consider using a new or existing |
| 215 | [Channel-associated interface](#Channel-Associated-Interfaces) between |
| 216 | `RenderFrameHostImpl` and `RenderFrameImpl`. |
| 217 | - If the message is sent from a renderer to the browser: |
| 218 | - If an existing interface is bound by `RenderFrameHostImpl` and |
Oksana Zhuravlova | b685db6 | 2020-02-21 20:14:01 | [diff] [blame] | 219 | acquired via `RenderFrame::GetBrowserInterfaceBroker` and the interface seems |
Ken Rockot | ab03512 | 2019-02-06 00:35:24 | [diff] [blame] | 220 | to be a good fit for this message, add the equivalent Mojo message |
| 221 | to that interface. |
Oksana Zhuravlova | cf17005 | 2019-09-23 19:56:27 | [diff] [blame] | 222 | - If no such interface exists, consider adding one and registering it |
| 223 | with `RenderFrameHostImpl`'s `BrowserInterfaceBroker`. See the |
Ken Rockot | ab03512 | 2019-02-06 00:35:24 | [diff] [blame] | 224 | [simple example](/docs/mojo_and_services.md#Example_Defining-a-New-Frame-Interface) |
Oksana Zhuravlova | cf17005 | 2019-09-23 19:56:27 | [diff] [blame] | 225 | in the "Intro to Mojo & Services" document. |
Ken Rockot | ab03512 | 2019-02-06 00:35:24 | [diff] [blame] | 226 | - If the message is sent from the browser to a renderer, consider |
| 227 | adding a Mojo equivalent to the `content.mojom.Frame` interface |
| 228 | defined |
| 229 | [here](https://cs.chromium.org/chromium/src/content/common/frame.mojom?rcl=138b66744ee9ee853cbb0ae8437b71eaa1fafaa9&l=42). |
| 230 | - If the routing endpoints are **not** frame objects (for example, they may |
| 231 | be `RenderView`/`RenderViewHost` objects), this is a special case which |
| 232 | does not yet have an easy conversion approach readily available. Contact |
| 233 | [[email protected]](https://groups.google.com/a/chromium.org/forum#!forum/chromium-mojo) |
| 234 | to propose or discuss options. |
| 235 | |
Oksana Zhuravlova | 355fa64 | 2019-02-15 22:21:04 | [diff] [blame] | 236 | *** aside |
| 237 | **NOTE**: If you are converting a sync IPC, see the section on |
| 238 | [Synchronous Calls](/mojo/public/cpp/bindings/README.md#Synchronous-Calls) |
| 239 | in the Mojo documentation. |
| 240 | *** |
| 241 | |
Ken Rockot | ab03512 | 2019-02-06 00:35:24 | [diff] [blame] | 242 | ### Dealing With Replies |
| 243 | |
| 244 | If the message is a **reply**, meaning it has a "request ID" which correlates it |
| 245 | to a prior message in the opposite direction, consider converting the |
| 246 | **request** message following the algorithm above. Unlike with legacy IPC, Mojo |
| 247 | messages support replies as a first-class concept. So for example if you have: |
| 248 | |
| 249 | ``` cpp |
| 250 | IPC_CONTROL_MESSAGE2(FooHostMsg_DoTheThing, |
| 251 | int /* request_id */, |
| 252 | std::string /* name */); |
| 253 | IPC_CONTROL_MESSAGE2(FooMsg_DidTheThing, |
| 254 | int /* request_id */, |
| 255 | bool /* success */); |
| 256 | ``` |
| 257 | |
| 258 | You should consider defining an interface `Foo` which is bound in |
| 259 | `RenderProcessHostImpl` and acquired from `RenderThreadImpl`, with the following |
| 260 | mojom definition: |
| 261 | |
| 262 | ``` cpp |
| 263 | interface Foo { |
| 264 | DoTheThing(string name) => (bool success); |
| 265 | }; |
| 266 | ``` |
Oksana Zhuravlova | 87b225a | 2019-03-07 01:08:03 | [diff] [blame] | 267 | See [Receiving responses](/mojo/public/cpp/bindings/README.md#receiving-responses) |
| 268 | for more information. |
Ken Rockot | ab03512 | 2019-02-06 00:35:24 | [diff] [blame] | 269 | |
| 270 | ## Repurposing `IPC::ParamTraits` and `IPC_STRUCT*` Invocations |
| 271 | |
| 272 | Occasionally it is useful to do partial IPC conversions, where you want to |
| 273 | convert a message to a Mojo interface method but you don't want to necessarily |
| 274 | convert every structure passed by the message. In this case, you can leverage |
| 275 | Mojo's |
Oksana Zhuravlova | a77a9a1 | 2021-05-07 18:02:10 | [diff] [blame] | 276 | [type-mapping](https://chromium.googlesource.com/chromium/src/+/main/mojo/public/cpp/bindings/README.md#Type-Mapping) |
Ken Rockot | ab03512 | 2019-02-06 00:35:24 | [diff] [blame] | 277 | system to repurpose existing `IPC::ParamTraits`. |
| 278 | |
| 279 | *** aside |
| 280 | **NOTE**: Although in some cases `IPC::ParamTraits<T>` specializations are |
| 281 | defined manually in library code, the `IPC_STRUCT*` macro helpers also define |
| 282 | `IPC::ParamTraits<T>` specializations under the hood. All advice in this section |
| 283 | pertains to both kinds of definitions. |
| 284 | *** |
| 285 | |
| 286 | If a mojom struct is declared without a struct body and is tagged with |
| 287 | `[Native]`, and a corresponding typemap is provided for the struct, the emitted |
| 288 | C++ bindings will -- as if by magic -- replace the mojom type with the |
| 289 | typemapped C++ type and will internally use the existing `IPC::ParamTraits<T>` |
| 290 | specialization for that type in order to serialize and deserialize the struct. |
| 291 | |
| 292 | For example, given the |
| 293 | [`resource_messages.h`](https://cs.chromium.org/chromium/src/content/common/resource_messages.h?rcl=2e7a430d8d88222c04ab3ffb0a143fa85b3cec5b&l=215) header |
| 294 | which defines an IPC mapping for `content::ResourceRequest`: |
| 295 | |
| 296 | ``` cpp |
| 297 | IPC_STRUCT_TRAITS_BEGIN(content::ResourceRequest) |
| 298 | IPC_STRUCT_TRAITS_MEMBER(method) |
| 299 | IPC_STRUCT_TRAITS_MEMBER(url) |
| 300 | // ... |
| 301 | IPC_STRUCT_TRAITS_END() |
| 302 | ``` |
| 303 | |
| 304 | and the |
| 305 | [`resource_request.h`](https://cs.chromium.org/chromium/src/content/common/resource_request.h?rcl=dce9e476a525e4ff0304787935dc1a8c38392ac8&l=32) header |
| 306 | which actually defines the `content::ResourceRequest` type: |
| 307 | |
| 308 | ``` cpp |
| 309 | namespace content { |
| 310 | |
| 311 | struct CONTENT_EXPORT ResourceRequest { |
| 312 | // ... |
| 313 | }; |
| 314 | |
| 315 | } // namespace content |
| 316 | ``` |
| 317 | |
| 318 | we can declare a corresponding "native" mojom struct: |
| 319 | |
| 320 | ``` cpp |
| 321 | module content.mojom; |
| 322 | |
| 323 | [Native] |
| 324 | struct URLRequest; |
| 325 | ``` |
| 326 | |
| 327 | and add a typemap like |
| 328 | [`url_request.typemap`](https://cs.chromium.org/chromium/src/content/common/url_request.typemap?rcl=4b5963fa744a706398f8f06a4cbbf70d7fa3213d) |
| 329 | to define how to map between them: |
| 330 | |
| 331 | ``` python |
| 332 | mojom = "//content/public/common/url_loader.mojom" |
| 333 | public_headers = [ "//content/common/resource_request.h" ] |
| 334 | traits_headers = [ "//content/common/resource_messages.h" ] |
| 335 | ... |
| 336 | type_mappings = [ "content.mojom.URLRequest=content::ResourceRequest" ] |
| 337 | ``` |
| 338 | |
| 339 | Note specifically that public_headers includes the definition of the native C++ |
| 340 | type, and traits_headers includes the definition of the legacy IPC traits. |
| 341 | |
| 342 | As a result of all this, other mojom files can now reference |
| 343 | `content.mojom.URLRequest` as a type for method parameters and other struct |
| 344 | fields, and the generated C++ bindings will represent those values exclusively |
| 345 | as `content::ResourceRequest` objects. |
| 346 | |
| 347 | This same basic approach can be used to leverage existing `IPC_ENUM_TRAITS` for |
| 348 | invocations for `[Native]` mojom enum aliases. |
| 349 | |
| 350 | *** aside |
| 351 | **NOTE:** Use of `[Native]` mojom definitions is strictly limited to C++ |
| 352 | bindings. If a mojom message depends on such definitions, it cannot be sent or |
| 353 | received by other language bindings. This feature also depends on continued |
| 354 | support for legacy IPC serialization and all uses of it should therefore be |
| 355 | treated as technical debt. |
| 356 | *** |
| 357 | |
Oksana Zhuravlova | 4f3692b | 2019-02-08 21:00:58 | [diff] [blame] | 358 | ## Blink-Specific Advice |
| 359 | |
| 360 | ### Variants |
| 361 | Let's assume we have a mojom file such as this: |
| 362 | |
| 363 | ``` cpp |
| 364 | module example.mojom; |
| 365 | |
| 366 | interface Foo { |
| 367 | SendData(string param1, array<int32> param2); |
| 368 | }; |
| 369 | ``` |
| 370 | |
| 371 | The following GN snippet will generate two concrete targets: `example` and |
| 372 | `example_blink`: |
| 373 | |
| 374 | ``` |
| 375 | mojom("example") { |
| 376 | sources = [ "example.mojom" ] |
| 377 | } |
| 378 | ``` |
| 379 | |
| 380 | The target `example` will generate Chromium-style C++ bindings using STL types: |
| 381 | |
| 382 | ``` cpp |
| 383 | // example.mojom.h |
| 384 | namespace example { |
| 385 | namespace mojom { |
| 386 | |
| 387 | class Example { |
| 388 | virtual void SendArray(const std::string& param1, const std::vector<int32_t>& param2) = 0; |
| 389 | } |
| 390 | |
| 391 | } // namespace mojom |
| 392 | } // namespace example |
| 393 | ``` |
| 394 | |
| 395 | The target `example_blink` will generate Blink-style C++ bindings using WTF types: |
| 396 | |
| 397 | ``` cpp |
| 398 | // example.mojom-blink.h |
| 399 | namespace example { |
| 400 | namespace mojom { |
| 401 | namespace blink { |
| 402 | |
| 403 | class Example { |
| 404 | virtual void SendArray(const WTF::String& param1, const WTF::Vector<int32_t>& param2) = 0; |
| 405 | } |
| 406 | |
| 407 | } // namespace blink |
| 408 | } // namespace mojom |
| 409 | } // namespace example |
| 410 | ``` |
| 411 | |
| 412 | Thanks to these separate sets of bindings no work is necessary to convert types |
| 413 | between Blink-style code and Chromium-style code. It is handled automatically |
| 414 | during message serialization and deserialization. |
| 415 | |
| 416 | For more information about variants, see |
| 417 | [this section](/mojo/public/cpp/bindings/README.md#Variants) of the C++ bindings |
| 418 | documentation. |
| 419 | |
| 420 | ### Binding callbacks |
| 421 | |
| 422 | Mojo methods that return a value take an instance of `base::OnceCallback`. |
| 423 | Use `WTF::Bind()` and an appropriate wrapper function depending on the type of |
| 424 | object and the callback. |
| 425 | |
Oksana Zhuravlova | 9f3b8ef | 2019-08-26 20:27:40 | [diff] [blame] | 426 | For garbage-collected (Oilpan) classes owning the `mojo::Remote`, it is recommended |
Oksana Zhuravlova | 6fac3d13 | 2019-02-19 23:58:33 | [diff] [blame] | 427 | to use `WrapWeakPersistent(this)` for connection error handlers since they |
| 428 | are not guaranteed to get called in a finite time period (wrapping the object |
| 429 | with `WrapPersistent` in this case would cause memory leaks). |
| 430 | |
| 431 | If the response can be discarded in case the object is not alive by the time |
| 432 | the response is received, use `WrapWeakPersistent(this)` for binding the response callback: |
Oksana Zhuravlova | 4f3692b | 2019-02-08 21:00:58 | [diff] [blame] | 433 | |
| 434 | ``` cpp |
Oksana Zhuravlova | 6fac3d13 | 2019-02-19 23:58:33 | [diff] [blame] | 435 | // src/third_party/blink/renderer/modules/device_orientation/device_sensor_entry.cc |
| 436 | sensor_.set_connection_error_handler(WTF::Bind( |
| 437 | &DeviceSensorEntry::HandleSensorError, WrapWeakPersistent(this))); |
| 438 | sensor_->ConfigureReadingChangeNotifications(/*enabled=*/false); |
| 439 | sensor_->AddConfiguration( |
| 440 | std::move(config), WTF::Bind(&DeviceSensorEntry::OnSensorAddConfiguration, |
| 441 | WrapWeakPersistent(this))); |
| 442 | ``` |
| 443 | |
| 444 | Otherwise (for example, if the response callback is used to resolve a Promise), |
| 445 | use `WrapPersistent(this)` to keep the object alive: |
| 446 | |
| 447 | ``` cpp |
| 448 | // src/third_party/blink/renderer/modules/nfc/nfc.cc |
| 449 | ScriptPromiseResolver* resolver = ScriptPromiseResolver::Create(script_state); |
| 450 | ... |
| 451 | nfc_->CancelAllWatches(WTF::Bind(&NFC::OnRequestCompleted, |
| 452 | WrapPersistent(this), |
| 453 | WrapPersistent(resolver))); |
Oksana Zhuravlova | 4f3692b | 2019-02-08 21:00:58 | [diff] [blame] | 454 | ``` |
| 455 | |
| 456 | Non-garbage-collected objects can use `WTF::Unretained(this)` for both response |
Oksana Zhuravlova | 9f3b8ef | 2019-08-26 20:27:40 | [diff] [blame] | 457 | and error handler callbacks when the `mojo::Remote` is owned by the object bound |
Oksana Zhuravlova | 4f3692b | 2019-02-08 21:00:58 | [diff] [blame] | 458 | to the callback or the object is guaranteed to outlive the Mojo connection for |
| 459 | another reason. Otherwise a weak pointer should be used. However, it is not a |
| 460 | common pattern since using Oilpan is recommended for all Blink code. |
| 461 | |
| 462 | ### Implementing Mojo interfaces in Blink |
| 463 | |
Oksana Zhuravlova | 9f3b8ef | 2019-08-26 20:27:40 | [diff] [blame] | 464 | Only a `mojo::Receiver` or `mojo::ReceiverSet` should be used when implementing a |
Oksana Zhuravlova | 4f3692b | 2019-02-08 21:00:58 | [diff] [blame] | 465 | Mojo interface in an Oilpan-managed object. The object must then have a pre-finalizer |
| 466 | to close any open pipes when the object is about to be swept as lazy sweeping |
| 467 | means that it may be invalid long before the destructor is called. This requires |
| 468 | setup in both the object header and implementation. |
| 469 | |
| 470 | ``` cpp |
| 471 | // MyObject.h |
| 472 | class MyObject : public GarbageCollected, |
| 473 | public example::mojom::blink::Example { |
| 474 | USING_PRE_FINALIZER(MyObject, Dispose); |
| 475 | |
| 476 | public: |
| 477 | MyObject(); |
| 478 | void Dispose(); |
| 479 | |
| 480 | // Implementation of example::mojom::blink::Example. |
| 481 | |
| 482 | private: |
Oksana Zhuravlova | 9f3b8ef | 2019-08-26 20:27:40 | [diff] [blame] | 483 | mojo::Receiver<example::mojom::blink::Example> m_receiver{this}; |
Oksana Zhuravlova | 4f3692b | 2019-02-08 21:00:58 | [diff] [blame] | 484 | }; |
| 485 | |
| 486 | // MyObject.cpp |
| 487 | void MyObject::Dispose() { |
Oksana Zhuravlova | 9f3b8ef | 2019-08-26 20:27:40 | [diff] [blame] | 488 | m_receiver.Close(); |
Oksana Zhuravlova | 4f3692b | 2019-02-08 21:00:58 | [diff] [blame] | 489 | } |
| 490 | ``` |
| 491 | |
| 492 | For more information about Blink's Garbage Collector, see |
| 493 | [Blink GC API Reference](/third_party/blink/renderer/platform/heap/BlinkGCAPIReference.md). |
| 494 | |
| 495 | ### Typemaps For Content and Blink Types |
Ken Rockot | ab03512 | 2019-02-06 00:35:24 | [diff] [blame] | 496 | |
| 497 | Using typemapping for messages that go between Blink and content browser code |
| 498 | can sometimes be tricky due to things like dependency cycles or confusion over |
| 499 | the correct place for some definition |
| 500 | to live. There are some example CLs provided here, but feel free to also contact |
| 501 | [[email protected]](https://groups.google.com/a/chromium.org/forum/#!forum/chromium-mojo) |
| 502 | with specific details if you encounter trouble. |
| 503 | |
| 504 | [This CL](https://codereview.chromium.org/2363533002) introduces a Mojom |
| 505 | definition and typemap for `ui::WindowOpenDisposition` as a precursor to the |
| 506 | IPC conversion below. |
| 507 | |
| 508 | The [follow-up CL](https://codereview.chromium.org/2363573002) uses that |
| 509 | definition along with several other new typemaps (including native typemaps as |
| 510 | described above) to convert the relatively large `ViewHostMsg_CreateWindow` |
| 511 | message to Mojo. |
| 512 | |
| 513 | ## Additional Support |
| 514 | |
| 515 | If this document was not helpful in some way, please post a message to your |
| 516 | friendly |
| 517 | [[email protected]](https://groups.google.com/a/chromium.org/forum/#!forum/chromium-mojo) |
| 518 | mailing list. |