blob: 1eecf0dd23bfb190b6a911e626b4bd06e2559380 [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"
rockotf59d2d62017-04-01 02:49:08229#include "sample/logger.mojom.h"
230
231class LoggerImpl : public sample::mojom::Logger {
232 public:
233 // NOTE: A common pattern for interface implementations which have one
Oksana Zhuravlovad5888c92019-08-23 19:43:06234 // instance per client is to take a PendingReceiver in the constructor.
rockotf59d2d62017-04-01 02:49:08235
Oksana Zhuravlovad5888c92019-08-23 19:43:06236 explicit LoggerImpl(mojo::PendingReceiver<sample::mojom::Logger> receiver)
237 : receiver_(this, std::move(receiver)) {}
Johanne6e768e92020-09-09 00:51:10238 Logger(const Logger&) = delete;
239 Logger& operator=(const Logger&) = delete;
Peter Boström2e6be142021-11-13 01:28:25240 ~Logger() override {}
rockotf59d2d62017-04-01 02:49:08241
242 // sample::mojom::Logger:
243 void Log(const std::string& message) override {
244 LOG(ERROR) << "[Logger] " << message;
245 }
246
247 private:
Oksana Zhuravlovad5888c92019-08-23 19:43:06248 mojo::Receiver<sample::mojom::Logger> receiver_;
rockotf59d2d62017-04-01 02:49:08249};
250```
251
Oksana Zhuravlovad5888c92019-08-23 19:43:06252Now we can construct a `LoggerImpl` over our `PendingReceiver<Logger>`, and the
rockotf59d2d62017-04-01 02:49:08253previously queued `Log` message will be dispatched ASAP on the `LoggerImpl`'s
Sam McNallyd482b4b2017-07-17 03:45:03254sequence:
rockotf59d2d62017-04-01 02:49:08255
256``` cpp
Oksana Zhuravlovad5888c92019-08-23 19:43:06257LoggerImpl impl(std::move(receiver));
rockotf59d2d62017-04-01 02:49:08258```
259
260The diagram below illustrates the following sequence of events, all set in
261motion by the above line of code:
262
Oksana Zhuravlovad5888c92019-08-23 19:43:062631. The `LoggerImpl` constructor is called, passing the `PendingReceiver<Logger>` along
264 to the `Receiver`.
2652. The `Receiver` takes ownership of the `PendingReceiver<Logger>`'s pipe endpoint and
rockotf59d2d62017-04-01 02:49:08266 begins watching it for readability. The pipe is readable immediately, so a
267 task is scheduled to read the pending `Log` message from the pipe ASAP.
Oksana Zhuravlovad5888c92019-08-23 19:43:062683. The `Log` message is read and deserialized, causing the `Receiver` to invoke
rockotf59d2d62017-04-01 02:49:08269 the `Logger::Log` implementation on its bound `LoggerImpl`.
270
Oksana Zhuravlovad5888c92019-08-23 19:43:06271![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:08272
273As a result, our implementation will eventually log the client's `"Hello!"`
274message via `LOG(ERROR)`.
275
276*** note
277**NOTE:** Messages will only be read and dispatched from a pipe as long as the
Oksana Zhuravlovad5888c92019-08-23 19:43:06278object which binds it (*i.e.* the `mojo::Receiver` in the above example) remains
rockotf59d2d62017-04-01 02:49:08279alive.
280***
281
282### Receiving Responses
283
284Some Mojom interface methods expect a response. Suppose we modify our `Logger`
285interface so that the last logged line can be queried like so:
286
287``` cpp
288module sample.mojom;
289
290interface Logger {
291 Log(string message);
292 GetTail() => (string message);
293};
294```
295
296The generated C++ interface will now look like:
297
298``` cpp
299namespace sample {
300namespace mojom {
301
302class Logger {
303 public:
304 virtual ~Logger() {}
305
306 virtual void Log(const std::string& message) = 0;
307
David 'Digit' Turner743836f82017-10-27 13:04:15308 using GetTailCallback = base::OnceCallback<void(const std::string& message)>;
rockotf59d2d62017-04-01 02:49:08309
David 'Digit' Turner743836f82017-10-27 13:04:15310 virtual void GetTail(GetTailCallback callback) = 0;
rockotf59d2d62017-04-01 02:49:08311}
312
313} // namespace mojom
314} // namespace sample
315```
316
317As before, both clients and implementations of this interface use the same
318signature for the `GetTail` method: implementations use the `callback` argument
319to *respond* to the request, while clients pass a `callback` argument to
Erik Chen94936ef2020-09-11 20:41:12320asynchronously `receive` the response. The parameter `GetTailCallback` passed to
321the implementation of `GetTail` is sequence-affine. It must be invoked on the
322same sequence that `GetTail` is called on. A client's `callback` runs on the
323same sequence on which they invoked `GetTail` (the sequence to which their
324`logger` is bound). Here's an updated implementation:
rockotf59d2d62017-04-01 02:49:08325
326```cpp
327class LoggerImpl : public sample::mojom::Logger {
328 public:
329 // NOTE: A common pattern for interface implementations which have one
Oksana Zhuravlovad5888c92019-08-23 19:43:06330 // instance per client is to take a PendingReceiver in the constructor.
rockotf59d2d62017-04-01 02:49:08331
Oksana Zhuravlovad5888c92019-08-23 19:43:06332 explicit LoggerImpl(mojo::PendingReceiver<sample::mojom::Logger> receiver)
333 : receiver_(this, std::move(receiver)) {}
rockotf59d2d62017-04-01 02:49:08334 ~Logger() override {}
Johanne6e768e92020-09-09 00:51:10335 Logger(const Logger&) = delete;
336 Logger& operator=(const Logger&) = delete;
rockotf59d2d62017-04-01 02:49:08337
338 // sample::mojom::Logger:
339 void Log(const std::string& message) override {
340 LOG(ERROR) << "[Logger] " << message;
341 lines_.push_back(message);
342 }
343
David 'Digit' Turner743836f82017-10-27 13:04:15344 void GetTail(GetTailCallback callback) override {
345 std::move(callback).Run(lines_.back());
rockotf59d2d62017-04-01 02:49:08346 }
347
348 private:
Oksana Zhuravlovad5888c92019-08-23 19:43:06349 mojo::Receiver<sample::mojom::Logger> receiver_;
rockotf59d2d62017-04-01 02:49:08350 std::vector<std::string> lines_;
rockotf59d2d62017-04-01 02:49:08351};
352```
353
354And an updated client call:
355
356``` cpp
357void OnGetTail(const std::string& message) {
358 LOG(ERROR) << "Tail was: " << message;
359}
360
David 'Digit' Turner743836f82017-10-27 13:04:15361logger->GetTail(base::BindOnce(&OnGetTail));
rockotf59d2d62017-04-01 02:49:08362```
363
364Behind the scenes, the implementation-side callback is actually serializing the
365response arguments and writing them onto the pipe for delivery back to the
366client. Meanwhile the client-side callback is invoked by some internal logic
367which watches the pipe for an incoming response message, reads and deserializes
368it once it arrives, and then invokes the callback with the deserialized
369parameters.
370
371### Connection Errors
372
Yuzhu Shen92e791aa2017-06-20 20:39:31373If a pipe is disconnected, both endpoints will be able to observe the connection
374error (unless the disconnection is caused by closing/destroying an endpoint, in
375which case that endpoint won't get such a notification). If there are remaining
376incoming messages for an endpoint on disconnection, the connection error won't
377be triggered until the messages are drained.
378
David Benjamin0ff61822019-04-29 19:00:05379Pipe disconnection may be caused by:
Yuzhu Shen92e791aa2017-06-20 20:39:31380* Mojo system-level causes: process terminated, resource exhausted, etc.
381* The bindings close the pipe due to a validation error when processing a
382 received message.
383* The peer endpoint is closed. For example, the remote side is a bound
Oksana Zhuravlovad5888c92019-08-23 19:43:06384 `mojo::Remote<T>` and it is destroyed.
rockotf59d2d62017-04-01 02:49:08385
386Regardless of the underlying cause, when a connection error is encountered on
Oksana Zhuravlovad5888c92019-08-23 19:43:06387a receiver endpoint, that endpoint's **disconnect handler** (if set) is
Anand K. Mistryff664b72019-11-08 00:50:10388invoked. This handler is a simple `base::OnceClosure` and may only be invoked
rockotf59d2d62017-04-01 02:49:08389*once* as long as the endpoint is bound to the same pipe. Typically clients and
390implementations use this handler to do some kind of cleanup or -- particuarly if
391the error was unexpected -- create a new pipe and attempt to establish a new
392connection with it.
393
Oksana Zhuravlovad5888c92019-08-23 19:43:06394All message pipe-binding C++ objects (*e.g.*, `mojo::Receiver<T>`,
395`mojo::Remote<T>`, *etc.*) support setting their disconnect handler
396via a `set_disconnect_handler` method.
rockotf59d2d62017-04-01 02:49:08397
Oksana Zhuravlovad5888c92019-08-23 19:43:06398We can set up another end-to-end `Logger` example to demonstrate disconnect handler
399invocation. Suppose that `LoggerImpl` had set up the following disconnect
rockotf59d2d62017-04-01 02:49:08400handler within its constructor:
401
402``` cpp
Oksana Zhuravlovad5888c92019-08-23 19:43:06403LoggerImpl::LoggerImpl(mojo::PendingReceiver<sample::mojom::Logger> receiver)
404 : receiver_(this, std::move(receiver)) {
405 receiver_.set_disconnect_handler(
jameswest14ae0132017-06-12 22:52:00406 base::BindOnce(&LoggerImpl::OnError, base::Unretained(this)));
rockotf59d2d62017-04-01 02:49:08407}
408
409void LoggerImpl::OnError() {
410 LOG(ERROR) << "Client disconnected! Purging log lines.";
411 lines_.clear();
412}
Oksana Zhuravlovad5888c92019-08-23 19:43:06413
414mojo::Remote<sample::mojom::Logger> logger;
415LoggerImpl impl(logger.BindNewPipeAndPassReceiver());
416logger->Log("OK cool");
417logger.reset(); // Closes the client end.
418
rockotf59d2d62017-04-01 02:49:08419```
420
Oksana Zhuravlovad5888c92019-08-23 19:43:06421As long as `impl` stays alive here, it will eventually receive the `Log` message
422followed immediately by an invocation of the bound callback which outputs
423`"Client disconnected! Purging log lines."`. Like all other receiver callbacks, a disconnect handler will
424**never** be invoked once its corresponding receiver object has been destroyed.
425
rockotf59d2d62017-04-01 02:49:08426The use of `base::Unretained` is *safe* because the error handler will never be
Oksana Zhuravlovad5888c92019-08-23 19:43:06427invoked beyond the lifetime of `receiver_`, and `this` owns `receiver_`.
rockotf59d2d62017-04-01 02:49:08428
Yuzhu Shen7afd7262017-11-16 22:30:26429### A Note About Endpoint Lifetime and Callbacks
Oksana Zhuravlovad5888c92019-08-23 19:43:06430Once a `mojo::Remote<T>` is destroyed, it is guaranteed that pending
Yuzhu Shen7afd7262017-11-16 22:30:26431callbacks as well as the connection error handler (if registered) won't be
432called.
433
Oksana Zhuravlovad5888c92019-08-23 19:43:06434Once a `mojo::Receiver<T>` is destroyed, it is guaranteed that no more method
Yuzhu Shen7afd7262017-11-16 22:30:26435calls are dispatched to the implementation and the connection error handler (if
436registered) won't be called.
437
John Abd-El-Maleka9154852017-12-21 23:39:48438### Best practices for dealing with process crashes and callbacks
439A common situation when calling mojo interface methods that take a callback is
440that the caller wants to know if the other endpoint is torn down (e.g. because
441of a crash). In that case, the consumer usually wants to know if the response
442callback won't be run. There are different solutions for this problem, depending
Oksana Zhuravlovad5888c92019-08-23 19:43:06443on how the `Remote<T>` is held:
4441. The consumer owns the `Remote<T>`: `set_disconnect_handler`
John Abd-El-Maleka9154852017-12-21 23:39:48445 should be used.
Oksana Zhuravlovad5888c92019-08-23 19:43:064462. The consumer doesn't own the `Remote<T>`: there are two helpers
John Abd-El-Maleka9154852017-12-21 23:39:48447 depending on the behavior that the caller wants. If the caller wants to
448 ensure that an error handler is run, then
449 [**`mojo::WrapCallbackWithDropHandler`**](https://cs.chromium.org/chromium/src/mojo/public/cpp/bindings/callback_helpers.h?l=46)
450 should be used. If the caller wants the callback to always be run, then
451 [**`mojo::WrapCallbackWithDefaultInvokeIfNotRun`**](https://cs.chromium.org/chromium/src/mojo/public/cpp/bindings/callback_helpers.h?l=40)
452 helper should be used. With both of these helpers, usual callback care should
453 be followed to ensure that the callbacks don't run after the consumer is
Oksana Zhuravlovad5888c92019-08-23 19:43:06454 destructed (e.g. because the owner of the `Remote<T>` outlives the
John Abd-El-Maleka9154852017-12-21 23:39:48455 consumer). This includes using
456 [**`base::WeakPtr`**](https://cs.chromium.org/chromium/src/base/memory/weak_ptr.h?l=5)
457 or
458 [**`base::RefCounted`**](https://cs.chromium.org/chromium/src/base/memory/ref_counted.h?l=246).
459 It should also be noted that with these helpers, the callbacks could be run
Oksana Zhuravlovad5888c92019-08-23 19:43:06460 synchronously while the Remote<T> is reset or destroyed.
John Abd-El-Maleka9154852017-12-21 23:39:48461
rockotf59d2d62017-04-01 02:49:08462### A Note About Ordering
463
464As mentioned in the previous section, closing one end of a pipe will eventually
465trigger a connection error on the other end. However it's important to note that
466this event is itself ordered with respect to any other event (*e.g.* writing a
467message) on the pipe.
468
469This means that it's safe to write something contrived like:
470
471``` cpp
Oksana Zhuravlovad5888c92019-08-23 19:43:06472LoggerImpl::LoggerImpl(mojo::PendingReceiver<sample::mojom::Logger> receiver,
473 base::OnceClosure disconnect_handler)
474 : receiver_(this, std::move(receiver)) {
475 receiver_.set_disconnect_handler(std::move(disconnect_handler));
476}
477
478void GoBindALogger(mojo::PendingReceiver<sample::mojom::Logger> receiver) {
rockotf59d2d62017-04-01 02:49:08479 base::RunLoop loop;
Oksana Zhuravlovad5888c92019-08-23 19:43:06480 LoggerImpl impl(std::move(receiver), loop.QuitClosure());
rockotf59d2d62017-04-01 02:49:08481 loop.Run();
482}
483
484void LogSomething() {
Oksana Zhuravlovad5888c92019-08-23 19:43:06485 mojo::Remote<sample::mojom::Logger> logger;
rockotf59d2d62017-04-01 02:49:08486 bg_thread->task_runner()->PostTask(
Oksana Zhuravlovad5888c92019-08-23 19:43:06487 FROM_HERE, base::BindOnce(&GoBindALogger, logger.BindNewPipeAndPassReceiver()));
rockotf59d2d62017-04-01 02:49:08488 logger->Log("OK Computer");
489}
490```
491
492When `logger` goes out of scope it immediately closes its end of the message
493pipe, but the impl-side won't notice this until it receives the sent `Log`
494message. Thus the `impl` above will first log our message and *then* see a
495connection error and break out of the run loop.
496
Sasha Bermeister995adc62017-12-07 02:36:43497## Types
498
Ken Rockot686e4132017-04-26 00:03:31499### Enums
500
Ken Rockot929282c2018-05-02 17:07:29501[Mojom enums](/mojo/public/tools/bindings/README.md#Enumeration-Types) translate
502directly to equivalent strongly-typed C++11 enum classes with `int32_t` as the
503underlying type. The typename and value names are identical between Mojom and
504C++. Mojo also always defines a special enumerator `kMaxValue` that shares the
505value of the highest enumerator: this makes it easy to record Mojo enums in
506histograms and interoperate with legacy IPC.
Ken Rockot686e4132017-04-26 00:03:31507
508For example, consider the following Mojom definition:
509
510```cpp
511module business.mojom;
512
513enum Department {
514 kEngineering,
Andrew Moylan341cece72017-06-22 22:03:02515 kMarketing,
Ken Rockot686e4132017-04-26 00:03:31516 kSales,
517};
518```
519
520This translates to the following C++ definition:
521
522```cpp
523namespace business {
524namespace mojom {
525
526enum class Department : int32_t {
527 kEngineering,
528 kMarketing,
529 kSales,
Daniel Chengcda1df5b2018-03-30 21:30:16530 kMaxValue = kSales,
Ken Rockot686e4132017-04-26 00:03:31531};
532
533} // namespace mojom
534} // namespace business
535```
536
537### Structs
538
Ken Rockot929282c2018-05-02 17:07:29539[Mojom structs](mojo/public/tools/bindings/README.md#Structs) can be used to
540define logical groupings of fields into a new composite type. Every Mojom struct
Ken Rockot686e4132017-04-26 00:03:31541elicits the generation of an identically named, representative C++ class, with
542identically named public fields of corresponding C++ types, and several helpful
543public methods.
544
545For example, consider the following Mojom struct:
546
547```cpp
548module business.mojom;
549
550struct Employee {
551 int64 id;
552 string username;
553 Department department;
554};
555```
556
557This would generate a C++ class like so:
558
559```cpp
560namespace business {
561namespace mojom {
562
563class Employee;
564
565using EmployeePtr = mojo::StructPtr<Employee>;
566
567class Employee {
568 public:
569 // Default constructor - applies default values, potentially ones specified
570 // explicitly within the Mojom.
571 Employee();
572
573 // Value constructor - an explicit argument for every field in the struct, in
574 // lexical Mojom definition order.
575 Employee(int64_t id, const std::string& username, Department department);
576
577 // Creates a new copy of this struct value
578 EmployeePtr Clone();
579
580 // Tests for equality with another struct value of the same type.
581 bool Equals(const Employee& other);
582
583 // Equivalent public fields with names identical to the Mojom.
584 int64_t id;
585 std::string username;
586 Department department;
587};
588
589} // namespace mojom
590} // namespace business
591```
592
593Note when used as a message parameter or as a field within another Mojom struct,
594a `struct` type is wrapped by the move-only `mojo::StructPtr` helper, which is
595roughly equivalent to a `std::unique_ptr` with some additional utility methods.
596This allows struct values to be nullable and struct types to be potentially
597self-referential.
598
David Benjamin0ff61822019-04-29 19:00:05599Every generated struct class has a static `New()` method which returns a new
Ken Rockot686e4132017-04-26 00:03:31600`mojo::StructPtr<T>` wrapping a new instance of the class constructed by
601forwarding the arguments from `New`. For example:
602
603```cpp
604mojom::EmployeePtr e1 = mojom::Employee::New();
605e1->id = 42;
606e1->username = "mojo";
607e1->department = mojom::Department::kEngineering;
608```
609
610is equivalent to
611
612```cpp
613auto e1 = mojom::Employee::New(42, "mojo", mojom::Department::kEngineering);
614```
615
616Now if we define an interface like:
617
618```cpp
619interface EmployeeManager {
620 AddEmployee(Employee e);
621};
622```
623
624We'll get this C++ interface to implement:
625
626```cpp
627class EmployeeManager {
628 public:
629 virtual ~EmployeManager() {}
630
631 virtual void AddEmployee(EmployeePtr e) = 0;
632};
633```
634
635And we can send this message from C++ code as follows:
636
637```cpp
638mojom::EmployeManagerPtr manager = ...;
639manager->AddEmployee(
640 Employee::New(42, "mojo", mojom::Department::kEngineering));
641
642// or
643auto e = Employee::New(42, "mojo", mojom::Department::kEngineering);
644manager->AddEmployee(std::move(e));
645```
646
647### Unions
648
649Similarly to [structs](#Structs), tagged unions generate an identically named,
650representative C++ class which is typically wrapped in a `mojo::StructPtr<T>`.
651
652Unlike structs, all generated union fields are private and must be retrieved and
Oksana Zhuravlovaa4da21f2019-03-20 20:41:58653manipulated using accessors. A field `foo` is accessible by `get_foo()` and
Ken Rockot686e4132017-04-26 00:03:31654settable by `set_foo()`. There is also a boolean `is_foo()` for each field which
655indicates whether the union is currently taking on the value of field `foo` in
656exclusion to all other union fields.
657
658Finally, every generated union class also has a nested `Tag` enum class which
659enumerates all of the named union fields. A Mojom union value's current type can
660be determined by calling the `which()` method which returns a `Tag`.
661
662For example, consider the following Mojom definitions:
663
664```cpp
665union Value {
666 int64 int_value;
Tom McKee1a5032f2018-08-02 17:14:55667 float float_value;
Ken Rockot686e4132017-04-26 00:03:31668 string string_value;
669};
670
671interface Dictionary {
672 AddValue(string key, Value value);
673};
674```
675
Tom McKee1a5032f2018-08-02 17:14:55676This generates the following C++ interface:
Ken Rockot686e4132017-04-26 00:03:31677
678```cpp
679class Value {
680 public:
Tom McKee1a5032f2018-08-02 17:14:55681 ~Value() {}
682};
683
684class Dictionary {
685 public:
686 virtual ~Dictionary() {}
Ken Rockot686e4132017-04-26 00:03:31687
688 virtual void AddValue(const std::string& key, ValuePtr value) = 0;
689};
690```
691
692And we can use it like so:
693
694```cpp
Daniel Chengdf901a302022-04-21 15:18:18695ValuePtr value = Value::NewIntValue(42);
Ken Rockot686e4132017-04-26 00:03:31696CHECK(value->is_int_value());
Daniel Chengdf901a302022-04-21 15:18:18697CHECK_EQ(value->which(), Value::Tag::kIntValue);
Ken Rockot686e4132017-04-26 00:03:31698
699value->set_float_value(42);
700CHECK(value->is_float_value());
Daniel Chengdf901a302022-04-21 15:18:18701CHECK_EQ(value->which(), Value::Tag::kFloatValue);
Ken Rockot686e4132017-04-26 00:03:31702
703value->set_string_value("bananas");
704CHECK(value->is_string_value());
Daniel Chengdf901a302022-04-21 15:18:18705CHECK_EQ(value->which(), Value::Tag::kStringValue);
Ken Rockot686e4132017-04-26 00:03:31706```
707
708Finally, note that if a union value is not currently occupied by a given field,
709attempts to access that field will DCHECK:
710
711```cpp
Daniel Chengdf901a302022-04-21 15:18:18712ValuePtr value = Value::NewIntValue(42);
Ken Rockot686e4132017-04-26 00:03:31713LOG(INFO) << "Value is " << value->string_value(); // DCHECK!
714```
715
rockotf59d2d62017-04-01 02:49:08716### Sending Interfaces Over Interfaces
717
Oksana Zhuravlovad5888c92019-08-23 19:43:06718We know how to create interface pipes and use their Remote and PendingReceiver endpoints
Ken Rockot686e4132017-04-26 00:03:31719in some interesting ways. This still doesn't add up to interesting IPC! The
720bread and butter of Mojo IPC is the ability to transfer interface endpoints
721across other interfaces, so let's take a look at how to accomplish that.
rockotf59d2d62017-04-01 02:49:08722
Oksana Zhuravlovad5888c92019-08-23 19:43:06723#### Sending Pending Receivers
rockotf59d2d62017-04-01 02:49:08724
725Consider a new example Mojom in `//sample/db.mojom`:
726
727``` cpp
728module db.mojom;
729
730interface Table {
731 void AddRow(int32 key, string data);
732};
733
734interface Database {
Oksana Zhuravlovad5888c92019-08-23 19:43:06735 AddTable(pending_receiver<Table> table);
rockotf59d2d62017-04-01 02:49:08736};
737```
738
739As noted in the
David Bokane59ea1f42020-08-04 14:40:21740[Mojom IDL documentation](/mojo/public/tools/bindings/README.md#Primitive-Types),
Oksana Zhuravlovad5888c92019-08-23 19:43:06741the `pending_receiver<Table>` syntax corresponds
742precisely to the `PendingReceiver<T>` type discussed in the sections above, and
rockotf59d2d62017-04-01 02:49:08743in fact the generated code for these interfaces is approximately:
744
745``` cpp
746namespace db {
747namespace mojom {
748
749class Table {
750 public:
751 virtual ~Table() {}
752
753 virtual void AddRow(int32_t key, const std::string& data) = 0;
754}
755
rockotf59d2d62017-04-01 02:49:08756class Database {
757 public:
758 virtual ~Database() {}
759
Oksana Zhuravlovad5888c92019-08-23 19:43:06760 virtual void AddTable(mojo::PendingReceiver<Table> table);
rockotf59d2d62017-04-01 02:49:08761};
762
rockotf59d2d62017-04-01 02:49:08763} // namespace mojom
764} // namespace db
765```
766
767We can put this all together now with an implementation of `Table` and
768`Database`:
769
770``` cpp
771#include "sample/db.mojom.h"
772
773class TableImpl : public db::mojom:Table {
774 public:
Oksana Zhuravlovad5888c92019-08-23 19:43:06775 explicit TableImpl(mojo::PendingReceiver<db::mojom::Table> receiver)
776 : receiver_(this, std::move(receiver)) {}
rockotf59d2d62017-04-01 02:49:08777 ~TableImpl() override {}
778
779 // db::mojom::Table:
780 void AddRow(int32_t key, const std::string& data) override {
781 rows_.insert({key, data});
782 }
783
784 private:
Oksana Zhuravlovad5888c92019-08-23 19:43:06785 mojo::Receiver<db::mojom::Table> receiver_;
rockotf59d2d62017-04-01 02:49:08786 std::map<int32_t, std::string> rows_;
787};
788
789class DatabaseImpl : public db::mojom::Database {
790 public:
Oksana Zhuravlovad5888c92019-08-23 19:43:06791 explicit DatabaseImpl(mojo::PendingReceiver<db::mojom::Database> receiver)
792 : receiver_(this, std::move(receiver)) {}
rockotf59d2d62017-04-01 02:49:08793 ~DatabaseImpl() override {}
794
795 // db::mojom::Database:
Oksana Zhuravlovad5888c92019-08-23 19:43:06796 void AddTable(mojo::PendingReceiver<db::mojom::Table> table) {
Jeremy Romancf9ae2f2017-08-24 17:06:37797 tables_.emplace_back(std::make_unique<TableImpl>(std::move(table)));
rockotf59d2d62017-04-01 02:49:08798 }
799
800 private:
Oksana Zhuravlovad5888c92019-08-23 19:43:06801 mojo::Receiver<db::mojom::Database> receiver_;
rockotf59d2d62017-04-01 02:49:08802 std::vector<std::unique_ptr<TableImpl>> tables_;
803};
804```
805
Oksana Zhuravlovad5888c92019-08-23 19:43:06806Pretty straightforward. The `pending_receiver<Table>` Mojom parameter to `AddTable` translates to
807a C++ `mojo::PendingReceiver<db::mojom::Table>`, which we know is just a
rockotf59d2d62017-04-01 02:49:08808strongly-typed message pipe handle. When `DatabaseImpl` gets an `AddTable` call,
Oksana Zhuravlovad5888c92019-08-23 19:43:06809it constructs a new `TableImpl` and binds it to the received `mojo::PendingReceiver<db::mojom::Table>`.
rockotf59d2d62017-04-01 02:49:08810
811Let's see how this can be used.
812
813``` cpp
Oksana Zhuravlovad5888c92019-08-23 19:43:06814mojo::Remote<db::mojom::Database> database;
815DatabaseImpl db_impl(database.BindNewPipeAndPassReceiver());
rockotf59d2d62017-04-01 02:49:08816
Oksana Zhuravlovad5888c92019-08-23 19:43:06817mojo::Remote<db::mojom::Table> table1, table2;
818database->AddTable(table1.BindNewPipeAndPassReceiver());
819database->AddTable(table2.BindNewPipeAndPassReceiver());
rockotf59d2d62017-04-01 02:49:08820
821table1->AddRow(1, "hiiiiiiii");
822table2->AddRow(2, "heyyyyyy");
823```
824
825Notice that we can again start using the new `Table` pipes immediately, even
Oksana Zhuravlovad5888c92019-08-23 19:43:06826while their `mojo::PendingReceiver<db::mojom::Table>` endpoints are still in transit.
rockotf59d2d62017-04-01 02:49:08827
Oksana Zhuravlovad5888c92019-08-23 19:43:06828#### Sending Remotes
rockotf59d2d62017-04-01 02:49:08829
Oksana Zhuravlovad5888c92019-08-23 19:43:06830Of course we can also send `Remote`s:
rockotf59d2d62017-04-01 02:49:08831
832``` cpp
833interface TableListener {
834 OnRowAdded(int32 key, string data);
835};
836
837interface Table {
838 AddRow(int32 key, string data);
839
Oksana Zhuravlovad5888c92019-08-23 19:43:06840 AddListener(pending_remote<TableListener> listener);
rockotf59d2d62017-04-01 02:49:08841};
842```
843
844This would generate a `Table::AddListener` signature like so:
845
846``` cpp
Oksana Zhuravlovad5888c92019-08-23 19:43:06847 virtual void AddListener(mojo::PendingRemote<TableListener> listener) = 0;
rockotf59d2d62017-04-01 02:49:08848```
849
850and this could be used like so:
851
852``` cpp
Oksana Zhuravlovad5888c92019-08-23 19:43:06853mojo::PendingRemote<db::mojom::TableListener> listener;
854TableListenerImpl impl(listener.InitWithNewPipeAndPassReceiver());
rockotf59d2d62017-04-01 02:49:08855table->AddListener(std::move(listener));
856```
857
858## Other Interface Binding Types
859
860The [Interfaces](#Interfaces) section above covers basic usage of the most
Oksana Zhuravlovad5888c92019-08-23 19:43:06861common bindings object types: `Remote`, `PendingReceiver`, and `Receiver`.
rockotf59d2d62017-04-01 02:49:08862While these types are probably the most commonly used in practice, there are
863several other ways of binding both client- and implementation-side interface
864pipes.
865
Oksana Zhuravlovad5888c92019-08-23 19:43:06866### Self-owned Receivers
rockotf59d2d62017-04-01 02:49:08867
Oksana Zhuravlovad5888c92019-08-23 19:43:06868A **self-owned receiver** exists as a standalone object which owns its interface
rockotf59d2d62017-04-01 02:49:08869implementation and automatically cleans itself up when its bound interface
870endpoint detects an error. The
Oksana Zhuravlovad5888c92019-08-23 19:43:06871[**`MakeSelfOwnedReceiver`**](https://cs.chromium.org/chromium/src/mojo/public/cpp/bindings/self_owned_receiver.h)
872function is used to create such a receiver.
rockotf59d2d62017-04-01 02:49:08873.
874
875``` cpp
876class LoggerImpl : public sample::mojom::Logger {
877 public:
878 LoggerImpl() {}
879 ~LoggerImpl() override {}
880
881 // sample::mojom::Logger:
882 void Log(const std::string& message) override {
883 LOG(ERROR) << "[Logger] " << message;
884 }
885
886 private:
Oksana Zhuravlovad5888c92019-08-23 19:43:06887 // NOTE: This doesn't own any Receiver object!
rockotf59d2d62017-04-01 02:49:08888};
889
Oksana Zhuravlovad5888c92019-08-23 19:43:06890mojo::Remote<db::mojom::Logger> logger;
891mojo::MakeSelfOwnedReceiver(std::make_unique<LoggerImpl>(),
892 logger.BindNewPipeAndPassReceiver());
rockotf59d2d62017-04-01 02:49:08893
894logger->Log("NOM NOM NOM MESSAGES");
895```
896
897Now as long as `logger` remains open somewhere in the system, the bound
scottmg66139202017-05-04 18:56:35898`LoggerImpl` on the other end will remain alive.
rockotf59d2d62017-04-01 02:49:08899
Oksana Zhuravlovad5888c92019-08-23 19:43:06900### Receiver Sets
rockotf59d2d62017-04-01 02:49:08901
902Sometimes it's useful to share a single implementation instance with multiple
Oksana Zhuravlovad5888c92019-08-23 19:43:06903clients. [**`ReceiverSet`**](https://cs.chromium.org/chromium/src/mojo/public/cpp/bindings/receiver_set.h)
rockotf59d2d62017-04-01 02:49:08904makes this easy. Consider the Mojom:
905
906``` cpp
907module system.mojom;
908
909interface Logger {
910 Log(string message);
911};
912
913interface LoggerProvider {
914 GetLogger(Logger& logger);
915};
916```
917
Oksana Zhuravlovad5888c92019-08-23 19:43:06918We can use `ReceiverSet` to bind multiple `Logger` pending receivers to a single
rockotf59d2d62017-04-01 02:49:08919implementation instance:
920
921``` cpp
922class LogManager : public system::mojom::LoggerProvider,
923 public system::mojom::Logger {
924 public:
Oksana Zhuravlovad5888c92019-08-23 19:43:06925 explicit LogManager(mojo::PendingReceiver<system::mojom::LoggerProvider> receiver)
926 : provider_receiver_(this, std::move(receiver)) {}
rockotf59d2d62017-04-01 02:49:08927 ~LogManager() {}
928
929 // system::mojom::LoggerProvider:
Oksana Zhuravlovad5888c92019-08-23 19:43:06930 void GetLogger(mojo::PendingReceiver<Logger> receiver) override {
931 logger_receivers_.Add(this, std::move(receiver));
rockotf59d2d62017-04-01 02:49:08932 }
933
934 // system::mojom::Logger:
935 void Log(const std::string& message) override {
936 LOG(ERROR) << "[Logger] " << message;
937 }
938
939 private:
Oksana Zhuravlovad5888c92019-08-23 19:43:06940 mojo::Receiver<system::mojom::LoggerProvider> provider_receiver_;
941 mojo::ReceiverSet<system::mojom::Logger> logger_receivers_;
rockotf59d2d62017-04-01 02:49:08942};
943
944```
945
946
Oksana Zhuravlovad5888c92019-08-23 19:43:06947### Remote Sets
rockotf59d2d62017-04-01 02:49:08948
Oksana Zhuravlovad5888c92019-08-23 19:43:06949Similar to the `ReceiverSet` above, sometimes it's useful to maintain a set of
950`Remote`s for *e.g.* a set of clients observing some event.
951[**`RemoteSet`**](https://cs.chromium.org/chromium/src/mojo/public/cpp/bindings/remote_set.h)
rockotf59d2d62017-04-01 02:49:08952is here to help. Take the Mojom:
953
954``` cpp
955module db.mojom;
956
957interface TableListener {
958 OnRowAdded(int32 key, string data);
959};
960
961interface Table {
962 AddRow(int32 key, string data);
Oksana Zhuravlovad5888c92019-08-23 19:43:06963 AddListener(pending_remote<TableListener> listener);
rockotf59d2d62017-04-01 02:49:08964};
965```
966
967An implementation of `Table` might look something like like this:
968
969``` cpp
970class TableImpl : public db::mojom::Table {
971 public:
972 TableImpl() {}
973 ~TableImpl() override {}
974
975 // db::mojom::Table:
976 void AddRow(int32_t key, const std::string& data) override {
977 rows_.insert({key, data});
978 listeners_.ForEach([key, &data](db::mojom::TableListener* listener) {
979 listener->OnRowAdded(key, data);
980 });
981 }
982
Oksana Zhuravlovad5888c92019-08-23 19:43:06983 void AddListener(mojo::PendingRemote<db::mojom::TableListener> listener) {
984 listeners_.Add(std::move(listener));
rockotf59d2d62017-04-01 02:49:08985 }
986
987 private:
Oksana Zhuravlovad5888c92019-08-23 19:43:06988 mojo::RemoteSet<db::mojom::Table> listeners_;
rockotf59d2d62017-04-01 02:49:08989 std::map<int32_t, std::string> rows_;
990};
991```
992
993## Associated Interfaces
994
Chase Phillips3f76e152018-07-18 20:45:26995Associated interfaces are interfaces which:
rockotf59d2d62017-04-01 02:49:08996
Chase Phillips3f76e152018-07-18 20:45:26997* enable running multiple interfaces over a single message pipe while
998 preserving message ordering.
Oksana Zhuravlovad5888c92019-08-23 19:43:06999* make it possible for the receiver to access a single message pipe from
Chase Phillips3f76e152018-07-18 20:45:261000 multiple sequences.
1001
1002### Mojom
1003
David Bokane59ea1f42020-08-04 14:40:211004New types `pending_associated_remote` and `pending_associated_receiver` are
1005introduced for remote/receiver fields. For example:
Chase Phillips3f76e152018-07-18 20:45:261006
1007``` cpp
1008interface Bar {};
1009
1010struct Qux {
David Bokane59ea1f42020-08-04 14:40:211011 pending_associated_remote<Bar> bar;
Chase Phillips3f76e152018-07-18 20:45:261012};
1013
1014interface Foo {
Oksana Zhuravlovad5888c92019-08-23 19:43:061015 // Uses associated remote.
David Bokane59ea1f42020-08-04 14:40:211016 PassBarRemote(pending_associated_remote<Bar> bar);
Oksana Zhuravlovad5888c92019-08-23 19:43:061017 // Uses associated receiver.
David Bokane59ea1f42020-08-04 14:40:211018 PassBarReceiver(pending_associated_receiver<Bar> bar);
Chase Phillips3f76e152018-07-18 20:45:261019 // Passes a struct with associated interface pointer.
1020 PassQux(Qux qux);
1021 // Uses associated interface pointer in callback.
David Bokane59ea1f42020-08-04 14:40:211022 AsyncGetBar() => (pending_associated_remote<Bar> bar);
Chase Phillips3f76e152018-07-18 20:45:261023};
1024```
1025
David Bokane59ea1f42020-08-04 14:40:211026In each case the interface impl/client will communicate using the same message
1027pipe over which the associated remote/receiver is passed.
Chase Phillips3f76e152018-07-18 20:45:261028
1029### Using associated interfaces in C++
1030
Oksana Zhuravlovad5888c92019-08-23 19:43:061031When generating C++ bindings, the pending_associated_remote of `Bar` is
1032mapped to `mojo::PendingAssociatedRemote<Bar>`; pending_associated_receiver to
1033`mojo::PendingAssociatedReceiver<Bar>`.
Chase Phillips3f76e152018-07-18 20:45:261034
1035``` cpp
1036// In mojom:
1037interface Foo {
1038 ...
David Bokane59ea1f42020-08-04 14:40:211039 PassBarRemote(pending_associated_remote<Bar> bar);
1040 PassBarReceiver(pending_associated_receiver<Bar> bar);
Chase Phillips3f76e152018-07-18 20:45:261041 ...
1042};
1043
1044// In C++:
1045class Foo {
1046 ...
David Bokane59ea1f42020-08-04 14:40:211047 virtual void PassBarRemote(mojo::PendingAssociatedRemote<Bar> bar) = 0;
1048 virtual void PassBarReceiver(mojo::PendingAssociatedReceiver<Bar> bar) = 0;
Chase Phillips3f76e152018-07-18 20:45:261049 ...
1050};
1051```
1052
Oksana Zhuravlovad5888c92019-08-23 19:43:061053#### Passing pending associated receivers
Chase Phillips3f76e152018-07-18 20:45:261054
David Bokane59ea1f42020-08-04 14:40:211055Assume you already have a `Remote<Foo> foo`, and you would like to call
1056`PassBarReceiver()` on it. You can do:
Chase Phillips3f76e152018-07-18 20:45:261057
1058``` cpp
Oksana Zhuravlovad5888c92019-08-23 19:43:061059mojo::PendingAssociatedRemote<Bar> pending_bar;
1060mojo::PendingAssociatedReceiver<Bar> bar_receiver = pending_bar.InitWithNewEndpointAndPassReceiver();
David Bokane59ea1f42020-08-04 14:40:211061foo->PassBarReceiver(std::move(bar_receiver));
Chase Phillips3f76e152018-07-18 20:45:261062
Oksana Zhuravlovad5888c92019-08-23 19:43:061063mojo::AssociatedRemote<Bar> bar;
1064bar.Bind(std::move(pending_bar));
1065bar->DoSomething();
Chase Phillips3f76e152018-07-18 20:45:261066```
1067
1068First, the code creates an associated interface of type `Bar`. It looks very
1069similar to what you would do to setup a non-associated interface. An
1070important difference is that one of the two associated endpoints (either
Oksana Zhuravlovad5888c92019-08-23 19:43:061071`bar_receiver` or `pending_bar`) must be sent over another interface. That is
Chase Phillips3f76e152018-07-18 20:45:261072how the interface is associated with an existing message pipe.
1073
Oksana Zhuravlovad5888c92019-08-23 19:43:061074It should be noted that you cannot call `bar->DoSomething()` before passing
1075`bar_receiver`. This is required by the FIFO-ness guarantee: at the receiver
Chase Phillips3f76e152018-07-18 20:45:261076side, when the message of `DoSomething` call arrives, we want to dispatch it to
Oksana Zhuravlovad5888c92019-08-23 19:43:061077the corresponding `AssociatedReceiver<Bar>` before processing any subsequent
1078messages. If `bar_receiver` is in a subsequent message, message dispatching gets
1079into a deadlock. On the other hand, as soon as `bar_receiver` is sent, `bar`
1080is usable. There is no need to wait until `bar_receiver` is bound to an
Chase Phillips3f76e152018-07-18 20:45:261081implementation at the remote side.
1082
Oksana Zhuravlovad5888c92019-08-23 19:43:061083`AssociatedRemote` provides a `BindNewEndpointAndPassReceiver` method
1084to make the code a little shorter. The following code achieves the same purpose:
Chase Phillips3f76e152018-07-18 20:45:261085
1086``` cpp
Oksana Zhuravlovad5888c92019-08-23 19:43:061087mojo::AssociatedRemote<Bar> bar;
David Bokane59ea1f42020-08-04 14:40:211088foo->PassBarReceiver(bar.BindNewEndpointAndPassReceiver());
Oksana Zhuravlovad5888c92019-08-23 19:43:061089bar->DoSomething();
Chase Phillips3f76e152018-07-18 20:45:261090```
1091
1092The implementation of `Foo` looks like this:
1093
1094``` cpp
1095class FooImpl : public Foo {
1096 ...
David Bokane59ea1f42020-08-04 14:40:211097 void PassBarReceiver(mojo::AssociatedReceiver<Bar> bar) override {
1098 bar_receiver_.Bind(std::move(bar));
Chase Phillips3f76e152018-07-18 20:45:261099 ...
1100 }
1101 ...
1102
Oksana Zhuravlovad5888c92019-08-23 19:43:061103 Receiver<Foo> foo_receiver_;
1104 AssociatedReceiver<Bar> bar_receiver_;
Chase Phillips3f76e152018-07-18 20:45:261105};
1106```
1107
Oksana Zhuravlovad5888c92019-08-23 19:43:061108In this example, `bar_receiver_`'s lifespan is tied to that of `FooImpl`. But you
Chase Phillips3f76e152018-07-18 20:45:261109don't have to do that. You can, for example, pass `bar2` to another sequence to
Oksana Zhuravlovad5888c92019-08-23 19:43:061110bind to an `AssociatedReceiver<Bar>` there.
Chase Phillips3f76e152018-07-18 20:45:261111
Oksana Zhuravlovad5888c92019-08-23 19:43:061112When the underlying message pipe is disconnected (e.g., `foo` or
1113`foo_receiver_` is destroyed), all associated interface endpoints (e.g.,
1114`bar` and `bar_receiver_`) will receive a disconnect error.
Chase Phillips3f76e152018-07-18 20:45:261115
Oksana Zhuravlovad5888c92019-08-23 19:43:061116#### Passing associated remotes
Chase Phillips3f76e152018-07-18 20:45:261117
Oksana Zhuravlovad5888c92019-08-23 19:43:061118Similarly, assume you have already got an `Remote<Foo> foo`, and you
David Bokane59ea1f42020-08-04 14:40:211119would like to call `PassBarRemote()` on it. You can do:
Chase Phillips3f76e152018-07-18 20:45:261120
1121``` cpp
Oksana Zhuravlovad5888c92019-08-23 19:43:061122mojo::AssociatedReceiver<Bar> bar_receiver(some_bar_impl);
1123mojo::PendingAssociatedRemote<Bar> bar;
1124mojo::PendingAssociatedReceiver<Bar> bar_pending_receiver = bar.InitWithNewEndpointAndPassReceiver();
David Bokane59ea1f42020-08-04 14:40:211125foo->PassBarRemote(std::move(bar));
Oksana Zhuravlovad5888c92019-08-23 19:43:061126bar_receiver.Bind(std::move(bar_pending_receiver));
Chase Phillips3f76e152018-07-18 20:45:261127```
1128
1129The following code achieves the same purpose:
1130
1131``` cpp
Oksana Zhuravlovad5888c92019-08-23 19:43:061132mojo::AssociatedReceiver<Bar> bar_receiver(some_bar_impl);
1133mojo::PendingAssociatedRemote<Bar> bar;
1134bar_receiver.Bind(bar.InitWithNewPipeAndPassReceiver());
David Bokane59ea1f42020-08-04 14:40:211135foo->PassBarRemote(std::move(bar));
Chase Phillips3f76e152018-07-18 20:45:261136```
1137
1138### Performance considerations
1139
Ken Rockotcd23f752020-06-20 01:22:311140When using associated interfaces on different sequences than the primary
1141sequence (where the primary interface lives):
Chase Phillips3f76e152018-07-18 20:45:261142
1143* Sending messages: send happens directly on the calling sequence. So there
1144 isn't sequence hopping.
1145* Receiving messages: associated interfaces bound on a different sequence from
Ken Rockotcd23f752020-06-20 01:22:311146 the primary interface incur an extra sequence hop during dispatch.
Chase Phillips3f76e152018-07-18 20:45:261147
1148Therefore, performance-wise associated interfaces are better suited for
Ken Rockotcd23f752020-06-20 01:22:311149scenarios where message receiving happens on the primary sequence.
Chase Phillips3f76e152018-07-18 20:45:261150
1151### Testing
1152
Ken Rockotcd23f752020-06-20 01:22:311153Associated interfaces need to be associated with a primary interface before
Chase Phillips3f76e152018-07-18 20:45:261154they can be used. This means one end of the associated interface must be sent
Ken Rockotcd23f752020-06-20 01:22:311155over one end of the primary interface, or over one end of another associated
1156interface which itself already has a primary interface.
Chase Phillips3f76e152018-07-18 20:45:261157
1158If you want to test an associated interface endpoint without first
Gyuyoung Kim7dd486c2020-09-15 01:47:181159associating it, you can use `AssociatedRemote::BindNewEndpointAndPassDedicatedReceiver`.
Oksana Zhuravlovad5888c92019-08-23 19:43:061160This will create working associated interface endpoints which are not actually
Adithya Srinivasan4b6c6082018-11-14 16:56:461161associated with anything else.
Chase Phillips3f76e152018-07-18 20:45:261162
1163### Read more
1164
1165* [Design: Mojo Associated Interfaces](https://docs.google.com/document/d/1nq3J_HbS-gvVfIoEhcVyxm1uY-9G_7lhD-4Kyxb1WIY/edit)
rockotf59d2d62017-04-01 02:49:081166
1167## Synchronous Calls
1168
Oksana Zhuravlova50bac902019-01-15 00:17:591169### Think carefully before you decide to use sync calls
rockotf59d2d62017-04-01 02:49:081170
Oksana Zhuravlova50bac902019-01-15 00:17:591171Although sync calls are convenient, you should avoid them whenever they
1172are not absolutely necessary:
1173
1174* Sync calls hurt parallelism and therefore hurt performance.
1175* Re-entrancy changes message order and produces call stacks that you
1176probably never think about while you are coding. It has always been a
1177huge pain.
1178* Sync calls may lead to deadlocks.
1179
1180### Mojom changes
1181
1182A new attribute `[Sync]` (or `[Sync=true]`) is introduced for methods.
1183For example:
1184
1185``` cpp
1186interface Foo {
1187 [Sync]
1188 SomeSyncCall() => (Bar result);
1189};
1190```
1191
1192It indicates that when `SomeSyncCall()` is called, the control flow of
1193the calling thread is blocked until the response is received.
1194
1195It is not allowed to use this attribute with functions that don’t have
1196responses. If you just need to wait until the service side finishes
1197processing the call, you can use an empty response parameter list:
1198
1199``` cpp
1200[Sync]
1201SomeSyncCallWithNoResult() => ();
1202```
1203
1204### Generated bindings (C++)
1205
1206The generated C++ interface of the Foo interface above is:
1207
1208``` cpp
1209class Foo {
1210 public:
1211 // The service side implements this signature. The client side can
1212 // also use this signature if it wants to call the method asynchronously.
1213 virtual void SomeSyncCall(SomeSyncCallCallback callback) = 0;
1214
1215 // The client side uses this signature to call the method synchronously.
1216 virtual bool SomeSyncCall(BarPtr* result);
1217};
1218```
1219
1220As you can see, the client side and the service side use different
1221signatures. At the client side, response is mapped to output parameters
1222and the boolean return value indicates whether the operation is
1223successful. (Returning false usually means a connection error has
1224occurred.)
1225
1226At the service side, a signature with callback is used. The reason is
1227that in some cases the implementation may need to do some asynchronous
1228work which the sync method’s result depends on.
1229
1230*** note
1231**NOTE:** you can also use the signature with callback at the client side to
1232call the method asynchronously.
1233***
1234
1235### Re-entrancy
1236
1237What happens on the calling thread while waiting for the response of a
1238sync method call? It continues to process incoming sync request messages
1239(i.e., sync method calls); block other messages, including async
1240messages and sync response messages that don’t match the ongoing sync
1241call.
1242
Ken Rockotab035122019-02-06 00:35:241243![Diagram illustrating sync call flow](/docs/images/mojo_sync_call_flow.png)
Oksana Zhuravlova50bac902019-01-15 00:17:591244
1245Please note that sync response messages that don’t match the ongoing
1246sync call cannot re-enter. That is because they correspond to sync calls
1247down in the call stack. Therefore, they need to be queued and processed
1248while the stack unwinds.
1249
1250### Avoid deadlocks
1251
1252Please note that the re-entrancy behavior doesn’t prevent deadlocks
1253involving async calls. You need to avoid call sequences such as:
1254
Ken Rockotab035122019-02-06 00:35:241255![Diagram illustrating a sync call deadlock](/docs/images/mojo_sync_call_deadlock.png)
Oksana Zhuravlova50bac902019-01-15 00:17:591256
1257### Read more
1258
1259* [Design Proposal: Mojo Sync Methods](
1260https://docs.google.com/document/d/1dixzFzZQW8e3ldjdM8Adbo8klXDDE4pVekwo5aLgUsE)
rockotf59d2d62017-04-01 02:49:081261
1262## Type Mapping
1263
1264In many instances you might prefer that your generated C++ bindings use a more
1265natural type to represent certain Mojom types in your interface methods. For one
1266example consider a Mojom struct such as the `Rect` below:
1267
1268``` cpp
1269module gfx.mojom;
1270
1271struct Rect {
1272 int32 x;
1273 int32 y;
1274 int32 width;
1275 int32 height;
1276};
1277
1278interface Canvas {
1279 void FillRect(Rect rect);
1280};
1281```
1282
1283The `Canvas` Mojom interface would normally generate a C++ interface like:
1284
1285``` cpp
1286class Canvas {
1287 public:
1288 virtual void FillRect(RectPtr rect) = 0;
1289};
1290```
1291
1292However, the Chromium tree already defines a native
1293[`gfx::Rect`](https://cs.chromium.org/chromium/src/ui/gfx/geometry/rect.h) which
1294is equivalent in meaning but which also has useful helper methods. Instead of
1295manually converting between a `gfx::Rect` and the Mojom-generated `RectPtr` at
1296every message boundary, wouldn't it be nice if the Mojom bindings generator
1297could instead generate:
1298
1299``` cpp
1300class Canvas {
1301 public:
1302 virtual void FillRect(const gfx::Rect& rect) = 0;
1303}
1304```
1305
1306The correct answer is, "Yes! That would be nice!" And fortunately, it can!
1307
rockotf59d2d62017-04-01 02:49:081308### Defining `StructTraits`
1309
1310In order to teach generated bindings code how to serialize an arbitrary native
1311type `T` as an arbitrary Mojom type `mojom::U`, we need to define an appropriate
1312specialization of the
1313[`mojo::StructTraits`](https://cs.chromium.org/chromium/src/mojo/public/cpp/bindings/struct_traits.h)
1314template.
1315
1316A valid specialization of `StructTraits` MUST define the following static
1317methods:
1318
1319* A single static accessor for every field of the Mojom struct, with the exact
Ken Rockot74de8b82020-03-10 00:50:201320 same name as the struct field. These accessors must all take a (preferably
1321 const) ref to an object of the native type, and must return a value compatible
1322 with the Mojom struct field's type. This is used to safely and consistently
1323 extract data from the native type during message serialization without
1324 incurring extra copying costs.
rockotf59d2d62017-04-01 02:49:081325
1326* A single static `Read` method which initializes an instance of the the native
1327 type given a serialized representation of the Mojom struct. The `Read` method
1328 must return a `bool` to indicate whether the incoming data is accepted
1329 (`true`) or rejected (`false`).
1330
rockotf59d2d62017-04-01 02:49:081331In order to define the mapping for `gfx::Rect`, we want the following
1332`StructTraits` specialization, which we'll define in
Stephen Nusko0ea37f3d2019-02-17 01:45:191333`//ui/gfx/geometry/mojo/geometry_mojom_traits.h`:
rockotf59d2d62017-04-01 02:49:081334
1335``` cpp
Stephen Nusko0ea37f3d2019-02-17 01:45:191336#include "mojo/public/cpp/bindings/mojom_traits.h"
rockotf59d2d62017-04-01 02:49:081337#include "ui/gfx/geometry/rect.h"
1338#include "ui/gfx/geometry/mojo/geometry.mojom.h"
1339
1340namespace mojo {
1341
1342template <>
1343class StructTraits<gfx::mojom::RectDataView, gfx::Rect> {
1344 public:
1345 static int32_t x(const gfx::Rect& r) { return r.x(); }
1346 static int32_t y(const gfx::Rect& r) { return r.y(); }
1347 static int32_t width(const gfx::Rect& r) { return r.width(); }
1348 static int32_t height(const gfx::Rect& r) { return r.height(); }
1349
1350 static bool Read(gfx::mojom::RectDataView data, gfx::Rect* out_rect);
1351};
1352
1353} // namespace mojo
1354```
1355
Stephen Nusko0ea37f3d2019-02-17 01:45:191356And in `//ui/gfx/geometry/mojo/geometry_mojom_traits.cc`:
rockotf59d2d62017-04-01 02:49:081357
1358``` cpp
Stephen Nusko0ea37f3d2019-02-17 01:45:191359#include "ui/gfx/geometry/mojo/geometry_mojom_traits.h"
rockotf59d2d62017-04-01 02:49:081360
1361namespace mojo {
1362
1363// static
rockotf59d2d62017-04-01 02:49:081364bool StructTraits<gfx::mojom::RectDataView, gfx::Rect>::Read(
1365 gfx::mojom::RectDataView data,
1366 gfx::Rect* out_rect) {
1367 if (data.width() < 0 || data.height() < 0)
1368 return false;
1369
1370 out_rect->SetRect(data.x(), data.y(), data.width(), data.height());
1371 return true;
1372};
1373
1374} // namespace mojo
1375```
1376
1377Note that the `Read()` method returns `false` if either the incoming `width` or
1378`height` fields are negative. This acts as a validation step during
1379deserialization: if a client sends a `gfx::Rect` with a negative width or
1380height, its message will be rejected and the pipe will be closed. In this way,
1381type mapping can serve to enable custom validation logic in addition to making
1382callsites and interface implemention more convenient.
1383
Oksana Zhuravlova4b594672018-11-06 21:58:251384When the struct fields have non-primitive types, e.g. string or array,
1385returning a read-only view of the data in the accessor is recommended to
1386avoid copying. It is safe because the input object is guaranteed to
1387outlive the usage of the result returned by the accessor method.
1388
1389The following example uses `StringPiece` to return a view of the GURL's
1390data (`//url/mojom/url_gurl_mojom_traits.h`):
1391
1392``` cpp
1393#include "base/strings/string_piece.h"
1394#include "url/gurl.h"
1395#include "url/mojom/url.mojom.h"
1396#include "url/url_constants.h"
1397
1398namespace mojo {
1399
1400template <>
1401struct StructTraits<url::mojom::UrlDataView, GURL> {
1402 static base::StringPiece url(const GURL& r) {
1403 if (r.possibly_invalid_spec().length() > url::kMaxURLChars ||
1404 !r.is_valid()) {
1405 return base::StringPiece();
1406 }
1407 return base::StringPiece(r.possibly_invalid_spec().c_str(),
1408 r.possibly_invalid_spec().length());
1409 }
1410} // namespace mojo
1411```
1412
rockotf59d2d62017-04-01 02:49:081413### Enabling a New Type Mapping
1414
1415We've defined the `StructTraits` necessary, but we still need to teach the
1416bindings generator (and hence the build system) about the mapping. To do this we
Ken Rockot6ddaf0e2020-03-18 19:49:191417must add some more information to our `mojom` target in GN:
rockotf59d2d62017-04-01 02:49:081418
1419```
Ken Rockot6ddaf0e2020-03-18 19:49:191420# Without a typemap
Ken Rockot74de8b82020-03-10 00:50:201421mojom("mojom") {
1422 sources = [
1423 "rect.mojom",
Ken Rockot6ddaf0e2020-03-18 19:49:191424 ]
1425}
1426
1427# With a typemap.
1428mojom("mojom") {
1429 sources = [
1430 "rect.mojom",
Ken Rockot74de8b82020-03-10 00:50:201431 ]
1432
Ken Rockot6ddaf0e2020-03-18 19:49:191433 cpp_typemaps = [
1434 {
1435 # NOTE: A single typemap entry can list multiple individual type mappings.
1436 # Each mapping assumes the same values for |traits_headers| etc below.
1437 #
1438 # To typemap a type with separate |traits_headers| etc, add a separate
1439 # entry to |cpp_typemaps|.
1440 types = [
1441 {
1442 mojom = "gfx.mojom.Rect"
1443 cpp = "::gfx::Rect"
1444 },
1445 ]
1446 traits_headers = [ "//ui/gfx/geometry/mojo/geometry_mojom_traits.h" ]
1447 traits_sources = [ "//ui/gfx/geometry/mojo/geometry_mojom_traits.cc" ]
1448 traits_public_deps = [ "//ui/gfx/geometry" ]
1449 },
1450 ]
Ken Rockot74de8b82020-03-10 00:50:201451}
rockotf59d2d62017-04-01 02:49:081452```
1453
Ken Rockot6ddaf0e2020-03-18 19:49:191454See typemap documentation in
1455[mojom.gni](https://cs.chromium.org/chromium/src/mojo/public/tools/bindings/mojom.gni)
1456for details on the above definition and other supported parameters.
1457
1458With this extra configuration present, any mojom references to `gfx.mojom.Rect`
1459(e.g. for method parameters or struct fields) will be `gfx::Rect` references in
1460generated C++ code.
Ken Rockot6ddaf0e2020-03-18 19:49:191461
Ken Rockot74de8b82020-03-10 00:50:201462For the Blink variant of bindings, add to the `blink_cpp_typemaps` list instead.
1463
1464### Type Mapping Without `traits_sources`
1465
Ken Rockot6ddaf0e2020-03-18 19:49:191466Using `traits_sources` in a typemap configuration means that the listed sources
1467will be baked directly into the corresponding `mojom` target's own sources. This
1468can be problematic if you want to use the same typemap for both Blink and
1469non-Blink bindings.
Ken Rockot74de8b82020-03-10 00:50:201470
1471For such cases, it is recommended that you define a separate `component` target
Ken Rockot6ddaf0e2020-03-18 19:49:191472for your typemap traits, and reference this in the `traits_public_deps` of the
1473typemap:
rockotf59d2d62017-04-01 02:49:081474
1475```
Ken Rockot6ddaf0e2020-03-18 19:49:191476mojom("mojom") {
1477 sources = [
1478 "rect.mojom",
1479 ]
1480
1481 cpp_typemaps = [
1482 {
1483 types = [
1484 {
1485 mojom = "gfx.mojom.Rect"
1486 cpp = "::gfx::Rect"
1487 },
1488 ]
1489 traits_headers = [ "//ui/gfx/geometry/mojo/geometry_mojom_traits.h" ]
1490 traits_public_deps = [ ":geometry_mojom_traits" ]
1491 },
1492 ]
1493}
1494
Ken Rockot74de8b82020-03-10 00:50:201495component("geometry_mojom_traits") {
1496 sources = [
1497 "//ui/gfx/geometry/mojo/geometry_mojom_traits.cc",
1498 "//ui/gfx/geometry/mojo/geometry_mojom_traits.h",
1499 ]
1500
1501 # The header of course needs corresponding COMPONENT_EXPORT() tags.
1502 defines = [ "IS_GEOMETRY_MOJOM_TRAITS_IMPL" ]
Ken Rockot74de8b82020-03-10 00:50:201503}
rockotf59d2d62017-04-01 02:49:081504```
1505
1506### StructTraits Reference
1507
1508Each of a `StructTraits` specialization's static getter methods -- one per
1509struct field -- must return a type which can be used as a data source for the
1510field during serialization. This is a quick reference mapping Mojom field type
1511to valid getter return types:
1512
1513| Mojom Field Type | C++ Getter Return Type |
1514|------------------------------|------------------------|
1515| `bool` | `bool`
1516| `int8` | `int8_t`
1517| `uint8` | `uint8_t`
1518| `int16` | `int16_t`
1519| `uint16` | `uint16_t`
1520| `int32` | `int32_t`
1521| `uint32` | `uint32_t`
1522| `int64` | `int64_t`
1523| `uint64` | `uint64_t`
1524| `float` | `float`
1525| `double` | `double`
1526| `handle` | `mojo::ScopedHandle`
1527| `handle<message_pipe>` | `mojo::ScopedMessagePipeHandle`
1528| `handle<data_pipe_consumer>` | `mojo::ScopedDataPipeConsumerHandle`
1529| `handle<data_pipe_producer>` | `mojo::ScopedDataPipeProducerHandle`
Robert Sesek59ddca62022-04-29 17:50:581530| `handle<platform>` | `mojo::PlatformHandle`
rockotf59d2d62017-04-01 02:49:081531| `handle<shared_buffer>` | `mojo::ScopedSharedBufferHandle`
Oksana Zhuravlovad5888c92019-08-23 19:43:061532| `pending_remote<Foo>` | `mojo::PendingRemote<Foo>`
1533| `pending_receiver<Foo>` | `mojo::PendingReceiver<Foo>`
1534| `pending_associated_remote<Foo>` | `mojo::PendingAssociatedRemote<Foo>`
1535| `pending_associated_receiver<Foo>` | `mojo::PendingAssociatedReceiver<Foo>`
rockotf59d2d62017-04-01 02:49:081536| `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).
1537| `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).
1538| `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).
1539| `FooEnum` | Value of any type that has an appropriate `EnumTraits` specialization defined. By default this inlcudes only the generated `FooEnum` type.
1540| `FooStruct` | Value or reference to any type that has an appropriate `StructTraits` specialization defined. By default this includes only the generated `FooStructPtr` type.
1541| `FooUnion` | Value of reference to any type that has an appropriate `UnionTraits` specialization defined. By default this includes only the generated `FooUnionPtr` type.
Anton Bikineev60ef3812021-05-15 18:05:031542| `Foo?` | `absl::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:081543
1544### Using Generated DataView Types
1545
1546Static `Read` methods on `StructTraits` specializations get a generated
1547`FooDataView` argument (such as the `RectDataView` in the example above) which
1548exposes a direct view of the serialized Mojom structure within an incoming
1549message's contents. In order to make this as easy to work with as possible, the
1550generated `FooDataView` types have a generated method corresponding to every
1551struct field:
1552
1553* For POD field types (*e.g.* bools, floats, integers) these are simple accessor
1554 methods with names identical to the field name. Hence in the `Rect` example we
1555 can access things like `data.x()` and `data.width()`. The return types
1556 correspond exactly to the mappings listed in the table above, under
1557 [StructTraits Reference](#StructTraits-Reference).
1558
Oksana Zhuravlovad5888c92019-08-23 19:43:061559* For handle and interface types (*e.g* `handle` or `pending_remote<Foo>`) these
rockotf59d2d62017-04-01 02:49:081560 are named `TakeFieldName` (for a field named `field_name`) and they return an
1561 appropriate move-only handle type by value. The return types correspond
1562 exactly to the mappings listed in the table above, under
1563 [StructTraits Reference](#StructTraits-Reference).
1564
1565* For all other field types (*e.g.*, enums, strings, arrays, maps, structs)
1566 these are named `ReadFieldName` (for a field named `field_name`) and they
1567 return a `bool` (to indicate success or failure in reading). On success they
1568 fill their output argument with the deserialized field value. The output
1569 argument may be a pointer to any type with an appropriate `StructTraits`
1570 specialization defined, as mentioned in the table above, under
1571 [StructTraits Reference](#StructTraits-Reference).
1572
1573An example would be useful here. Suppose we introduced a new Mojom struct:
1574
1575``` cpp
1576struct RectPair {
1577 Rect left;
1578 Rect right;
1579};
1580```
1581
1582and a corresponding C++ type:
1583
1584``` cpp
1585class RectPair {
1586 public:
1587 RectPair() {}
1588
1589 const gfx::Rect& left() const { return left_; }
1590 const gfx::Rect& right() const { return right_; }
1591
1592 void Set(const gfx::Rect& left, const gfx::Rect& right) {
1593 left_ = left;
1594 right_ = right;
1595 }
1596
1597 // ... some other stuff
1598
1599 private:
1600 gfx::Rect left_;
1601 gfx::Rect right_;
1602};
1603```
1604
1605Our traits to map `gfx::mojom::RectPair` to `gfx::RectPair` might look like
1606this:
1607
1608``` cpp
1609namespace mojo {
1610
1611template <>
1612class StructTraits
1613 public:
1614 static const gfx::Rect& left(const gfx::RectPair& pair) {
1615 return pair.left();
1616 }
1617
1618 static const gfx::Rect& right(const gfx::RectPair& pair) {
1619 return pair.right();
1620 }
1621
1622 static bool Read(gfx::mojom::RectPairDataView data, gfx::RectPair* out_pair) {
1623 gfx::Rect left, right;
1624 if (!data.ReadLeft(&left) || !data.ReadRight(&right))
1625 return false;
1626 out_pair->Set(left, right);
1627 return true;
1628 }
1629} // namespace mojo
1630```
1631
1632Generated `ReadFoo` methods always convert `multi_word_field_name` fields to
1633`ReadMultiWordFieldName` methods.
1634
Andrew Moylan341cece72017-06-22 22:03:021635<a name="Blink-Type-Mapping"></a>
rockotf59d2d62017-04-01 02:49:081636### Variants
1637
1638By now you may have noticed that additional C++ sources are generated when a
1639Mojom is processed. These exist due to type mapping, and the source files we
1640refer to throughout this docuemnt (namely `foo.mojom.cc` and `foo.mojom.h`) are
1641really only one **variant** (the *default* or *chromium* variant) of the C++
1642bindings for a given Mojom file.
1643
1644The only other variant currently defined in the tree is the *blink* variant,
1645which produces a few additional files:
1646
1647```
1648out/gen/sample/db.mojom-blink.cc
1649out/gen/sample/db.mojom-blink.h
1650```
1651
1652These files mirror the definitions in the default variant but with different
1653C++ types in place of certain builtin field and parameter types. For example,
1654Mojom strings are represented by `WTF::String` instead of `std::string`. To
1655avoid symbol collisions, the variant's symbols are nested in an extra inner
1656namespace, so Blink consumer of the interface might write something like:
1657
1658```
1659#include "sample/db.mojom-blink.h"
1660
1661class TableImpl : public db::mojom::blink::Table {
1662 public:
1663 void AddRow(int32_t key, const WTF::String& data) override {
1664 // ...
1665 }
1666};
1667```
1668
1669In addition to using different C++ types for builtin strings, arrays, and maps,
Ken Rockot74de8b82020-03-10 00:50:201670the custom typemaps applied to Blink bindings are managed separately from
1671regular bindings.
rockotf59d2d62017-04-01 02:49:081672
Ken Rockot74de8b82020-03-10 00:50:201673`mojom` targets support a `blink_cpp_typemaps` parameter in addition to the
1674regular `cpp_typemaps`. This lists the typemaps to apply to Blink bindings.
1675
1676To depend specifically on generated Blink bindings, reference
1677`${target_name}_blink`. So for example, with the definition:
1678
1679```
1680# In //foo/mojom
1681mojom("mojom") {
1682 sources = [
1683 "db.mojom",
1684 ]
1685}
1686```
1687
1688C++ sources can depend on the Blink bindings by depending on
1689`"//foo/mojom:mojom_blink"`.
1690
1691Finally note that both bindings variants share some common definitions which are
1692unaffected by differences in the type-mapping configuration (like enums, and
1693structures describing serialized object formats). These definitions are
1694generated in *shared* sources:
rockotf59d2d62017-04-01 02:49:081695
1696```
1697out/gen/sample/db.mojom-shared.cc
1698out/gen/sample/db.mojom-shared.h
1699out/gen/sample/db.mojom-shared-internal.h
1700```
1701
1702Including either variant's header (`db.mojom.h` or `db.mojom-blink.h`)
Andrew Moylan341cece72017-06-22 22:03:021703implicitly includes the shared header, but may wish to include *only* the shared
1704header in some instances.
rockotf59d2d62017-04-01 02:49:081705
Ken Rockot74de8b82020-03-10 00:50:201706C++ sources can depend on shared sources only, by referencing the
1707`"${target_name}_shared"` target, e.g. `"//foo/mojom:mojom_shared"` in the
1708example above.
rockotf59d2d62017-04-01 02:49:081709
Lukasz Anforowiczdbe67ccd2021-11-03 15:30:381710For converting between Blink and non-Blink variants, please see
1711`//third_party/blink/public/platform/cross_variant_mojo_util.h`.
1712
rockotf59d2d62017-04-01 02:49:081713## Versioning Considerations
1714
1715For general documentation of versioning in the Mojom IDL see
David Benjamin0ff61822019-04-29 19:00:051716[Versioning](/mojo/public/tools/bindings/README.md#Versioning).
rockotf59d2d62017-04-01 02:49:081717
1718This section briefly discusses some C++-specific considerations relevant to
1719versioned Mojom types.
1720
1721### Querying Interface Versions
1722
Oksana Zhuravlovad5888c92019-08-23 19:43:061723`Remote` defines the following methods to query or assert remote interface
rockotf59d2d62017-04-01 02:49:081724version:
1725
1726```cpp
Anand K. Mistryff664b72019-11-08 00:50:101727void QueryVersion(base::OnceCallback<void(uint32_t)> callback);
rockotf59d2d62017-04-01 02:49:081728```
1729
1730This queries the remote endpoint for the version number of its binding. When a
1731response is received `callback` is invoked with the remote version number. Note
Oksana Zhuravlovad5888c92019-08-23 19:43:061732that this value is cached by the `Remote` instance to avoid redundant
rockotf59d2d62017-04-01 02:49:081733queries.
1734
1735```cpp
1736void RequireVersion(uint32_t version);
1737```
1738
1739Informs the remote endpoint that a minimum version of `version` is required by
1740the client. If the remote endpoint cannot support that version, it will close
1741its end of the pipe immediately, preventing any other requests from being
1742received.
1743
1744### Versioned Enums
1745
Daniel Cheng9e3bbfa2021-02-22 23:00:371746All extensible enums should have one enumerator value designated as the default
1747using the `[Default]` attribute. When Mojo deserializes an enum value that is
1748not defined in the current version of the enum definition, that value will be
1749transparently mapped to the `[Default]` enumerator value. Implementations can
1750use the presence of this enumerator value to correctly handle version skew.
rockotf59d2d62017-04-01 02:49:081751
1752```cpp
1753[Extensible]
1754enum Department {
Daniel Cheng9e3bbfa2021-02-22 23:00:371755 [Default] kUnknown,
1756 kSales,
1757 kDev,
1758 kResearch,
rockotf59d2d62017-04-01 02:49:081759};
1760```
1761
Sasha Bermeister995adc62017-12-07 02:36:431762### Using Mojo Bindings in Chrome
1763
Oksana Zhuravlova87b225a2019-03-07 01:08:031764See [Converting Legacy Chrome IPC To Mojo](/docs/mojo_ipc_conversion.md).
Sasha Bermeister995adc62017-12-07 02:36:431765
rockotf59d2d62017-04-01 02:49:081766### Additional Documentation
1767
Raphael Kubo da Costa8c6451ba2019-05-01 16:55:121768[Calling Mojo From Blink](/docs/mojo_ipc_conversion.md#Blink_Specific-Advice):
1769A brief overview of what it looks like to use Mojom C++ bindings from
1770within Blink code.