blob: 9eff612fb6e568b0bf4990c862ba4e4973055732 [file] [log] [blame] [view]
Ken Rockot686e4132017-04-26 00:03:311# Mojo C++ Bindings API
Ken Rockot929282c2018-05-02 17:07:292This document is a subset of the [Mojo documentation](/mojo/README.md).
rockotf59d2d62017-04-01 02:49:083
4[TOC]
5
6## Overview
7The Mojo C++ Bindings API leverages the
Ken Rockot929282c2018-05-02 17:07:298[C++ System API](/mojo/public/cpp/system/README.md) to provide a more natural
9set of primitives for communicating over Mojo message pipes. Combined with
10generated code from the
11[Mojom IDL and bindings generator](/mojo/public/tools/bindings/README.md), users
12can easily connect interface clients and implementations across arbitrary intra-
David Benjamin0ff61822019-04-29 19:00:0513and inter-process boundaries.
rockotf59d2d62017-04-01 02:49:0814
15This document provides a detailed guide to bindings API usage with example code
16snippets. For a detailed API references please consult the headers in
Ken Rockot929282c2018-05-02 17:07:2917[//mojo/public/cpp/bindings](https://cs.chromium.org/chromium/src/mojo/public/cpp/bindings/README.md).
rockotf59d2d62017-04-01 02:49:0818
Oksana Zhuravlova70c47af2018-07-06 22:48:2419For a simplified guide targeted at Chromium developers, see [this
Ken Rockotab035122019-02-06 00:35:2420link](/docs/mojo_and_services.md).
Erik Chen3fdc02bc2018-06-28 03:13:4821
rockotf59d2d62017-04-01 02:49:0822## Getting Started
23
24When a Mojom IDL file is processed by the bindings generator, C++ code is
25emitted in a series of `.h` and `.cc` files with names based on the input
26`.mojom` file. Suppose we create the following Mojom file at
Oksana Zhuravlovad5fea16d2018-08-15 00:02:1727`//services/db/public/mojom/db.mojom`:
rockotf59d2d62017-04-01 02:49:0828
29```
30module db.mojom;
31
32interface Table {
33 AddRow(int32 key, string data);
34};
35
36interface Database {
37 CreateTable(Table& table);
38};
39```
40
41And a GN target to generate the bindings in
Oksana Zhuravlovad5fea16d2018-08-15 00:02:1742`//services/db/public/mojom/BUILD.gn`:
rockotf59d2d62017-04-01 02:49:0843
44```
45import("//mojo/public/tools/bindings/mojom.gni")
46
Oksana Zhuravlovad5fea16d2018-08-15 00:02:1747mojom("mojom") {
rockotf59d2d62017-04-01 02:49:0848 sources = [
49 "db.mojom",
50 ]
51}
52```
53
David 'Digit' Turner743836f82017-10-27 13:04:1554Ensure that any target that needs this interface depends on it, e.g. with a line like:
55
56```
Oksana Zhuravlovad5fea16d2018-08-15 00:02:1757 deps += [ '//services/db/public/mojom' ]
David 'Digit' Turner743836f82017-10-27 13:04:1558```
59
rockotf59d2d62017-04-01 02:49:0860If we then build this target:
61
62```
Oksana Zhuravlovad5fea16d2018-08-15 00:02:1763ninja -C out/r services/db/public/mojom
rockotf59d2d62017-04-01 02:49:0864```
65
66This will produce several generated source files, some of which are relevant to
67C++ bindings. Two of these files are:
68
69```
Oksana Zhuravlovad5fea16d2018-08-15 00:02:1770out/gen/services/db/public/mojom/db.mojom.cc
71out/gen/services/db/public/mojom/db.mojom.h
rockotf59d2d62017-04-01 02:49:0872```
73
74You can include the above generated header in your sources in order to use the
75definitions therein:
76
77``` cpp
Oksana Zhuravlovad5fea16d2018-08-15 00:02:1778#include "services/business/public/mojom/factory.mojom.h"
rockotf59d2d62017-04-01 02:49:0879
80class TableImpl : public db::mojom::Table {
81 // ...
82};
83```
84
85This document covers the different kinds of definitions generated by Mojom IDL
86for C++ consumers and how they can effectively be used to communicate across
87message pipes.
88
89*** note
90**NOTE:** Using C++ bindings from within Blink code is typically subject to
91special constraints which require the use of a different generated header.
92For details, see [Blink Type Mapping](#Blink-Type-Mapping).
93***
94
95## Interfaces
96
97Mojom IDL interfaces are translated to corresponding C++ (pure virtual) class
98interface definitions in the generated header, consisting of a single generated
99method signature for each request message on the interface. Internally there is
100also generated code for serialization and deserialization of messages, but this
101detail is hidden from bindings consumers.
102
103### Basic Usage
104
105Let's consider a new `//sample/logger.mojom` to define a simple logging
106interface which clients can use to log simple string messages:
107
108``` cpp
109module sample.mojom;
110
111interface Logger {
112 Log(string message);
113};
114```
115
Mehran Mahmoudi0f7e56f32019-10-31 19:23:27116Running this through the bindings generator will produce a `logger.mojom.h`
rockotf59d2d62017-04-01 02:49:08117with the following definitions (modulo unimportant details):
118
119``` cpp
120namespace sample {
121namespace mojom {
122
123class Logger {
124 virtual ~Logger() {}
125
126 virtual void Log(const std::string& message) = 0;
127};
128
rockotf59d2d62017-04-01 02:49:08129} // namespace mojom
130} // namespace sample
131```
132
Oksana Zhuravlovad5888c92019-08-23 19:43:06133### Remote and PendingReceiver
rockotf59d2d62017-04-01 02:49:08134
135In the world of Mojo bindings libraries these are effectively strongly-typed
Oksana Zhuravlovad5888c92019-08-23 19:43:06136message pipe endpoints. If a `Remote<T>` is bound to a message pipe
rockotf59d2d62017-04-01 02:49:08137endpoint, it can be dereferenced to make calls on an opaque `T` interface. These
138calls immediately serialize their arguments (using generated code) and write a
139corresponding message to the pipe.
140
Oksana Zhuravlovad5888c92019-08-23 19:43:06141A `PendingReceiver<T>` is essentially just a typed container to hold the other
142end of a `Remote<T>`'s pipe -- the receiving end -- until it can be
143routed to some implementation which will **bind** it. The `PendingReceiver<T>`
rockotf59d2d62017-04-01 02:49:08144doesn't actually *do* anything other than hold onto a pipe endpoint and carry
145useful compile-time type information.
146
Oksana Zhuravlovad5888c92019-08-23 19:43:06147![Diagram illustrating Remote and PendingReceiver on either end of a message pipe](/docs/images/mojo_pipe.png)
rockotf59d2d62017-04-01 02:49:08148
149So how do we create a strongly-typed message pipe?
150
151### Creating Interface Pipes
152
Ken Rockotf4d8a942017-05-13 00:10:37153One way to do this is by manually creating a pipe and wrapping each end with a
154strongly-typed object:
rockotf59d2d62017-04-01 02:49:08155
156``` cpp
157#include "sample/logger.mojom.h"
158
159mojo::MessagePipe pipe;
Oksana Zhuravlovad5888c92019-08-23 19:43:06160mojo::Remote<sample::mojom::Logger> logger(
161 mojo::PendingRemote<sample::mojom::Logger>(std::move(pipe.handle0), 0));
162mojo::PendingReceiver<sample::mojom::Logger> receiver(std::move(pipe.handle1));
rockotf59d2d62017-04-01 02:49:08163```
164
Ken Rockotf4d8a942017-05-13 00:10:37165That's pretty verbose, but the C++ Bindings library provides a more convenient
Oksana Zhuravlovad5888c92019-08-23 19:43:06166way to accomplish the same thing. [remote.h](https://cs.chromium.org/chromium/src/mojo/public/cpp/bindings/remote.h)
167defines a `BindNewPipeAndPassReceiver` method:
rockotf59d2d62017-04-01 02:49:08168
169``` cpp
Oksana Zhuravlovad5888c92019-08-23 19:43:06170mojo::Remote<sample::mojom::Logger> logger;
Austin Sullivan03fb1922020-10-02 14:27:45171auto receiver = logger.BindNewPipeAndPassReceiver();
rockotf59d2d62017-04-01 02:49:08172```
173
Ken Rockotf4d8a942017-05-13 00:10:37174This second snippet is equivalent to the first one.
rockotf59d2d62017-04-01 02:49:08175
176*** note
Oksana Zhuravlovad5888c92019-08-23 19:43:06177**NOTE:** In the first example above you may notice usage of the
178`mojo::PendingRemote<Logger>`. This is similar to a `PendingReceiver<T>`
179in that it merely holds onto a pipe handle and cannot actually read or
180write messages on the pipe. Both this type and `PendingReceiver<T>` are safe
181to move freely from sequence to sequence, whereas a bound `Remote<T>` is bound
182to a single sequence.
rockotf59d2d62017-04-01 02:49:08183
Oksana Zhuravlovad5888c92019-08-23 19:43:06184A `Remote<T>` may be unbound by calling its `Unbind()` method,
185which returns a new `PendingRemote<T>`. Conversely, an `Remote<T>` may
186bind (and thus take ownership of) an `PendingRemote<T>` so that interface
rockotf59d2d62017-04-01 02:49:08187calls can be made on the pipe.
188
Oksana Zhuravlovad5888c92019-08-23 19:43:06189The sequence-bound nature of `Remote<T>` is necessary to support safe
rockotf59d2d62017-04-01 02:49:08190dispatch of its [message responses](#Receiving-Responses) and
191[connection error notifications](#Connection-Errors).
192***
193
Oksana Zhuravlovad5888c92019-08-23 19:43:06194Once the `PendingRemote<Logger>` is bound we can immediately begin calling `Logger`
rockotf59d2d62017-04-01 02:49:08195interface methods on it, which will immediately write messages into the pipe.
196These messages will stay queued on the receiving end of the pipe until someone
197binds to it and starts reading them.
198
199``` cpp
200logger->Log("Hello!");
201```
202
203This actually writes a `Log` message to the pipe.
204
Oksana Zhuravlovad5888c92019-08-23 19:43:06205![Diagram illustrating a message traveling on a pipe from Remote<Logger> to PendingReceiver<Logger>](/docs/images/mojo_message.png)
rockotf59d2d62017-04-01 02:49:08206
Oksana Zhuravlovad5888c92019-08-23 19:43:06207But as mentioned above, `PendingReceiver` *doesn't actually do anything*, so
rockotf59d2d62017-04-01 02:49:08208that message will just sit on the pipe forever. We need a way to read messages
209off the other end of the pipe and dispatch them. We have to
Oksana Zhuravlovad5888c92019-08-23 19:43:06210**bind the pending receiver**.
rockotf59d2d62017-04-01 02:49:08211
Oksana Zhuravlovad5888c92019-08-23 19:43:06212### Binding a Pending Receiver
rockotf59d2d62017-04-01 02:49:08213
214There are many different helper classes in the bindings library for binding the
Oksana Zhuravlovad5888c92019-08-23 19:43:06215receiving end of a message pipe. The most primitive among them is `mojo::Receiver<T>`.
216A `mojo::Receiver<T>` bridges an implementation of `T`
217with a single bound message pipe endpoint (via a `mojo::PendingReceiver<T>`),
rockotf59d2d62017-04-01 02:49:08218which it continuously watches for readability.
219
Oksana Zhuravlovad5888c92019-08-23 19:43:06220Any time the bound pipe becomes readable, the `Receiver` will schedule a task to
rockotf59d2d62017-04-01 02:49:08221read, deserialize (using generated code), and dispatch all available messages to
222the bound `T` implementation. Below is a sample implementation of the `Logger`
Oksana Zhuravlovad5888c92019-08-23 19:43:06223interface. Notice that the implementation itself owns a `mojo::Receiver`. This is
224a common pattern, since a bound implementation must outlive any `mojo::Receiver`
rockotf59d2d62017-04-01 02:49:08225which binds it.
226
227``` cpp
228#include "base/logging.h"
229#include "base/macros.h"
230#include "sample/logger.mojom.h"
231
232class LoggerImpl : public sample::mojom::Logger {
233 public:
234 // NOTE: A common pattern for interface implementations which have one
Oksana Zhuravlovad5888c92019-08-23 19:43:06235 // instance per client is to take a PendingReceiver in the constructor.
rockotf59d2d62017-04-01 02:49:08236
Oksana Zhuravlovad5888c92019-08-23 19:43:06237 explicit LoggerImpl(mojo::PendingReceiver<sample::mojom::Logger> receiver)
238 : receiver_(this, std::move(receiver)) {}
rockotf59d2d62017-04-01 02:49:08239 ~Logger() override {}
Johanne6e768e92020-09-09 00:51:10240 Logger(const Logger&) = delete;
241 Logger& operator=(const Logger&) = delete;
rockotf59d2d62017-04-01 02:49:08242
243 // sample::mojom::Logger:
244 void Log(const std::string& message) override {
245 LOG(ERROR) << "[Logger] " << message;
246 }
247
248 private:
Oksana Zhuravlovad5888c92019-08-23 19:43:06249 mojo::Receiver<sample::mojom::Logger> receiver_;
rockotf59d2d62017-04-01 02:49:08250};
251```
252
Oksana Zhuravlovad5888c92019-08-23 19:43:06253Now we can construct a `LoggerImpl` over our `PendingReceiver<Logger>`, and the
rockotf59d2d62017-04-01 02:49:08254previously queued `Log` message will be dispatched ASAP on the `LoggerImpl`'s
Sam McNallyd482b4b2017-07-17 03:45:03255sequence:
rockotf59d2d62017-04-01 02:49:08256
257``` cpp
Oksana Zhuravlovad5888c92019-08-23 19:43:06258LoggerImpl impl(std::move(receiver));
rockotf59d2d62017-04-01 02:49:08259```
260
261The diagram below illustrates the following sequence of events, all set in
262motion by the above line of code:
263
Oksana Zhuravlovad5888c92019-08-23 19:43:062641. The `LoggerImpl` constructor is called, passing the `PendingReceiver<Logger>` along
265 to the `Receiver`.
2662. The `Receiver` takes ownership of the `PendingReceiver<Logger>`'s pipe endpoint and
rockotf59d2d62017-04-01 02:49:08267 begins watching it for readability. The pipe is readable immediately, so a
268 task is scheduled to read the pending `Log` message from the pipe ASAP.
Oksana Zhuravlovad5888c92019-08-23 19:43:062693. The `Log` message is read and deserialized, causing the `Receiver` to invoke
rockotf59d2d62017-04-01 02:49:08270 the `Logger::Log` implementation on its bound `LoggerImpl`.
271
Oksana Zhuravlovad5888c92019-08-23 19:43:06272![Diagram illustrating the progression of binding a pending receiver, reading a pending message, and dispatching it](/docs/images/mojo_receiver_and_dispatch.png)
rockotf59d2d62017-04-01 02:49:08273
274As a result, our implementation will eventually log the client's `"Hello!"`
275message via `LOG(ERROR)`.
276
277*** note
278**NOTE:** Messages will only be read and dispatched from a pipe as long as the
Oksana Zhuravlovad5888c92019-08-23 19:43:06279object which binds it (*i.e.* the `mojo::Receiver` in the above example) remains
rockotf59d2d62017-04-01 02:49:08280alive.
281***
282
283### Receiving Responses
284
285Some Mojom interface methods expect a response. Suppose we modify our `Logger`
286interface so that the last logged line can be queried like so:
287
288``` cpp
289module sample.mojom;
290
291interface Logger {
292 Log(string message);
293 GetTail() => (string message);
294};
295```
296
297The generated C++ interface will now look like:
298
299``` cpp
300namespace sample {
301namespace mojom {
302
303class Logger {
304 public:
305 virtual ~Logger() {}
306
307 virtual void Log(const std::string& message) = 0;
308
David 'Digit' Turner743836f82017-10-27 13:04:15309 using GetTailCallback = base::OnceCallback<void(const std::string& message)>;
rockotf59d2d62017-04-01 02:49:08310
David 'Digit' Turner743836f82017-10-27 13:04:15311 virtual void GetTail(GetTailCallback callback) = 0;
rockotf59d2d62017-04-01 02:49:08312}
313
314} // namespace mojom
315} // namespace sample
316```
317
318As before, both clients and implementations of this interface use the same
319signature for the `GetTail` method: implementations use the `callback` argument
320to *respond* to the request, while clients pass a `callback` argument to
Erik Chen94936ef2020-09-11 20:41:12321asynchronously `receive` the response. The parameter `GetTailCallback` passed to
322the implementation of `GetTail` is sequence-affine. It must be invoked on the
323same sequence that `GetTail` is called on. A client's `callback` runs on the
324same sequence on which they invoked `GetTail` (the sequence to which their
325`logger` is bound). Here's an updated implementation:
rockotf59d2d62017-04-01 02:49:08326
327```cpp
328class LoggerImpl : public sample::mojom::Logger {
329 public:
330 // NOTE: A common pattern for interface implementations which have one
Oksana Zhuravlovad5888c92019-08-23 19:43:06331 // instance per client is to take a PendingReceiver in the constructor.
rockotf59d2d62017-04-01 02:49:08332
Oksana Zhuravlovad5888c92019-08-23 19:43:06333 explicit LoggerImpl(mojo::PendingReceiver<sample::mojom::Logger> receiver)
334 : receiver_(this, std::move(receiver)) {}
rockotf59d2d62017-04-01 02:49:08335 ~Logger() override {}
Johanne6e768e92020-09-09 00:51:10336 Logger(const Logger&) = delete;
337 Logger& operator=(const Logger&) = delete;
rockotf59d2d62017-04-01 02:49:08338
339 // sample::mojom::Logger:
340 void Log(const std::string& message) override {
341 LOG(ERROR) << "[Logger] " << message;
342 lines_.push_back(message);
343 }
344
David 'Digit' Turner743836f82017-10-27 13:04:15345 void GetTail(GetTailCallback callback) override {
346 std::move(callback).Run(lines_.back());
rockotf59d2d62017-04-01 02:49:08347 }
348
349 private:
Oksana Zhuravlovad5888c92019-08-23 19:43:06350 mojo::Receiver<sample::mojom::Logger> receiver_;
rockotf59d2d62017-04-01 02:49:08351 std::vector<std::string> lines_;
rockotf59d2d62017-04-01 02:49:08352};
353```
354
355And an updated client call:
356
357``` cpp
358void OnGetTail(const std::string& message) {
359 LOG(ERROR) << "Tail was: " << message;
360}
361
David 'Digit' Turner743836f82017-10-27 13:04:15362logger->GetTail(base::BindOnce(&OnGetTail));
rockotf59d2d62017-04-01 02:49:08363```
364
365Behind the scenes, the implementation-side callback is actually serializing the
366response arguments and writing them onto the pipe for delivery back to the
367client. Meanwhile the client-side callback is invoked by some internal logic
368which watches the pipe for an incoming response message, reads and deserializes
369it once it arrives, and then invokes the callback with the deserialized
370parameters.
371
372### Connection Errors
373
Yuzhu Shen92e791aa2017-06-20 20:39:31374If a pipe is disconnected, both endpoints will be able to observe the connection
375error (unless the disconnection is caused by closing/destroying an endpoint, in
376which case that endpoint won't get such a notification). If there are remaining
377incoming messages for an endpoint on disconnection, the connection error won't
378be triggered until the messages are drained.
379
David Benjamin0ff61822019-04-29 19:00:05380Pipe disconnection may be caused by:
Yuzhu Shen92e791aa2017-06-20 20:39:31381* Mojo system-level causes: process terminated, resource exhausted, etc.
382* The bindings close the pipe due to a validation error when processing a
383 received message.
384* The peer endpoint is closed. For example, the remote side is a bound
Oksana Zhuravlovad5888c92019-08-23 19:43:06385 `mojo::Remote<T>` and it is destroyed.
rockotf59d2d62017-04-01 02:49:08386
387Regardless of the underlying cause, when a connection error is encountered on
Oksana Zhuravlovad5888c92019-08-23 19:43:06388a receiver endpoint, that endpoint's **disconnect handler** (if set) is
Anand K. Mistryff664b72019-11-08 00:50:10389invoked. This handler is a simple `base::OnceClosure` and may only be invoked
rockotf59d2d62017-04-01 02:49:08390*once* as long as the endpoint is bound to the same pipe. Typically clients and
391implementations use this handler to do some kind of cleanup or -- particuarly if
392the error was unexpected -- create a new pipe and attempt to establish a new
393connection with it.
394
Oksana Zhuravlovad5888c92019-08-23 19:43:06395All message pipe-binding C++ objects (*e.g.*, `mojo::Receiver<T>`,
396`mojo::Remote<T>`, *etc.*) support setting their disconnect handler
397via a `set_disconnect_handler` method.
rockotf59d2d62017-04-01 02:49:08398
Oksana Zhuravlovad5888c92019-08-23 19:43:06399We can set up another end-to-end `Logger` example to demonstrate disconnect handler
400invocation. Suppose that `LoggerImpl` had set up the following disconnect
rockotf59d2d62017-04-01 02:49:08401handler within its constructor:
402
403``` cpp
Oksana Zhuravlovad5888c92019-08-23 19:43:06404LoggerImpl::LoggerImpl(mojo::PendingReceiver<sample::mojom::Logger> receiver)
405 : receiver_(this, std::move(receiver)) {
406 receiver_.set_disconnect_handler(
jameswest14ae0132017-06-12 22:52:00407 base::BindOnce(&LoggerImpl::OnError, base::Unretained(this)));
rockotf59d2d62017-04-01 02:49:08408}
409
410void LoggerImpl::OnError() {
411 LOG(ERROR) << "Client disconnected! Purging log lines.";
412 lines_.clear();
413}
Oksana Zhuravlovad5888c92019-08-23 19:43:06414
415mojo::Remote<sample::mojom::Logger> logger;
416LoggerImpl impl(logger.BindNewPipeAndPassReceiver());
417logger->Log("OK cool");
418logger.reset(); // Closes the client end.
419
rockotf59d2d62017-04-01 02:49:08420```
421
Oksana Zhuravlovad5888c92019-08-23 19:43:06422As long as `impl` stays alive here, it will eventually receive the `Log` message
423followed immediately by an invocation of the bound callback which outputs
424`"Client disconnected! Purging log lines."`. Like all other receiver callbacks, a disconnect handler will
425**never** be invoked once its corresponding receiver object has been destroyed.
426
rockotf59d2d62017-04-01 02:49:08427The use of `base::Unretained` is *safe* because the error handler will never be
Oksana Zhuravlovad5888c92019-08-23 19:43:06428invoked beyond the lifetime of `receiver_`, and `this` owns `receiver_`.
rockotf59d2d62017-04-01 02:49:08429
Yuzhu Shen7afd7262017-11-16 22:30:26430### A Note About Endpoint Lifetime and Callbacks
Oksana Zhuravlovad5888c92019-08-23 19:43:06431Once a `mojo::Remote<T>` is destroyed, it is guaranteed that pending
Yuzhu Shen7afd7262017-11-16 22:30:26432callbacks as well as the connection error handler (if registered) won't be
433called.
434
Oksana Zhuravlovad5888c92019-08-23 19:43:06435Once a `mojo::Receiver<T>` is destroyed, it is guaranteed that no more method
Yuzhu Shen7afd7262017-11-16 22:30:26436calls are dispatched to the implementation and the connection error handler (if
437registered) won't be called.
438
John Abd-El-Maleka9154852017-12-21 23:39:48439### Best practices for dealing with process crashes and callbacks
440A common situation when calling mojo interface methods that take a callback is
441that the caller wants to know if the other endpoint is torn down (e.g. because
442of a crash). In that case, the consumer usually wants to know if the response
443callback won't be run. There are different solutions for this problem, depending
Oksana Zhuravlovad5888c92019-08-23 19:43:06444on how the `Remote<T>` is held:
4451. The consumer owns the `Remote<T>`: `set_disconnect_handler`
John Abd-El-Maleka9154852017-12-21 23:39:48446 should be used.
Oksana Zhuravlovad5888c92019-08-23 19:43:064472. The consumer doesn't own the `Remote<T>`: there are two helpers
John Abd-El-Maleka9154852017-12-21 23:39:48448 depending on the behavior that the caller wants. If the caller wants to
449 ensure that an error handler is run, then
450 [**`mojo::WrapCallbackWithDropHandler`**](https://cs.chromium.org/chromium/src/mojo/public/cpp/bindings/callback_helpers.h?l=46)
451 should be used. If the caller wants the callback to always be run, then
452 [**`mojo::WrapCallbackWithDefaultInvokeIfNotRun`**](https://cs.chromium.org/chromium/src/mojo/public/cpp/bindings/callback_helpers.h?l=40)
453 helper should be used. With both of these helpers, usual callback care should
454 be followed to ensure that the callbacks don't run after the consumer is
Oksana Zhuravlovad5888c92019-08-23 19:43:06455 destructed (e.g. because the owner of the `Remote<T>` outlives the
John Abd-El-Maleka9154852017-12-21 23:39:48456 consumer). This includes using
457 [**`base::WeakPtr`**](https://cs.chromium.org/chromium/src/base/memory/weak_ptr.h?l=5)
458 or
459 [**`base::RefCounted`**](https://cs.chromium.org/chromium/src/base/memory/ref_counted.h?l=246).
460 It should also be noted that with these helpers, the callbacks could be run
Oksana Zhuravlovad5888c92019-08-23 19:43:06461 synchronously while the Remote<T> is reset or destroyed.
John Abd-El-Maleka9154852017-12-21 23:39:48462
rockotf59d2d62017-04-01 02:49:08463### A Note About Ordering
464
465As mentioned in the previous section, closing one end of a pipe will eventually
466trigger a connection error on the other end. However it's important to note that
467this event is itself ordered with respect to any other event (*e.g.* writing a
468message) on the pipe.
469
470This means that it's safe to write something contrived like:
471
472``` cpp
Oksana Zhuravlovad5888c92019-08-23 19:43:06473LoggerImpl::LoggerImpl(mojo::PendingReceiver<sample::mojom::Logger> receiver,
474 base::OnceClosure disconnect_handler)
475 : receiver_(this, std::move(receiver)) {
476 receiver_.set_disconnect_handler(std::move(disconnect_handler));
477}
478
479void GoBindALogger(mojo::PendingReceiver<sample::mojom::Logger> receiver) {
rockotf59d2d62017-04-01 02:49:08480 base::RunLoop loop;
Oksana Zhuravlovad5888c92019-08-23 19:43:06481 LoggerImpl impl(std::move(receiver), loop.QuitClosure());
rockotf59d2d62017-04-01 02:49:08482 loop.Run();
483}
484
485void LogSomething() {
Oksana Zhuravlovad5888c92019-08-23 19:43:06486 mojo::Remote<sample::mojom::Logger> logger;
rockotf59d2d62017-04-01 02:49:08487 bg_thread->task_runner()->PostTask(
Oksana Zhuravlovad5888c92019-08-23 19:43:06488 FROM_HERE, base::BindOnce(&GoBindALogger, logger.BindNewPipeAndPassReceiver()));
rockotf59d2d62017-04-01 02:49:08489 logger->Log("OK Computer");
490}
491```
492
493When `logger` goes out of scope it immediately closes its end of the message
494pipe, but the impl-side won't notice this until it receives the sent `Log`
495message. Thus the `impl` above will first log our message and *then* see a
496connection error and break out of the run loop.
497
Sasha Bermeister995adc62017-12-07 02:36:43498## Types
499
Ken Rockot686e4132017-04-26 00:03:31500### Enums
501
Ken Rockot929282c2018-05-02 17:07:29502[Mojom enums](/mojo/public/tools/bindings/README.md#Enumeration-Types) translate
503directly to equivalent strongly-typed C++11 enum classes with `int32_t` as the
504underlying type. The typename and value names are identical between Mojom and
505C++. Mojo also always defines a special enumerator `kMaxValue` that shares the
506value of the highest enumerator: this makes it easy to record Mojo enums in
507histograms and interoperate with legacy IPC.
Ken Rockot686e4132017-04-26 00:03:31508
509For example, consider the following Mojom definition:
510
511```cpp
512module business.mojom;
513
514enum Department {
515 kEngineering,
Andrew Moylan341cece72017-06-22 22:03:02516 kMarketing,
Ken Rockot686e4132017-04-26 00:03:31517 kSales,
518};
519```
520
521This translates to the following C++ definition:
522
523```cpp
524namespace business {
525namespace mojom {
526
527enum class Department : int32_t {
528 kEngineering,
529 kMarketing,
530 kSales,
Daniel Chengcda1df5b2018-03-30 21:30:16531 kMaxValue = kSales,
Ken Rockot686e4132017-04-26 00:03:31532};
533
534} // namespace mojom
535} // namespace business
536```
537
538### Structs
539
Ken Rockot929282c2018-05-02 17:07:29540[Mojom structs](mojo/public/tools/bindings/README.md#Structs) can be used to
541define logical groupings of fields into a new composite type. Every Mojom struct
Ken Rockot686e4132017-04-26 00:03:31542elicits the generation of an identically named, representative C++ class, with
543identically named public fields of corresponding C++ types, and several helpful
544public methods.
545
546For example, consider the following Mojom struct:
547
548```cpp
549module business.mojom;
550
551struct Employee {
552 int64 id;
553 string username;
554 Department department;
555};
556```
557
558This would generate a C++ class like so:
559
560```cpp
561namespace business {
562namespace mojom {
563
564class Employee;
565
566using EmployeePtr = mojo::StructPtr<Employee>;
567
568class Employee {
569 public:
570 // Default constructor - applies default values, potentially ones specified
571 // explicitly within the Mojom.
572 Employee();
573
574 // Value constructor - an explicit argument for every field in the struct, in
575 // lexical Mojom definition order.
576 Employee(int64_t id, const std::string& username, Department department);
577
578 // Creates a new copy of this struct value
579 EmployeePtr Clone();
580
581 // Tests for equality with another struct value of the same type.
582 bool Equals(const Employee& other);
583
584 // Equivalent public fields with names identical to the Mojom.
585 int64_t id;
586 std::string username;
587 Department department;
588};
589
590} // namespace mojom
591} // namespace business
592```
593
594Note when used as a message parameter or as a field within another Mojom struct,
595a `struct` type is wrapped by the move-only `mojo::StructPtr` helper, which is
596roughly equivalent to a `std::unique_ptr` with some additional utility methods.
597This allows struct values to be nullable and struct types to be potentially
598self-referential.
599
David Benjamin0ff61822019-04-29 19:00:05600Every generated struct class has a static `New()` method which returns a new
Ken Rockot686e4132017-04-26 00:03:31601`mojo::StructPtr<T>` wrapping a new instance of the class constructed by
602forwarding the arguments from `New`. For example:
603
604```cpp
605mojom::EmployeePtr e1 = mojom::Employee::New();
606e1->id = 42;
607e1->username = "mojo";
608e1->department = mojom::Department::kEngineering;
609```
610
611is equivalent to
612
613```cpp
614auto e1 = mojom::Employee::New(42, "mojo", mojom::Department::kEngineering);
615```
616
617Now if we define an interface like:
618
619```cpp
620interface EmployeeManager {
621 AddEmployee(Employee e);
622};
623```
624
625We'll get this C++ interface to implement:
626
627```cpp
628class EmployeeManager {
629 public:
630 virtual ~EmployeManager() {}
631
632 virtual void AddEmployee(EmployeePtr e) = 0;
633};
634```
635
636And we can send this message from C++ code as follows:
637
638```cpp
639mojom::EmployeManagerPtr manager = ...;
640manager->AddEmployee(
641 Employee::New(42, "mojo", mojom::Department::kEngineering));
642
643// or
644auto e = Employee::New(42, "mojo", mojom::Department::kEngineering);
645manager->AddEmployee(std::move(e));
646```
647
648### Unions
649
650Similarly to [structs](#Structs), tagged unions generate an identically named,
651representative C++ class which is typically wrapped in a `mojo::StructPtr<T>`.
652
653Unlike structs, all generated union fields are private and must be retrieved and
Oksana Zhuravlovaa4da21f2019-03-20 20:41:58654manipulated using accessors. A field `foo` is accessible by `get_foo()` and
Ken Rockot686e4132017-04-26 00:03:31655settable by `set_foo()`. There is also a boolean `is_foo()` for each field which
656indicates whether the union is currently taking on the value of field `foo` in
657exclusion to all other union fields.
658
659Finally, every generated union class also has a nested `Tag` enum class which
660enumerates all of the named union fields. A Mojom union value's current type can
661be determined by calling the `which()` method which returns a `Tag`.
662
663For example, consider the following Mojom definitions:
664
665```cpp
666union Value {
667 int64 int_value;
Tom McKee1a5032f2018-08-02 17:14:55668 float float_value;
Ken Rockot686e4132017-04-26 00:03:31669 string string_value;
670};
671
672interface Dictionary {
673 AddValue(string key, Value value);
674};
675```
676
Tom McKee1a5032f2018-08-02 17:14:55677This generates the following C++ interface:
Ken Rockot686e4132017-04-26 00:03:31678
679```cpp
680class Value {
681 public:
Tom McKee1a5032f2018-08-02 17:14:55682 ~Value() {}
683};
684
685class Dictionary {
686 public:
687 virtual ~Dictionary() {}
Ken Rockot686e4132017-04-26 00:03:31688
689 virtual void AddValue(const std::string& key, ValuePtr value) = 0;
690};
691```
692
693And we can use it like so:
694
695```cpp
696ValuePtr value = Value::New();
697value->set_int_value(42);
698CHECK(value->is_int_value());
699CHECK_EQ(value->which(), Value::Tag::INT_VALUE);
700
701value->set_float_value(42);
702CHECK(value->is_float_value());
703CHECK_EQ(value->which(), Value::Tag::FLOAT_VALUE);
704
705value->set_string_value("bananas");
706CHECK(value->is_string_value());
707CHECK_EQ(value->which(), Value::Tag::STRING_VALUE);
708```
709
710Finally, note that if a union value is not currently occupied by a given field,
711attempts to access that field will DCHECK:
712
713```cpp
714ValuePtr value = Value::New();
715value->set_int_value(42);
716LOG(INFO) << "Value is " << value->string_value(); // DCHECK!
717```
718
rockotf59d2d62017-04-01 02:49:08719### Sending Interfaces Over Interfaces
720
Oksana Zhuravlovad5888c92019-08-23 19:43:06721We know how to create interface pipes and use their Remote and PendingReceiver endpoints
Ken Rockot686e4132017-04-26 00:03:31722in some interesting ways. This still doesn't add up to interesting IPC! The
723bread and butter of Mojo IPC is the ability to transfer interface endpoints
724across other interfaces, so let's take a look at how to accomplish that.
rockotf59d2d62017-04-01 02:49:08725
Oksana Zhuravlovad5888c92019-08-23 19:43:06726#### Sending Pending Receivers
rockotf59d2d62017-04-01 02:49:08727
728Consider a new example Mojom in `//sample/db.mojom`:
729
730``` cpp
731module db.mojom;
732
733interface Table {
734 void AddRow(int32 key, string data);
735};
736
737interface Database {
Oksana Zhuravlovad5888c92019-08-23 19:43:06738 AddTable(pending_receiver<Table> table);
rockotf59d2d62017-04-01 02:49:08739};
740```
741
742As noted in the
David Bokane59ea1f42020-08-04 14:40:21743[Mojom IDL documentation](/mojo/public/tools/bindings/README.md#Primitive-Types),
Oksana Zhuravlovad5888c92019-08-23 19:43:06744the `pending_receiver<Table>` syntax corresponds
745precisely to the `PendingReceiver<T>` type discussed in the sections above, and
rockotf59d2d62017-04-01 02:49:08746in fact the generated code for these interfaces is approximately:
747
748``` cpp
749namespace db {
750namespace mojom {
751
752class Table {
753 public:
754 virtual ~Table() {}
755
756 virtual void AddRow(int32_t key, const std::string& data) = 0;
757}
758
rockotf59d2d62017-04-01 02:49:08759class Database {
760 public:
761 virtual ~Database() {}
762
Oksana Zhuravlovad5888c92019-08-23 19:43:06763 virtual void AddTable(mojo::PendingReceiver<Table> table);
rockotf59d2d62017-04-01 02:49:08764};
765
rockotf59d2d62017-04-01 02:49:08766} // namespace mojom
767} // namespace db
768```
769
770We can put this all together now with an implementation of `Table` and
771`Database`:
772
773``` cpp
774#include "sample/db.mojom.h"
775
776class TableImpl : public db::mojom:Table {
777 public:
Oksana Zhuravlovad5888c92019-08-23 19:43:06778 explicit TableImpl(mojo::PendingReceiver<db::mojom::Table> receiver)
779 : receiver_(this, std::move(receiver)) {}
rockotf59d2d62017-04-01 02:49:08780 ~TableImpl() override {}
781
782 // db::mojom::Table:
783 void AddRow(int32_t key, const std::string& data) override {
784 rows_.insert({key, data});
785 }
786
787 private:
Oksana Zhuravlovad5888c92019-08-23 19:43:06788 mojo::Receiver<db::mojom::Table> receiver_;
rockotf59d2d62017-04-01 02:49:08789 std::map<int32_t, std::string> rows_;
790};
791
792class DatabaseImpl : public db::mojom::Database {
793 public:
Oksana Zhuravlovad5888c92019-08-23 19:43:06794 explicit DatabaseImpl(mojo::PendingReceiver<db::mojom::Database> receiver)
795 : receiver_(this, std::move(receiver)) {}
rockotf59d2d62017-04-01 02:49:08796 ~DatabaseImpl() override {}
797
798 // db::mojom::Database:
Oksana Zhuravlovad5888c92019-08-23 19:43:06799 void AddTable(mojo::PendingReceiver<db::mojom::Table> table) {
Jeremy Romancf9ae2f2017-08-24 17:06:37800 tables_.emplace_back(std::make_unique<TableImpl>(std::move(table)));
rockotf59d2d62017-04-01 02:49:08801 }
802
803 private:
Oksana Zhuravlovad5888c92019-08-23 19:43:06804 mojo::Receiver<db::mojom::Database> receiver_;
rockotf59d2d62017-04-01 02:49:08805 std::vector<std::unique_ptr<TableImpl>> tables_;
806};
807```
808
Oksana Zhuravlovad5888c92019-08-23 19:43:06809Pretty straightforward. The `pending_receiver<Table>` Mojom parameter to `AddTable` translates to
810a C++ `mojo::PendingReceiver<db::mojom::Table>`, which we know is just a
rockotf59d2d62017-04-01 02:49:08811strongly-typed message pipe handle. When `DatabaseImpl` gets an `AddTable` call,
Oksana Zhuravlovad5888c92019-08-23 19:43:06812it constructs a new `TableImpl` and binds it to the received `mojo::PendingReceiver<db::mojom::Table>`.
rockotf59d2d62017-04-01 02:49:08813
814Let's see how this can be used.
815
816``` cpp
Oksana Zhuravlovad5888c92019-08-23 19:43:06817mojo::Remote<db::mojom::Database> database;
818DatabaseImpl db_impl(database.BindNewPipeAndPassReceiver());
rockotf59d2d62017-04-01 02:49:08819
Oksana Zhuravlovad5888c92019-08-23 19:43:06820mojo::Remote<db::mojom::Table> table1, table2;
821database->AddTable(table1.BindNewPipeAndPassReceiver());
822database->AddTable(table2.BindNewPipeAndPassReceiver());
rockotf59d2d62017-04-01 02:49:08823
824table1->AddRow(1, "hiiiiiiii");
825table2->AddRow(2, "heyyyyyy");
826```
827
828Notice that we can again start using the new `Table` pipes immediately, even
Oksana Zhuravlovad5888c92019-08-23 19:43:06829while their `mojo::PendingReceiver<db::mojom::Table>` endpoints are still in transit.
rockotf59d2d62017-04-01 02:49:08830
Oksana Zhuravlovad5888c92019-08-23 19:43:06831#### Sending Remotes
rockotf59d2d62017-04-01 02:49:08832
Oksana Zhuravlovad5888c92019-08-23 19:43:06833Of course we can also send `Remote`s:
rockotf59d2d62017-04-01 02:49:08834
835``` cpp
836interface TableListener {
837 OnRowAdded(int32 key, string data);
838};
839
840interface Table {
841 AddRow(int32 key, string data);
842
Oksana Zhuravlovad5888c92019-08-23 19:43:06843 AddListener(pending_remote<TableListener> listener);
rockotf59d2d62017-04-01 02:49:08844};
845```
846
847This would generate a `Table::AddListener` signature like so:
848
849``` cpp
Oksana Zhuravlovad5888c92019-08-23 19:43:06850 virtual void AddListener(mojo::PendingRemote<TableListener> listener) = 0;
rockotf59d2d62017-04-01 02:49:08851```
852
853and this could be used like so:
854
855``` cpp
Oksana Zhuravlovad5888c92019-08-23 19:43:06856mojo::PendingRemote<db::mojom::TableListener> listener;
857TableListenerImpl impl(listener.InitWithNewPipeAndPassReceiver());
rockotf59d2d62017-04-01 02:49:08858table->AddListener(std::move(listener));
859```
860
861## Other Interface Binding Types
862
863The [Interfaces](#Interfaces) section above covers basic usage of the most
Oksana Zhuravlovad5888c92019-08-23 19:43:06864common bindings object types: `Remote`, `PendingReceiver`, and `Receiver`.
rockotf59d2d62017-04-01 02:49:08865While these types are probably the most commonly used in practice, there are
866several other ways of binding both client- and implementation-side interface
867pipes.
868
Oksana Zhuravlovad5888c92019-08-23 19:43:06869### Self-owned Receivers
rockotf59d2d62017-04-01 02:49:08870
Oksana Zhuravlovad5888c92019-08-23 19:43:06871A **self-owned receiver** exists as a standalone object which owns its interface
rockotf59d2d62017-04-01 02:49:08872implementation and automatically cleans itself up when its bound interface
873endpoint detects an error. The
Oksana Zhuravlovad5888c92019-08-23 19:43:06874[**`MakeSelfOwnedReceiver`**](https://cs.chromium.org/chromium/src/mojo/public/cpp/bindings/self_owned_receiver.h)
875function is used to create such a receiver.
rockotf59d2d62017-04-01 02:49:08876.
877
878``` cpp
879class LoggerImpl : public sample::mojom::Logger {
880 public:
881 LoggerImpl() {}
882 ~LoggerImpl() override {}
883
884 // sample::mojom::Logger:
885 void Log(const std::string& message) override {
886 LOG(ERROR) << "[Logger] " << message;
887 }
888
889 private:
Oksana Zhuravlovad5888c92019-08-23 19:43:06890 // NOTE: This doesn't own any Receiver object!
rockotf59d2d62017-04-01 02:49:08891};
892
Oksana Zhuravlovad5888c92019-08-23 19:43:06893mojo::Remote<db::mojom::Logger> logger;
894mojo::MakeSelfOwnedReceiver(std::make_unique<LoggerImpl>(),
895 logger.BindNewPipeAndPassReceiver());
rockotf59d2d62017-04-01 02:49:08896
897logger->Log("NOM NOM NOM MESSAGES");
898```
899
900Now as long as `logger` remains open somewhere in the system, the bound
scottmg66139202017-05-04 18:56:35901`LoggerImpl` on the other end will remain alive.
rockotf59d2d62017-04-01 02:49:08902
Oksana Zhuravlovad5888c92019-08-23 19:43:06903### Receiver Sets
rockotf59d2d62017-04-01 02:49:08904
905Sometimes it's useful to share a single implementation instance with multiple
Oksana Zhuravlovad5888c92019-08-23 19:43:06906clients. [**`ReceiverSet`**](https://cs.chromium.org/chromium/src/mojo/public/cpp/bindings/receiver_set.h)
rockotf59d2d62017-04-01 02:49:08907makes this easy. Consider the Mojom:
908
909``` cpp
910module system.mojom;
911
912interface Logger {
913 Log(string message);
914};
915
916interface LoggerProvider {
917 GetLogger(Logger& logger);
918};
919```
920
Oksana Zhuravlovad5888c92019-08-23 19:43:06921We can use `ReceiverSet` to bind multiple `Logger` pending receivers to a single
rockotf59d2d62017-04-01 02:49:08922implementation instance:
923
924``` cpp
925class LogManager : public system::mojom::LoggerProvider,
926 public system::mojom::Logger {
927 public:
Oksana Zhuravlovad5888c92019-08-23 19:43:06928 explicit LogManager(mojo::PendingReceiver<system::mojom::LoggerProvider> receiver)
929 : provider_receiver_(this, std::move(receiver)) {}
rockotf59d2d62017-04-01 02:49:08930 ~LogManager() {}
931
932 // system::mojom::LoggerProvider:
Oksana Zhuravlovad5888c92019-08-23 19:43:06933 void GetLogger(mojo::PendingReceiver<Logger> receiver) override {
934 logger_receivers_.Add(this, std::move(receiver));
rockotf59d2d62017-04-01 02:49:08935 }
936
937 // system::mojom::Logger:
938 void Log(const std::string& message) override {
939 LOG(ERROR) << "[Logger] " << message;
940 }
941
942 private:
Oksana Zhuravlovad5888c92019-08-23 19:43:06943 mojo::Receiver<system::mojom::LoggerProvider> provider_receiver_;
944 mojo::ReceiverSet<system::mojom::Logger> logger_receivers_;
rockotf59d2d62017-04-01 02:49:08945};
946
947```
948
949
Oksana Zhuravlovad5888c92019-08-23 19:43:06950### Remote Sets
rockotf59d2d62017-04-01 02:49:08951
Oksana Zhuravlovad5888c92019-08-23 19:43:06952Similar to the `ReceiverSet` above, sometimes it's useful to maintain a set of
953`Remote`s for *e.g.* a set of clients observing some event.
954[**`RemoteSet`**](https://cs.chromium.org/chromium/src/mojo/public/cpp/bindings/remote_set.h)
rockotf59d2d62017-04-01 02:49:08955is here to help. Take the Mojom:
956
957``` cpp
958module db.mojom;
959
960interface TableListener {
961 OnRowAdded(int32 key, string data);
962};
963
964interface Table {
965 AddRow(int32 key, string data);
Oksana Zhuravlovad5888c92019-08-23 19:43:06966 AddListener(pending_remote<TableListener> listener);
rockotf59d2d62017-04-01 02:49:08967};
968```
969
970An implementation of `Table` might look something like like this:
971
972``` cpp
973class TableImpl : public db::mojom::Table {
974 public:
975 TableImpl() {}
976 ~TableImpl() override {}
977
978 // db::mojom::Table:
979 void AddRow(int32_t key, const std::string& data) override {
980 rows_.insert({key, data});
981 listeners_.ForEach([key, &data](db::mojom::TableListener* listener) {
982 listener->OnRowAdded(key, data);
983 });
984 }
985
Oksana Zhuravlovad5888c92019-08-23 19:43:06986 void AddListener(mojo::PendingRemote<db::mojom::TableListener> listener) {
987 listeners_.Add(std::move(listener));
rockotf59d2d62017-04-01 02:49:08988 }
989
990 private:
Oksana Zhuravlovad5888c92019-08-23 19:43:06991 mojo::RemoteSet<db::mojom::Table> listeners_;
rockotf59d2d62017-04-01 02:49:08992 std::map<int32_t, std::string> rows_;
993};
994```
995
996## Associated Interfaces
997
Chase Phillips3f76e152018-07-18 20:45:26998Associated interfaces are interfaces which:
rockotf59d2d62017-04-01 02:49:08999
Chase Phillips3f76e152018-07-18 20:45:261000* enable running multiple interfaces over a single message pipe while
1001 preserving message ordering.
Oksana Zhuravlovad5888c92019-08-23 19:43:061002* make it possible for the receiver to access a single message pipe from
Chase Phillips3f76e152018-07-18 20:45:261003 multiple sequences.
1004
1005### Mojom
1006
David Bokane59ea1f42020-08-04 14:40:211007New types `pending_associated_remote` and `pending_associated_receiver` are
1008introduced for remote/receiver fields. For example:
Chase Phillips3f76e152018-07-18 20:45:261009
1010``` cpp
1011interface Bar {};
1012
1013struct Qux {
David Bokane59ea1f42020-08-04 14:40:211014 pending_associated_remote<Bar> bar;
Chase Phillips3f76e152018-07-18 20:45:261015};
1016
1017interface Foo {
Oksana Zhuravlovad5888c92019-08-23 19:43:061018 // Uses associated remote.
David Bokane59ea1f42020-08-04 14:40:211019 PassBarRemote(pending_associated_remote<Bar> bar);
Oksana Zhuravlovad5888c92019-08-23 19:43:061020 // Uses associated receiver.
David Bokane59ea1f42020-08-04 14:40:211021 PassBarReceiver(pending_associated_receiver<Bar> bar);
Chase Phillips3f76e152018-07-18 20:45:261022 // Passes a struct with associated interface pointer.
1023 PassQux(Qux qux);
1024 // Uses associated interface pointer in callback.
David Bokane59ea1f42020-08-04 14:40:211025 AsyncGetBar() => (pending_associated_remote<Bar> bar);
Chase Phillips3f76e152018-07-18 20:45:261026};
1027```
1028
David Bokane59ea1f42020-08-04 14:40:211029In each case the interface impl/client will communicate using the same message
1030pipe over which the associated remote/receiver is passed.
Chase Phillips3f76e152018-07-18 20:45:261031
1032### Using associated interfaces in C++
1033
Oksana Zhuravlovad5888c92019-08-23 19:43:061034When generating C++ bindings, the pending_associated_remote of `Bar` is
1035mapped to `mojo::PendingAssociatedRemote<Bar>`; pending_associated_receiver to
1036`mojo::PendingAssociatedReceiver<Bar>`.
Chase Phillips3f76e152018-07-18 20:45:261037
1038``` cpp
1039// In mojom:
1040interface Foo {
1041 ...
David Bokane59ea1f42020-08-04 14:40:211042 PassBarRemote(pending_associated_remote<Bar> bar);
1043 PassBarReceiver(pending_associated_receiver<Bar> bar);
Chase Phillips3f76e152018-07-18 20:45:261044 ...
1045};
1046
1047// In C++:
1048class Foo {
1049 ...
David Bokane59ea1f42020-08-04 14:40:211050 virtual void PassBarRemote(mojo::PendingAssociatedRemote<Bar> bar) = 0;
1051 virtual void PassBarReceiver(mojo::PendingAssociatedReceiver<Bar> bar) = 0;
Chase Phillips3f76e152018-07-18 20:45:261052 ...
1053};
1054```
1055
Oksana Zhuravlovad5888c92019-08-23 19:43:061056#### Passing pending associated receivers
Chase Phillips3f76e152018-07-18 20:45:261057
David Bokane59ea1f42020-08-04 14:40:211058Assume you already have a `Remote<Foo> foo`, and you would like to call
1059`PassBarReceiver()` on it. You can do:
Chase Phillips3f76e152018-07-18 20:45:261060
1061``` cpp
Oksana Zhuravlovad5888c92019-08-23 19:43:061062mojo::PendingAssociatedRemote<Bar> pending_bar;
1063mojo::PendingAssociatedReceiver<Bar> bar_receiver = pending_bar.InitWithNewEndpointAndPassReceiver();
David Bokane59ea1f42020-08-04 14:40:211064foo->PassBarReceiver(std::move(bar_receiver));
Chase Phillips3f76e152018-07-18 20:45:261065
Oksana Zhuravlovad5888c92019-08-23 19:43:061066mojo::AssociatedRemote<Bar> bar;
1067bar.Bind(std::move(pending_bar));
1068bar->DoSomething();
Chase Phillips3f76e152018-07-18 20:45:261069```
1070
1071First, the code creates an associated interface of type `Bar`. It looks very
1072similar to what you would do to setup a non-associated interface. An
1073important difference is that one of the two associated endpoints (either
Oksana Zhuravlovad5888c92019-08-23 19:43:061074`bar_receiver` or `pending_bar`) must be sent over another interface. That is
Chase Phillips3f76e152018-07-18 20:45:261075how the interface is associated with an existing message pipe.
1076
Oksana Zhuravlovad5888c92019-08-23 19:43:061077It should be noted that you cannot call `bar->DoSomething()` before passing
1078`bar_receiver`. This is required by the FIFO-ness guarantee: at the receiver
Chase Phillips3f76e152018-07-18 20:45:261079side, when the message of `DoSomething` call arrives, we want to dispatch it to
Oksana Zhuravlovad5888c92019-08-23 19:43:061080the corresponding `AssociatedReceiver<Bar>` before processing any subsequent
1081messages. If `bar_receiver` is in a subsequent message, message dispatching gets
1082into a deadlock. On the other hand, as soon as `bar_receiver` is sent, `bar`
1083is usable. There is no need to wait until `bar_receiver` is bound to an
Chase Phillips3f76e152018-07-18 20:45:261084implementation at the remote side.
1085
Oksana Zhuravlovad5888c92019-08-23 19:43:061086`AssociatedRemote` provides a `BindNewEndpointAndPassReceiver` method
1087to make the code a little shorter. The following code achieves the same purpose:
Chase Phillips3f76e152018-07-18 20:45:261088
1089``` cpp
Oksana Zhuravlovad5888c92019-08-23 19:43:061090mojo::AssociatedRemote<Bar> bar;
David Bokane59ea1f42020-08-04 14:40:211091foo->PassBarReceiver(bar.BindNewEndpointAndPassReceiver());
Oksana Zhuravlovad5888c92019-08-23 19:43:061092bar->DoSomething();
Chase Phillips3f76e152018-07-18 20:45:261093```
1094
1095The implementation of `Foo` looks like this:
1096
1097``` cpp
1098class FooImpl : public Foo {
1099 ...
David Bokane59ea1f42020-08-04 14:40:211100 void PassBarReceiver(mojo::AssociatedReceiver<Bar> bar) override {
1101 bar_receiver_.Bind(std::move(bar));
Chase Phillips3f76e152018-07-18 20:45:261102 ...
1103 }
1104 ...
1105
Oksana Zhuravlovad5888c92019-08-23 19:43:061106 Receiver<Foo> foo_receiver_;
1107 AssociatedReceiver<Bar> bar_receiver_;
Chase Phillips3f76e152018-07-18 20:45:261108};
1109```
1110
Oksana Zhuravlovad5888c92019-08-23 19:43:061111In this example, `bar_receiver_`'s lifespan is tied to that of `FooImpl`. But you
Chase Phillips3f76e152018-07-18 20:45:261112don't have to do that. You can, for example, pass `bar2` to another sequence to
Oksana Zhuravlovad5888c92019-08-23 19:43:061113bind to an `AssociatedReceiver<Bar>` there.
Chase Phillips3f76e152018-07-18 20:45:261114
Oksana Zhuravlovad5888c92019-08-23 19:43:061115When the underlying message pipe is disconnected (e.g., `foo` or
1116`foo_receiver_` is destroyed), all associated interface endpoints (e.g.,
1117`bar` and `bar_receiver_`) will receive a disconnect error.
Chase Phillips3f76e152018-07-18 20:45:261118
Oksana Zhuravlovad5888c92019-08-23 19:43:061119#### Passing associated remotes
Chase Phillips3f76e152018-07-18 20:45:261120
Oksana Zhuravlovad5888c92019-08-23 19:43:061121Similarly, assume you have already got an `Remote<Foo> foo`, and you
David Bokane59ea1f42020-08-04 14:40:211122would like to call `PassBarRemote()` on it. You can do:
Chase Phillips3f76e152018-07-18 20:45:261123
1124``` cpp
Oksana Zhuravlovad5888c92019-08-23 19:43:061125mojo::AssociatedReceiver<Bar> bar_receiver(some_bar_impl);
1126mojo::PendingAssociatedRemote<Bar> bar;
1127mojo::PendingAssociatedReceiver<Bar> bar_pending_receiver = bar.InitWithNewEndpointAndPassReceiver();
David Bokane59ea1f42020-08-04 14:40:211128foo->PassBarRemote(std::move(bar));
Oksana Zhuravlovad5888c92019-08-23 19:43:061129bar_receiver.Bind(std::move(bar_pending_receiver));
Chase Phillips3f76e152018-07-18 20:45:261130```
1131
1132The following code achieves the same purpose:
1133
1134``` cpp
Oksana Zhuravlovad5888c92019-08-23 19:43:061135mojo::AssociatedReceiver<Bar> bar_receiver(some_bar_impl);
1136mojo::PendingAssociatedRemote<Bar> bar;
1137bar_receiver.Bind(bar.InitWithNewPipeAndPassReceiver());
David Bokane59ea1f42020-08-04 14:40:211138foo->PassBarRemote(std::move(bar));
Chase Phillips3f76e152018-07-18 20:45:261139```
1140
1141### Performance considerations
1142
Ken Rockotcd23f752020-06-20 01:22:311143When using associated interfaces on different sequences than the primary
1144sequence (where the primary interface lives):
Chase Phillips3f76e152018-07-18 20:45:261145
1146* Sending messages: send happens directly on the calling sequence. So there
1147 isn't sequence hopping.
1148* Receiving messages: associated interfaces bound on a different sequence from
Ken Rockotcd23f752020-06-20 01:22:311149 the primary interface incur an extra sequence hop during dispatch.
Chase Phillips3f76e152018-07-18 20:45:261150
1151Therefore, performance-wise associated interfaces are better suited for
Ken Rockotcd23f752020-06-20 01:22:311152scenarios where message receiving happens on the primary sequence.
Chase Phillips3f76e152018-07-18 20:45:261153
1154### Testing
1155
Ken Rockotcd23f752020-06-20 01:22:311156Associated interfaces need to be associated with a primary interface before
Chase Phillips3f76e152018-07-18 20:45:261157they can be used. This means one end of the associated interface must be sent
Ken Rockotcd23f752020-06-20 01:22:311158over one end of the primary interface, or over one end of another associated
1159interface which itself already has a primary interface.
Chase Phillips3f76e152018-07-18 20:45:261160
1161If you want to test an associated interface endpoint without first
Gyuyoung Kim7dd486c2020-09-15 01:47:181162associating it, you can use `AssociatedRemote::BindNewEndpointAndPassDedicatedReceiver`.
Oksana Zhuravlovad5888c92019-08-23 19:43:061163This will create working associated interface endpoints which are not actually
Adithya Srinivasan4b6c6082018-11-14 16:56:461164associated with anything else.
Chase Phillips3f76e152018-07-18 20:45:261165
1166### Read more
1167
1168* [Design: Mojo Associated Interfaces](https://docs.google.com/document/d/1nq3J_HbS-gvVfIoEhcVyxm1uY-9G_7lhD-4Kyxb1WIY/edit)
rockotf59d2d62017-04-01 02:49:081169
1170## Synchronous Calls
1171
Oksana Zhuravlova50bac902019-01-15 00:17:591172### Think carefully before you decide to use sync calls
rockotf59d2d62017-04-01 02:49:081173
Oksana Zhuravlova50bac902019-01-15 00:17:591174Although sync calls are convenient, you should avoid them whenever they
1175are not absolutely necessary:
1176
1177* Sync calls hurt parallelism and therefore hurt performance.
1178* Re-entrancy changes message order and produces call stacks that you
1179probably never think about while you are coding. It has always been a
1180huge pain.
1181* Sync calls may lead to deadlocks.
1182
1183### Mojom changes
1184
1185A new attribute `[Sync]` (or `[Sync=true]`) is introduced for methods.
1186For example:
1187
1188``` cpp
1189interface Foo {
1190 [Sync]
1191 SomeSyncCall() => (Bar result);
1192};
1193```
1194
1195It indicates that when `SomeSyncCall()` is called, the control flow of
1196the calling thread is blocked until the response is received.
1197
1198It is not allowed to use this attribute with functions that don’t have
1199responses. If you just need to wait until the service side finishes
1200processing the call, you can use an empty response parameter list:
1201
1202``` cpp
1203[Sync]
1204SomeSyncCallWithNoResult() => ();
1205```
1206
1207### Generated bindings (C++)
1208
1209The generated C++ interface of the Foo interface above is:
1210
1211``` cpp
1212class Foo {
1213 public:
1214 // The service side implements this signature. The client side can
1215 // also use this signature if it wants to call the method asynchronously.
1216 virtual void SomeSyncCall(SomeSyncCallCallback callback) = 0;
1217
1218 // The client side uses this signature to call the method synchronously.
1219 virtual bool SomeSyncCall(BarPtr* result);
1220};
1221```
1222
1223As you can see, the client side and the service side use different
1224signatures. At the client side, response is mapped to output parameters
1225and the boolean return value indicates whether the operation is
1226successful. (Returning false usually means a connection error has
1227occurred.)
1228
1229At the service side, a signature with callback is used. The reason is
1230that in some cases the implementation may need to do some asynchronous
1231work which the sync method’s result depends on.
1232
1233*** note
1234**NOTE:** you can also use the signature with callback at the client side to
1235call the method asynchronously.
1236***
1237
1238### Re-entrancy
1239
1240What happens on the calling thread while waiting for the response of a
1241sync method call? It continues to process incoming sync request messages
1242(i.e., sync method calls); block other messages, including async
1243messages and sync response messages that don’t match the ongoing sync
1244call.
1245
Ken Rockotab035122019-02-06 00:35:241246![Diagram illustrating sync call flow](/docs/images/mojo_sync_call_flow.png)
Oksana Zhuravlova50bac902019-01-15 00:17:591247
1248Please note that sync response messages that don’t match the ongoing
1249sync call cannot re-enter. That is because they correspond to sync calls
1250down in the call stack. Therefore, they need to be queued and processed
1251while the stack unwinds.
1252
1253### Avoid deadlocks
1254
1255Please note that the re-entrancy behavior doesn’t prevent deadlocks
1256involving async calls. You need to avoid call sequences such as:
1257
Ken Rockotab035122019-02-06 00:35:241258![Diagram illustrating a sync call deadlock](/docs/images/mojo_sync_call_deadlock.png)
Oksana Zhuravlova50bac902019-01-15 00:17:591259
1260### Read more
1261
1262* [Design Proposal: Mojo Sync Methods](
1263https://docs.google.com/document/d/1dixzFzZQW8e3ldjdM8Adbo8klXDDE4pVekwo5aLgUsE)
rockotf59d2d62017-04-01 02:49:081264
1265## Type Mapping
1266
1267In many instances you might prefer that your generated C++ bindings use a more
1268natural type to represent certain Mojom types in your interface methods. For one
1269example consider a Mojom struct such as the `Rect` below:
1270
1271``` cpp
1272module gfx.mojom;
1273
1274struct Rect {
1275 int32 x;
1276 int32 y;
1277 int32 width;
1278 int32 height;
1279};
1280
1281interface Canvas {
1282 void FillRect(Rect rect);
1283};
1284```
1285
1286The `Canvas` Mojom interface would normally generate a C++ interface like:
1287
1288``` cpp
1289class Canvas {
1290 public:
1291 virtual void FillRect(RectPtr rect) = 0;
1292};
1293```
1294
1295However, the Chromium tree already defines a native
1296[`gfx::Rect`](https://cs.chromium.org/chromium/src/ui/gfx/geometry/rect.h) which
1297is equivalent in meaning but which also has useful helper methods. Instead of
1298manually converting between a `gfx::Rect` and the Mojom-generated `RectPtr` at
1299every message boundary, wouldn't it be nice if the Mojom bindings generator
1300could instead generate:
1301
1302``` cpp
1303class Canvas {
1304 public:
1305 virtual void FillRect(const gfx::Rect& rect) = 0;
1306}
1307```
1308
1309The correct answer is, "Yes! That would be nice!" And fortunately, it can!
1310
rockotf59d2d62017-04-01 02:49:081311### Defining `StructTraits`
1312
1313In order to teach generated bindings code how to serialize an arbitrary native
1314type `T` as an arbitrary Mojom type `mojom::U`, we need to define an appropriate
1315specialization of the
1316[`mojo::StructTraits`](https://cs.chromium.org/chromium/src/mojo/public/cpp/bindings/struct_traits.h)
1317template.
1318
1319A valid specialization of `StructTraits` MUST define the following static
1320methods:
1321
1322* A single static accessor for every field of the Mojom struct, with the exact
Ken Rockot74de8b82020-03-10 00:50:201323 same name as the struct field. These accessors must all take a (preferably
1324 const) ref to an object of the native type, and must return a value compatible
1325 with the Mojom struct field's type. This is used to safely and consistently
1326 extract data from the native type during message serialization without
1327 incurring extra copying costs.
rockotf59d2d62017-04-01 02:49:081328
1329* A single static `Read` method which initializes an instance of the the native
1330 type given a serialized representation of the Mojom struct. The `Read` method
1331 must return a `bool` to indicate whether the incoming data is accepted
1332 (`true`) or rejected (`false`).
1333
rockotf59d2d62017-04-01 02:49:081334In order to define the mapping for `gfx::Rect`, we want the following
1335`StructTraits` specialization, which we'll define in
Stephen Nusko0ea37f3d2019-02-17 01:45:191336`//ui/gfx/geometry/mojo/geometry_mojom_traits.h`:
rockotf59d2d62017-04-01 02:49:081337
1338``` cpp
Stephen Nusko0ea37f3d2019-02-17 01:45:191339#include "mojo/public/cpp/bindings/mojom_traits.h"
rockotf59d2d62017-04-01 02:49:081340#include "ui/gfx/geometry/rect.h"
1341#include "ui/gfx/geometry/mojo/geometry.mojom.h"
1342
1343namespace mojo {
1344
1345template <>
1346class StructTraits<gfx::mojom::RectDataView, gfx::Rect> {
1347 public:
1348 static int32_t x(const gfx::Rect& r) { return r.x(); }
1349 static int32_t y(const gfx::Rect& r) { return r.y(); }
1350 static int32_t width(const gfx::Rect& r) { return r.width(); }
1351 static int32_t height(const gfx::Rect& r) { return r.height(); }
1352
1353 static bool Read(gfx::mojom::RectDataView data, gfx::Rect* out_rect);
1354};
1355
1356} // namespace mojo
1357```
1358
Stephen Nusko0ea37f3d2019-02-17 01:45:191359And in `//ui/gfx/geometry/mojo/geometry_mojom_traits.cc`:
rockotf59d2d62017-04-01 02:49:081360
1361``` cpp
Stephen Nusko0ea37f3d2019-02-17 01:45:191362#include "ui/gfx/geometry/mojo/geometry_mojom_traits.h"
rockotf59d2d62017-04-01 02:49:081363
1364namespace mojo {
1365
1366// static
rockotf59d2d62017-04-01 02:49:081367bool StructTraits<gfx::mojom::RectDataView, gfx::Rect>::Read(
1368 gfx::mojom::RectDataView data,
1369 gfx::Rect* out_rect) {
1370 if (data.width() < 0 || data.height() < 0)
1371 return false;
1372
1373 out_rect->SetRect(data.x(), data.y(), data.width(), data.height());
1374 return true;
1375};
1376
1377} // namespace mojo
1378```
1379
1380Note that the `Read()` method returns `false` if either the incoming `width` or
1381`height` fields are negative. This acts as a validation step during
1382deserialization: if a client sends a `gfx::Rect` with a negative width or
1383height, its message will be rejected and the pipe will be closed. In this way,
1384type mapping can serve to enable custom validation logic in addition to making
1385callsites and interface implemention more convenient.
1386
Oksana Zhuravlova4b594672018-11-06 21:58:251387When the struct fields have non-primitive types, e.g. string or array,
1388returning a read-only view of the data in the accessor is recommended to
1389avoid copying. It is safe because the input object is guaranteed to
1390outlive the usage of the result returned by the accessor method.
1391
1392The following example uses `StringPiece` to return a view of the GURL's
1393data (`//url/mojom/url_gurl_mojom_traits.h`):
1394
1395``` cpp
1396#include "base/strings/string_piece.h"
1397#include "url/gurl.h"
1398#include "url/mojom/url.mojom.h"
1399#include "url/url_constants.h"
1400
1401namespace mojo {
1402
1403template <>
1404struct StructTraits<url::mojom::UrlDataView, GURL> {
1405 static base::StringPiece url(const GURL& r) {
1406 if (r.possibly_invalid_spec().length() > url::kMaxURLChars ||
1407 !r.is_valid()) {
1408 return base::StringPiece();
1409 }
1410 return base::StringPiece(r.possibly_invalid_spec().c_str(),
1411 r.possibly_invalid_spec().length());
1412 }
1413} // namespace mojo
1414```
1415
rockotf59d2d62017-04-01 02:49:081416### Enabling a New Type Mapping
1417
1418We've defined the `StructTraits` necessary, but we still need to teach the
1419bindings generator (and hence the build system) about the mapping. To do this we
Ken Rockot6ddaf0e2020-03-18 19:49:191420must add some more information to our `mojom` target in GN:
rockotf59d2d62017-04-01 02:49:081421
1422```
Ken Rockot6ddaf0e2020-03-18 19:49:191423# Without a typemap
Ken Rockot74de8b82020-03-10 00:50:201424mojom("mojom") {
1425 sources = [
1426 "rect.mojom",
Ken Rockot6ddaf0e2020-03-18 19:49:191427 ]
1428}
1429
1430# With a typemap.
1431mojom("mojom") {
1432 sources = [
1433 "rect.mojom",
Ken Rockot74de8b82020-03-10 00:50:201434 ]
1435
Ken Rockot6ddaf0e2020-03-18 19:49:191436 cpp_typemaps = [
1437 {
1438 # NOTE: A single typemap entry can list multiple individual type mappings.
1439 # Each mapping assumes the same values for |traits_headers| etc below.
1440 #
1441 # To typemap a type with separate |traits_headers| etc, add a separate
1442 # entry to |cpp_typemaps|.
1443 types = [
1444 {
1445 mojom = "gfx.mojom.Rect"
1446 cpp = "::gfx::Rect"
1447 },
1448 ]
1449 traits_headers = [ "//ui/gfx/geometry/mojo/geometry_mojom_traits.h" ]
1450 traits_sources = [ "//ui/gfx/geometry/mojo/geometry_mojom_traits.cc" ]
1451 traits_public_deps = [ "//ui/gfx/geometry" ]
1452 },
1453 ]
Ken Rockot74de8b82020-03-10 00:50:201454}
rockotf59d2d62017-04-01 02:49:081455```
1456
Ken Rockot6ddaf0e2020-03-18 19:49:191457See typemap documentation in
1458[mojom.gni](https://cs.chromium.org/chromium/src/mojo/public/tools/bindings/mojom.gni)
1459for details on the above definition and other supported parameters.
1460
1461With this extra configuration present, any mojom references to `gfx.mojom.Rect`
1462(e.g. for method parameters or struct fields) will be `gfx::Rect` references in
1463generated C++ code.
Ken Rockot6ddaf0e2020-03-18 19:49:191464
Ken Rockot74de8b82020-03-10 00:50:201465For the Blink variant of bindings, add to the `blink_cpp_typemaps` list instead.
1466
1467### Type Mapping Without `traits_sources`
1468
Ken Rockot6ddaf0e2020-03-18 19:49:191469Using `traits_sources` in a typemap configuration means that the listed sources
1470will be baked directly into the corresponding `mojom` target's own sources. This
1471can be problematic if you want to use the same typemap for both Blink and
1472non-Blink bindings.
Ken Rockot74de8b82020-03-10 00:50:201473
1474For such cases, it is recommended that you define a separate `component` target
Ken Rockot6ddaf0e2020-03-18 19:49:191475for your typemap traits, and reference this in the `traits_public_deps` of the
1476typemap:
rockotf59d2d62017-04-01 02:49:081477
1478```
Ken Rockot6ddaf0e2020-03-18 19:49:191479mojom("mojom") {
1480 sources = [
1481 "rect.mojom",
1482 ]
1483
1484 cpp_typemaps = [
1485 {
1486 types = [
1487 {
1488 mojom = "gfx.mojom.Rect"
1489 cpp = "::gfx::Rect"
1490 },
1491 ]
1492 traits_headers = [ "//ui/gfx/geometry/mojo/geometry_mojom_traits.h" ]
1493 traits_public_deps = [ ":geometry_mojom_traits" ]
1494 },
1495 ]
1496}
1497
Ken Rockot74de8b82020-03-10 00:50:201498component("geometry_mojom_traits") {
1499 sources = [
1500 "//ui/gfx/geometry/mojo/geometry_mojom_traits.cc",
1501 "//ui/gfx/geometry/mojo/geometry_mojom_traits.h",
1502 ]
1503
1504 # The header of course needs corresponding COMPONENT_EXPORT() tags.
1505 defines = [ "IS_GEOMETRY_MOJOM_TRAITS_IMPL" ]
Ken Rockot74de8b82020-03-10 00:50:201506}
rockotf59d2d62017-04-01 02:49:081507```
1508
1509### StructTraits Reference
1510
1511Each of a `StructTraits` specialization's static getter methods -- one per
1512struct field -- must return a type which can be used as a data source for the
1513field during serialization. This is a quick reference mapping Mojom field type
1514to valid getter return types:
1515
1516| Mojom Field Type | C++ Getter Return Type |
1517|------------------------------|------------------------|
1518| `bool` | `bool`
1519| `int8` | `int8_t`
1520| `uint8` | `uint8_t`
1521| `int16` | `int16_t`
1522| `uint16` | `uint16_t`
1523| `int32` | `int32_t`
1524| `uint32` | `uint32_t`
1525| `int64` | `int64_t`
1526| `uint64` | `uint64_t`
1527| `float` | `float`
1528| `double` | `double`
1529| `handle` | `mojo::ScopedHandle`
1530| `handle<message_pipe>` | `mojo::ScopedMessagePipeHandle`
1531| `handle<data_pipe_consumer>` | `mojo::ScopedDataPipeConsumerHandle`
1532| `handle<data_pipe_producer>` | `mojo::ScopedDataPipeProducerHandle`
1533| `handle<shared_buffer>` | `mojo::ScopedSharedBufferHandle`
Oksana Zhuravlovad5888c92019-08-23 19:43:061534| `pending_remote<Foo>` | `mojo::PendingRemote<Foo>`
1535| `pending_receiver<Foo>` | `mojo::PendingReceiver<Foo>`
1536| `pending_associated_remote<Foo>` | `mojo::PendingAssociatedRemote<Foo>`
1537| `pending_associated_receiver<Foo>` | `mojo::PendingAssociatedReceiver<Foo>`
rockotf59d2d62017-04-01 02:49:081538| `string` | Value or reference to any type `T` that has a `mojo::StringTraits` specialization defined. By default this includes `std::string`, `base::StringPiece`, and `WTF::String` (Blink).
1539| `array<T>` | Value or reference to any type `T` that has a `mojo::ArrayTraits` specialization defined. By default this includes `std::vector<T>`, `mojo::CArray<T>`, and `WTF::Vector<T>` (Blink).
1540| `map<K, V>` | Value or reference to any type `T` that has a `mojo::MapTraits` specialization defined. By default this includes `std::map<T>`, `mojo::unordered_map<T>`, and `WTF::HashMap<T>` (Blink).
1541| `FooEnum` | Value of any type that has an appropriate `EnumTraits` specialization defined. By default this inlcudes only the generated `FooEnum` type.
1542| `FooStruct` | Value or reference to any type that has an appropriate `StructTraits` specialization defined. By default this includes only the generated `FooStructPtr` type.
1543| `FooUnion` | Value of reference to any type that has an appropriate `UnionTraits` specialization defined. By default this includes only the generated `FooUnionPtr` type.
Ryan Sleevi9353d6dc2019-08-29 16:47:341544| `Foo?` | `base::Optional<CppType>`, where `CppType` is the value type defined by the appropriate traits class specialization (e.g. `StructTraits`, `mojo::MapTraits`, etc.). This may be customized by the [typemapping](#Enabling-a-New-Type-Mapping).
rockotf59d2d62017-04-01 02:49:081545
1546### Using Generated DataView Types
1547
1548Static `Read` methods on `StructTraits` specializations get a generated
1549`FooDataView` argument (such as the `RectDataView` in the example above) which
1550exposes a direct view of the serialized Mojom structure within an incoming
1551message's contents. In order to make this as easy to work with as possible, the
1552generated `FooDataView` types have a generated method corresponding to every
1553struct field:
1554
1555* For POD field types (*e.g.* bools, floats, integers) these are simple accessor
1556 methods with names identical to the field name. Hence in the `Rect` example we
1557 can access things like `data.x()` and `data.width()`. The return types
1558 correspond exactly to the mappings listed in the table above, under
1559 [StructTraits Reference](#StructTraits-Reference).
1560
Oksana Zhuravlovad5888c92019-08-23 19:43:061561* For handle and interface types (*e.g* `handle` or `pending_remote<Foo>`) these
rockotf59d2d62017-04-01 02:49:081562 are named `TakeFieldName` (for a field named `field_name`) and they return an
1563 appropriate move-only handle type by value. The return types correspond
1564 exactly to the mappings listed in the table above, under
1565 [StructTraits Reference](#StructTraits-Reference).
1566
1567* For all other field types (*e.g.*, enums, strings, arrays, maps, structs)
1568 these are named `ReadFieldName` (for a field named `field_name`) and they
1569 return a `bool` (to indicate success or failure in reading). On success they
1570 fill their output argument with the deserialized field value. The output
1571 argument may be a pointer to any type with an appropriate `StructTraits`
1572 specialization defined, as mentioned in the table above, under
1573 [StructTraits Reference](#StructTraits-Reference).
1574
1575An example would be useful here. Suppose we introduced a new Mojom struct:
1576
1577``` cpp
1578struct RectPair {
1579 Rect left;
1580 Rect right;
1581};
1582```
1583
1584and a corresponding C++ type:
1585
1586``` cpp
1587class RectPair {
1588 public:
1589 RectPair() {}
1590
1591 const gfx::Rect& left() const { return left_; }
1592 const gfx::Rect& right() const { return right_; }
1593
1594 void Set(const gfx::Rect& left, const gfx::Rect& right) {
1595 left_ = left;
1596 right_ = right;
1597 }
1598
1599 // ... some other stuff
1600
1601 private:
1602 gfx::Rect left_;
1603 gfx::Rect right_;
1604};
1605```
1606
1607Our traits to map `gfx::mojom::RectPair` to `gfx::RectPair` might look like
1608this:
1609
1610``` cpp
1611namespace mojo {
1612
1613template <>
1614class StructTraits
1615 public:
1616 static const gfx::Rect& left(const gfx::RectPair& pair) {
1617 return pair.left();
1618 }
1619
1620 static const gfx::Rect& right(const gfx::RectPair& pair) {
1621 return pair.right();
1622 }
1623
1624 static bool Read(gfx::mojom::RectPairDataView data, gfx::RectPair* out_pair) {
1625 gfx::Rect left, right;
1626 if (!data.ReadLeft(&left) || !data.ReadRight(&right))
1627 return false;
1628 out_pair->Set(left, right);
1629 return true;
1630 }
1631} // namespace mojo
1632```
1633
1634Generated `ReadFoo` methods always convert `multi_word_field_name` fields to
1635`ReadMultiWordFieldName` methods.
1636
Andrew Moylan341cece72017-06-22 22:03:021637<a name="Blink-Type-Mapping"></a>
rockotf59d2d62017-04-01 02:49:081638### Variants
1639
1640By now you may have noticed that additional C++ sources are generated when a
1641Mojom is processed. These exist due to type mapping, and the source files we
1642refer to throughout this docuemnt (namely `foo.mojom.cc` and `foo.mojom.h`) are
1643really only one **variant** (the *default* or *chromium* variant) of the C++
1644bindings for a given Mojom file.
1645
1646The only other variant currently defined in the tree is the *blink* variant,
1647which produces a few additional files:
1648
1649```
1650out/gen/sample/db.mojom-blink.cc
1651out/gen/sample/db.mojom-blink.h
1652```
1653
1654These files mirror the definitions in the default variant but with different
1655C++ types in place of certain builtin field and parameter types. For example,
1656Mojom strings are represented by `WTF::String` instead of `std::string`. To
1657avoid symbol collisions, the variant's symbols are nested in an extra inner
1658namespace, so Blink consumer of the interface might write something like:
1659
1660```
1661#include "sample/db.mojom-blink.h"
1662
1663class TableImpl : public db::mojom::blink::Table {
1664 public:
1665 void AddRow(int32_t key, const WTF::String& data) override {
1666 // ...
1667 }
1668};
1669```
1670
1671In addition to using different C++ types for builtin strings, arrays, and maps,
Ken Rockot74de8b82020-03-10 00:50:201672the custom typemaps applied to Blink bindings are managed separately from
1673regular bindings.
rockotf59d2d62017-04-01 02:49:081674
Ken Rockot74de8b82020-03-10 00:50:201675`mojom` targets support a `blink_cpp_typemaps` parameter in addition to the
1676regular `cpp_typemaps`. This lists the typemaps to apply to Blink bindings.
1677
1678To depend specifically on generated Blink bindings, reference
1679`${target_name}_blink`. So for example, with the definition:
1680
1681```
1682# In //foo/mojom
1683mojom("mojom") {
1684 sources = [
1685 "db.mojom",
1686 ]
1687}
1688```
1689
1690C++ sources can depend on the Blink bindings by depending on
1691`"//foo/mojom:mojom_blink"`.
1692
1693Finally note that both bindings variants share some common definitions which are
1694unaffected by differences in the type-mapping configuration (like enums, and
1695structures describing serialized object formats). These definitions are
1696generated in *shared* sources:
rockotf59d2d62017-04-01 02:49:081697
1698```
1699out/gen/sample/db.mojom-shared.cc
1700out/gen/sample/db.mojom-shared.h
1701out/gen/sample/db.mojom-shared-internal.h
1702```
1703
1704Including either variant's header (`db.mojom.h` or `db.mojom-blink.h`)
Andrew Moylan341cece72017-06-22 22:03:021705implicitly includes the shared header, but may wish to include *only* the shared
1706header in some instances.
rockotf59d2d62017-04-01 02:49:081707
Ken Rockot74de8b82020-03-10 00:50:201708C++ sources can depend on shared sources only, by referencing the
1709`"${target_name}_shared"` target, e.g. `"//foo/mojom:mojom_shared"` in the
1710example above.
rockotf59d2d62017-04-01 02:49:081711
1712## Versioning Considerations
1713
1714For general documentation of versioning in the Mojom IDL see
David Benjamin0ff61822019-04-29 19:00:051715[Versioning](/mojo/public/tools/bindings/README.md#Versioning).
rockotf59d2d62017-04-01 02:49:081716
1717This section briefly discusses some C++-specific considerations relevant to
1718versioned Mojom types.
1719
1720### Querying Interface Versions
1721
Oksana Zhuravlovad5888c92019-08-23 19:43:061722`Remote` defines the following methods to query or assert remote interface
rockotf59d2d62017-04-01 02:49:081723version:
1724
1725```cpp
Anand K. Mistryff664b72019-11-08 00:50:101726void QueryVersion(base::OnceCallback<void(uint32_t)> callback);
rockotf59d2d62017-04-01 02:49:081727```
1728
1729This queries the remote endpoint for the version number of its binding. When a
1730response is received `callback` is invoked with the remote version number. Note
Oksana Zhuravlovad5888c92019-08-23 19:43:061731that this value is cached by the `Remote` instance to avoid redundant
rockotf59d2d62017-04-01 02:49:081732queries.
1733
1734```cpp
1735void RequireVersion(uint32_t version);
1736```
1737
1738Informs the remote endpoint that a minimum version of `version` is required by
1739the client. If the remote endpoint cannot support that version, it will close
1740its end of the pipe immediately, preventing any other requests from being
1741received.
1742
1743### Versioned Enums
1744
1745For convenience, every extensible enum has a generated helper function to
1746determine whether a received enum value is known by the implementation's current
1747version of the enum definition. For example:
1748
1749```cpp
1750[Extensible]
1751enum Department {
1752 SALES,
1753 DEV,
1754 RESEARCH,
1755};
1756```
1757
1758generates the function in the same namespace as the generated C++ enum type:
1759
1760```cpp
1761inline bool IsKnownEnumValue(Department value);
1762```
1763
Sasha Bermeister995adc62017-12-07 02:36:431764### Using Mojo Bindings in Chrome
1765
Oksana Zhuravlova87b225a2019-03-07 01:08:031766See [Converting Legacy Chrome IPC To Mojo](/docs/mojo_ipc_conversion.md).
Sasha Bermeister995adc62017-12-07 02:36:431767
rockotf59d2d62017-04-01 02:49:081768### Additional Documentation
1769
Raphael Kubo da Costa8c6451ba2019-05-01 16:55:121770[Calling Mojo From Blink](/docs/mojo_ipc_conversion.md#Blink_Specific-Advice):
1771A brief overview of what it looks like to use Mojom C++ bindings from
1772within Blink code.