blob: c5ec846ce5ab2f80016da05d4d8d70eca0ec47c8 [file] [log] [blame] [view]
Erik Chen3fdc02bc2018-06-28 03:13:481# Mojo For Chromium Developers
2
3## Overview
4
5This document contains the minimum amount of information needed for a developer
6to start using Mojo in Chromium. For more detailed documentation on the C++
7bindings, see [this link](/mojo/public/cpp/bindings/README.md).
8
9## Terminology
10
11A **message pipe** is a pair of **endpoints**. Each endpoint has a queue of
12incoming messages, and writing a message to one endpoint effectively enqueues
13that message on the other endpoint. Message pipes are thus bidirectional.
14
15A **mojom** file describes **interfaces** which describe strongly typed message
16structures, similar to proto files.
17
Tom McKee1a5032f2018-08-02 17:14:5518Given a **mojom interface** and a **message pipe**, the two **endpoints**
Erik Chen3fdc02bc2018-06-28 03:13:4819can be given the labels **InterfacePtr** and **Binding**. This now describes a
20strongly typed **message pipe** which transports messages described by the
21**mojom interface**. The **InterfacePtr** is the **endpoint** which "sends"
22messages, and the **Binding** "receives" messages. Note that the **message
23pipe** itself is still bidirectional, and it's possible for a message to have a
24response callback, which the **InterfacePtr** would receive.
25
26Another way to think of this is that an **InterfacePtr** is capable of making
27remote calls on an implementation of the mojom interface associated with the
28**Binding**.
29
30The **Binding** itself is just glue that wires the endpoint's message queue up
31to some implementation of the interface provided by the developer.
32
33## Example
34
35Let's apply this to Chrome. Let's say we want to send a "Ping" message from a
36Browser to a Renderer. First we need to define the mojom interface.
37
38```
39module example.mojom;
40interface PingResponder {
41 // Receives a "Ping" and responds with a random integer.
42 Ping() => (int random);
43};
44```
45
46Now let's make a MessagePipe.
47```cpp
48example::mojom::PingResponderPtr ping_responder;
49example::mojom::PingResponderRequest request = mojo::MakeRequest(&ping_responder);
50```
51
52In this example, ```ping_responder``` is the **InterfacePtr**, and ```request```
53is an **InterfaceRequest**, which is a **Binding** precursor that will shortly
54be turned into a **Binding**. Now we can send our Ping message.
55
56```cpp
57auto callback = base::Bind(&OnPong);
58ping_responder->Ping(callback);
59```
60
61Important aside: If we want to receive the the response, we must keep the object
62```ping_responder``` alive. After all, it's just a wrapper around a **Message
63Pipe endpoint**, if it were to go away, there'd be nothing left to receive the
64response.
65
66We're done! Of course, if everything were this easy, this document wouldn't need
67to exist. We've taken the hard problem of sending a message from the Browser to
68a Renderer, and transformed it into a problem where we just need to take the
69```request``` object, pass it to the Renderer, turn it into a **Binding**, and
70implement the interface.
71
72In Chrome, processes host services, and the services themselves are connected to
73a Service Manager via **message pipes**. It's easy to pass ```request``` to the
74appropriate Renderer using the Service Manager, but this requires explicitly
75declaring our intentions via manifest files. For this example, we'll use the
76content_browser service [manifest
77file](https://cs.chromium.org/chromium/src/content/public/app/mojo/content_browser_manifest.json)
78and the content_renderer service [manifest
79file](https://cs.chromium.org/chromium/src/content/public/app/mojo/content_renderer_manifest.json).
80
81```js
82content_renderer_manifest.json:
83...
84 "interface_provider_specs": {
85 "service_manager:connector": {
86 "provides": {
87 "cool_ping_feature": [
88 "example::mojom::PingResponder"
89 ]
90 },
91 },
92...
93```
94
95```js
96content_browser_manifest.json:
97...
98 "interface_provider_specs": {
99 "service_manager:connector": {
100 "requires": {
101 "content_renderer": [ "cool_ping_feature" ],
102 },
103 },
104 },
105...
106```
107
108These changes indicate that the content_renderer service provides the interface
109PingResponder, under the **capability** named "cool_ping_feature". And the
110content_browser services intends to use this feature.
111```content::BindInterface``` is a helper function that takes ```request``` and
112sends it to the renderer process via the Service Manager.
113
114```cpp
115content::RenderProcessHost* host = GetRenderProcessHost();
116content::BindInterface(host, std::move(request));
117```
118
119Putting this all together for the browser process:
120```cpp
121example::mojom::PingResponderPtr ping_responder; // Make sure to keep this alive! Otherwise the response will never be received.
122example::mojom::PingResponderRequest request = mojo::MakeRequest(&ping_responder);
123ping_responder->Ping(base::BindOnce(&OnPong));
124content::RenderProcessHost* host = GetRenderProcessHost();
125content::BindInterface(host, std::move(request));
126```
127
128In the Renderer process, we need to write an implementation for PingResponder,
129and ensure that a **Binding** is created using the transported ```request```. In a
130standalone Mojo service, this would require us to implement
131```service_manager::Service::OnBindInterface()```. In Chrome, this is abstracted
132behind ```content::ConnectionFilters``` and
133```service_manager::BinderRegistry```. This is typically done in
134```RenderThreadImpl::Init```.
135
136```cpp
137class PingResponderImpl : mojom::PingResponder {
138 void BindToInterface(example::mojom::PingResponderRequest request) {
139 binding_.reset(
140 new mojo::Binding<mojom::MemlogClient>(this, std::move(request)));
141 }
142 void Ping(PingCallback callback) { std::move(callback).Run(4); }
143 std::unique_ptr<mojo::Binding<mojom::PingResponder>> binding_;
144};
145
146RenderThreadImpl::Init() {
147...
148 this->ping_responder = std::make_unique<PingResponderImpl>();
149 auto registry = base::MakeUnique<service_manager::BinderRegistry>();
150
151 // This makes the assumption that |this->ping_responder| will outlive |registry|.
152 registry->AddInterface(base::Bind(&PingResponderImpl::BindToInterface), base::Unretained(this->ping_responder.get()));
153
154 GetServiceManagerConnection()->AddConnectionFilter(
155 base::MakeUnique<SimpleConnectionFilter>(std::move(registry)));
156...
157```