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

Side by Side Diff: mojo/public/cpp/bindings/README.md

Issue 2783223004: Adds lots of Mojo documentation (Closed)
Patch Set: Created 3 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 # ![Mojo Graphic](https://goo.gl/6CdlbH) Mojo C++ Bindings API
2 This document is a subset of the [Mojo documentation](/mojo).
3
4 [TOC]
5
6 ## Overview
7 The Mojo C++ Bindings API leverages the
8 [C++ System API](/mojo/public/cpp/system) to provide a more natural set of
9 primitives for communicating over Mojo message pipes. Combined with generated
10 code from the [Mojom IDL and bindings generator](/mojo/public/tools/bindings),
11 users can easily connect interface clients and implementations across arbitrary
12 intra- and inter-process bounaries.
13
14 This document provides a detailed guide to bindings API usage with example code
15 snippets. For a detailed API references please consult the headers in
16 [//mojo/public/cpp/bindings](https://cs.chromium.org/chromium/src/mojo/public/cp p/bindings/).
17
18 ## Getting Started
19
20 When a Mojom IDL file is processed by the bindings generator, C++ code is
21 emitted in a series of `.h` and `.cc` files with names based on the input
22 `.mojom` file. Suppose we create the following Mojom file at
23 `//services/db/public/interfaces/db.mojom`:
24
25 ```
26 module db.mojom;
27
28 interface Table {
29 AddRow(int32 key, string data);
30 };
31
32 interface Database {
33 CreateTable(Table& table);
34 };
35 ```
36
37 And a GN target to generate the bindings in
38 `//services/db/public/interfaces/BUILD.gn`:
39
40 ```
41 import("//mojo/public/tools/bindings/mojom.gni")
42
43 mojom("interfaces") {
44 sources = [
45 "db.mojom",
46 ]
47 }
48 ```
49
50 If we then build this target:
51
52 ```
53 ninja -C out/r services/db/public/interfaces
54 ```
55
56 This will produce several generated source files, some of which are relevant to
57 C++ bindings. Two of these files are:
58
59 ```
60 out/gen/services/business/public/interfaces/factory.mojom.cc
61 out/gen/services/business/public/interfaces/factory.mojom.h
62 ```
63
64 You can include the above generated header in your sources in order to use the
65 definitions therein:
66
67 ``` cpp
68 #include "services/business/public/interfaces/factory.mojom.h"
69
70 class TableImpl : public db::mojom::Table {
71 // ...
72 };
73 ```
74
75 This document covers the different kinds of definitions generated by Mojom IDL
76 for C++ consumers and how they can effectively be used to communicate across
77 message pipes.
78
79 *** note
80 **NOTE:** Using C++ bindings from within Blink code is typically subject to
81 special constraints which require the use of a different generated header.
82 For details, see [Blink Type Mapping](#Blink-Type-Mapping).
83 ***
84
85 ## Interfaces
86
87 Mojom IDL interfaces are translated to corresponding C++ (pure virtual) class
88 interface definitions in the generated header, consisting of a single generated
89 method signature for each request message on the interface. Internally there is
90 also generated code for serialization and deserialization of messages, but this
91 detail is hidden from bindings consumers.
92
93 ### Basic Usage
94
95 Let's consider a new `//sample/logger.mojom` to define a simple logging
96 interface which clients can use to log simple string messages:
97
98 ``` cpp
99 module sample.mojom;
100
101 interface Logger {
102 Log(string message);
103 };
104 ```
105
106 Running this through the bindings generator will produce a `logging.mojom.h`
107 with the following definitions (modulo unimportant details):
108
109 ``` cpp
110 namespace sample {
111 namespace mojom {
112
113 class Logger {
114 virtual ~Logger() {}
115
116 virtual void Log(const std::string& message) = 0;
117 };
118
119 using LoggerPtr = mojo::InterfacePtr<Logger>;
120 using LoggerRequest = mojo::InterfaceRequest<Logger>;
121
122 } // namespace mojom
123 } // namespace sample
124 ```
125
126 Makes sense. Let's take a closer look at those type aliases at the end.
127
128 ### InterfacePtr and InterfaceRequest
129
130 You will notice the type aliases for `LoggerPtr` and
131 `LoggerRequest` are using two of the most fundamental template types in the C++
132 bindings library: **`InterfacePtr<T>`** and **`InterfaceRequest<T>`**.
133
134 In the world of Mojo bindings libraries these are effectively strongly-typed
135 message pipe endpoints. If an `InterfacePtr<T>` is bound to a message pipe
136 endpoint, it can be dereferenced to make calls on an opaque `T` interface. These
137 calls immediately serialize their arguments (using generated code) and write a
138 corresponding message to the pipe.
139
140 An `InterfaceRequest<T>` is essentially just a typed container to hold the other
141 end of an `InterfacePtr<T>`'s pipe -- the receiving end -- until it can be
142 routed to some implementation which will **bind** it. The `InterfaceRequest<T>`
143 doesn't actually *do* anything other than hold onto a pipe endpoint and carry
144 useful compile-time type information.
145
146 ![Diagram illustrating InterfacePtr and InterfaceRequest on either end of a mess age pipe](https://docs.google.com/drawings/d/17d5gvErbQ6DthEBMS7I1WhCh9bz0n12pvN jydzuRfTI/pub?w=600&h=100)
147
148 So how do we create a strongly-typed message pipe?
149
150 ### Creating Interface Pipes
151
152 One way to do this is by manually creating a pipe and binding each end:
153
154 ``` cpp
155 #include "sample/logger.mojom.h"
156
157 mojo::MessagePipe pipe;
158 sample::mojom::LoggerPtr logger;
159 sample::mojom::LoggerRequest request;
160
161 logger.Bind(sample::mojom::LoggerPtrInfo(std::move(pipe.handle0), 0u));
162 request.Bind(std::move(pipe.handle1));
163 ```
164
165 That's pretty verbose, but the C++ Bindings library provides more convenient
166 ways to accomplish the same thing. [interface_request.h](https://cs.chromium.org /chromium/src/mojo/public/cpp/bindings/interface_request.h)
167 defines a `MakeRequest` function:
168
169 ``` cpp
170 sample::mojom::LoggerPtr logger;
171 sample::mojom::LoggerRequest request = mojo::MakeRequest(&logger);
172 ```
173
174 and the `InterfaceRequest<T>` constructor can also take an explicit
175 `InterfacePtr<T>*` output argument:
176
177 ``` cpp
178 sample::mojom::LoggerPtr logger;
179 sample::mojom::LoggerRequest request(&logger);
180 ```
181
182 Both of these last two snippets are equivalent to the first one.
183
184 *** note
185 **NOTE:** In the first example above you may notice usage of the `LoggerPtrInfo`
186 type, which is a generated alias for `mojo::InterfacePtrInfo<Logger>`. This is
187 similar to an `InterfaceRequest<T>` in that it merely holds onto a pipe handle
188 and cannot actually read or write messages on the pipe. Both this type and
189 `InterfaceRequest<T>` are safe to move freely from thread to thread, whereas a
190 bound `InterfacePtr<T>` is bound to a single thread.
191
192 An `InterfacePtr<T>` may be unbound by calling its `PassInterface()` method,
193 which returns a new `InterfacePtrInfo<T>`. Conversely, an `InterfacePtr<T>` may
194 bind (and thus take ownership of) an `InterfacePtrInfo<T>` so that interface
195 calls can be made on the pipe.
196
197 The thread-bound nature of `InterfacePtr<T>` is necessary to support safe
198 dispatch of its [message responses](#Receiving-Responses) and
199 [connection error notifications](#Connection-Errors).
200 ***
201
202 Once the `LoggerPtr` is bound we can immediately begin calling `Logger`
203 interface methods on it, which will immediately write messages into the pipe.
204 These messages will stay queued on the receiving end of the pipe until someone
205 binds to it and starts reading them.
206
207 ``` cpp
208 logger->Log("Hello!");
209 ```
210
211 This actually writes a `Log` message to the pipe.
212
213 ![Diagram illustrating a message traveling on a pipe from LoggerPtr to LoggerReq uest](https://docs.google.com/a/google.com/drawings/d/1jWEc6jJIP2ed77Gg4JJ3EVC7h vnwcImNqQJywFwpT8g/pub?w=648&h=123)
214
215 But as mentioned above, `InterfaceRequest` *doesn't actually do anything*, so
216 that message will just sit on the pipe forever. We need a way to read messages
217 off the other end of the pipe and dispatch them. We have to
218 **bind the interface request**.
219
220 ### Binding an Interface Request
221
222 There are many different helper classes in the bindings library for binding the
223 receiving end of a message pipe. The most primitive among them is the aptly
224 named `mojo::Binding<T>`. A `mojo::Binding<T>` bridges an implementation of `T`
225 with a single bound message pipe endpoint (via a `mojo::InterfaceRequest<T>`),
226 which it continuously watches for readability.
227
228 Any time the bound pipe becomes readable, the `Binding` will schedule a task to
229 read, deserialize (using generated code), and dispatch all available messages to
230 the bound `T` implementation. Below is a sample implementation of the `Logger`
231 interface. Notice that the implementation itself owns a `mojo::Binding`. This is
232 a common pattern, since a bound implementation must outlive any `mojo::Binding`
233 which binds it.
234
235 ``` cpp
236 #include "base/logging.h"
237 #include "base/macros.h"
238 #include "sample/logger.mojom.h"
239
240 class LoggerImpl : public sample::mojom::Logger {
241 public:
242 // NOTE: A common pattern for interface implementations which have one
243 // instance per client is to take an InterfaceRequest in the constructor.
244
245 explicit LoggerImpl(sample::mojom::LoggerRequest request)
246 : binding_(this, std::move(request)) {}
247 ~Logger() override {}
248
249 // sample::mojom::Logger:
250 void Log(const std::string& message) override {
251 LOG(ERROR) << "[Logger] " << message;
252 }
253
254 private:
255 mojo::Binding<sample::mojom::Logger> binding_;
256
257 DISALLOW_COPY_AND_ASSIGN(LoggerImpl);
258 };
259 ```
260
261 Now we can construct a `LoggerImpl` over our pending `LoggerRequest`, and the
262 previously queued `Log` message will be dispatched ASAP on the `LoggerImpl`'s
263 thread:
264
265 ``` cpp
266 LoggerImpl impl(std::move(request));
267 ```
268
269 The diagram below illustrates the following sequence of events, all set in
270 motion by the above line of code:
271
272 1. The `LoggerImpl` constructor is called, passing the `LoggerRequest` along
273 to the `Binding`.
274 2. The `Binding` takes ownership of the `LoggerRequest`'s pipe endpoint and
275 begins watching it for readability. The pipe is readable immediately, so a
276 task is scheduled to read the pending `Log` message from the pipe ASAP.
277 3. The `Log` message is read and deserialized, causing the `Binding` to invoke
278 the `Logger::Log` implementation on its bound `LoggerImpl`.
279
280 ![Diagram illustrating the progression of binding a request, reading a pending m essage, and dispatching it](https://docs.google.com/drawings/d/1c73-PegT4lmjfHox hWrHTQXRvzxgb0wdeBa35WBwZ3Q/pub?w=550&h=500)
281
282 As a result, our implementation will eventually log the client's `"Hello!"`
283 message via `LOG(ERROR)`.
284
285 *** note
286 **NOTE:** Messages will only be read and dispatched from a pipe as long as the
287 object which binds it (*i.e.* the `mojo::Binding` in the above example) remains
288 alive.
289 ***
290
291 ### Receiving Responses
292
293 Some Mojom interface methods expect a response. Suppose we modify our `Logger`
294 interface so that the last logged line can be queried like so:
295
296 ``` cpp
297 module sample.mojom;
298
299 interface Logger {
300 Log(string message);
301 GetTail() => (string message);
302 };
303 ```
304
305 The generated C++ interface will now look like:
306
307 ``` cpp
308 namespace sample {
309 namespace mojom {
310
311 class Logger {
312 public:
313 virtual ~Logger() {}
314
315 virtual void Log(const std::string& message) = 0;
316
317 using GetTailCallback = base::Callback<void(const std::string& message)>;
318
319 virtual void GetTail(const GetTailCallback& callback) = 0;
320 }
321
322 } // namespace mojom
323 } // namespace sample
324 ```
325
326 As before, both clients and implementations of this interface use the same
327 signature for the `GetTail` method: implementations use the `callback` argument
328 to *respond* to the request, while clients pass a `callback` argument to
329 asynchronously `receive` the response. Here's an updated implementation:
330
331 ```cpp
332 class LoggerImpl : public sample::mojom::Logger {
333 public:
334 // NOTE: A common pattern for interface implementations which have one
335 // instance per client is to take an InterfaceRequest in the constructor.
336
337 explicit LoggerImpl(sample::mojom::LoggerRequest request)
338 : binding_(this, std::move(request)) {}
339 ~Logger() override {}
340
341 // sample::mojom::Logger:
342 void Log(const std::string& message) override {
343 LOG(ERROR) << "[Logger] " << message;
344 lines_.push_back(message);
345 }
346
347 void GetTail(const GetTailCallback& callback) override {
348 callback.Run(lines_.back());
349 }
350
351 private:
352 mojo::Binding<sample::mojom::Logger> binding_;
353 std::vector<std::string> lines_;
354
355 DISALLOW_COPY_AND_ASSIGN(LoggerImpl);
356 };
357 ```
358
359 And an updated client call:
360
361 ``` cpp
362 void OnGetTail(const std::string& message) {
363 LOG(ERROR) << "Tail was: " << message;
364 }
365
366 logger->GetTail(base::Bind(&OnGetTail));
367 ```
368
369 Behind the scenes, the implementation-side callback is actually serializing the
370 response arguments and writing them onto the pipe for delivery back to the
371 client. Meanwhile the client-side callback is invoked by some internal logic
372 which watches the pipe for an incoming response message, reads and deserializes
373 it once it arrives, and then invokes the callback with the deserialized
374 parameters.
375
376 ### Connection Errors
377
378 If there are no remaining messages available on a pipe and the remote end has
379 been closed, a connection error will be triggered on the local end. Connection
380 errors may also be triggered by automatic forced local pipe closure due to
381 *e.g.* a validation error when processing a received message.
382
383 Regardless of the underlying cause, when a connection error is encountered on
384 a binding endpoint, that endpoint's **connection error handler** (if set) is
385 invoked. This handler is a simple `base::Closure` and may only be invoked
386 *once* as long as the endpoint is bound to the same pipe. Typically clients and
387 implementations use this handler to do some kind of cleanup or -- particuarly if
388 the error was unexpected -- create a new pipe and attempt to establish a new
389 connection with it.
390
391 All message pipe-binding C++ objects (*e.g.*, `mojo::Binding<T>`,
392 `mojo::InterfacePtr<T>`, *etc.*) support setting their connection error handler
393 via a `set_connection_error_handler` method.
394
395 We can set up another end-to-end `Logger` example to demonstrate error handler
396 invocation:
397
398 ``` cpp
399 sample::mojom::LoggerPtr logger;
400 LoggerImpl impl(mojo::MakeRequest(&logger));
401 impl.set_connection_error_handler(base::Bind([] { LOG(ERROR) << "Bye."; }));
402 logger->Log("OK cool");
403 logger.reset(); // Closes the client end.
404 ```
405
406 As long as `impl` stays alive here, it will eventually receive the `Log` message
407 followed immediately by an invocation of the bound callback which outputs
408 `"Bye."`. Like all other bindings callbacks, a connection error handler will
409 **never** be invoked once its corresponding binding object has been destroyed.
410
411 In fact, suppose instead that `LoggerImpl` had set up the following error
412 handler within its constructor:
413
414 ``` cpp
415 LoggerImpl::LoggerImpl(sample::mojom::LoggerRequest request)
416 : binding_(this, std::move(request)) {
417 binding_.set_connection_error_handler(
418 base::Bind(&LoggerImpl::OnError, base::Unretained(this)));
419 }
420
421 void LoggerImpl::OnError() {
422 LOG(ERROR) << "Client disconnected! Purging log lines.";
423 lines_.clear();
424 }
425 ```
426
427 The use of `base::Unretained` is *safe* because the error handler will never be
428 invoked beyond the lifetime of `binding_`, and `this` owns `binding_`.
429
430 ### A Note About Ordering
431
432 As mentioned in the previous section, closing one end of a pipe will eventually
433 trigger a connection error on the other end. However it's important to note that
434 this event is itself ordered with respect to any other event (*e.g.* writing a
435 message) on the pipe.
436
437 This means that it's safe to write something contrived like:
438
439 ``` cpp
440 void GoBindALogger(sample::mojom::LoggerRequest request) {
441 LoggerImpl impl(std::move(request));
442 base::RunLoop loop;
443 impl.set_connection_error_handler(loop.QuitClosure());
444 loop.Run();
445 }
446
447 void LogSomething() {
448 sample::mojom::LoggerPtr logger;
449 bg_thread->task_runner()->PostTask(
450 FROM_HERE, base::BindOnce(&GoBindALogger, mojo::MakeRequest(&logger)));
451 logger->Log("OK Computer");
452 }
453 ```
454
455 When `logger` goes out of scope it immediately closes its end of the message
456 pipe, but the impl-side won't notice this until it receives the sent `Log`
457 message. Thus the `impl` above will first log our message and *then* see a
458 connection error and break out of the run loop.
459
460 ### Sending Interfaces Over Interfaces
461
462 Now we know how to create interface pipes and use their Ptr and Request
463 endpoints in some interesting ways. This still doesn't add up to interesting
464 IPC! The bread and butter of Mojo IPC is the ability to transfer interface
465 endpoints across other interfaces, so let's take a look at how to accomplish
466 that.
467
468 #### Sending Interface Requests
469
470 Consider a new example Mojom in `//sample/db.mojom`:
471
472 ``` cpp
473 module db.mojom;
474
475 interface Table {
476 void AddRow(int32 key, string data);
477 };
478
479 interface Database {
480 AddTable(Table& table);
481 };
482 ```
483
484 As noted in the
485 [Mojom IDL documentation](/mojo/public/tools/bindings#Primitive-Types),
486 the `Table&` syntax denotes a `Table` interface request. This corresponds
487 precisely to the `InterfaceRequest<T>` type discussed in the sections above, and
488 in fact the generated code for these interfaces is approximately:
489
490 ``` cpp
491 namespace db {
492 namespace mojom {
493
494 class Table {
495 public:
496 virtual ~Table() {}
497
498 virtual void AddRow(int32_t key, const std::string& data) = 0;
499 }
500
501 using TablePtr = mojo::InterfacePtr<Table>;
502 using TableRequest = mojo::InterfaceRequest<Table>;
503
504 class Database {
505 public:
506 virtual ~Database() {}
507
508 virtual void AddTable(TableRequest table);
509 };
510
511 using DatabasePtr = mojo::InterfacePtr<Database>;
512 using DatabaseRequest = mojo::InterfaceRequest<Database>;
513
514 } // namespace mojom
515 } // namespace db
516 ```
517
518 We can put this all together now with an implementation of `Table` and
519 `Database`:
520
521 ``` cpp
522 #include "sample/db.mojom.h"
523
524 class TableImpl : public db::mojom:Table {
525 public:
526 explicit TableImpl(db::mojom::TableRequest request)
527 : binding_(this, std::move(request)) {}
528 ~TableImpl() override {}
529
530 // db::mojom::Table:
531 void AddRow(int32_t key, const std::string& data) override {
532 rows_.insert({key, data});
533 }
534
535 private:
536 mojo::Binding<db::mojom::Table> binding_;
537 std::map<int32_t, std::string> rows_;
538 };
539
540 class DatabaseImpl : public db::mojom::Database {
541 public:
542 explicit DatabaseImpl(db::mojom::DatabaseRequest request)
543 : binding_(this, std::move(request)) {}
544 ~DatabaseImpl() override {}
545
546 // db::mojom::Database:
547 void AddTable(db::mojom::TableRequest table) {
548 tables_.emplace_back(base::MakeUnique<TableImpl>(std::move(table)));
549 }
550
551 private:
552 mojo::Binding<db::mojom::Database> binding_;
553 std::vector<std::unique_ptr<TableImpl>> tables_;
554 };
555 ```
556
557 Pretty straightforward. The `Table&` Mojom paramter to `AddTable` translates to
558 a C++ `db::mojom::TableRequest`, aliased from
559 `mojo::InterfaceRequest<db::mojom::Table>`, which we know is just a
560 strongly-typed message pipe handle. When `DatabaseImpl` gets an `AddTable` call,
561 it constructs a new `TableImpl` and binds it to the received `TableRequest`.
562
563 Let's see how this can be used.
564
565 ``` cpp
566 db::mojom::DatabasePtr database;
567 DatabaseImpl db_impl(mojo::MakeRequest(&database));
568
569 db::mojom::TablePtr table1, table2;
570 database->AddTable(mojo::MakeRequest(&table1));
571 database->AddTable(mojo::MakeRequest(&table2));
572
573 table1->AddRow(1, "hiiiiiiii");
574 table2->AddRow(2, "heyyyyyy");
575 ```
576
577 Notice that we can again start using the new `Table` pipes immediately, even
578 while their `TableRequest` endpoints are still in transit.
579
580 #### Sending InterfacePtrs
581
582 Of course we can also send `InterfacePtr`s:
583
584 ``` cpp
585 interface TableListener {
586 OnRowAdded(int32 key, string data);
587 };
588
589 interface Table {
590 AddRow(int32 key, string data);
591
592 AddListener(TableListener listener);
593 };
594 ```
595
596 This would generate a `Table::AddListener` signature like so:
597
598 ``` cpp
599 virtual void AddListener(TableListenerPtr listener) = 0;
600 ```
601
602 and this could be used like so:
603
604 ``` cpp
605 db::mojom::TableListenerPtr listener;
606 TableListenerImpl impl(mojo::MakeRequest(&listener));
607 table->AddListener(std::move(listener));
608 ```
609
610 ## Other Interface Binding Types
611
612 The [Interfaces](#Interfaces) section above covers basic usage of the most
613 common bindings object types: `InterfacePtr`, `InterfaceRequest`, and `Binding`.
614 While these types are probably the most commonly used in practice, there are
615 several other ways of binding both client- and implementation-side interface
616 pipes.
617
618 ### Strong Bindings
619
620 A **strong binding** exists as a standalone object which owns its interface
621 implementation and automatically cleans itself up when its bound interface
622 endpoint detects an error. The
623 [**`MakeStrongBinding`**](https://cs.chromim.org/chromium/src//mojo/public/cpp/b indings/strong_binding.h)
624 function is used to create such a binding.
625 .
626
627 ``` cpp
628 class LoggerImpl : public sample::mojom::Logger {
629 public:
630 LoggerImpl() {}
631 ~LoggerImpl() override {}
632
633 // sample::mojom::Logger:
634 void Log(const std::string& message) override {
635 LOG(ERROR) << "[Logger] " << message;
636 }
637
638 private:
639 // NOTE: This doesn't own any Binding object!
640 };
641
642 db::mojom::LoggerPtr logger;
643 mojo::MakeStrongBinding(base::MakeUnique<DatabaseImpl>(),
644 mojo::MakeRequest(&logger));
645
646 logger->Log("NOM NOM NOM MESSAGES");
647 ```
648
649 Now as long as `logger` remains open somewhere in the system, the bound
650 `DatabaseImpl` on the other end will remain alive.
651
652 ### Binding Sets
653
654 Sometimes it's useful to share a single implementation instance with multiple
655 clients. [**`BindingSet`**](https://cs.chromium.org/chromium/src/mojo/public/cpp /bindings/binding_set.h)
656 makes this easy. Consider the Mojom:
657
658 ``` cpp
659 module system.mojom;
660
661 interface Logger {
662 Log(string message);
663 };
664
665 interface LoggerProvider {
666 GetLogger(Logger& logger);
667 };
668 ```
669
670 We can use `BindingSet` to bind multiple `Logger` requests to a single
671 implementation instance:
672
673 ``` cpp
674 class LogManager : public system::mojom::LoggerProvider,
675 public system::mojom::Logger {
676 public:
677 explicit LogManager(system::mojom::LoggerProviderRequest request)
678 : provider_binding_(this, std::move(request)) {}
679 ~LogManager() {}
680
681 // system::mojom::LoggerProvider:
682 void GetLogger(LoggerRequest request) override {
683 logger_bindings_.AddBinding(this, std::move(request));
684 }
685
686 // system::mojom::Logger:
687 void Log(const std::string& message) override {
688 LOG(ERROR) << "[Logger] " << message;
689 }
690
691 private:
692 mojo::Binding<system::mojom::LoggerProvider> provider_binding_;
693 mojo::BindingSet<system::mojom::Logger> logger_bindings_;
694 };
695
696 ```
697
698
699 ### InterfacePtr Sets
700
701 Similar to the `BindingSet` above, sometimes it's useful to maintain a set of
702 `InterfacePtr`s for *e.g.* a set of clients observing some event.
703 [**`InterfacePtrSet`**](https://cs.chromium.org/chromium/src/mojo/public/cpp/bin dings/interface_ptr_set.h)
704 is here to help. Take the Mojom:
705
706 ``` cpp
707 module db.mojom;
708
709 interface TableListener {
710 OnRowAdded(int32 key, string data);
711 };
712
713 interface Table {
714 AddRow(int32 key, string data);
715 AddListener(TableListener listener);
716 };
717 ```
718
719 An implementation of `Table` might look something like like this:
720
721 ``` cpp
722 class TableImpl : public db::mojom::Table {
723 public:
724 TableImpl() {}
725 ~TableImpl() override {}
726
727 // db::mojom::Table:
728 void AddRow(int32_t key, const std::string& data) override {
729 rows_.insert({key, data});
730 listeners_.ForEach([key, &data](db::mojom::TableListener* listener) {
731 listener->OnRowAdded(key, data);
732 });
733 }
734
735 void AddListener(db::mojom::TableListenerPtr listener) {
736 listeners_.AddPtr(std::move(listener));
737 }
738
739 private:
740 mojo::InterfacePtrSet<db::mojom::Table> listeners_;
741 std::map<int32_t, std::string> rows_;
742 };
743 ```
744
745 ## Associated Interfaces
746
747 See [this document](https://www.chromium.org/developers/design-documents/mojo/as sociated-interfaces).
748
749 TODO: Move the above doc into the repository markdown docs.
750
751 ## Synchronous Calls
752
753 See [this document](https://www.chromium.org/developers/design-documents/mojo/sy nchronous-calls)
754
755 TODO: Move the above doc into the repository markdown docs.
756
757 ## Type Mapping
758
759 In many instances you might prefer that your generated C++ bindings use a more
760 natural type to represent certain Mojom types in your interface methods. For one
761 example consider a Mojom struct such as the `Rect` below:
762
763 ``` cpp
764 module gfx.mojom;
765
766 struct Rect {
767 int32 x;
768 int32 y;
769 int32 width;
770 int32 height;
771 };
772
773 interface Canvas {
774 void FillRect(Rect rect);
775 };
776 ```
777
778 The `Canvas` Mojom interface would normally generate a C++ interface like:
779
780 ``` cpp
781 class Canvas {
782 public:
783 virtual void FillRect(RectPtr rect) = 0;
784 };
785 ```
786
787 However, the Chromium tree already defines a native
788 [`gfx::Rect`](https://cs.chromium.org/chromium/src/ui/gfx/geometry/rect.h) which
789 is equivalent in meaning but which also has useful helper methods. Instead of
790 manually converting between a `gfx::Rect` and the Mojom-generated `RectPtr` at
791 every message boundary, wouldn't it be nice if the Mojom bindings generator
792 could instead generate:
793
794 ``` cpp
795 class Canvas {
796 public:
797 virtual void FillRect(const gfx::Rect& rect) = 0;
798 }
799 ```
800
801 The correct answer is, "Yes! That would be nice!" And fortunately, it can!
802
803 ### Global Configuration
804
805 While this feature is quite powerful, it introduces some unavoidable complexity
806 into build system. This stems from the fact that type-mapping is an inherently
807 viral concept: if `gfx::mojom::Rect` is mapped to `gfx::Rect` anywhere, the
808 mapping needs to apply *everywhere*.
809
810 For this reason we have a few global typemap configurations defined in
811 [chromium_bindings_configuration.gni](https://cs.chromium.com/chromium/src/mojo/ public/tools/bindings/chromium_bindings_configuration.gni)
812 and
813 [blink_bindings_configuration.gni](https://cs.chromium.com/chromium/src/mojo/pub lic/tools/bindings/blink_bindings_configuration.gni). These configure the two su pported [variants](#Variants) of Mojom generated
814 bindings in the repository. Read more on this in the sections that follow.
815
816 For now, let's take a look at how to express the mapping from `gfx::mojom::Rect`
817 to `gfx::Rect`.
818
819 ### Defining `StructTraits`
820
821 In order to teach generated bindings code how to serialize an arbitrary native
822 type `T` as an arbitrary Mojom type `mojom::U`, we need to define an appropriate
823 specialization of the
824 [`mojo::StructTraits`](https://cs.chromium.org/chromium/src/mojo/public/cpp/bind ings/struct_traits.h)
825 template.
826
827 A valid specialization of `StructTraits` MUST define the following static
828 methods:
829
830 * A single static accessor for every field of the Mojom struct, with the exact
831 same name as the struct field. These accessors must all take a const ref to
832 an object of the native type, and must return a value compatible with the
833 Mojom struct field's type. This is used to safely and consistently extract
834 data from the native type during message serialization without incurring extra
835 copying costs.
836
837 * A single static `Read` method which initializes an instance of the the native
838 type given a serialized representation of the Mojom struct. The `Read` method
839 must return a `bool` to indicate whether the incoming data is accepted
840 (`true`) or rejected (`false`).
841
842 There are other methods a `StructTraits` specialization may define to satisfy
843 some less common requirements. See
844 [Advanced StructTraits Usage](#Advanced-StructTraits-Usage) for details.
845
846 In order to define the mapping for `gfx::Rect`, we want the following
847 `StructTraits` specialization, which we'll define in
848 `//ui/gfx/geometry/mojo/geometry_struct_traits.h`:
849
850 ``` cpp
851 #include "mojo/public/cpp/bindings/struct_traits.h"
852 #include "ui/gfx/geometry/rect.h"
853 #include "ui/gfx/geometry/mojo/geometry.mojom.h"
854
855 namespace mojo {
856
857 template <>
858 class StructTraits<gfx::mojom::RectDataView, gfx::Rect> {
859 public:
860 static int32_t x(const gfx::Rect& r) { return r.x(); }
861 static int32_t y(const gfx::Rect& r) { return r.y(); }
862 static int32_t width(const gfx::Rect& r) { return r.width(); }
863 static int32_t height(const gfx::Rect& r) { return r.height(); }
864
865 static bool Read(gfx::mojom::RectDataView data, gfx::Rect* out_rect);
866 };
867
868 } // namespace mojo
869 ```
870
871 And in `//ui/gfx/geometry/mojo/geometry_struct_traits.cc`:
872
873 ``` cpp
874 #include "ui/gfx/geometry/mojo/geometry_struct_traits.h"
875
876 namespace mojo {
877
878 // static
879 template <>
880 bool StructTraits<gfx::mojom::RectDataView, gfx::Rect>::Read(
881 gfx::mojom::RectDataView data,
882 gfx::Rect* out_rect) {
883 if (data.width() < 0 || data.height() < 0)
884 return false;
885
886 out_rect->SetRect(data.x(), data.y(), data.width(), data.height());
887 return true;
888 };
889
890 } // namespace mojo
891 ```
892
893 Note that the `Read()` method returns `false` if either the incoming `width` or
894 `height` fields are negative. This acts as a validation step during
895 deserialization: if a client sends a `gfx::Rect` with a negative width or
896 height, its message will be rejected and the pipe will be closed. In this way,
897 type mapping can serve to enable custom validation logic in addition to making
898 callsites and interface implemention more convenient.
899
900 ### Enabling a New Type Mapping
901
902 We've defined the `StructTraits` necessary, but we still need to teach the
903 bindings generator (and hence the build system) about the mapping. To do this we
904 must create a **typemap** file, which uses familiar GN syntax to describe the
905 new type mapping.
906
907 Let's place this `geometry.typemap` file alongside our Mojom file:
908
909 ```
910 mojom = "//ui/gfx/geometry/mojo/geometry.mojom"
911 public_headers = [ "//ui/gfx/geometry/rect.h" ]
912 traits_headers = [ "//ui/gfx/geometry/mojo/geometry_struct_traits.h" ]
913 sources = [ "//ui/gfx/geometry/mojo/geometry_struct_traits.cc" ]
914 public_deps = [ "//ui/gfx/geometry" ]
915 type_mappings = [
916 "gfx.mojom.Rect=gfx::Rect",
917 ]
918 ```
919
920 Let's look at each of the variables above:
921
922 * `mojom`: Specifies the `mojom` file to which the typemap applies. Many
923 typemaps may apply to the same `mojom` file, but any given typemap may only
924 apply to a single `mojom` file.
925 * `public_headers`: Additional headers required by any code which would depend
926 on the Mojom definition of `gfx.mojom.Rect` now that the typemap is applied.
927 Any headers required for the native target type definition should be listed
928 here.
929 * `traits_headers`: Headers which contain the relevant `StructTraits`
930 specialization(s) for any type mappings described by this file.
931 * `sources`: Any private implementation sources needed for the `StructTraits`
932 definition.
933 * `public_deps`: Target dependencies exposed by the `public_headers` and
934 `traits_headers`.
935 * `deps`: Target dependencies exposed by `sources` but not already covered by
936 `public_deps`.
937 * `type_mappings`: A list of type mappings to be applied for this typemap. The
938 strings in this list are of the format `"MojomType=CppType"`, where
939 `MojomType` must be a fully qualified Mojom typename and `CppType` must be a
940 fully qualified C++ typename. Additional attributes may be specified in square
941 brackets following the `CppType`:
942 * `move_only`: The `CppType` is move-only and should be passed by value
943 in any generated method signatures. Note that `move_only` is transitive,
944 so containers of `MojomType` will translate to containers of `CppType`
945 also passed by value.
946 * `copyable_pass_by_value`: Forces values of type `CppType` to be passed by
947 value without moving them. Unlike `move_only`, this is not transitive.
948 * `nullable_is_same_type`: By default a non-nullable `MojomType` will be
949 mapped to `CppType` while a nullable `MojomType?` will be mapped to
950 `base::Optional<CppType>`. If this attribute is set, the `base::Optional`
951 wrapper is omitted for nullable `MojomType?` values, but the
952 `StructTraits` definition for this type mapping must define additional
953 `IsNull` and `SetToNull` methods. See
954 [Specializing Nullability](#Specializing-Nullability) below.
955
956
957 Now that we have the typemap file we need to add it to a local list of typemaps
958 that can be added to the global configuration. We create a new
959 `//ui/gfx/typemaps.gni` file with the following contents:
960
961 ```
962 typemaps = [
963 "//ui/gfx/geometry/mojo/geometry.typemap",
964 ]
965 ```
966
967 And finally we can reference this file in the global default (Chromium) bindings
968 configuration by adding it to `_typemap_imports` in
969 [chromium_bindings_configuration.gni](https://cs.chromium.com/chromium/src/mojo/ public/tools/bindings/chromium_bindings_configuration.gni):
970
971 ```
972 _typemap_imports = [
973 ...,
974 "//ui/gfx/typemaps.gni",
975 ...,
976 ]
977 ```
978
979 ### StructTraits Reference
980
981 Each of a `StructTraits` specialization's static getter methods -- one per
982 struct field -- must return a type which can be used as a data source for the
983 field during serialization. This is a quick reference mapping Mojom field type
984 to valid getter return types:
985
986 | Mojom Field Type | C++ Getter Return Type |
987 |------------------------------|------------------------|
988 | `bool` | `bool`
989 | `int8` | `int8_t`
990 | `uint8` | `uint8_t`
991 | `int16` | `int16_t`
992 | `uint16` | `uint16_t`
993 | `int32` | `int32_t`
994 | `uint32` | `uint32_t`
995 | `int64` | `int64_t`
996 | `uint64` | `uint64_t`
997 | `float` | `float`
998 | `double` | `double`
999 | `handle` | `mojo::ScopedHandle`
1000 | `handle<message_pipe>` | `mojo::ScopedMessagePipeHandle`
1001 | `handle<data_pipe_consumer>` | `mojo::ScopedDataPipeConsumerHandle`
1002 | `handle<data_pipe_producer>` | `mojo::ScopedDataPipeProducerHandle`
1003 | `handle<shared_buffer>` | `mojo::ScopedSharedBufferHandle`
1004 | `FooInterface` | `FooInterfacePtr`
1005 | `FooInterface&` | `FooInterfaceRequest`
1006 | `associated FooInterface` | `FooAssociatedInterfacePtr`
1007 | `associated FooInterface&` | `FooAssociatedInterfaceRequest`
1008 | `string` | Value or reference to any type `T` that has a ` mojo::StringTraits` specialization defined. By default this includes `std::strin g`, `base::StringPiece`, and `WTF::String` (Blink).
1009 | `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).
1010 | `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).
1011 | `FooEnum` | Value of any type that has an appropriate `Enum Traits` specialization defined. By default this inlcudes only the generated `Foo Enum` type.
1012 | `FooStruct` | Value or reference to any type that has an appr opriate `StructTraits` specialization defined. By default this includes only the generated `FooStructPtr` type.
1013 | `FooUnion` | Value of reference to any type that has an appr opriate `UnionTraits` specialization defined. By default this includes only the generated `FooUnionPtr` type.
1014
1015 ### Using Generated DataView Types
1016
1017 Static `Read` methods on `StructTraits` specializations get a generated
1018 `FooDataView` argument (such as the `RectDataView` in the example above) which
1019 exposes a direct view of the serialized Mojom structure within an incoming
1020 message's contents. In order to make this as easy to work with as possible, the
1021 generated `FooDataView` types have a generated method corresponding to every
1022 struct field:
1023
1024 * For POD field types (*e.g.* bools, floats, integers) these are simple accessor
1025 methods with names identical to the field name. Hence in the `Rect` example we
1026 can access things like `data.x()` and `data.width()`. The return types
1027 correspond exactly to the mappings listed in the table above, under
1028 [StructTraits Reference](#StructTraits-Reference).
1029
1030 * For handle and interface types (*e.g* `handle` or `FooInterface&`) these
1031 are named `TakeFieldName` (for a field named `field_name`) and they return an
1032 appropriate move-only handle type by value. The return types correspond
1033 exactly to the mappings listed in the table above, under
1034 [StructTraits Reference](#StructTraits-Reference).
1035
1036 * For all other field types (*e.g.*, enums, strings, arrays, maps, structs)
1037 these are named `ReadFieldName` (for a field named `field_name`) and they
1038 return a `bool` (to indicate success or failure in reading). On success they
1039 fill their output argument with the deserialized field value. The output
1040 argument may be a pointer to any type with an appropriate `StructTraits`
1041 specialization defined, as mentioned in the table above, under
1042 [StructTraits Reference](#StructTraits-Reference).
1043
1044 An example would be useful here. Suppose we introduced a new Mojom struct:
1045
1046 ``` cpp
1047 struct RectPair {
1048 Rect left;
1049 Rect right;
1050 };
1051 ```
1052
1053 and a corresponding C++ type:
1054
1055 ``` cpp
1056 class RectPair {
1057 public:
1058 RectPair() {}
1059
1060 const gfx::Rect& left() const { return left_; }
1061 const gfx::Rect& right() const { return right_; }
1062
1063 void Set(const gfx::Rect& left, const gfx::Rect& right) {
1064 left_ = left;
1065 right_ = right;
1066 }
1067
1068 // ... some other stuff
1069
1070 private:
1071 gfx::Rect left_;
1072 gfx::Rect right_;
1073 };
1074 ```
1075
1076 Our traits to map `gfx::mojom::RectPair` to `gfx::RectPair` might look like
1077 this:
1078
1079 ``` cpp
1080 namespace mojo {
1081
1082 template <>
1083 class StructTraits
1084 public:
1085 static const gfx::Rect& left(const gfx::RectPair& pair) {
1086 return pair.left();
1087 }
1088
1089 static const gfx::Rect& right(const gfx::RectPair& pair) {
1090 return pair.right();
1091 }
1092
1093 static bool Read(gfx::mojom::RectPairDataView data, gfx::RectPair* out_pair) {
1094 gfx::Rect left, right;
1095 if (!data.ReadLeft(&left) || !data.ReadRight(&right))
1096 return false;
1097 out_pair->Set(left, right);
1098 return true;
1099 }
1100 } // namespace mojo
1101 ```
1102
1103 Generated `ReadFoo` methods always convert `multi_word_field_name` fields to
1104 `ReadMultiWordFieldName` methods.
1105
1106 ### Variants
1107
1108 By now you may have noticed that additional C++ sources are generated when a
1109 Mojom is processed. These exist due to type mapping, and the source files we
1110 refer to throughout this docuemnt (namely `foo.mojom.cc` and `foo.mojom.h`) are
1111 really only one **variant** (the *default* or *chromium* variant) of the C++
1112 bindings for a given Mojom file.
1113
1114 The only other variant currently defined in the tree is the *blink* variant,
1115 which produces a few additional files:
1116
1117 ```
1118 out/gen/sample/db.mojom-blink.cc
1119 out/gen/sample/db.mojom-blink.h
1120 ```
1121
1122 These files mirror the definitions in the default variant but with different
1123 C++ types in place of certain builtin field and parameter types. For example,
1124 Mojom strings are represented by `WTF::String` instead of `std::string`. To
1125 avoid symbol collisions, the variant's symbols are nested in an extra inner
1126 namespace, so Blink consumer of the interface might write something like:
1127
1128 ```
1129 #include "sample/db.mojom-blink.h"
1130
1131 class TableImpl : public db::mojom::blink::Table {
1132 public:
1133 void AddRow(int32_t key, const WTF::String& data) override {
1134 // ...
1135 }
1136 };
1137 ```
1138
1139 In addition to using different C++ types for builtin strings, arrays, and maps,
1140 the global typemap configuration for default and "blink" variants are completely
1141 separate. To add a typemap for the Blink configuration, you can modify
1142 [blink_bindings_configuration.gni](https://cs.chromium.org/chromium/src/mojo/pub lic/tools/bindings/blink_bindings_configuration.gni).
1143
1144 All variants share some definitions which are unaffected by differences in the
1145 type mapping configuration (enums, for example). These definitions are generated
1146 in *shared* sources:
1147
1148 ```
1149 out/gen/sample/db.mojom-shared.cc
1150 out/gen/sample/db.mojom-shared.h
1151 out/gen/sample/db.mojom-shared-internal.h
1152 ```
1153
1154 Including either variant's header (`db.mojom.h` or `db.mojom-blink.h`)
1155 implicitly includes the shared header, but you have on some occasions wish to
1156 include *only* the shared header in some instances.
1157
1158 Finally, note that for `mojom` GN targets, there is implicitly a corresponding
1159 `mojom_{variant}` target defined for any supported bindings configuration. So
1160 for example if you've defined in `//sample/BUILD.gn`:
1161
1162 ```
1163 import("mojo/public/tools/bindings/mojom.gni")
1164
1165 mojom("interfaces") {
1166 sources = [
1167 "db.mojom",
1168 ]
1169 }
1170 ```
1171
1172 Code in Blink which wishes to use the generated Blink-variant definitions must
1173 depend on `"//sample:interfaces_blink"`.
1174
1175 ## Versioning Considerations
1176
1177 For general documentation of versioning in the Mojom IDL see
1178 [Versioning](/mojo/public/tools/bindings#Versioning).
1179
1180 This section briefly discusses some C++-specific considerations relevant to
1181 versioned Mojom types.
1182
1183 ### Querying Interface Versions
1184
1185 `InterfacePtr` defines the following methods to query or assert remote interface
1186 version:
1187
1188 ```cpp
1189 void QueryVersion(const base::Callback<void(uint32_t)>& callback);
1190 ```
1191
1192 This queries the remote endpoint for the version number of its binding. When a
1193 response is received `callback` is invoked with the remote version number. Note
1194 that this value is cached by the `InterfacePtr` instance to avoid redundant
1195 queries.
1196
1197 ```cpp
1198 void RequireVersion(uint32_t version);
1199 ```
1200
1201 Informs the remote endpoint that a minimum version of `version` is required by
1202 the client. If the remote endpoint cannot support that version, it will close
1203 its end of the pipe immediately, preventing any other requests from being
1204 received.
1205
1206 ### Versioned Enums
1207
1208 For convenience, every extensible enum has a generated helper function to
1209 determine whether a received enum value is known by the implementation's current
1210 version of the enum definition. For example:
1211
1212 ```cpp
1213 [Extensible]
1214 enum Department {
1215 SALES,
1216 DEV,
1217 RESEARCH,
1218 };
1219 ```
1220
1221 generates the function in the same namespace as the generated C++ enum type:
1222
1223 ```cpp
1224 inline bool IsKnownEnumValue(Department value);
1225 ```
1226
1227 ### Additional Documentation
1228
1229 [Calling Mojo From Blink](https://www.chromium.org/developers/design-documents/m ojo/calling-mojo-from-blink)
1230 : A brief overview of what it looks like to use Mojom C++ bindings from
1231 within Blink code.
OLDNEW
« ipc/README.md ('K') | « mojo/public/cpp/README.md ('k') | mojo/public/cpp/system/README.md » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698