Chromium Code Reviews| 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 |