Chromium Code Reviews| Index: ipc/README.md |
| diff --git a/ipc/README.md b/ipc/README.md |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..ba08e0753059bb2194ffccc6ef9349705ca53ef4 |
| --- /dev/null |
| +++ b/ipc/README.md |
| @@ -0,0 +1,664 @@ |
| +# Converting Legacy Chrome IPC To Mojo |
| + |
| +Looking for [Mojo Documentation](/mojo)? |
| + |
| +[TOC] |
| + |
| +## Overview |
| + |
| +The `//ipc` directory contains interfaces and implementation for Chrome's |
| +legacy IPC system, including `IPC::Channel` and various macros for defining |
| +messages and type serialization. For details on using this system please see the |
| +original |
| +[documentation](https://www.chromium.org/developers/design-documents/inter-process-communication). |
| + |
| +Legacy IPC is **deprecated**, and Chrome developers are strongly discouraged |
| +from introducing new messages using this system. [Mojo](/mojo) is the correct |
| +IPC system to use moving forward. This document introduces developers to the |
| +various tools available to help with conversion of legacy IPC messages to Mojo. |
| +It assumes familiarity with [Mojom](/mojo/public/tools/bindings) syntax and |
| +general use of Mojo [C++ bindings](/mojo/public/cpp/bindings). |
| + |
| +In traditional Chrome IPC, we have One Big Pipe (the `IPC::Channel`) between |
| +each connected process. Sending an IPC from one process to another means knowing |
| +how to get a handle to the Channel interface (*e.g.,* |
| +[RenderProcessHost::GetChannel]( |
| +https://cs.chromium.org/chromium/src/content/public/browser/render_process_host.h?rcl=722be98f7e4d7551710fb9cf30674750cdd0d857&l=196) |
| +when sending from the browser to a renderer process), and then having either an |
| +`IPC::MessageFilter` or some other appropriate `IPC::Listener` implementation |
| +installed in the right place on the other side of the channel. |
| + |
| +Because of this arrangement, any message sent on a channel is sent in FIFO order |
| +with respect to all other messages on the channel. While this may be easier to |
| +reason about in general, it carries with it the unfortunate consequence that |
| +many unrelated messages in the system have an implicit, often unintended |
| +ordering dependency. |
| + |
| +It's primarily for this reason that conversion to Mojo IPC can be more |
| +challenging than would otherwise be necessary, and that is why we have a number |
| +of different tools available to facilitate such conversions. |
| + |
| +## Deciding What to Do |
| + |
| +There are few questions you should ask yourself before embarking upon any IPC |
| +message conversion journey. Should this be part of a service? Does message |
| +ordering matter with respect to other parts of the system? What is the meaning |
| +of life? |
| + |
| +### Moving Messages to Services |
| + |
| +We have a small but growing number of services defined in |
| +[`//services`](https://cs.chromium.org/chromium/src/services), each of which has |
| +some set of public interfaces defined in their `public/interfaces` subdirectory. |
| +In the limit we want all IPC interfaces to be defined by some Mojom in these |
| +directories, so this is the preferred destination for any new message |
| +conversions. |
|
jam
2017/04/04 16:05:55
services/ for the foreseeable future is where foun
|
| + |
| +If you need help deciding where a message should live, or if you feel it would |
| +be appropriate to introduce a new service to implement some feature or large set |
| +of messages, please post to |
| +[`services-dev@chromium.org`](https://groups.google.com/a/chromium.org/forum/#!forum/services-dev) |
| +with questions, concerns, and/or a brief proposal or design doc describing |
| +the augmentation of an existing service or introduction of a new service. |
| + |
| +See the [Using Services](#Using-Services) section below for details. |
| + |
| +When converting messages that still require tight coupling to content or Chrome |
| +code or which require unchanged ordering with respect to one or more remaining |
| +legacy IPC messages, it is often not immediately feasible to move a message |
| +definition or handler implementation into a service. |
| + |
| +### Moving Messages to Not-Services |
| + |
| +While this isn't strictly possible because everything is a service now, we model |
| +all existing content processes as service instances and provide helpers to make |
| +interface exposure and consumption between them relatively easy. |
| + |
| +See [Using Content's Connectors](#Using-Content_s-Connectors) for details on |
| +the recommended way to accomplish this. |
| + |
| +See |
| +[Using Content's Interface Registries](#Using-Content_s-Interface-Registries) |
| +for details on the **deprecated** way to accomplish this. |
| + |
| +Note that when converting messages to standalone Mojo interfaces, every |
| +interface connection operates 100% independently of each other. This means that |
| +ordering is only guaranteed over a single interface (ignoring |
| +[associated interfaces](/mojo/public/tools/bindings#Associated-Interfaces).) |
| +Consider this example: |
| + |
| +``` cpp |
| +mojom::FrobinatorPtr frob1; |
| +RenderThread::Get()->GetConnector()->BindInterface( |
| + foo_service::mojom::kServiceName, &frob1); |
| + |
| +mojom::FrobinatorPtr frob2; |
| +RenderThread::Get()->GetConnector()->BindInterface( |
| + foo_service::mojom::kServiceName, &frob2); |
| + |
| +// These are ordered on |frob1|. |
| +frob1->Frobinate(1); |
| +frob1->Frobinate(2); |
| + |
| +// These are ordered on |frob2|. |
| +frob2->Frobinate(1); |
| +frob2->Frobinate(2); |
| + |
| +// It is entirely possible, however, that the renderer receives: |
| +// |
| +// [frob1]Frobinate(1) |
| +// [frob2]Frobinate(1) |
| +// [frob1]Frobinate(2) |
| +// [frob2]Frobinate(2) |
| +// |
| +// Because |frob1| and |frob2| guarantee no mutual ordering. |
| +``` |
| + |
| +Also note that neither interface is ordered with respect to legacy |
| +`IPC::Channel` messages. This can present significant problems when converting a |
| +single message or group of messages which must retain ordering with respect to |
| +others still on the Channel. |
| + |
| +### When Ordering Matters |
| + |
| +If ordering really matters with respect to other legacy messages in the system, |
| +as is often the case for *e.g.* frame and navigation-related messages, you |
| +almost certainly want to take advantage of |
| +[Channel-associated interfaces](#Using-Channel-associated-Interfaces) to |
| +eliminate any risk of introducing subtle behavioral changes. |
| + |
| +Even if ordering only matters among a small set of messages which you intend to |
| +move entirely to Mojom, you may wish to move them one-by-one in separate CLs. |
| +In that case, it may make sense to use a Channel-associated interface during the |
| +transitional period. Once all relevant messages are fully relocated into a |
| +single Mojom interface, it's trivial to lift the interface away from Channel |
| +association and into a proper independent service connection. |
| + |
| +## Using Services |
| + |
| +Suppose you have some IPC messages for safely decoding a PNG image: |
| + |
| +``` cpp |
| +IPC_MESSAGE_CONTROL2(UtilityMsg_DecodePNG, |
| + int32_t request_id, |
| + std::string /* png_data */); |
| +IPC_MESSAGE_CONTROL2(UtilityHostMsg_PNGDecoded, |
| + int32_t request_id, |
| + int32_t width, int32_t height, |
| + std::string /* rgba_data */); |
| +``` |
| + |
| +This seems like a perfect fit for an addition to the sandboxed `data_decoder` |
| +service. Your first order of business is to translate this into a suitable |
| +public interface definition within that service: |
| + |
| +``` cpp |
| +// src/services/data_decoder/public/interfaces/png_decoder.mojom |
| +module data_decoder.mojom; |
| + |
| +interface PngDecoder { |
| + Decode(array<uint8> png_data) |
| + => (int32 width, int32 height, array<uint32> rbga_data); |
| +}; |
| +``` |
| + |
| +and you'll also want to define the implementation within |
| +`//services/data_decoder`, pluging in some appropriate binder so the service |
| +knows how to bind incoming interface requests to your implementation: |
| + |
| +``` cpp |
| +// src/services/data_decoder/png_decoder_impl.h |
| +class PngDecoderImpl : public mojom::PngDecoder { |
| + public: |
| + static void BindRequest(mojom::PngDecoderRequest request) { /* ... */ } |
| + |
| + // mojom::PngDecoder: |
| + void Decode(const std::vector<uint8_t>& png_data, |
| + const DecodeCallback& callback) override { /* ... */ } |
| + // ... |
| +}; |
| + |
| +// src/services/data_decoder/data_decoder_service.cc |
| +// Not quite legitimate pseudocode... |
| +DataDecoderService::DataDecoderService() { |
| + // ... |
| + registry_.AddInterface(base::Bind(&PngDecoderImpl::BindRequest)); |
| +} |
| +``` |
| + |
| +and finally you need to update the usage of the old IPC by probably deleting |
| +lots of ugly code which sets up a `UtilityProcessHostImpl` and replacing it |
| +with something like: |
| + |
| +``` cpp |
| +void OnDecodedPng(const std::vector<uint8_t>& rgba_data) { /* ... */ } |
| + |
| +data_decoder::mojom::PngDecoderPtr png_decoder; |
| +connector->BindInterface(data_decoder::mojom::kServiceName, |
| + mojo::MakeRequest(&png_decoder)); |
| +png_decoder->Decode(untrusted_png_data, base::Bind(&OnDecodedPng)); |
| +``` |
| + |
| +Where to get a [`Connector`](https://cs.chromium.org/chromium/src/services/service_manager/public/cpp/connector.h) |
| +is an interesting question, and the answer ultimately depends on where your code |
| +is written. All service instances get a primordial `Connector` which can be |
| +cloned arbitrarily many times and passed around to different threads. |
| + |
| +If you're writing service code the answer is trivial since each `Service` |
| +instance has direct access to a `Connector`. If you're writing code at or above |
| +the content layer, the answer is slightly more interesting and is explained in |
| +the [Using Content's Connectors](#Using-Content_s-Connectors) section below. |
| + |
| +## Using Content's Connectors |
| + |
| +As explained earlier in this document, all content processes are modeled as |
| +service instances today. This means that all content processes have at least |
| +one [`Connector`](https://cs.chromium.org/chromium/src/services/service_manager/public/cpp/connector.h) |
| +instance which can be used to bind interfaces exposed by other services. |
| + |
| +We define [`content::ServiceManagerConnection`](https://cs.chromium.org/chromium/src/content/public/common/service_manager_connection.h?rcl=dd92156efac57169b45aeb0094111b8d94302b12&l=38) |
| +as a helper which fully encapsulates the service instance state within a given |
| +Content process. The main thread of the browser process can access the global |
| +instance by calling |
| +[`content::ServiceManager::GetForProcess()`](https://cs.chromium.org/chromium/src/content/public/common/service_manager_connection.h?rcl=dd92156efac57169b45aeb0094111b8d94302b12&l=56), |
| +and this object has a `GetConnector()` method which exposes the `Connector` for |
| +that process. |
| + |
| +The main thread of any Content child process can use |
| +`content::ChildThread::GetServiceManagerConnection` or |
| +`content::ChildThread::GetConnector` directly. |
| + |
| +For example, any interfaces registered in |
| +[`RenderProcessHostImpl::RegisterMojoInterfaces()`](https://cs.chromium.org/chromium/src/content/browser/renderer_host/render_process_host_impl.cc?rcl=dd92156efac57169b45aeb0094111b8d94302b12&l=1203) |
| +can be acquired by a renderer as follows: |
| + |
| +``` cpp |
| +mojom::FooPtr foo; |
| +content::RenderThread::Get()->GetConnector()->BindInterface( |
| + content::mojom::kBrowserServiceName, &foo); |
| +foo->DoSomePrettyCoolIPC(); |
| +``` |
| + |
| +### On Other Threads |
| + |
| +`Connector` instances can be created and asynchronously associated with each |
| +other to maximize flexibility in when and how outgoing interface requests are |
| +initiated. |
| + |
| +For example if a background (*e.g.,* worker) thread in a renderer process wants |
| +to make an outgoing service request, it can construct its own `Connector` -- |
| +which may be used immediately and retained on that thread -- and asynchronously |
| +associate it with the main-thread `Connector` like so: |
| + |
| +``` cpp |
| +class Thinger { |
| + public: |
| + explicit Thinger(scoped_refptr<base::TaskRunner> main_thread_task_runner) { |
| + service_manager::mojom::ConnectorRequest request; |
| + |
| + // Of course we could also retain |connector| if we intend to use it again. |
| + auto connector = service_manager::Connector::Create(&request); |
| + connector->BindInterface("best_service_ever", &thinger_); |
| + thinger_->DoTheThing(); |
| + |
| + // Doesn't really matter when this happens, as long as it eventually |
| + // happens. |
| + main_thread_task_runner->PostTask( |
| + FROM_HERE, base::BindOnce(&Thinger::BindConnectorOnMainThread, |
| + std::move(request))); |
| + } |
| + |
| + private: |
| + static void BindConnectorOnMainThread( |
| + service_manager::mojom::ConnectorRequest request) { |
| + DCHECK(RenderThreadImpl::Get()); |
| + RenderThreadImpl::Get()->GetConnector()->BindConnectorRequest( |
| + std::move(request)); |
| + } |
| + |
| + mojom::ThingerPtr thinger_; |
| + |
| + DISALLOW_COPY_AND_ASSIGN(Thinger); |
| +}; |
| +``` |
| + |
| +## Using Content's Interface Registries |
| + |
| +**NOTE:** This section is here mainly for posterity and documentation of |
| +existing usage. Please use `Connector` instead of using an `InterfaceProvider` |
| +directly. |
| + |
| +For convenience the Service Manager's |
| +[client library](https://cs.chromium.org/chromium/src/services/service_manager/public/cpp/) |
| +exposes two useful types: `InterfaceRegistry` and `InterfaceProvider`. These |
| +objects generally exist as an intertwined pair with an `InterfaceRegistry` in |
| +one process and a corresponding `InterfaceProvider` in another process. |
| + |
| +The `InterfaceRegistry` is essentially just a mapping from interface name |
| +to binder function: |
| + |
| +``` cpp |
| +void BindFrobinator(mojom::FrobinatorRequest request) { |
| + mojo::MakeStrongBinding(base::MakeUnique<FrobinatorImpl>, std::move(request)); |
| +} |
| + |
| +// |registry| will hereby handle all incoming requests for "mojom::Frobinator" |
| +// using the above function, which binds the request pipe handle to a new |
| +// instance of |FrobinatorImpl|. |
| +registry->AddInterface(base::Bind(&BindFrobinator)); |
| +``` |
| + |
| +while an `InterfaceProvider` exposes a means of requesting interfaces from a |
| +remote `InterfaceRegistry`: |
| + |
| +``` cpp |
| +mojom::FrobinatorPtr frob; |
| + |
| +// MakeRequest creates a new pipe, and GetInterface sends one end of it to |
| +// the remote InterfaceRegistry along with the "mojom::Frobinator" name. The |
| +// other end of the pipe is bound to |frob| which may immediately begin sending |
| +// messages. |
| +provider->GetInterface(mojo::MakeRequest(&frob)); |
| +frob->DoTheFrobinator(); |
| +``` |
| + |
| +For convenience, we stick an `InterfaceRegistry` and corresponding |
| +`InterfaceProvider` in several places at the Content layer to facilitate |
| +interface connection between browser and renderer processes: |
| + |
| +| `InterfaceRegistry` | `InterfaceProvider` | |
| +|---------------------------------------------|--------------------------------------------| |
| +| `RenderProcessHost::GetInterfaceRegistry()` | `RenderThreadImpl::GetRemoteInterfaces()` | |
| +| `RenderThreadImpl::GetInterfaceRegistry()` | `RenderProcessHost::GetRemoteInterfaces()` | |
| +| `RenderFrameHost::GetInterfaceRegistry()` | `RenderFrame::GetRemoteInterfaces()` | |
| +| `RenderFrame::GetInterfaceRegistry()` | `RenderFrameHost::GetRemoteInterfaces()` | |
| + |
| +As noted above, use of these registries is generally discouraged. |
| + |
| +## Using Channel-associated Interfaces |
| + |
| +**NOTE**: Channel-associated interfaces are an interim solution to make the |
| +transition to Mojo IPC easier in Chrome. You should not design new features |
| +which rely on this system. The ballpark date of deletion for `IPC::Channel` is |
| +projected to be somewhere around mid-2019, and obviously Channel-associated |
| +interfaces can't live beyond that point. |
| + |
| +Mojo has support for the concept of |
| +[associated interfaces](/mojo/public/tools/bindings#Associated-Interfaces). |
| +One interface is "associated" with another when it's a logically separate |
| +interface but it shares an underlying message pipe, causing both interfaces to |
| +maintain mutual FIFO message ordering. For example: |
| + |
| +``` cpp |
| +// db.mojom |
| +module db.mojom; |
| + |
| +interface Table { |
| + void AddRow(string data); |
| +}; |
| + |
| +interface Database { |
| + QuerySize() => (uint64 size); |
| + AddTable(associated Table& table) |
| +}; |
| + |
| +// db_client.cc |
| +db::mojom::DatabasePtr db = /* ... get it from somewhere... */ |
| +db::mojom::TableAssociatedPtr new_table; |
| +db->AddTable(mojo::MakeRequest(&new_table)); |
| +new_table->AddRow("my hovercraft is full of eels"); |
| +db->QuerySize(base::Bind([](uint64_t size) { /* ... */ })); |
| +``` |
| + |
| +In the above code, the `AddTable` message will always arrive before the `AddRow` |
| +message, which itself will always arrive before the `QuerySize` message. If the |
| +`Table` interface were not associated with the `Database` pipe, it would be |
| +possible for the `QuerySize` message to be received before `AddRow`, |
| +potentially leading to unintended behavior. |
| + |
| +The legacy `IPC::Channel` used everywhere today is in fact just another Mojo |
| +interface, and developers have the ability to associate other arbitrary Mojo |
| +interfaces with any given Channel. This means that you can define a set of Mojo |
| +messages to convert old IPC messages, and implement them in a way which |
| +perfectly preserves current message ordering. |
| + |
| +There are many different facilities in place for taking advantage of |
| +Channel-associated interfaces, and the right one for your use case depends on |
| +how the legacy IPC message is used today. The subsections below cover various |
| +interesting scenarios. |
| + |
| +### Basic Usage |
| + |
| +The most primitive way to use Channel-associated interfaces is by working |
| +directly with `IPC::Channel` (IO thread) or more commonly `IPC::ChannelProxy` |
| +(main thread). There are a handful of interesting interface methods here. |
| + |
| +**On the IO thread** (*e.g.,* typically when working with process hosts that |
| +aren't for render processes), the interesting methods are as follows: |
| + |
| +[`IPC::Channel::GetAssociatedInterfaceSupport`](https://cs.chromium.org/chromium/src/ipc/ipc_channel.h?rcl=a896ff44a395a50ab18f5120f20b7eb5a9550247&l=235) |
| +returns an object for working with interfaces associated with the `Channel`. |
| +This is never null. |
| + |
| +[`IPC::Channel::AssociatedInterfaceSupport::AddAssociatedInterface<T>`]( |
| +https://cs.chromium.org/chromium/src/ipc/ipc_channel.h?rcl=a896ff44a395a50ab18f5120f20b7eb5a9550247&l=115) |
| +allows you to add a binding function to handle all incoming requests for a |
| +specific type of associated interface. Callbacks added here are called on the IO |
| +thread any time a corresponding interface request arrives on the `Channel.` If |
| +no callback is registered for an incoming interface request, the request falls |
| +through to the Channel's `Listener` via |
| +[`IPC::Listener::OnAssociatedInterfaceRequest`](https://cs.chromium.org/chromium/src/ipc/ipc_listener.h?rcl=a896ff44a395a50ab18f5120f20b7eb5a9550247&l=40). |
| + |
| +[`IPC::Channel::AssociatedInterfaceSupport::GetRemoteAssociatedInterface<T>`]( |
| +https://cs.chromium.org/chromium/src/ipc/ipc_channel.h?rcl=a896ff44a395a50ab18f5120f20b7eb5a9550247&l=124) |
| +requests a Channel-associated interface from the remote endpoint of the channel. |
| + |
| +**On the main thread**, typically when working with `RenderProcessHost`, basic |
| +usage involves calls to |
| +[`IPC::ChannelProxy::GetRemoteAssociatedInterface<T>`]( |
| +https://cs.chromium.org/chromium/src/ipc/ipc_channel_proxy.h?rcl=a896ff44a395a50ab18f5120f20b7eb5a9550247&l=196) |
| +when making outgoing interface requests, or some implementation of |
| +[`IPC::Listener::OnAssociatedInterfaceRequest`](https://cs.chromium.org/chromium/src/ipc/ipc_listener.h?rcl=a896ff44a395a50ab18f5120f20b7eb5a9550247&l=40) |
| +when handling incoming ones. |
| + |
| +TODO - Add docs for using AssociatedInterfaceRegistry where possible. |
| + |
| +### BrowserMessageFilter |
| + |
| +[BrowserMessageFilter](https://cs.chromium.org/chromium/src/content/public/browser/browser_message_filter.h?rcl=805f2ca5aa0902f56885ea3c8c0a42cb80d84522&l=37) |
| +is a popular helper for listening to incoming legacy IPC messages on the browser |
| +process IO thread and (typically) handling them there. |
| + |
| +A common and totally reasonable tactic for converting a group of messages on an |
| +existing `BrowserMessageFilter` is to define a similiarly named Mojom interface |
| +in an inner `mojom` namespace (*e.g.,* a `content::FooMessageFilter` would have |
| +a corresponding `content::mojom::FooMessageFilter` interface), and have the |
| +`BrowserMessageFilter` implementation also implement |
| +`BrowserAssociatedInterface<T>`. |
| + |
| +Real code is probably the most useful explanation, so here are some example |
| +conversion CLs which demonstrate practical `BrowserAssociatedInterface` usage. |
| + |
| +[FrameHostMsg_SetCookie](https://codereview.chromium.org/2167513003) - This |
| +CL introduces a `content::mojom::RenderFrameMessageFilter` interface |
| +corresponding to the existing `content::RenderFrameMessageFilter` implementation |
| +of `BrowserMessageFilter`. Of particular interest is the fact that it only |
| +converts **one** of the messages on that filter. This is fine because ordering |
| +among the messages -- Mojom or otherwise -- is unchanged. |
| + |
| +[FrameHostMsg_GetCookie](https://codereview.chromium.org/2202723005) - A small |
| +follow-up to the above CL, this converts another message on the same filter. It |
| +is common to convert a large group of messages one-by-one in separate CLs. Also |
| +note that this message, unlike the one above on the same interface, is |
| +synchronous. |
| + |
| +[ViewHostMsg_GenerateRoutingID](https://codereview.chromium.org/2351333002) - |
| +Another small CL to introduce a new `BrowserAssociatedInterface`. |
| + |
| +### Routed Per-Frame Messages To the Browser |
| + |
| +Many legacy IPC messages are "routed" -- they carry a routing ID parameter which |
| +is interpreted by the channel endpoint and used to pass a received message on to |
| +some other more specific handler. |
| + |
| +Messages received by the browser with a frame routing ID for example are routed |
| +to the RenderFrameHost's owning [`WebContents`](https://cs.chromium.org/chromium/src/content/browser/web_contents/web_contents_impl.h?rcl=a12e52d81346dd23d8284763d44c4ee657f11cea&l=447) |
| +with the corresponding `RenderFrameHostImpl` as additional context. |
| + |
| +[This CL](https://codereview.chromium.org/2310583002) introduces usage of |
| +[`WebContentsFrameBindingSet<T>`](https://cs.chromium.org/chromium/src/content/public/browser/web_contents_binding_set.h?rcl=d364139fee76154a1d9fa8875ad0cbb5ccb523c3&l=112), which helps establish |
| +per-frame bindings for Channel-associated interfaces. Some hidden magic is done |
| +to make it so that interface requests from a remote |
| +[`RenderFrame AssociatedInterfaceProvider`](https://cs.chromium.org/chromium/src/content/public/renderer/render_frame.h?rcl=d364139fee76154a1d9fa8875ad0cbb5ccb523c3&l=170) |
| +are routed to the appropriate `WebContentsFrameBindingSet`, typically installed |
| +(as in this CL) by a `WebContentsObserver`. |
| + |
| +When a message is received by an interface implementation using a |
| +`WebContentsFrameBindingSet`, that object's `dispatch_context()` can be used |
| +to retrieve the `RenderFrameHostImpl` targeted by the message. See the above CL |
| +for additional clarity. |
| + |
| +### Other Routed Messages To the Browser |
| + |
| +Other routing IDs are used when targeting either specific `RenderViewHost` or |
| +`RenderWidgetHost` instances. We don't currently have any facilities in place |
| +to assist with these conversions. Because render views are essentially a |
| +deprecated concept, messages targeting "view" routes should not be converted |
| +as-is, but should instead be moved to target either widgets or frames |
| +accordingly. |
| + |
| +Facilities to assist in conversion of widget-routed messages may be added in the |
| +future. Who knows, maybe you'll be the brave developer to add them (and to then |
| +update this documentation, of course!) If you decide this is exactly what you |
| +need but are nervous about the prospect of writing it yourself, please send a |
| +friendly message to [chromium-mojo@chromium.org](https://groups.google.com/a/chromium.org/forum/#!forum/chromium-mojo) |
| +explaining the use case so we can help you get things done. |
| + |
| +### Messages to a Renderer |
| + |
| +[This CL](https://codereview.chromium.org/2381493003) converts `ViewMsg_New` |
| +to a Mojo interface, by virtue of the fact that |
| +`IPC::ChannelProxy::GetRemoteAssociatedInterface` from the browser process |
| +results in an associated interface request arriving at |
| +`ChildThreadImpl::OnAssociatedInterfaceRequest` in the corresponding child |
| +process. |
| + |
| +Similar message conversions are done by [this CL](https://codereview.chromium.org/2400313002). |
| + |
| +Note that we do not currently have any helpers for converting routed messages |
| +from browser to renderer. Please confer with |
| +[chromium-mojo@chromium.org](https://groups.google.com/a/chromium.org/forum/#!forum/chromium-mojo) |
| +if such a use case is blocking your work. |
| + |
| +## Miscellany |
| + |
| +### Using Legacy IPC Traits |
| + |
| +InsSome circumstances there may be a C++ enum, struct, or class that you want |
| +to use in a Mojom via [type mapping](/mojo/public/cpp/bindings#Type-Mapping), |
| +and that type may already have `IPC::ParamTraits` defined (possibly via |
| +`IPC_STRUCT_TRAITS*` macros) for legacy IPC. |
| + |
| +If this is the case and the Mojom which uses the type will definitely only be |
| +called from and implemented in C++ code, *and* you have sufficient reason to |
| +avoid moving or duplicating the type definition in Mojom, you can take advantage |
| +of the existing `ParamTraits`. |
| + |
| +#### The [Native] Attribute |
| +In order to do this you must declare a placeholder type in Mojom somewhere, like |
| +so: |
| + |
| +``` |
| +module foo.mojom; |
| + |
| +[Native] |
| +enum WindowType; |
| + |
| +[Native] |
| +struct MyGiganticStructure; |
| +``` |
| + |
| +The rest of your Mojom will use this typename when referring to the type, but |
| +the wire format used is defined entirely by `IPC::ParamTraits<T>` for whatever |
| +`T` to which you typemap the Mojom type. For example if you typemap |
| +`foo::mojom::MyGiganticStructure` to `foo::MyGiganticStructure`, your typemap |
| +must point to some header which defines |
| +`IPC::ParamTraits<foo::MyGiganticStructure>`. |
| + |
| +Note that if your `ParamTraits` are defined manually (*i.e.* not by invocation |
| +of `IPC_STRUCT_TRAITS*` macros) you must also ensure that they define the new |
| +`GetSize` method: |
| + |
| +``` cpp |
| +static void GetSize(base::PickleSizer* sizer, const param_type& p) { |
| + // ... |
| +} |
| +``` |
| + |
| +`base::PickleSizer` has an interface analogous to `base::Pickle`, except that it |
| +merely accumulates a byte count rather than accumulating serialized data. |
| + |
| +There are several examples of this traits implementation in common IPC traits |
| +defined [here](https://code.google.com/p/chromium/codesearch#chromium/src/ipc/ipc_message_utils.h). |
| + |
| +#### A Practical Example |
| + |
| +Given the [`resource_messages.h`](https://cs.chromium.org/chromium/src/content/common/resource_messages.h?rcl=2e7a430d8d88222c04ab3ffb0a143fa85b3cec5b&l=215) |
| +header with the following definition: |
| + |
| +``` cpp |
| +IPC_STRUCT_TRAITS_BEGIN(content::ResourceRequest) |
| + IPC_STRUCT_TRAITS_MEMBER(method) |
| + IPC_STRUCT_TRAITS_MEMBER(url) |
| + // ... |
| +IPC_STRUCT_TRAITS_END() |
| +``` |
| + |
| +and the [`resource_request.h`](https://cs.chromium.org/chromium/src/content/common/resource_request.h?rcl=dce9e476a525e4ff0304787935dc1a8c38392ac8&l=32) |
| +header with the definition for `content::ResourceRequest`: |
| + |
| +``` cpp |
| +namespace content { |
| + |
| +struct CONTENT_EXPORT ResourceRequest { |
| + // ... |
| +}; |
| + |
| +} // namespace content |
| +``` |
| + |
| +we can declare a corresponding Mojom type: |
| + |
| +``` |
| +module content.mojom; |
| + |
| +[Native] |
| +struct URLRequest; |
| +``` |
| + |
| +and add a typemap like [url_request.typemap](https://cs.chromium.org/chromium/src/content/common/url_request.typemap) |
| +to define the mapping: |
| + |
| +``` |
| +mojom = "//content/common/url_loader.mojom" |
| +public_headers = [ "//content/common/resource_request.h" ] |
| +traits_headers = [ "//content/common/resource_messages.h" ] |
| +... |
| +type_mappings = [ "content.mojom.URLRequest=content::ResourceRequest" ] |
| +``` |
| + |
| +Note specifically that `public_headers` includes the definition of the native |
| +C++ type, and `traits_headers` includes the definition of the legacy IPC traits. |
| + |
| +Finally, note that this same approach can be used to leverage existing |
| +`IPC_ENUM_TRAITS` for `[Native]` Mojom enum aliases. |
| + |
| +### Typemaps With Content and Blink Types |
| + |
| +Using typemapping for messages that go between Blink and content browser code |
| +can sometimes be tricky due to things like dependency cycles or confusion over |
| +the correct place for some definition to live. There are some example |
| +CLs provided here, but feel free to also contact |
| +[chromium-mojo@chromium.org](https://groups.google.com/a/chromium.org/forum/#!forum/chromium-mojo) |
| +with specific details if you encounter trouble. |
| + |
| +[This CL](https://codereview.chromium.org/2363533002) introduces a Mojom |
| +definition and typemap for |
| +`ui::WindowOpenDisposition` as a precursor to the IPC conversion below. |
| + |
| +The [follow-up CL](https://codereview.chromium.org/2363573002) uses that |
| +definition along with several other new typemaps (including native typemaps as |
| +described above in [Using Legacy IPC Traits](#Using-Legacy-IPC-Traits)) to |
| +convert the relatively large `ViewHostMsg_CreateWindow` message to Mojo. |
| + |
| +### Utility Process Messages |
| + |
| +Given that there are no interesting ordering dependencies among disparate IPC |
| +messages to and from utility processes, and because the utility process is |
| +already sort of a mixed bag of unrelated IPCs, the correct way to convert |
| +utility process IPCs to Mojo is to move them into services. |
| + |
| +We already have support for running services out-of-process (with or without a |
| +sandbox), and many utility process operations already have a suitable service |
| +home they could be moved to. For example, the `data_decoder` service in |
| +[`//services/data_decoder`](https://cs.chromium.org/chromium/src/services/data_decoder/) |
| +is a good place to stick utility process IPCs that do decoding of relatively |
| +complex and untrusted data, of which (at the time of this writing) there are |
| +quite a few. |
| + |
| +When in doubt, contact |
| +[`services-dev@chromium.org`](https://groups.google.com/a/chromium.org/forum/#!forum/services-dev) |
| +with ideas, questions, suggestions, etc. |
| + |
| +### Additional Documentation |
| + |
| +[Chrome IPC to Mojo IPC Cheat Sheet](https://www.chromium.org/developers/design-documents/mojo/chrome-ipc-to-mojo-ipc-cheat-sheet) |
| +: A slightly dated but still valuable document covering some details |
| + regarding the conceptual mapping between legacy IPC and Mojo. |
| + |
| +[Mojo Migration Guide](https://www.chromium.org/developers/design-documents/mojo/mojo-migration-guide) |
| +: Another slightly (more) data document covering the basics of IPC conversion |
| + to Mojo. |
| + |
| + TODO: The migration guide above should probably be deleted and the good |
| + parts merged into this document. |