OLD | NEW |
1 # Mojo in Chromium | 1 # Mojo in Chromium |
2 | 2 |
3 **THIS DOCUIMENT IS A WORK IN PROGRESS.** As long as this notice exists, you | 3 **THIS DOCUIMENT IS A WORK IN PROGRESS.** As long as this notice exists, you |
4 should probably ignore everything below it. | 4 should probably ignore everything below it. |
5 | 5 |
6 This document is intended to serve as a Mojo primer for Chromium developers. No | 6 This document is intended to serve as a Mojo primer for Chromium developers. No |
7 prior knowledge of Mojo is assumed, but you should have a decent grasp of C++ | 7 prior knowledge of Mojo is assumed, but you should have a decent grasp of C++ |
8 and be familiar with Chromium's multi-process architecture as well as common | 8 and be familiar with Chromium's multi-process architecture as well as common |
9 concepts used throughout Chromium such as smart pointers, message loops, | 9 concepts used throughout Chromium such as smart pointers, message loops, |
10 callback binding, and so on. | 10 callback binding, and so on. |
(...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
86 A message pipe is a lightweight primitive for reliable, bidirectional, queued | 86 A message pipe is a lightweight primitive for reliable, bidirectional, queued |
87 transfer of relatively small packets of data. Every pipe endpoint is identified | 87 transfer of relatively small packets of data. Every pipe endpoint is identified |
88 by a **handle** -- a unique process-wide integer identifying the endpoint to the | 88 by a **handle** -- a unique process-wide integer identifying the endpoint to the |
89 EDK. | 89 EDK. |
90 | 90 |
91 A single message across a pipe consists of a binary payload and an array of zero | 91 A single message across a pipe consists of a binary payload and an array of zero |
92 or more handles to be transferred. A pipe's endpoints may live in the same | 92 or more handles to be transferred. A pipe's endpoints may live in the same |
93 process or in two different processes. | 93 process or in two different processes. |
94 | 94 |
95 Pipes are easy to create. The `mojo::MessagePipe` type (see | 95 Pipes are easy to create. The `mojo::MessagePipe` type (see |
96 `/third_party/mojo/src/mojo/public/cpp/system/message_pipe.h`) provides a nice | 96 `/mojo/public/cpp/system/message_pipe.h`) provides a nice |
97 class wrapper with each endpoint represented as a scoped handle type (see | 97 class wrapper with each endpoint represented as a scoped handle type (see |
98 members `handle0` and `handle1` and the definition of | 98 members `handle0` and `handle1` and the definition of |
99 `mojo::ScopedMessagePipeHandle`). In the same header you can find | 99 `mojo::ScopedMessagePipeHandle`). In the same header you can find |
100 `WriteMessageRaw` and `ReadMessageRaw` definitions. These are in theory all one | 100 `WriteMessageRaw` and `ReadMessageRaw` definitions. These are in theory all one |
101 needs to begin pushing things from one endpoint to the other. | 101 needs to begin pushing things from one endpoint to the other. |
102 | 102 |
103 While it's worth being aware of `mojo::MessagePipe` and the associated raw I/O | 103 While it's worth being aware of `mojo::MessagePipe` and the associated raw I/O |
104 functions, you will rarely if ever have a use for them. Instead you'll typically | 104 functions, you will rarely if ever have a use for them. Instead you'll typically |
105 use bindings code generated from mojom interface definitions, along with the | 105 use bindings code generated from mojom interface definitions, along with the |
106 public bindings API which mostly hides the underlying pipes. | 106 public bindings API which mostly hides the underlying pipes. |
(...skipping 29 matching lines...) Expand all Loading... |
136 Before we see an example implementation and usage of the Frobinator, there are a | 136 Before we see an example implementation and usage of the Frobinator, there are a |
137 handful of interesting bits in the public C++ bindings API you should be | 137 handful of interesting bits in the public C++ bindings API you should be |
138 familiar with. These complement generated bindings code and generally obviate | 138 familiar with. These complement generated bindings code and generally obviate |
139 any need to use a `mojo::MessagePipe` directly. | 139 any need to use a `mojo::MessagePipe` directly. |
140 | 140 |
141 In all of the cases below, `T` is the type of a generated bindings class | 141 In all of the cases below, `T` is the type of a generated bindings class |
142 interface, such as the `frob::Frobinator` discussed above. | 142 interface, such as the `frob::Frobinator` discussed above. |
143 | 143 |
144 #### `mojo::InterfacePtr<T>` | 144 #### `mojo::InterfacePtr<T>` |
145 | 145 |
146 Defined in `/third_party/mojo/src/mojo/public/cpp/bindings/interface_ptr.h`. | 146 Defined in `/mojo/public/cpp/bindings/interface_ptr.h`. |
147 | 147 |
148 `mojo::InterfacePtr<T>` is a typed proxy for a service of type `T`, which can be | 148 `mojo::InterfacePtr<T>` is a typed proxy for a service of type `T`, which can be |
149 bound to a message pipe endpoint. This class implements every interface method | 149 bound to a message pipe endpoint. This class implements every interface method |
150 on `T` by serializing a message (encoding the method call and its arguments) and | 150 on `T` by serializing a message (encoding the method call and its arguments) and |
151 writing it to the pipe (if bound.) This is the standard way for C++ code to talk | 151 writing it to the pipe (if bound.) This is the standard way for C++ code to talk |
152 to any Mojo service. | 152 to any Mojo service. |
153 | 153 |
154 For illustrative purposes only, we can create a message pipe and bind an | 154 For illustrative purposes only, we can create a message pipe and bind an |
155 `InterfacePtr` to one end as follows: | 155 `InterfacePtr` to one end as follows: |
156 | 156 |
157 ``` | 157 ``` |
158 mojo::MessagePipe pipe; | 158 mojo::MessagePipe pipe; |
159 mojo::InterfacePtr<frob::Frobinator> frobinator; | 159 mojo::InterfacePtr<frob::Frobinator> frobinator; |
160 frobinator.Bind( | 160 frobinator.Bind( |
161 mojo::InterfacePtrInfo<frob::Frobinator>(pipe.handle0.Pass(), 0u)); | 161 mojo::InterfacePtrInfo<frob::Frobinator>(pipe.handle0.Pass(), 0u)); |
162 ``` | 162 ``` |
163 | 163 |
164 You could then call `frobinator->Frobinate()` and read the encoded `Frobinate` | 164 You could then call `frobinator->Frobinate()` and read the encoded `Frobinate` |
165 message from the other side of the pipe (`handle1`.) You most likely don't want | 165 message from the other side of the pipe (`handle1`.) You most likely don't want |
166 to do this though, because as you'll soon see there's a nicer way to establish | 166 to do this though, because as you'll soon see there's a nicer way to establish |
167 service pipes. | 167 service pipes. |
168 | 168 |
169 #### `mojo::InterfaceRequest<T>` | 169 #### `mojo::InterfaceRequest<T>` |
170 | 170 |
171 Defined in `/third_party/mojo/src/mojo/public/cpp/bindings/interface_request.h`. | 171 Defined in `/mojo/public/cpp/bindings/interface_request.h`. |
172 | 172 |
173 `mojo::InterfaceRequest<T>` is a typed container for a message pipe endpoint | 173 `mojo::InterfaceRequest<T>` is a typed container for a message pipe endpoint |
174 that should _eventually_ be bound to a service implementation. An | 174 that should _eventually_ be bound to a service implementation. An |
175 `InterfaceRequest` doesn't actually _do_ anything, it's just a way of holding | 175 `InterfaceRequest` doesn't actually _do_ anything, it's just a way of holding |
176 onto an endpoint without losing interface type information. | 176 onto an endpoint without losing interface type information. |
177 | 177 |
178 A common usage pattern is to create a pipe, bind one end to an | 178 A common usage pattern is to create a pipe, bind one end to an |
179 `InterfacePtr<T>`, and pass the other end off to someone else (say, over some | 179 `InterfacePtr<T>`, and pass the other end off to someone else (say, over some |
180 other message pipe) who is expected to eventually bind it to a concrete service | 180 other message pipe) who is expected to eventually bind it to a concrete service |
181 implementation. `InterfaceRequest<T>` is here for that purpose and is, as we'll | 181 implementation. `InterfaceRequest<T>` is here for that purpose and is, as we'll |
(...skipping 14 matching lines...) Expand all Loading... |
196 ``` | 196 ``` |
197 | 197 |
198 At this point we could start making calls to `frobinator->Frobinate()` as | 198 At this point we could start making calls to `frobinator->Frobinate()` as |
199 before, but they'll just sit in queue waiting for the request side to be bound. | 199 before, but they'll just sit in queue waiting for the request side to be bound. |
200 Note that the basic logic in the snippet above is such a common pattern that | 200 Note that the basic logic in the snippet above is such a common pattern that |
201 there's a convenient API function which does it for us. | 201 there's a convenient API function which does it for us. |
202 | 202 |
203 #### `mojo::GetProxy<T>` | 203 #### `mojo::GetProxy<T>` |
204 | 204 |
205 Defined in | 205 Defined in |
206 `/third_party/mojo/src/mojo/public/cpp/bindings/interface`_request.h`. | 206 `/mojo/public/cpp/bindings/interface`_request.h`. |
207 | 207 |
208 `mojo::GetProxy<T>` is the function you will most commonly use to create a new | 208 `mojo::GetProxy<T>` is the function you will most commonly use to create a new |
209 message pipe. Its signature is as follows: | 209 message pipe. Its signature is as follows: |
210 | 210 |
211 ``` | 211 ``` |
212 template <typename T> | 212 template <typename T> |
213 mojo::InterfaceRequest<T> GetProxy(mojo::InterfacePtr<T>* ptr); | 213 mojo::InterfaceRequest<T> GetProxy(mojo::InterfacePtr<T>* ptr); |
214 ``` | 214 ``` |
215 | 215 |
216 This function creates a new message pipe, binds one end to the given | 216 This function creates a new message pipe, binds one end to the given |
217 `InterfacePtr` argument, and binds the other end to a new `InterfaceRequest` | 217 `InterfacePtr` argument, and binds the other end to a new `InterfaceRequest` |
218 which it then returns. Equivalent to the sample code just above is the following | 218 which it then returns. Equivalent to the sample code just above is the following |
219 snippet: | 219 snippet: |
220 | 220 |
221 ``` | 221 ``` |
222 mojo::InterfacePtr<frob::Frobinator> frobinator; | 222 mojo::InterfacePtr<frob::Frobinator> frobinator; |
223 mojo::InterfaceRequest<frob::Frobinator> frobinator_request = | 223 mojo::InterfaceRequest<frob::Frobinator> frobinator_request = |
224 mojo::GetProxy(&frobinator); | 224 mojo::GetProxy(&frobinator); |
225 ``` | 225 ``` |
226 | 226 |
227 #### `mojo::Binding<T>` | 227 #### `mojo::Binding<T>` |
228 | 228 |
229 Defined in `/third_party/mojo/src/mojo/public/cpp/bindings/binding.h`. | 229 Defined in `/mojo/public/cpp/bindings/binding.h`. |
230 | 230 |
231 Binds one end of a message pipe to an implementation of service `T`. A message | 231 Binds one end of a message pipe to an implementation of service `T`. A message |
232 sent from the other end of the pipe will be read and, if successfully decoded as | 232 sent from the other end of the pipe will be read and, if successfully decoded as |
233 a `T` message, will invoke the corresponding call on the bound `T` | 233 a `T` message, will invoke the corresponding call on the bound `T` |
234 implementation. A `Binding<T>` must be constructed over an instance of `T` | 234 implementation. A `Binding<T>` must be constructed over an instance of `T` |
235 (which itself usually owns said `Binding` object), and its bound pipe is usually | 235 (which itself usually owns said `Binding` object), and its bound pipe is usually |
236 taken from a passed `InterfaceRequest<T>`. | 236 taken from a passed `InterfaceRequest<T>`. |
237 | 237 |
238 A common usage pattern looks something like this: | 238 A common usage pattern looks something like this: |
239 | 239 |
240 ``` | 240 ``` |
241 #include "components/frob/public/interfaces/frobinator.mojom.h" | 241 #include "components/frob/public/interfaces/frobinator.mojom.h" |
242 #include "third_party/mojo/src/mojo/public/cpp/bindings/binding.h" | 242 #include "mojo/public/cpp/bindings/binding.h" |
243 #include "third_party/mojo/src/mojo/public/cpp/bindings/interface_request.h" | 243 #include "mojo/public/cpp/bindings/interface_request.h" |
244 | 244 |
245 class FrobinatorImpl : public frob::Frobinator { | 245 class FrobinatorImpl : public frob::Frobinator { |
246 public: | 246 public: |
247 FrobinatorImpl(mojo::InterfaceRequest<frob::Frobinator> request) | 247 FrobinatorImpl(mojo::InterfaceRequest<frob::Frobinator> request) |
248 : binding_(this, request.Pass()) {} | 248 : binding_(this, request.Pass()) {} |
249 ~FrobinatorImpl() override {} | 249 ~FrobinatorImpl() override {} |
250 | 250 |
251 private: | 251 private: |
252 // frob::Frobinator: | 252 // frob::Frobinator: |
253 void Frobinate() override { /* ... */ } | 253 void Frobinate() override { /* ... */ } |
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
289 1. The message is passed on to the receiver. In this case the receiver is | 289 1. The message is passed on to the receiver. In this case the receiver is |
290 generated bindings code, via `Binding<T>`. This code decodes and validates | 290 generated bindings code, via `Binding<T>`. This code decodes and validates |
291 the `Frobinate` message. | 291 the `Frobinate` message. |
292 1. `FrobinatorImpl::Frobinate()` is called on the bound implementation. | 292 1. `FrobinatorImpl::Frobinate()` is called on the bound implementation. |
293 | 293 |
294 So as you can see, the call to `Frobinate()` may result in up to two thread hops | 294 So as you can see, the call to `Frobinate()` may result in up to two thread hops |
295 and one process hop before the service implementation is invoked. | 295 and one process hop before the service implementation is invoked. |
296 | 296 |
297 #### `mojo::StrongBinding<T>` | 297 #### `mojo::StrongBinding<T>` |
298 | 298 |
299 Defined in `third_party/mojo/src/mojo/public/cpp/bindings/strong_binding.h`. | 299 Defined in `mojo/public/cpp/bindings/strong_binding.h`. |
300 | 300 |
301 `mojo::StrongBinding<T>` is just like `mojo::Binding<T>` with the exception that | 301 `mojo::StrongBinding<T>` is just like `mojo::Binding<T>` with the exception that |
302 a `StrongBinding` takes ownership of the bound `T` instance. The instance is | 302 a `StrongBinding` takes ownership of the bound `T` instance. The instance is |
303 destroyed whenever the bound message pipe is closed. This is convenient in cases | 303 destroyed whenever the bound message pipe is closed. This is convenient in cases |
304 where you want a service implementation to live as long as the pipe it's | 304 where you want a service implementation to live as long as the pipe it's |
305 servicing, but like all features with clever lifetime semantics, it should be | 305 servicing, but like all features with clever lifetime semantics, it should be |
306 used with caution. | 306 used with caution. |
307 | 307 |
308 ## The Mojo Shell | 308 ## The Mojo Shell |
309 | 309 |
(...skipping 110 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
420 you build should probably go there. Let's create some basic files to kick things | 420 you build should probably go there. Let's create some basic files to kick things |
421 off. You may want to start a new local Git branch to isolate any changes you | 421 off. You may want to start a new local Git branch to isolate any changes you |
422 make while working through this. | 422 make while working through this. |
423 | 423 |
424 First create a new `//components/hello` directory. Inside this directory we're | 424 First create a new `//components/hello` directory. Inside this directory we're |
425 going to add the following files: | 425 going to add the following files: |
426 | 426 |
427 **components/hello/main.cc** | 427 **components/hello/main.cc** |
428 ``` | 428 ``` |
429 #include "base/logging.h" | 429 #include "base/logging.h" |
430 #include "third_party/mojo/src/mojo/public/c/system/main.h" | 430 #include "mojo/public/c/system/main.h" |
431 | 431 |
432 MojoResult MojoMain(MojoHandle shell_handle) { | 432 MojoResult MojoMain(MojoHandle shell_handle) { |
433 LOG(ERROR) << "Hello, world!"; | 433 LOG(ERROR) << "Hello, world!"; |
434 return MOJO_RESULT_OK; | 434 return MOJO_RESULT_OK; |
435 }; | 435 }; |
436 ``` | 436 ``` |
437 | 437 |
438 **components/hello/BUILD.gn** | 438 **components/hello/BUILD.gn** |
439 ``` | 439 ``` |
440 import("//mojo/public/mojo_application.gni") | 440 import("//mojo/public/mojo_application.gni") |
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
480 An app that prints `"Hello, world!"` isn't terribly interesting. At a bare | 480 An app that prints `"Hello, world!"` isn't terribly interesting. At a bare |
481 minimum your app should implement `mojo::ApplicationDelegate` and expose at | 481 minimum your app should implement `mojo::ApplicationDelegate` and expose at |
482 least one service to connecting applications. | 482 least one service to connecting applications. |
483 | 483 |
484 Let's update `main.cc` with the following contents: | 484 Let's update `main.cc` with the following contents: |
485 | 485 |
486 **components/hello/main.cc** | 486 **components/hello/main.cc** |
487 ``` | 487 ``` |
488 #include "components/hello/hello_app.h" | 488 #include "components/hello/hello_app.h" |
489 #include "mojo/application/public/cpp/application_runner.h" | 489 #include "mojo/application/public/cpp/application_runner.h" |
490 #include "third_party/mojo/src/mojo/public/c/system/main.h" | 490 #include "mojo/public/c/system/main.h" |
491 | 491 |
492 MojoResult MojoMain(MojoHandle shell_handle) { | 492 MojoResult MojoMain(MojoHandle shell_handle) { |
493 mojo::ApplicationRunner runner(new hello::HelloApp); | 493 mojo::ApplicationRunner runner(new hello::HelloApp); |
494 return runner.Run(shell_handle); | 494 return runner.Run(shell_handle); |
495 }; | 495 }; |
496 ``` | 496 ``` |
497 | 497 |
498 This is a pretty typical looking `MojoMain`. Most of the time this is all you | 498 This is a pretty typical looking `MojoMain`. Most of the time this is all you |
499 want -- a `mojo::ApplicationRunner` constructed over a | 499 want -- a `mojo::ApplicationRunner` constructed over a |
500 `mojo::ApplicationDelegate` instance, `Run()` with the pipe handle received from | 500 `mojo::ApplicationDelegate` instance, `Run()` with the pipe handle received from |
501 the shell. We'll add some new files to the app as well: | 501 the shell. We'll add some new files to the app as well: |
502 | 502 |
503 **components/hello/public/interfaces/greeter.mojom** | 503 **components/hello/public/interfaces/greeter.mojom** |
504 ``` | 504 ``` |
505 module hello; | 505 module hello; |
506 interface Greeter { | 506 interface Greeter { |
507 Greet(string name) => (string greeting); | 507 Greet(string name) => (string greeting); |
508 }; | 508 }; |
509 ``` | 509 ``` |
510 | 510 |
511 Note the new arrow syntax on the `Greet` method. This indicates that the caller | 511 Note the new arrow syntax on the `Greet` method. This indicates that the caller |
512 expects a response from the service. | 512 expects a response from the service. |
513 | 513 |
514 **components/hello/public/interfaces/BUILD.gn** | 514 **components/hello/public/interfaces/BUILD.gn** |
515 ``` | 515 ``` |
516 import("//third_party/mojo/src/mojo/public/tools/bindings/mojom.gni") | 516 import("//mojo/public/tools/bindings/mojom.gni") |
517 | 517 |
518 mojom("interfaces") { | 518 mojom("interfaces") { |
519 sources = [ | 519 sources = [ |
520 "greeter.mojom", | 520 "greeter.mojom", |
521 ] | 521 ] |
522 } | 522 } |
523 ``` | 523 ``` |
524 | 524 |
525 **components/hello/hello_app.h** | 525 **components/hello/hello_app.h** |
526 ``` | 526 ``` |
(...skipping 29 matching lines...) Expand all Loading... |
556 | 556 |
557 #endif // COMPONENTS_HELLO_HELLO_APP_H_ | 557 #endif // COMPONENTS_HELLO_HELLO_APP_H_ |
558 ``` | 558 ``` |
559 | 559 |
560 | 560 |
561 **components/hello/hello_app.cc** | 561 **components/hello/hello_app.cc** |
562 ``` | 562 ``` |
563 #include "base/macros.h" | 563 #include "base/macros.h" |
564 #include "components/hello/hello_app.h" | 564 #include "components/hello/hello_app.h" |
565 #include "mojo/application/public/cpp/application_connection.h" | 565 #include "mojo/application/public/cpp/application_connection.h" |
566 #include "third_party/mojo/src/mojo/public/cpp/bindings/interface_request.h" | 566 #include "mojo/public/cpp/bindings/interface_request.h" |
567 #include "third_party/mojo/src/mojo/public/cpp/bindings/strong_binding.h" | 567 #include "mojo/public/cpp/bindings/strong_binding.h" |
568 | 568 |
569 namespace hello { | 569 namespace hello { |
570 | 570 |
571 namespace { | 571 namespace { |
572 | 572 |
573 class GreeterImpl : public Greeter { | 573 class GreeterImpl : public Greeter { |
574 public: | 574 public: |
575 GreeterImpl(mojo::InterfaceRequest<Greeter> request) | 575 GreeterImpl(mojo::InterfaceRequest<Greeter> request) |
576 : binding_(this, request.Pass()) { | 576 : binding_(this, request.Pass()) { |
577 } | 577 } |
(...skipping 386 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
964 | 964 |
965 This is still a work in progress and might not really take shape until the | 965 This is still a work in progress and might not really take shape until the |
966 Blink+Chromium merge. In the meantime there are some end-to-end WebUI examples | 966 Blink+Chromium merge. In the meantime there are some end-to-end WebUI examples |
967 in `/content/browser/webui/web_ui_mojo_browsertest.cc`. In particular, | 967 in `/content/browser/webui/web_ui_mojo_browsertest.cc`. In particular, |
968 `WebUIMojoTest.ConnectToApplication` connects from a WebUI frame to a test app | 968 `WebUIMojoTest.ConnectToApplication` connects from a WebUI frame to a test app |
969 running in a new utility process. | 969 running in a new utility process. |
970 | 970 |
971 ## FAQ | 971 ## FAQ |
972 | 972 |
973 Nothing here yet! | 973 Nothing here yet! |
OLD | NEW |