OLD | NEW |
---|---|
(Empty) | |
1 # Converting Legacy Chrome IPC To Mojo | |
2 | |
3 Looking for [Mojo Documentation](/mojo)? | |
4 | |
5 [TOC] | |
6 | |
7 ## Overview | |
8 | |
9 The `//ipc` directory contains interfaces and implementation for Chrome's | |
10 legacy IPC system, including `IPC::Channel` and various macros for defining | |
11 messages and type serialization. For details on using this system please see the | |
12 original | |
13 [documentation](https://www.chromium.org/developers/design-documents/inter-proce ss-communication). | |
14 | |
15 Legacy IPC is **deprecated**, and Chrome developers are strongly discouraged | |
16 from introducing new messages using this system. [Mojo](/mojo) is the correct | |
17 IPC system to use moving forward. This document introduces developers to the | |
18 various tools available to help with conversion of legacy IPC messages to Mojo. | |
19 It assumes familiarity with [Mojom](/mojo/public/tools/bindings) syntax and | |
20 general use of Mojo [C++ bindings](/mojo/public/cpp/bindings). | |
21 | |
22 In traditional Chrome IPC, we have One Big Pipe (the `IPC::Channel`) between | |
23 each connected process. Sending an IPC from one process to another means knowing | |
24 how to get a handle to the Channel interface (*e.g.,* | |
25 [RenderProcessHost::GetChannel]( | |
26 https://cs.chromium.org/chromium/src/content/public/browser/render_process_host. h?rcl=722be98f7e4d7551710fb9cf30674750cdd0d857&l=196) | |
27 when sending from the browser to a renderer process), and then having either an | |
28 `IPC::MessageFilter` or some other appropriate `IPC::Listener` implementation | |
29 installed in the right place on the other side of the channel. | |
30 | |
31 Because of this arrangement, any message sent on a channel is sent in FIFO order | |
32 with respect to all other messages on the channel. While this may be easier to | |
33 reason about in general, it carries with it the unfortunate consequence that | |
34 many unrelated messages in the system have an implicit, often unintended | |
35 ordering dependency. | |
36 | |
37 It's primarily for this reason that conversion to Mojo IPC can be more | |
38 challenging than would otherwise be necessary, and that is why we have a number | |
39 of different tools available to facilitate such conversions. | |
40 | |
41 ## Deciding What to Do | |
42 | |
43 There are few questions you should ask yourself before embarking upon any IPC | |
44 message conversion journey. Should this be part of a service? Does message | |
45 ordering matter with respect to other parts of the system? What is the meaning | |
46 of life? | |
47 | |
48 ### Moving Messages to Services | |
49 | |
50 We have a small but growing number of services defined in | |
51 [`//services`](https://cs.chromium.org/chromium/src/services), each of which has | |
52 some set of public interfaces defined in their `public/interfaces` subdirectory. | |
53 In the limit we want all IPC interfaces to be defined by some Mojom in these | |
54 directories, so this is the preferred destination for any new message | |
55 conversions. | |
jam
2017/04/04 16:05:55
services/ for the foreseeable future is where foun
| |
56 | |
57 If you need help deciding where a message should live, or if you feel it would | |
58 be appropriate to introduce a new service to implement some feature or large set | |
59 of messages, please post to | |
60 [`services-dev@chromium.org`](https://groups.google.com/a/chromium.org/forum/#!f orum/services-dev) | |
61 with questions, concerns, and/or a brief proposal or design doc describing | |
62 the augmentation of an existing service or introduction of a new service. | |
63 | |
64 See the [Using Services](#Using-Services) section below for details. | |
65 | |
66 When converting messages that still require tight coupling to content or Chrome | |
67 code or which require unchanged ordering with respect to one or more remaining | |
68 legacy IPC messages, it is often not immediately feasible to move a message | |
69 definition or handler implementation into a service. | |
70 | |
71 ### Moving Messages to Not-Services | |
72 | |
73 While this isn't strictly possible because everything is a service now, we model | |
74 all existing content processes as service instances and provide helpers to make | |
75 interface exposure and consumption between them relatively easy. | |
76 | |
77 See [Using Content's Connectors](#Using-Content_s-Connectors) for details on | |
78 the recommended way to accomplish this. | |
79 | |
80 See | |
81 [Using Content's Interface Registries](#Using-Content_s-Interface-Registries) | |
82 for details on the **deprecated** way to accomplish this. | |
83 | |
84 Note that when converting messages to standalone Mojo interfaces, every | |
85 interface connection operates 100% independently of each other. This means that | |
86 ordering is only guaranteed over a single interface (ignoring | |
87 [associated interfaces](/mojo/public/tools/bindings#Associated-Interfaces).) | |
88 Consider this example: | |
89 | |
90 ``` cpp | |
91 mojom::FrobinatorPtr frob1; | |
92 RenderThread::Get()->GetConnector()->BindInterface( | |
93 foo_service::mojom::kServiceName, &frob1); | |
94 | |
95 mojom::FrobinatorPtr frob2; | |
96 RenderThread::Get()->GetConnector()->BindInterface( | |
97 foo_service::mojom::kServiceName, &frob2); | |
98 | |
99 // These are ordered on |frob1|. | |
100 frob1->Frobinate(1); | |
101 frob1->Frobinate(2); | |
102 | |
103 // These are ordered on |frob2|. | |
104 frob2->Frobinate(1); | |
105 frob2->Frobinate(2); | |
106 | |
107 // It is entirely possible, however, that the renderer receives: | |
108 // | |
109 // [frob1]Frobinate(1) | |
110 // [frob2]Frobinate(1) | |
111 // [frob1]Frobinate(2) | |
112 // [frob2]Frobinate(2) | |
113 // | |
114 // Because |frob1| and |frob2| guarantee no mutual ordering. | |
115 ``` | |
116 | |
117 Also note that neither interface is ordered with respect to legacy | |
118 `IPC::Channel` messages. This can present significant problems when converting a | |
119 single message or group of messages which must retain ordering with respect to | |
120 others still on the Channel. | |
121 | |
122 ### When Ordering Matters | |
123 | |
124 If ordering really matters with respect to other legacy messages in the system, | |
125 as is often the case for *e.g.* frame and navigation-related messages, you | |
126 almost certainly want to take advantage of | |
127 [Channel-associated interfaces](#Using-Channel-associated-Interfaces) to | |
128 eliminate any risk of introducing subtle behavioral changes. | |
129 | |
130 Even if ordering only matters among a small set of messages which you intend to | |
131 move entirely to Mojom, you may wish to move them one-by-one in separate CLs. | |
132 In that case, it may make sense to use a Channel-associated interface during the | |
133 transitional period. Once all relevant messages are fully relocated into a | |
134 single Mojom interface, it's trivial to lift the interface away from Channel | |
135 association and into a proper independent service connection. | |
136 | |
137 ## Using Services | |
138 | |
139 Suppose you have some IPC messages for safely decoding a PNG image: | |
140 | |
141 ``` cpp | |
142 IPC_MESSAGE_CONTROL2(UtilityMsg_DecodePNG, | |
143 int32_t request_id, | |
144 std::string /* png_data */); | |
145 IPC_MESSAGE_CONTROL2(UtilityHostMsg_PNGDecoded, | |
146 int32_t request_id, | |
147 int32_t width, int32_t height, | |
148 std::string /* rgba_data */); | |
149 ``` | |
150 | |
151 This seems like a perfect fit for an addition to the sandboxed `data_decoder` | |
152 service. Your first order of business is to translate this into a suitable | |
153 public interface definition within that service: | |
154 | |
155 ``` cpp | |
156 // src/services/data_decoder/public/interfaces/png_decoder.mojom | |
157 module data_decoder.mojom; | |
158 | |
159 interface PngDecoder { | |
160 Decode(array<uint8> png_data) | |
161 => (int32 width, int32 height, array<uint32> rbga_data); | |
162 }; | |
163 ``` | |
164 | |
165 and you'll also want to define the implementation within | |
166 `//services/data_decoder`, pluging in some appropriate binder so the service | |
167 knows how to bind incoming interface requests to your implementation: | |
168 | |
169 ``` cpp | |
170 // src/services/data_decoder/png_decoder_impl.h | |
171 class PngDecoderImpl : public mojom::PngDecoder { | |
172 public: | |
173 static void BindRequest(mojom::PngDecoderRequest request) { /* ... */ } | |
174 | |
175 // mojom::PngDecoder: | |
176 void Decode(const std::vector<uint8_t>& png_data, | |
177 const DecodeCallback& callback) override { /* ... */ } | |
178 // ... | |
179 }; | |
180 | |
181 // src/services/data_decoder/data_decoder_service.cc | |
182 // Not quite legitimate pseudocode... | |
183 DataDecoderService::DataDecoderService() { | |
184 // ... | |
185 registry_.AddInterface(base::Bind(&PngDecoderImpl::BindRequest)); | |
186 } | |
187 ``` | |
188 | |
189 and finally you need to update the usage of the old IPC by probably deleting | |
190 lots of ugly code which sets up a `UtilityProcessHostImpl` and replacing it | |
191 with something like: | |
192 | |
193 ``` cpp | |
194 void OnDecodedPng(const std::vector<uint8_t>& rgba_data) { /* ... */ } | |
195 | |
196 data_decoder::mojom::PngDecoderPtr png_decoder; | |
197 connector->BindInterface(data_decoder::mojom::kServiceName, | |
198 mojo::MakeRequest(&png_decoder)); | |
199 png_decoder->Decode(untrusted_png_data, base::Bind(&OnDecodedPng)); | |
200 ``` | |
201 | |
202 Where to get a [`Connector`](https://cs.chromium.org/chromium/src/services/servi ce_manager/public/cpp/connector.h) | |
203 is an interesting question, and the answer ultimately depends on where your code | |
204 is written. All service instances get a primordial `Connector` which can be | |
205 cloned arbitrarily many times and passed around to different threads. | |
206 | |
207 If you're writing service code the answer is trivial since each `Service` | |
208 instance has direct access to a `Connector`. If you're writing code at or above | |
209 the content layer, the answer is slightly more interesting and is explained in | |
210 the [Using Content's Connectors](#Using-Content_s-Connectors) section below. | |
211 | |
212 ## Using Content's Connectors | |
213 | |
214 As explained earlier in this document, all content processes are modeled as | |
215 service instances today. This means that all content processes have at least | |
216 one [`Connector`](https://cs.chromium.org/chromium/src/services/service_manager/ public/cpp/connector.h) | |
217 instance which can be used to bind interfaces exposed by other services. | |
218 | |
219 We define [`content::ServiceManagerConnection`](https://cs.chromium.org/chromium /src/content/public/common/service_manager_connection.h?rcl=dd92156efac57169b45a eb0094111b8d94302b12&l=38) | |
220 as a helper which fully encapsulates the service instance state within a given | |
221 Content process. The main thread of the browser process can access the global | |
222 instance by calling | |
223 [`content::ServiceManager::GetForProcess()`](https://cs.chromium.org/chromium/sr c/content/public/common/service_manager_connection.h?rcl=dd92156efac57169b45aeb0 094111b8d94302b12&l=56), | |
224 and this object has a `GetConnector()` method which exposes the `Connector` for | |
225 that process. | |
226 | |
227 The main thread of any Content child process can use | |
228 `content::ChildThread::GetServiceManagerConnection` or | |
229 `content::ChildThread::GetConnector` directly. | |
230 | |
231 For example, any interfaces registered in | |
232 [`RenderProcessHostImpl::RegisterMojoInterfaces()`](https://cs.chromium.org/chro mium/src/content/browser/renderer_host/render_process_host_impl.cc?rcl=dd92156ef ac57169b45aeb0094111b8d94302b12&l=1203) | |
233 can be acquired by a renderer as follows: | |
234 | |
235 ``` cpp | |
236 mojom::FooPtr foo; | |
237 content::RenderThread::Get()->GetConnector()->BindInterface( | |
238 content::mojom::kBrowserServiceName, &foo); | |
239 foo->DoSomePrettyCoolIPC(); | |
240 ``` | |
241 | |
242 ### On Other Threads | |
243 | |
244 `Connector` instances can be created and asynchronously associated with each | |
245 other to maximize flexibility in when and how outgoing interface requests are | |
246 initiated. | |
247 | |
248 For example if a background (*e.g.,* worker) thread in a renderer process wants | |
249 to make an outgoing service request, it can construct its own `Connector` -- | |
250 which may be used immediately and retained on that thread -- and asynchronously | |
251 associate it with the main-thread `Connector` like so: | |
252 | |
253 ``` cpp | |
254 class Thinger { | |
255 public: | |
256 explicit Thinger(scoped_refptr<base::TaskRunner> main_thread_task_runner) { | |
257 service_manager::mojom::ConnectorRequest request; | |
258 | |
259 // Of course we could also retain |connector| if we intend to use it again. | |
260 auto connector = service_manager::Connector::Create(&request); | |
261 connector->BindInterface("best_service_ever", &thinger_); | |
262 thinger_->DoTheThing(); | |
263 | |
264 // Doesn't really matter when this happens, as long as it eventually | |
265 // happens. | |
266 main_thread_task_runner->PostTask( | |
267 FROM_HERE, base::BindOnce(&Thinger::BindConnectorOnMainThread, | |
268 std::move(request))); | |
269 } | |
270 | |
271 private: | |
272 static void BindConnectorOnMainThread( | |
273 service_manager::mojom::ConnectorRequest request) { | |
274 DCHECK(RenderThreadImpl::Get()); | |
275 RenderThreadImpl::Get()->GetConnector()->BindConnectorRequest( | |
276 std::move(request)); | |
277 } | |
278 | |
279 mojom::ThingerPtr thinger_; | |
280 | |
281 DISALLOW_COPY_AND_ASSIGN(Thinger); | |
282 }; | |
283 ``` | |
284 | |
285 ## Using Content's Interface Registries | |
286 | |
287 **NOTE:** This section is here mainly for posterity and documentation of | |
288 existing usage. Please use `Connector` instead of using an `InterfaceProvider` | |
289 directly. | |
290 | |
291 For convenience the Service Manager's | |
292 [client library](https://cs.chromium.org/chromium/src/services/service_manager/p ublic/cpp/) | |
293 exposes two useful types: `InterfaceRegistry` and `InterfaceProvider`. These | |
294 objects generally exist as an intertwined pair with an `InterfaceRegistry` in | |
295 one process and a corresponding `InterfaceProvider` in another process. | |
296 | |
297 The `InterfaceRegistry` is essentially just a mapping from interface name | |
298 to binder function: | |
299 | |
300 ``` cpp | |
301 void BindFrobinator(mojom::FrobinatorRequest request) { | |
302 mojo::MakeStrongBinding(base::MakeUnique<FrobinatorImpl>, std::move(request)); | |
303 } | |
304 | |
305 // |registry| will hereby handle all incoming requests for "mojom::Frobinator" | |
306 // using the above function, which binds the request pipe handle to a new | |
307 // instance of |FrobinatorImpl|. | |
308 registry->AddInterface(base::Bind(&BindFrobinator)); | |
309 ``` | |
310 | |
311 while an `InterfaceProvider` exposes a means of requesting interfaces from a | |
312 remote `InterfaceRegistry`: | |
313 | |
314 ``` cpp | |
315 mojom::FrobinatorPtr frob; | |
316 | |
317 // MakeRequest creates a new pipe, and GetInterface sends one end of it to | |
318 // the remote InterfaceRegistry along with the "mojom::Frobinator" name. The | |
319 // other end of the pipe is bound to |frob| which may immediately begin sending | |
320 // messages. | |
321 provider->GetInterface(mojo::MakeRequest(&frob)); | |
322 frob->DoTheFrobinator(); | |
323 ``` | |
324 | |
325 For convenience, we stick an `InterfaceRegistry` and corresponding | |
326 `InterfaceProvider` in several places at the Content layer to facilitate | |
327 interface connection between browser and renderer processes: | |
328 | |
329 | `InterfaceRegistry` | `InterfaceProvider` | | |
330 |---------------------------------------------|--------------------------------- -----------| | |
331 | `RenderProcessHost::GetInterfaceRegistry()` | `RenderThreadImpl::GetRemoteInte rfaces()` | | |
332 | `RenderThreadImpl::GetInterfaceRegistry()` | `RenderProcessHost::GetRemoteInt erfaces()` | | |
333 | `RenderFrameHost::GetInterfaceRegistry()` | `RenderFrame::GetRemoteInterface s()` | | |
334 | `RenderFrame::GetInterfaceRegistry()` | `RenderFrameHost::GetRemoteInter faces()` | | |
335 | |
336 As noted above, use of these registries is generally discouraged. | |
337 | |
338 ## Using Channel-associated Interfaces | |
339 | |
340 **NOTE**: Channel-associated interfaces are an interim solution to make the | |
341 transition to Mojo IPC easier in Chrome. You should not design new features | |
342 which rely on this system. The ballpark date of deletion for `IPC::Channel` is | |
343 projected to be somewhere around mid-2019, and obviously Channel-associated | |
344 interfaces can't live beyond that point. | |
345 | |
346 Mojo has support for the concept of | |
347 [associated interfaces](/mojo/public/tools/bindings#Associated-Interfaces). | |
348 One interface is "associated" with another when it's a logically separate | |
349 interface but it shares an underlying message pipe, causing both interfaces to | |
350 maintain mutual FIFO message ordering. For example: | |
351 | |
352 ``` cpp | |
353 // db.mojom | |
354 module db.mojom; | |
355 | |
356 interface Table { | |
357 void AddRow(string data); | |
358 }; | |
359 | |
360 interface Database { | |
361 QuerySize() => (uint64 size); | |
362 AddTable(associated Table& table) | |
363 }; | |
364 | |
365 // db_client.cc | |
366 db::mojom::DatabasePtr db = /* ... get it from somewhere... */ | |
367 db::mojom::TableAssociatedPtr new_table; | |
368 db->AddTable(mojo::MakeRequest(&new_table)); | |
369 new_table->AddRow("my hovercraft is full of eels"); | |
370 db->QuerySize(base::Bind([](uint64_t size) { /* ... */ })); | |
371 ``` | |
372 | |
373 In the above code, the `AddTable` message will always arrive before the `AddRow` | |
374 message, which itself will always arrive before the `QuerySize` message. If the | |
375 `Table` interface were not associated with the `Database` pipe, it would be | |
376 possible for the `QuerySize` message to be received before `AddRow`, | |
377 potentially leading to unintended behavior. | |
378 | |
379 The legacy `IPC::Channel` used everywhere today is in fact just another Mojo | |
380 interface, and developers have the ability to associate other arbitrary Mojo | |
381 interfaces with any given Channel. This means that you can define a set of Mojo | |
382 messages to convert old IPC messages, and implement them in a way which | |
383 perfectly preserves current message ordering. | |
384 | |
385 There are many different facilities in place for taking advantage of | |
386 Channel-associated interfaces, and the right one for your use case depends on | |
387 how the legacy IPC message is used today. The subsections below cover various | |
388 interesting scenarios. | |
389 | |
390 ### Basic Usage | |
391 | |
392 The most primitive way to use Channel-associated interfaces is by working | |
393 directly with `IPC::Channel` (IO thread) or more commonly `IPC::ChannelProxy` | |
394 (main thread). There are a handful of interesting interface methods here. | |
395 | |
396 **On the IO thread** (*e.g.,* typically when working with process hosts that | |
397 aren't for render processes), the interesting methods are as follows: | |
398 | |
399 [`IPC::Channel::GetAssociatedInterfaceSupport`](https://cs.chromium.org/chromium /src/ipc/ipc_channel.h?rcl=a896ff44a395a50ab18f5120f20b7eb5a9550247&l=235) | |
400 returns an object for working with interfaces associated with the `Channel`. | |
401 This is never null. | |
402 | |
403 [`IPC::Channel::AssociatedInterfaceSupport::AddAssociatedInterface<T>`]( | |
404 https://cs.chromium.org/chromium/src/ipc/ipc_channel.h?rcl=a896ff44a395a50ab18f5 120f20b7eb5a9550247&l=115) | |
405 allows you to add a binding function to handle all incoming requests for a | |
406 specific type of associated interface. Callbacks added here are called on the IO | |
407 thread any time a corresponding interface request arrives on the `Channel.` If | |
408 no callback is registered for an incoming interface request, the request falls | |
409 through to the Channel's `Listener` via | |
410 [`IPC::Listener::OnAssociatedInterfaceRequest`](https://cs.chromium.org/chromium /src/ipc/ipc_listener.h?rcl=a896ff44a395a50ab18f5120f20b7eb5a9550247&l=40). | |
411 | |
412 [`IPC::Channel::AssociatedInterfaceSupport::GetRemoteAssociatedInterface<T>`]( | |
413 https://cs.chromium.org/chromium/src/ipc/ipc_channel.h?rcl=a896ff44a395a50ab18f5 120f20b7eb5a9550247&l=124) | |
414 requests a Channel-associated interface from the remote endpoint of the channel. | |
415 | |
416 **On the main thread**, typically when working with `RenderProcessHost`, basic | |
417 usage involves calls to | |
418 [`IPC::ChannelProxy::GetRemoteAssociatedInterface<T>`]( | |
419 https://cs.chromium.org/chromium/src/ipc/ipc_channel_proxy.h?rcl=a896ff44a395a50 ab18f5120f20b7eb5a9550247&l=196) | |
420 when making outgoing interface requests, or some implementation of | |
421 [`IPC::Listener::OnAssociatedInterfaceRequest`](https://cs.chromium.org/chromium /src/ipc/ipc_listener.h?rcl=a896ff44a395a50ab18f5120f20b7eb5a9550247&l=40) | |
422 when handling incoming ones. | |
423 | |
424 TODO - Add docs for using AssociatedInterfaceRegistry where possible. | |
425 | |
426 ### BrowserMessageFilter | |
427 | |
428 [BrowserMessageFilter](https://cs.chromium.org/chromium/src/content/public/brows er/browser_message_filter.h?rcl=805f2ca5aa0902f56885ea3c8c0a42cb80d84522&l=37) | |
429 is a popular helper for listening to incoming legacy IPC messages on the browser | |
430 process IO thread and (typically) handling them there. | |
431 | |
432 A common and totally reasonable tactic for converting a group of messages on an | |
433 existing `BrowserMessageFilter` is to define a similiarly named Mojom interface | |
434 in an inner `mojom` namespace (*e.g.,* a `content::FooMessageFilter` would have | |
435 a corresponding `content::mojom::FooMessageFilter` interface), and have the | |
436 `BrowserMessageFilter` implementation also implement | |
437 `BrowserAssociatedInterface<T>`. | |
438 | |
439 Real code is probably the most useful explanation, so here are some example | |
440 conversion CLs which demonstrate practical `BrowserAssociatedInterface` usage. | |
441 | |
442 [FrameHostMsg_SetCookie](https://codereview.chromium.org/2167513003) - This | |
443 CL introduces a `content::mojom::RenderFrameMessageFilter` interface | |
444 corresponding to the existing `content::RenderFrameMessageFilter` implementation | |
445 of `BrowserMessageFilter`. Of particular interest is the fact that it only | |
446 converts **one** of the messages on that filter. This is fine because ordering | |
447 among the messages -- Mojom or otherwise -- is unchanged. | |
448 | |
449 [FrameHostMsg_GetCookie](https://codereview.chromium.org/2202723005) - A small | |
450 follow-up to the above CL, this converts another message on the same filter. It | |
451 is common to convert a large group of messages one-by-one in separate CLs. Also | |
452 note that this message, unlike the one above on the same interface, is | |
453 synchronous. | |
454 | |
455 [ViewHostMsg_GenerateRoutingID](https://codereview.chromium.org/2351333002) - | |
456 Another small CL to introduce a new `BrowserAssociatedInterface`. | |
457 | |
458 ### Routed Per-Frame Messages To the Browser | |
459 | |
460 Many legacy IPC messages are "routed" -- they carry a routing ID parameter which | |
461 is interpreted by the channel endpoint and used to pass a received message on to | |
462 some other more specific handler. | |
463 | |
464 Messages received by the browser with a frame routing ID for example are routed | |
465 to the RenderFrameHost's owning [`WebContents`](https://cs.chromium.org/chromium /src/content/browser/web_contents/web_contents_impl.h?rcl=a12e52d81346dd23d82847 63d44c4ee657f11cea&l=447) | |
466 with the corresponding `RenderFrameHostImpl` as additional context. | |
467 | |
468 [This CL](https://codereview.chromium.org/2310583002) introduces usage of | |
469 [`WebContentsFrameBindingSet<T>`](https://cs.chromium.org/chromium/src/content/p ublic/browser/web_contents_binding_set.h?rcl=d364139fee76154a1d9fa8875ad0cbb5ccb 523c3&l=112), which helps establish | |
470 per-frame bindings for Channel-associated interfaces. Some hidden magic is done | |
471 to make it so that interface requests from a remote | |
472 [`RenderFrame AssociatedInterfaceProvider`](https://cs.chromium.org/chromium/src /content/public/renderer/render_frame.h?rcl=d364139fee76154a1d9fa8875ad0cbb5ccb5 23c3&l=170) | |
473 are routed to the appropriate `WebContentsFrameBindingSet`, typically installed | |
474 (as in this CL) by a `WebContentsObserver`. | |
475 | |
476 When a message is received by an interface implementation using a | |
477 `WebContentsFrameBindingSet`, that object's `dispatch_context()` can be used | |
478 to retrieve the `RenderFrameHostImpl` targeted by the message. See the above CL | |
479 for additional clarity. | |
480 | |
481 ### Other Routed Messages To the Browser | |
482 | |
483 Other routing IDs are used when targeting either specific `RenderViewHost` or | |
484 `RenderWidgetHost` instances. We don't currently have any facilities in place | |
485 to assist with these conversions. Because render views are essentially a | |
486 deprecated concept, messages targeting "view" routes should not be converted | |
487 as-is, but should instead be moved to target either widgets or frames | |
488 accordingly. | |
489 | |
490 Facilities to assist in conversion of widget-routed messages may be added in the | |
491 future. Who knows, maybe you'll be the brave developer to add them (and to then | |
492 update this documentation, of course!) If you decide this is exactly what you | |
493 need but are nervous about the prospect of writing it yourself, please send a | |
494 friendly message to [chromium-mojo@chromium.org](https://groups.google.com/a/chr omium.org/forum/#!forum/chromium-mojo) | |
495 explaining the use case so we can help you get things done. | |
496 | |
497 ### Messages to a Renderer | |
498 | |
499 [This CL](https://codereview.chromium.org/2381493003) converts `ViewMsg_New` | |
500 to a Mojo interface, by virtue of the fact that | |
501 `IPC::ChannelProxy::GetRemoteAssociatedInterface` from the browser process | |
502 results in an associated interface request arriving at | |
503 `ChildThreadImpl::OnAssociatedInterfaceRequest` in the corresponding child | |
504 process. | |
505 | |
506 Similar message conversions are done by [this CL](https://codereview.chromium.or g/2400313002). | |
507 | |
508 Note that we do not currently have any helpers for converting routed messages | |
509 from browser to renderer. Please confer with | |
510 [chromium-mojo@chromium.org](https://groups.google.com/a/chromium.org/forum/#!fo rum/chromium-mojo) | |
511 if such a use case is blocking your work. | |
512 | |
513 ## Miscellany | |
514 | |
515 ### Using Legacy IPC Traits | |
516 | |
517 InsSome circumstances there may be a C++ enum, struct, or class that you want | |
518 to use in a Mojom via [type mapping](/mojo/public/cpp/bindings#Type-Mapping), | |
519 and that type may already have `IPC::ParamTraits` defined (possibly via | |
520 `IPC_STRUCT_TRAITS*` macros) for legacy IPC. | |
521 | |
522 If this is the case and the Mojom which uses the type will definitely only be | |
523 called from and implemented in C++ code, *and* you have sufficient reason to | |
524 avoid moving or duplicating the type definition in Mojom, you can take advantage | |
525 of the existing `ParamTraits`. | |
526 | |
527 #### The [Native] Attribute | |
528 In order to do this you must declare a placeholder type in Mojom somewhere, like | |
529 so: | |
530 | |
531 ``` | |
532 module foo.mojom; | |
533 | |
534 [Native] | |
535 enum WindowType; | |
536 | |
537 [Native] | |
538 struct MyGiganticStructure; | |
539 ``` | |
540 | |
541 The rest of your Mojom will use this typename when referring to the type, but | |
542 the wire format used is defined entirely by `IPC::ParamTraits<T>` for whatever | |
543 `T` to which you typemap the Mojom type. For example if you typemap | |
544 `foo::mojom::MyGiganticStructure` to `foo::MyGiganticStructure`, your typemap | |
545 must point to some header which defines | |
546 `IPC::ParamTraits<foo::MyGiganticStructure>`. | |
547 | |
548 Note that if your `ParamTraits` are defined manually (*i.e.* not by invocation | |
549 of `IPC_STRUCT_TRAITS*` macros) you must also ensure that they define the new | |
550 `GetSize` method: | |
551 | |
552 ``` cpp | |
553 static void GetSize(base::PickleSizer* sizer, const param_type& p) { | |
554 // ... | |
555 } | |
556 ``` | |
557 | |
558 `base::PickleSizer` has an interface analogous to `base::Pickle`, except that it | |
559 merely accumulates a byte count rather than accumulating serialized data. | |
560 | |
561 There are several examples of this traits implementation in common IPC traits | |
562 defined [here](https://code.google.com/p/chromium/codesearch#chromium/src/ipc/ip c_message_utils.h). | |
563 | |
564 #### A Practical Example | |
565 | |
566 Given the [`resource_messages.h`](https://cs.chromium.org/chromium/src/content/c ommon/resource_messages.h?rcl=2e7a430d8d88222c04ab3ffb0a143fa85b3cec5b&l=215) | |
567 header with the following definition: | |
568 | |
569 ``` cpp | |
570 IPC_STRUCT_TRAITS_BEGIN(content::ResourceRequest) | |
571 IPC_STRUCT_TRAITS_MEMBER(method) | |
572 IPC_STRUCT_TRAITS_MEMBER(url) | |
573 // ... | |
574 IPC_STRUCT_TRAITS_END() | |
575 ``` | |
576 | |
577 and the [`resource_request.h`](https://cs.chromium.org/chromium/src/content/comm on/resource_request.h?rcl=dce9e476a525e4ff0304787935dc1a8c38392ac8&l=32) | |
578 header with the definition for `content::ResourceRequest`: | |
579 | |
580 ``` cpp | |
581 namespace content { | |
582 | |
583 struct CONTENT_EXPORT ResourceRequest { | |
584 // ... | |
585 }; | |
586 | |
587 } // namespace content | |
588 ``` | |
589 | |
590 we can declare a corresponding Mojom type: | |
591 | |
592 ``` | |
593 module content.mojom; | |
594 | |
595 [Native] | |
596 struct URLRequest; | |
597 ``` | |
598 | |
599 and add a typemap like [url_request.typemap](https://cs.chromium.org/chromium/sr c/content/common/url_request.typemap) | |
600 to define the mapping: | |
601 | |
602 ``` | |
603 mojom = "//content/common/url_loader.mojom" | |
604 public_headers = [ "//content/common/resource_request.h" ] | |
605 traits_headers = [ "//content/common/resource_messages.h" ] | |
606 ... | |
607 type_mappings = [ "content.mojom.URLRequest=content::ResourceRequest" ] | |
608 ``` | |
609 | |
610 Note specifically that `public_headers` includes the definition of the native | |
611 C++ type, and `traits_headers` includes the definition of the legacy IPC traits. | |
612 | |
613 Finally, note that this same approach can be used to leverage existing | |
614 `IPC_ENUM_TRAITS` for `[Native]` Mojom enum aliases. | |
615 | |
616 ### Typemaps With Content and Blink Types | |
617 | |
618 Using typemapping for messages that go between Blink and content browser code | |
619 can sometimes be tricky due to things like dependency cycles or confusion over | |
620 the correct place for some definition to live. There are some example | |
621 CLs provided here, but feel free to also contact | |
622 [chromium-mojo@chromium.org](https://groups.google.com/a/chromium.org/forum/#!fo rum/chromium-mojo) | |
623 with specific details if you encounter trouble. | |
624 | |
625 [This CL](https://codereview.chromium.org/2363533002) introduces a Mojom | |
626 definition and typemap for | |
627 `ui::WindowOpenDisposition` as a precursor to the IPC conversion below. | |
628 | |
629 The [follow-up CL](https://codereview.chromium.org/2363573002) uses that | |
630 definition along with several other new typemaps (including native typemaps as | |
631 described above in [Using Legacy IPC Traits](#Using-Legacy-IPC-Traits)) to | |
632 convert the relatively large `ViewHostMsg_CreateWindow` message to Mojo. | |
633 | |
634 ### Utility Process Messages | |
635 | |
636 Given that there are no interesting ordering dependencies among disparate IPC | |
637 messages to and from utility processes, and because the utility process is | |
638 already sort of a mixed bag of unrelated IPCs, the correct way to convert | |
639 utility process IPCs to Mojo is to move them into services. | |
640 | |
641 We already have support for running services out-of-process (with or without a | |
642 sandbox), and many utility process operations already have a suitable service | |
643 home they could be moved to. For example, the `data_decoder` service in | |
644 [`//services/data_decoder`](https://cs.chromium.org/chromium/src/services/data_d ecoder/) | |
645 is a good place to stick utility process IPCs that do decoding of relatively | |
646 complex and untrusted data, of which (at the time of this writing) there are | |
647 quite a few. | |
648 | |
649 When in doubt, contact | |
650 [`services-dev@chromium.org`](https://groups.google.com/a/chromium.org/forum/#!f orum/services-dev) | |
651 with ideas, questions, suggestions, etc. | |
652 | |
653 ### Additional Documentation | |
654 | |
655 [Chrome IPC to Mojo IPC Cheat Sheet](https://www.chromium.org/developers/design- documents/mojo/chrome-ipc-to-mojo-ipc-cheat-sheet) | |
656 : A slightly dated but still valuable document covering some details | |
657 regarding the conceptual mapping between legacy IPC and Mojo. | |
658 | |
659 [Mojo Migration Guide](https://www.chromium.org/developers/design-documents/mojo /mojo-migration-guide) | |
660 : Another slightly (more) data document covering the basics of IPC conversion | |
661 to Mojo. | |
662 | |
663 TODO: The migration guide above should probably be deleted and the good | |
664 parts merged into this document. | |
OLD | NEW |