Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(179)

Side by Side Diff: docs/mojo_in_chromium.md

Issue 1915003005: Remove Mojo markdown docs, since it's now on the sites page. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 4 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 # Mojo in Chromium
2
3 This document is intended to serve as a Mojo primer for Chromium developers. No
4 prior knowledge of Mojo is assumed.
5
6 [TOC]
7
8 ## Should I Bother Reading This?
9
10 If you're planning to build a Chromium feature that needs IPC and you aren't
11 already using Mojo, YES! **Legacy IPC is deprecated.**
12
13 ## Why Mojo?
14
15 TL;DR: The long-term intent is to refactor Chromium into a large set of smaller
16 services.
17
18 We can be smarter about:
19
20 * Which services we bring up or don't
21 * How we isolate these services to improve security and stability
22 * Which binary features we ship to one user or another
23
24 A more robust messaging layer opens the door for a number of interesting
25 possibilities; in particular it allows us to integrate a large number of
26 components without link-time interdependencies, and it breaks down the growing
27 number of interesting cross-language boundaries across the codebase.
28
29 Much has been learned from using Chromium IPC and maintaining Chromium
30 dependencies in anger over the past several years and we feel there's now a
31 significant opportunity to make life easier for developers, and to help them
32 build more and better features, faster, and with much less cost to users.
33
34 ## Mojo Overview
35
36 The Mojo system API provides a small suite of low-level IPC primitives:
37 **message pipes**, **data pipes**, and **shared buffers**. On top of this API
38 we've built higher-level bindings APIs to simplify messaging for consumers
39 writing C++, Java, or JavaScript code.
40
41 This document focuses primarily on using C++ bindings with message pipes, which
42 is likely to be the most common usage encountered by Chromium developers.
43
44 ### Message Pipes
45
46 A message pipe is a lightweight primitive for reliable bidirectional transfer of
47 relatively small packets of data. Unsurprisingly a pipe has two endpoints, and
48 either endpoint may be transferred over another message pipe.
49
50 Because we bootstrap a primordial message pipe between the browser process and
51 each child process, this in turn means that you can create a new pipe and
52 ultimately send either end to any process, and the two ends will still be
53 able to talk to each other seamlessly and exclusively. Goodbye, routing IDs!
54
55 While message pipes can carry arbitrary packets of unstructured data we
56 generally use them in conjunction with generated bindings to ensure a
57 consistent, well-defined, versioned message structure on all endpoints.
58
59 ### Mojom
60
61 Mojom is the IDL for Mojo interfaces. Given a `.mojom` file, the bindings
62 generator outputs bindings for all three of the currently supported languages.
63
64 For example:
65
66 ```
67 // src/components/frob/public/interfaces/frobinator.mojom
68 module frob.mojom;
69
70 interface Frobinator {
71 Frobinate();
72 };
73 ```
74
75 would generate the following outputs:
76
77 ```
78 out/Debug/gen/components/frob/public/interfaces/frobinator.mojom.cc
79 out/Debug/gen/components/frob/public/interfaces/frobinator.mojom.h
80 out/Debug/gen/components/frob/public/interfaces/frobinator.mojom.js
81 out/Debug/gen/components/frob/public/interfaces/frobinator.mojom.srcjar
82 ...
83 ```
84
85 The generated code hides away all the details of serializing and deserializing
86 messages on either end of a pipe.
87
88 The C++ header (`frobinator.mojom.h`) defines an abstract class for each
89 mojom interface specified. Namespaces are derived from the `module` name.
90
91 **NOTE:** Chromium convention for component `foo`'s module name is `foo.mojom`.
92 This means all mojom-generated C++ typenames for component `foo` will live in
93 the `foo::mojom` namespace to avoid collisions with non-generated typenames.
94
95 In this example the generated `frob::mojom::Frobinator` has a single
96 pure virtual function:
97
98 ```cpp
99 namespace frob {
100
101 class Frobinator {
102 public:
103 virtual void Frobinate() = 0;
104 };
105
106 } // namespace frob
107 ```
108
109 To create a `Frobinator` service, one simply implements `foo::Frobinator` and
110 provides a means of binding pipes to it.
111
112 ### Binding to Pipes
113
114 Let's look at some sample code:
115
116 ```cpp
117 // src/components/frob/frobinator_impl.cc
118
119 #include "components/frob/public/interfaces/frobinator.mojom.h"
120 #include "mojo/public/cpp/bindings/binding.h"
121 #include "mojo/public/cpp/bindings/interface_request.h"
122
123 namespace frob {
124
125 class FrobinatorImpl : public mojom::Frobinator {
126 public:
127 FrobinatorImpl(mojom::FrobinatorRequest request)
128 : binding_(this, std::move(request)) {}
129 ~FrobinatorImpl() override {}
130
131 // mojom::Frobinator:
132 void Frobinate() override { DLOG(INFO) << "I can't stop frobinating!"; }
133
134 private:
135 mojo::Binding<mojom::Frobinator> binding_;
136 };
137
138 } // namespace frob
139 ```
140
141 The first thing to note is that `mojo::Binding<T>` *binds* one end of a message
142 pipe to an implementation of a service. This means it watches that end of the
143 pipe for incoming messages; it knows how to decode messages for interface `T`,
144 and it dispatches them to methods on the bound `T` implementation.
145
146 `mojom::FrobinatorRequest` is a generated type alias for
147 `mojo::InterfaceRequest<mojom::Frobinator>` and is essentially semantic sugar
148 for a strongly-typed message pipe endpoint. A common way to create new message
149 pipes is via the `GetProxy` call defined in `interface_request.h`:
150
151 ```cpp
152 mojom::FrobinatorPtr proxy;
153 mojom::FrobinatorRequest request = mojo::GetProxy(&proxy);
154 ```
155
156 This creates a new message pipe with one end owned by `proxy` and the other end
157 owned by `request`. It has the nice property of attaching common type
158 information to each end of the pipe.
159
160 Note that `InterfaceRequest<T>` doesn't actually **do** anything. It just scopes
161 a pipe endpoint and associates it with an interface type at compile time. As
162 such, other typed service binding primitives such as `mojo::Binding<T>` take
163 these objects as input when they need an endpoint to bind to.
164
165 `mojom::FrobinatorPtr` is a generated type alias for
166 `mojo::InterfacePtr<mojom::Frobinator>`. An `InterfacePtr<T>` scopes a message
167 pipe endpoint as well, but it also internally implements every method on `T` by
168 serializing a corresponding message and writing it to the pipe.
169
170 Hence we can put this together to talk to a `FrobinatorImpl` over a pipe:
171
172 ```cpp
173 frob:mojom::FrobinatorPtr frobinator;
174 frob::FrobinatorImpl impl(GetProxy(&frobinator));
175
176 // Tada!
177 frobinator->Frobinate();
178 ```
179
180 Behind the scenes this serializes a message corresponding to the `Frobinate`
181 request and writes it to one end of the pipe. Eventually (and incidentally,
182 very soon after), `impl`'s internal `mojo::Binding` will decode this message and
183 dispatch a call to `impl.Frobinate()`.
184
185 **NOTE:** In this example the service and client are in the same process, and
186 this works just fine. If they were in different processes (see the example below
187 in [Exposing Services in Chromium](#Exposing-Services-in-Chromium)), the call
188 to `Frobinate()` would look exactly the same!
189
190 ### Responding to Requests
191
192 A common idiom in Chromium IPC is to keep track of IPC requests with some kind
193 of opaque identifier (i.e. an integer *request ID*) so that you can later
194 respond to a specific request using some nominally related message in the other
195 direction.
196
197 This is baked into mojom interface definitions. We can extend our `Frobinator`
198 service like so:
199
200 ```
201 module frob.mojom;
202
203 interface Frobinator {
204 Frobinate();
205 GetFrobinationLevels() => (int min, int max);
206 };
207 ```
208
209 and update our implementation:
210
211 ```cpp
212 class FrobinatorImpl : public mojom::Frobinator {
213 public:
214 // ...
215
216 // mojom::Frobinator:
217 void Frobinate() override { /* ... */ }
218 void GetFrobinationLevels(const GetFrobinationLevelsCallback& callback) {
219 callback.Run(1, 42);
220 }
221 };
222 ```
223
224 When the service implementation runs `callback`, the response arguments are
225 serialized and sent back over the pipe. The proxy on the other end knows how to
226 read this response and will in turn dispatch it to a callback on that end:
227
228 ```cpp
229 void ShowLevels(int min, int max) {
230 DLOG(INFO) << "Frobinator min=" << min << " max=" << max;
231 }
232
233 // ...
234
235 mojom::FrobinatorPtr frobinator;
236 FrobinatorImpl impl(GetProxy(&frobinator));
237
238 frobinator->GetFrobinatorLevels(base::Bind(&ShowLevels));
239 ```
240
241 This does what you'd expect.
242
243 ## Exposing Services in Chromium
244
245 There are a number of ways one might expose services across various surfaces of
246 the browser. One common approach now is to use a
247 [`content::ServiceRegistry` (link)](https://goo.gl/uEhx06). These come in
248 pairs generally spanning a process boundary, and they provide primitive service
249 registration and connection interfaces. For one example, [every
250 `RenderFrameHost` has a `ServiceRegistry`](https://goo.gl/4YR3j5), as does
251 [every corresponding `RenderFrame`](https://goo.gl/YhrgXa). These registries are
252 intertwined.
253
254 The gist is that you can add a service to the local side of the registry -- it's
255 just a mapping from interface name to factory function -- or you can connect by
256 name to services registered on the remote side.
257
258 **NOTE:** In this context the "factory function" is simply a callback which
259 takes a pipe endpoint and does something with it. It's expected that you'll
260 either bind it to a service implementation of some kind or you will close it, ef fectively rejecting the connection request.
261
262 We can build a simple browser-side `FrobinatorImpl` service that has access to a
263 `BrowserContext` for any frame which connects to it:
264
265 ```cpp
266 #include "base/macros.h"
267 #include "components/frob/public/interfaces/frobinator.mojom.h"
268 #include "content/public/browser/browser_context.h"
269 #include "mojo/public/cpp/system/interface_request.h"
270 #include "mojo/public/cpp/system/strong_binding.h"
271
272 namespace frob {
273
274 class FrobinatorImpl : public mojom::Frobinator {
275 public:
276 FrobinatorImpl(content::BrowserContext* context,
277 mojom::FrobinatorRequest request)
278 : context_(context), binding_(this, std::move(request)) {}
279 ~FrobinatorImpl() override {}
280
281 // A factory function to use in conjunction with ServiceRegistry.
282 static void Create(content::BrowserContext* context,
283 mojom::FrobinatorRequest request) {
284 // See comment below for why this doesn't leak.
285 new FrobinatorImpl(context, std::move(request));
286 }
287
288 private:
289 // mojom::Frobinator:
290 void Frobinate() override { /* ... */ }
291
292 content::BrowserContext* context_;
293
294 // A StrongBinding is just like a Binding, except that it takes ownership of
295 // its bound implementation and deletes itself (and the impl) if and when the
296 // bound pipe encounters an error or is closed on the other end.
297 mojo::StrongBinding<mojom::Frobinator> binding_;
298
299 DISALLOW_COPY_AND_ASSIGN(FrobinatorImpl);
300 };
301
302 } // namespace frob
303 ```
304
305 Now somewhere in the browser we register the Frobinator service with each
306 `RenderFrameHost` ([this](https://goo.gl/HEFn63) is a popular spot):
307
308 ```cpp
309 frame_host->GetServiceRegistry()->AddService<frob::mojom::Frobinator>(
310 base::Bind(
311 &frob::FrobinatorImpl::Create,
312 base::Unretained(frame_host->GetProcess()->GetBrowserContext())));
313 ```
314
315 And in the render process we can now do something like:
316
317 ```cpp
318 mojom::FrobinatorPtr frobinator;
319 render_frame->GetServiceRegistry()->ConnectToRemoteService(
320 mojo::GetProxy(&frobinator));
321
322 // It's IPC!
323 frobinator->Frobinate();
324 ```
325
326 There are now plenty of concrete examples of Mojo usage in the Chromium tree.
327 Poke around at existing mojom files and see how their implementions are built
328 and connected.
329
330 ## Mojo in Blink
331
332 *TODO*
333
334 This is a work in progress. TL;DR: We'll also soon begin using Mojo services
335 from Blink so that the platform layer can consume browser services
336 directly via Mojo. The long-term goal there is to eliminate `content/renderer`.
337
338 ## Questions, Discussion, etc.
339
340 A good place to find highly concentrated doses of people who know and care
341 about Mojo in Chromium would be the [chromium-mojo](https://goo.gl/A4ebWB)
342 mailing list[.](https://goo.gl/L70ihQ)
OLDNEW
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698