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

Side by Side Diff: docs/mojo_in_chromium.md

Issue 1309473002: WIP: Migrate Wiki content over to src/docs (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 5 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « docs/mandriva_msttcorefonts.md ('k') | docs/ninja_build.md » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 **THIS DOCUIMENT IS A WORK IN PROGRESS.** As long as this notice exists, you sho uld probably ignore everything below it.
2
3
4
5 # Introduction
6
7 This document is intended to serve as a Mojo primer for Chromium developers. No prior knowledge of Mojo is assumed, but you should have a decent grasp of C++ an d be familiar with Chromium's multi-process architecture as well as common conce pts used throughout Chromium such as smart pointers, message loops, callback bin ding, and so on.
8
9 ## Should I Bother Reading This?
10
11 If you're planning to build a Chromium feature that needs IPC and you aren't alr eady using Mojo, you probably want to read this. **Legacy IPC** -- _i.e._, `foo_ messages.h` files, message filters, and the suite of `IPC_MESSAGE_*` macros -- * *is on the verge of deprecation.**
12
13 ## Why Mojo?
14
15 Mojo provides IPC primitives for pushing messages and data around between transf errable endpoints which may or may not cross process boundaries; it simplifies t hreading with regard to IPC; it standardizes message serialization in a way that 's resilient to versioning issues; and it can be used with relative ease and con sistency across a number of languages including C++, Java, and `JavaScript` -- a ll languages which comprise a significant share of Chromium code.
16
17 The messaging protocol doesn't strictly need to be used for IPC though, and ther e are some higher-level reasons for this adoption and for the specific approach to integration outlined in this document.
18
19 ### Code Health
20
21 At the moment we have fairly weak separation between components, with DEPS being the strongest line of defense against increasing complexity.
22
23 A component Foo might hold a reference to some bit of component Bar's internal s tate, or it might expect Bar to initialize said internal state in some particula r order. These sorts of problems are reasonably well-mitigated by the code revie w process, but they can (and do) still slip through the cracks, and they have a noticeable cumulative effect on complexity as the code base continues to grow.
24
25 We think we can make a lasting positive impact on code health by establishing mo re concrete boundaries between components, and this is something a library like Mojo gives us an opportunity to do.
26
27 ### Modularity
28
29 In addition to code health -- which alone could be addressed in any number of wa ys that don't involve Mojo -- this approach opens doors to build and distribute parts of Chrome separately from the main binary.
30
31 While we're not currently taking advantage of this capability, doing so remains a long-term goal due to prohibitive binary size constraints in emerging mobile m arkets. Many open questions around the feasibility of this goal should be answer ed by the experimental Mandoline project as it unfolds, but the Chromium project can be technically prepared for such a transition in the meantime.
32
33 ### Mandoline
34
35 The Mandoline project is producing a potential replacement for `src/content`. Be cause Mandoline components are Mojo apps, and Chromium is now capable of loading Mojo apps (somethings we'll discuss later), Mojo apps can be shared between bo th projects with minimal effort. Developing your feature as or within a Mojo app lication can mean you're contributing to both Chromium and Mandoline.
36
37 # Mojo Overview
38
39 This section provides a general overview of Mojo and some of its API features. Y ou can probably skip straight to [Your First Mojo Application](#Your_First_Mojo_ Application.md) if you just want to get to some practical sample code.
40
41 The Mojo Embedder Development Kit (EDK) provides a suite of low-level IPC primit ives: **message pipes**, **data pipes**, and **shared buffers**. We'll focus pri marily on message pipes and the C++ bindings API in this document.
42
43 _TODO: Java and JS bindings APIs should also be covered here._
44
45 ## Message Pipes
46
47 A message pipe is a lightweight primitive for reliable, bidirectional, queued tr ansfer of relatively small packets of data. Every pipe endpoint is identified b y a **handle** -- a unique process-wide integer identifying the endpoint to the EDK.
48
49 A single message across a pipe consists of a binary payload and an array of zero or more handles to be transferred. A pipe's endpoints may live in the same proc ess or in two different processes.
50
51 Pipes are easy to create. The `mojo::MessagePipe` type (see [//third\_party/mojo /src/mojo/public/cpp/system/message\_pipe.h](https://code.google.com/p/chromium/ codesearch#chromium/src/third_party/mojo/src/mojo/public/cpp/system/message_pipe .h)) provides a nice class wrapper with each endpoint represented as a scoped ha ndle type (see members `handle0` and `handle1` and the definition of `mojo::Scop edMessagePipeHandle`). In the same header you can find `WriteMessageRaw` and `Re adMessageRaw` definitions. These are in theory all one needs to begin pushing th ings from one endpoint to the other.
52
53 While it's worth being aware of `mojo::MessagePipe` and the associated raw I/O f unctions, you will rarely if ever have a use for them. Instead you'll typically use bindings code generated from mojom interface definitions, along with the pub lic bindings API which mostly hides the underlying pipes.
54
55 ## Mojom Bindings
56
57 Mojom is the IDL for Mojo interfaces. When given a mojom file, the bindings gene rator outputs a collection of bindings libraries for each supported language. Mo jom syntax is fairly straightforward (TODO: Link to a mojom language spec?). Con sider the example mojom file below:
58
59 ```
60 // frobinator.mojom
61 module frob;
62 interface Frobinator {
63 Frobinate();
64 };
65 ```
66
67 This can be used to generate bindings for a very simple `Frobinator` interface. Bindings are generated at build time and will match the location of the mojom so urce file itself, mapped into the generated output directory for your Chromium b uild. In this case one can expect to find files named `frobinator.mojom.js`, `fr obinator.mojom.cc`, `frobinator.mojom.h`, _etc._
68
69 The C++ header (`frobinator.mojom.h`) generated from this mojom will define a pu re virtual class interface named `frob::Frobinator` with a pure virtual method o f signature `void Frobinate()`. Any class which implements this interface is eff ectively a `Frobinator` service.
70
71 ## C++ Bindings API
72
73 Before we see an example implementation and usage of the Frobinator, there are a handful of interesting bits in the public C++ bindings API you should be famili ar with. These complement generated bindings code and generally obviate any need to use a `mojo::MessagePipe` directly.
74
75 In all of the cases below, `T` is the type of a generated bindings class interfa ce, such as the `frob::Frobinator` discussed above.
76
77 ### `mojo::InterfacePtr<T>`
78
79 Defined in [//third\_party/mojo/src/mojo/public/cpp/bindings/interface\_ptr.h](h ttps://code.google.com/p/chromium/codesearch#chromium/src/third_party/mojo/src/m ojo/public/cpp/bindings/interface_ptr.h).
80
81 `mojo::InterfacePtr<T>` is a typed proxy for a service of type `T`, which can be bound to a message pipe endpoint. This class implements every interface method on `T` by serializing a message (encoding the method call and its arguments) and writing it to the pipe (if bound.) This is the standard way for C++ code to tal k to any Mojo service.
82
83 For illustrative purposes only, we can create a message pipe and bind an `Interf acePtr` to one end as follows:
84
85 ```
86 mojo::MessagePipe pipe;
87 mojo::InterfacePtr<frob::Frobinator> frobinator;
88 frobinator.Bind(
89 mojo::InterfacePtrInfo<frob::Frobinator>(pipe.handle0.Pass(), 0u));
90 ```
91
92 You could then call `frobinator->Frobinate()` and read the encoded `Frobinate` m essage from the other side of the pipe (`handle1`.) You most likely don't want t o do this though, because as you'll soon see there's a nicer way to establish se rvice pipes.
93
94 ### `mojo::InterfaceRequest<T>`
95
96 Defined in [//third\_party/mojo/src/mojo/public/cpp/bindings/interface\_request. h](https://code.google.com/p/chromium/codesearch#chromium/src/third_party/mojo/s rc/mojo/public/cpp/bindings/interface_request.h).
97
98 `mojo::InterfaceRequest<T>` is a typed container for a message pipe endpoint tha t should _eventually_ be bound to a service implementation. An `InterfaceRequest ` doesn't actually _do_ anything, it's just a way of holding onto an endpoint wi thout losing interface type information.
99
100 A common usage pattern is to create a pipe, bind one end to an `InterfacePtr<T>` , and pass the other end off to someone else (say, over some other message pipe) who is expected to eventually bind it to a concrete service implementation. `In terfaceRequest<T>` is here for that purpose and is, as we'll see later, a first- class concept in Mojom interface definitions.
101
102 As with `InterfacePtr<T>`, we can manually bind an `InterfaceRequest<T>` to a pi pe endpoint:
103
104 ```
105 mojo::MessagePipe pipe;
106
107 mojo::InterfacePtr<frob::Frobinator> frobinator;
108 frobinator.Bind(
109 mojo::InterfacePtrInfo<frob::Frobinator>(pipe.handle0.Pass(), 0u));
110
111 mojo::InterfaceRequest<frob::Frobinator> frobinator_request;
112 frobinator_request.Bind(pipe.handle1.Pass());
113 ```
114
115 At this point we could start making calls to `frobinator->Frobinate()` as before , but they'll just sit in queue waiting for the request side to be bound. Note t hat the basic logic in the snippet above is such a common pattern that there's a convenient API function which does it for us.
116
117 ### `mojo::GetProxy<T>`
118
119 Defined in [//third\_party/mojo/src/mojo/public/cpp/bindings/interface\_request. h](https://code.google.com/p/chromium/codesearch#chromium/src/third_party/mojo/s rc/mojo/public/cpp/bindings/interface_request.h).
120
121 `mojo::GetProxy<T>` is the function you will most commonly use to create a new m essage pipe. Its signature is as follows:
122
123 ```
124 template <typename T>
125 mojo::InterfaceRequest<T> GetProxy(mojo::InterfacePtr<T>* ptr);
126 ```
127
128 This function creates a new message pipe, binds one end to the given `InterfaceP tr` argument, and binds the other end to a new `InterfaceRequest` which it then returns. Equivalent to the sample code just above is the following snippet:
129
130 ```
131 mojo::InterfacePtr<frob::Frobinator> frobinator;
132 mojo::InterfaceRequest<frob::Frobinator> frobinator_request =
133 mojo::GetProxy(&frobinator);
134 ```
135
136 ### `mojo::Binding<T>`
137
138 Defined in [//third\_party/mojo/src/mojo/public/cpp/bindings/binding.h](https:// code.google.com/p/chromium/codesearch#chromium/src/third_party/mojo/src/mojo/pub lic/cpp/bindings/binding.h).
139
140 Binds one end of a message pipe to an implementation of service `T`. A message s ent from the other end of the pipe will be read and, if successfully decoded as a `T` message, will invoke the corresponding call on the bound `T` implementatio n. A `Binding<T>` must be constructed over an instance of `T` (which itself usua lly owns said `Binding` object), and its bound pipe is usually taken from a pass ed `InterfaceRequest<T>`.
141
142 A common usage pattern looks something like this:
143
144 ```
145 #include "components/frob/public/interfaces/frobinator.mojom.h"
146 #include "third_party/mojo/src/mojo/public/cpp/bindings/binding.h"
147 #include "third_party/mojo/src/mojo/public/cpp/bindings/interface_request.h"
148
149 class FrobinatorImpl : public frob::Frobinator {
150 public:
151 FrobinatorImpl(mojo::InterfaceRequest<frob::Frobinator> request)
152 : binding_(this, request.Pass()) {}
153 ~FrobinatorImpl() override {}
154
155 private:
156 // frob::Frobinator:
157 void Frobinate() override { /* ... */ }
158
159 mojo::Binding<frob::Frobinator> binding_;
160 };
161 ```
162
163 And then we could write some code to test this:
164
165 ```
166 // Fun fact: The bindings generator emits a type alias like this for every
167 // interface type. frob::FrobinatorPtr is an InterfacePtr<frob::Frobinator>.
168 frob::FrobinatorPtr frobinator;
169 scoped_ptr<FrobinatorImpl> impl(
170 new FrobinatorImpl(mojo::GetProxy(&frobinator)));
171 frobinator->Frobinate();
172 ```
173
174 This will _eventually_ call `FrobinatorImpl::Frobinate()`. "Eventually," because the sequence of events when `frobinator->Frobinate()` is called is roughly as f ollows:
175
176 1. A new message buffer is allocated and filled with an encoded 'Frobinate' me ssage.
177 1. The EDK is asked to write this message to the pipe endpoint owned by the `F robinatorPtr`.
178 1. If the call didn't happen on the Mojo IPC thread for this process, EDK hops to the Mojo IPC thread.
179 1. The EDK writes the message to the pipe. In this case the pipe endpoints liv e in the same process, so this essentially a glorified `memcpy`. If they lived i n different processes this would be the point at which the data moved across a r eal IPC channel.
180 1. The EDK on the other end of the pipe is awoken on the Mojo IPC thread and a lerted to the message arrival.
181 1. The EDK reads the message.
182 1. If the bound receiver doesn't live on the Mojo IPC thread, the EDK hops to the receiver's thread.
183 1. The message is passed on to the receiver. In this case the receiver is gene rated bindings code, via `Binding<T>`. This code decodes and validates the `Frob inate` message.
184 1. `FrobinatorImpl::Frobinate()` is called on the bound implementation.
185
186 So as you can see, the call to `Frobinate()` may result in up to two thread hops and one process hop before the service implementation is invoked.
187
188 ### `mojo::StrongBinding<T>`
189
190 Defined in [//third\_party/mojo/src/mojo/public/cpp/bindings/strong\_binding.h]( https://code.google.com/p/chromium/codesearch#chromium/src/third_party/mojo/src/ mojo/public/cpp/bindings/strong_binding.h).
191
192 `mojo::StrongBinding<T>` is just like `mojo::Binding<T>` with the exception that a `StrongBinding` takes ownership of the bound `T` instance. The instance is de stroyed whenever the bound message pipe is closed. This is convenient in cases w here you want a service implementation to live as long as the pipe it's servicin g, but like all features with clever lifetime semantics, it should be used with caution.
193
194 ## The Mojo Shell
195
196 Both Chromium and Mandoline run a central **shell** component which is used to c oordinate communication among all Mojo applications (see the next section for an overview of Mojo applications.)
197
198 Every application receives a proxy to this shell upon initialization, and it is exclusively through this proxy that an application can request connections to ot her applications. The `mojo::Shell` interface provided by this proxy is defined as follows:
199
200 ```
201 module mojo;
202 interface Shell {
203 ConnectToApplication(URLRequest application_url,
204 ServiceProvider&? services,
205 ServiceProvider? exposed_services);
206 QuitApplication();
207 };
208 ```
209
210 and as for the `mojo::ServiceProvider` interface:
211
212 ```
213 module mojo;
214 interface ServiceProvider {
215 ConnectToService(string interface_name, handle<message_pipe> pipe);
216 };
217 ```
218
219 Definitions for these interfaces can be found in [//mojo/application/public/inte rfaces](https://code.google.com/p/chromium/codesearch#chromium/src/mojo/applicat ion/public/interfaces/). Also note that `mojo::URLRequest` is a Mojo struct defi ned in [//mojo/services/network/public/interfaces/url\_loader.mojom](https://cod e.google.com/p/chromium/codesearch#chromium/src/mojo/services/network/public/int erfaces/url_loader.mojom).
220
221 Note that there's some new syntax in the mojom for `ConnectToApplication` above. The '?' signifies a nullable value and the '&' signifies an interface request r ather than an interface proxy.
222
223 The argument `ServiceProvider&? services` indicates that the caller should pass an `InterfaceRequest<ServiceProvider>` as the second argument, but that it need not be bound to a pipe (i.e., it can be "null" in which case it's ignored.)
224
225 The argument `ServiceProvider? exposed_services` indicates that the caller shoul d pass an `InterfacePtr<ServiceProvider>` as the third argument, but that it may also be null.
226
227 `ConnectToApplication` asks the shell to establish a connection between the call er and some other app the shell might know about. In the event that a connection can be established -- which may involve the shell starting a new instance of th e target app -- the given `services` request (if not null) will be bound to a se rvice provider in the target app. The target app may in turn use the passed `exp osed_services` proxy (if not null) to request services from the connecting app.
228
229 ## Mojo Applications
230
231 All code which runs in a Mojo environment, apart from the shell itself (see abov e), belongs to one Mojo **application** or another**`**`**. The term "applicatio n" in this context is a common source of confusion, but it's really a simple con cept. In essence an application is anything which implements the following Mojom interface:
232
233 ```
234 module mojo;
235 interface Application {
236 Initialize(Shell shell, string url);
237 AcceptConnection(string requestor_url,
238 ServiceProvider&? services,
239 ServiceProvider? exposed_services,
240 string resolved_url);
241 OnQuitRequested() => (bool can_quit);
242 };
243 ```
244
245 Of course, in Chromium and Mandoline environments this interface is obscured fro m application code and applications should generally just implement `mojo::Appli cationDelegate` (defined in [//mojo/application/public/cpp/application\_delegate .h](https://code.google.com/p/chromium/codesearch#chromium/src/mojo/application/ public/cpp/application_delegate.h).) We'll see a concrete example of this in the next section, [Your First Mojo Application](#Your_First_Mojo_Application.md).
246
247 The takeaway here is that an application can be anything. It's not necessarily a new process (though at the moment, it's at least a new thread). Applications ca n connect to each other, and these connections are the mechanism through which s eparate components expose services to each other.
248
249 **`**`**NOTE: This is not true in Chromium today, but it should be eventually. F or some components (like render frames, or arbitrary browser process code) we pr ovide APIs which allow non-Mojo-app-code to masquerade as a Mojo app and therefo re connect to real Mojo apps through the shell.
250
251 ## Other IPC Primitives
252
253 Finally, it's worth making brief mention of the other types of IPC primitives Mo jo provides apart from message pipes. A **data pipe** is a unidirectional channe l for pushing around raw data in bulk, and a **shared buffer** is (unsurprisingl y) a shared memory primitive. Both of these objects use the same type of transfe rable handle as message pipe endpoints, and can therefore be transferred across message pipes, potentially to other processes.
254
255 # Your First Mojo Application
256
257 In this section, we're going to build a simple Mojo application that can be run in isolation using Mandoline's `mojo_runner` binary. After that we'll add a serv ice to the app and set up a test suite to connect and test that service.
258
259 ## Hello, world!
260
261 So, you're building a new Mojo app and it has to live somewhere. For the foresee able future we'll likely be treating `//components` as a sort of top-level home for new Mojo apps in the Chromium tree. Any component application you build shou ld probably go there. Let's create some basic files to kick things off. You may want to start a new local Git branch to isolate any changes you make while worki ng through this.
262
263 First create a new `//components/hello` directory. Inside this directory we're g oing to add the following files:
264
265 **components/hello/main.cc**
266 ```
267 #include "base/logging.h"
268 #include "third_party/mojo/src/mojo/public/c/system/main.h"
269
270 MojoResult MojoMain(MojoHandle shell_handle) {
271 LOG(ERROR) << "Hello, world!";
272 return MOJO_RESULT_OK;
273 };
274 ```
275
276
277 **components/hello/BUILD.gn**
278 ```
279 import("//mojo/public/mojo_application.gni")
280
281 mojo_native_application("hello") {
282 sources = [
283 "main.cc",
284 ]
285 deps = [
286 "//base",
287 "//mojo/environment:chromium",
288 ]
289 }
290 ```
291
292 For the sake of this example you'll also want to add your component as a depende ncy somewhere in your local checkout to ensure its build files are generated. Th e easiest thing to do there is probably to add a dependency on `"//components/he llo"` in the `"gn_all"` target of the top-level `//BUILD.gn`.
293
294 Assuming you have a GN output directory at `out_gn/Debug`, you can build the Moj o runner along with your shiny new app:
295
296 ```
297 ninja -C out_gn/Debug mojo_runner components/hello
298 ```
299
300 In addition to the `mojo_runner` executable, this will produce a new binary at ` out_gn/Debug/hello/hello.mojo`. This binary is essentially a shared library whic h exports your `MojoMain` function.
301
302 `mojo_runner` takes an application URL as its only argument and runs the corresp onding application. In its current state it resolves `mojo`-scheme URLs such tha t `"mojo:foo"` maps to the file `"foo/foo.mojo"` relative to the `mojo_runner` p ath (_i.e._ your output directory.) This means you can run your new app with the following command:
303
304 ```
305 out_gn/Debug/mojo_runner mojo:hello
306 ```
307
308 You should see our little `"Hello, world!"` error log followed by a hanging appl ication. You can `^C` to kill it.
309
310 ## Exposing Services
311
312 An app that prints `"Hello, world!"` isn't terribly interesting. At a bare minim um your app should implement `mojo::ApplicationDelegate` and expose at least one service to connecting applications.
313
314 Let's update `main.cc` with the following contents:
315
316 **components/hello/main.cc**
317 ```
318 #include "components/hello/hello_app.h"
319 #include "mojo/application/public/cpp/application_runner.h"
320 #include "third_party/mojo/src/mojo/public/c/system/main.h"
321
322 MojoResult MojoMain(MojoHandle shell_handle) {
323 mojo::ApplicationRunner runner(new hello::HelloApp);
324 return runner.Run(shell_handle);
325 };
326 ```
327
328 This is a pretty typical looking `MojoMain`. Most of the time this is all you wa nt -- a `mojo::ApplicationRunner` constructed over a `mojo::ApplicationDelegate` instance, `Run()` with the pipe handle received from the shell. We'll add some new files to the app as well:
329
330 **components/hello/public/interfaces/greeter.mojom**
331 ```
332 module hello;
333 interface Greeter {
334 Greet(string name) => (string greeting);
335 };
336 ```
337
338 Note the new arrow syntax on the `Greet` method. This indicates that the caller expects a response from the service.
339
340 **components/hello/public/interfaces/BUILD.gn**
341 ```
342 import("//third_party/mojo/src/mojo/public/tools/bindings/mojom.gni")
343
344 mojom("interfaces") {
345 sources = [
346 "greeter.mojom",
347 ]
348 }
349 ```
350
351 **components/hello/hello\_app.h**
352 ```
353 #ifndef COMPONENTS_HELLO_HELLO_APP_H_
354 #define COMPONENTS_HELLO_HELLO_APP_H_
355
356 #include "base/macros.h"
357 #include "components/hello/public/interfaces/greeter.mojom.h"
358 #include "mojo/application/public/cpp/application_delegate.h"
359 #include "mojo/application/public/cpp/interface_factory.h"
360
361 namespace hello {
362
363 class HelloApp : public mojo::ApplicationDelegate,
364 public mojo::InterfaceFactory<Greeter> {
365 public:
366 HelloApp();
367 ~HelloApp() override;
368
369 private:
370 // mojo::ApplicationDelegate:
371 bool ConfigureIncomingConnection(
372 mojo::ApplicationConnection* connection) override;
373
374 // mojo::InterfaceFactory<Greeter>:
375 void Create(mojo::ApplicationConnection* connection,
376 mojo::InterfaceRequest<Greeter> request) override;
377
378 DISALLOW_COPY_AND_ASSIGN(HelloApp);
379 };
380
381 } // namespace hello
382
383 #endif // COMPONENTS_HELLO_HELLO_APP_H_
384 ```
385
386
387 **components/hello/hello\_app.cc**
388 ```
389 #include "base/macros.h"
390 #include "components/hello/hello_app.h"
391 #include "mojo/application/public/cpp/application_connection.h"
392 #include "third_party/mojo/src/mojo/public/cpp/bindings/interface_request.h"
393 #include "third_party/mojo/src/mojo/public/cpp/bindings/strong_binding.h"
394
395 namespace hello {
396
397 namespace {
398
399 class GreeterImpl : public Greeter {
400 public:
401 GreeterImpl(mojo::InterfaceRequest<Greeter> request)
402 : binding_(this, request.Pass()) {
403 }
404
405 ~GreeterImpl() override {}
406
407 private:
408 // Greeter:
409 void Greet(const mojo::String& name, const GreetCallback& callback) override {
410 callback.Run("Hello, " + std::string(name) + "!");
411 }
412
413 mojo::StrongBinding<Greeter> binding_;
414
415 DISALLOW_COPY_AND_ASSIGN(GreeterImpl);
416 };
417
418 } // namespace
419
420 HelloApp::HelloApp() {
421 }
422
423 HelloApp::~HelloApp() {
424 }
425
426 bool HelloApp::ConfigureIncomingConnection(
427 mojo::ApplicationConnection* connection) {
428 connection->AddService<Greeter>(this);
429 return true;
430 }
431
432 void HelloApp::Create(
433 mojo::ApplicationConnection* connection,
434 mojo::InterfaceRequest<Greeter> request) {
435 new GreeterImpl(request.Pass());
436 }
437
438 } // namespace hello
439 ```
440
441 And finally we need to update our app's `BUILD.gn` to add some new sources and d ependencies:
442
443 **components/hello/BUILD.gn**
444 ```
445 import("//mojo/public/mojo_application.gni")
446
447 source_set("lib") {
448 sources = [
449 "hello_app.cc",
450 "hello_app.h",
451 ]
452 deps = [
453 "//base",
454 "//components/hello/public/interfaces",
455 "//mojo/application/public/cpp",
456 "//mojo/environment:chromium",
457 ]
458 }
459
460 mojo_native_application("hello") {
461 sources = [
462 "main.cc",
463 ],
464 deps = [ ":lib" ]
465 }
466 ```
467
468 Note that we build the bulk of our application sources as a static library separ ate from the `MojoMain` definition. Following this convention is particularly us eful for Chromium integration, as we'll see later.
469
470 There's a lot going on here and it would be useful to familiarize yourself with the definitions of `mojo::ApplicationDelegate`, `mojo::ApplicationConnection`, a nd `mojo::InterfaceFactory<T>`. The TL;DR though is that if someone connects to this app and requests a service named `"hello::Greeter"`, the app will create a new `GreeterImpl` and bind it to that request pipe. From there the connecting ap p can call `Greeter` interface methods and they'll be routed to that `GreeterImp l` instance.
471
472 Although this appears to be a more interesting application, we need some way to actually connect and test the behavior of our new service. Let's write an app te st!
473
474 ## App Tests
475
476 App tests run inside a test application, giving test code access to a shell whic h can connect to one or more applications-under-test.
477
478 First let's introduce some test code:
479
480 **components/hello/hello\_apptest.cc**
481 ```
482 #include "base/bind.h"
483 #include "base/callback.h"
484 #include "base/logging.h"
485 #include "base/macros.h"
486 #include "base/run_loop.h"
487 #include "components/hello/public/interfaces/greeter.mojom.h"
488 #include "mojo/application/public/cpp/application_impl.h"
489 #include "mojo/application/public/cpp/application_test_base.h"
490
491 namespace hello {
492 namespace {
493
494 class HelloAppTest : public mojo::test::ApplicationTestBase {
495 public:
496 HelloAppTest() {}
497 ~HelloAppTest() override {}
498
499 void SetUp() override {
500 ApplicationTestBase::SetUp();
501 mojo::URLRequestPtr app_url = mojo::URLRequest::New();
502 app_url->url = "mojo:hello";
503 application_impl()->ConnectToService(app_url.Pass(), &greeter_);
504 }
505
506 Greeter* greeter() { return greeter_.get(); }
507
508 private:
509 GreeterPtr greeter_;
510
511 DISALLOW_COPY_AND_ASSIGN(HelloAppTest);
512 };
513
514 void ExpectGreeting(const mojo::String& expected_greeting,
515 const base::Closure& continuation,
516 const mojo::String& actual_greeting) {
517 EXPECT_EQ(expected_greeting, actual_greeting);
518 continuation.Run();
519 };
520
521 TEST_F(HelloAppTest, GreetWorld) {
522 base::RunLoop loop;
523 greeter()->Greet("world", base::Bind(&ExpectGreeting, "Hello, world!",
524 loop.QuitClosure()));
525 loop.Run();
526 }
527
528 } // namespace
529 } // namespace hello
530 ```
531
532 We also need to add a new rule to `//components/hello/BUILD.gn`:
533
534 ```
535 mojo_native_application("apptests") {
536 output_name = "hello_apptests"
537 testonly = true
538 sources = [
539 "hello_apptest.cc",
540 ]
541 deps = [
542 "//base",
543 "//mojo/application/public/cpp:test_support",
544 ]
545 public_deps = [
546 "//components/hello/public/interfaces",
547 ]
548 data_deps = [ ":hello" ]
549 }
550 ```
551
552 Note that the `//components/hello:apptests` target does **not** have a binary de pendency on either `HelloApp` or `GreeterImpl` implementations; instead it depen ds only on the component's public interface definitions.
553
554 The `data_deps` entry ensures that `hello.mojo` is up-to-date when `apptests` is built. This is desirable because the test connects to `"mojo:hello"` which will in turn load `hello.mojo` from disk.
555
556 You can now build the test suite:
557
558 ```
559 ninja -C out_gn/Debug components/hello:apptests
560 ```
561
562 and run it:
563
564 ```
565 out_gn/Debug/mojo_runner mojo:hello_apptests
566 ```
567
568 You should see one test (`HelloAppTest.GreetWorld`) passing.
569
570 One particularly interesting bit of code in this test is in the `SetUp` method:
571
572 ```
573 mojo::URLRequestPtr app_url = mojo::URLRequest::New();
574 app_url->url = "mojo:hello";
575 application_impl()->ConnectToService(app_url.Pass(), &greeter_);
576 ```
577
578 `ConnectToService` is a convenience method provided by `mojo::ApplicationImpl`, and it's essentially a shortcut for calling out to the shell's `ConnectToApplica tion` method with the given application URL (in this case `"mojo:hello"`) and th en connecting to a specific service provided by that app via its `ServiceProvide r`'s `ConnectToService` method.
579
580 Note that generated interface bindings include a constant string to identify eac h interface by name; so for example the generated `hello::Greeter` type defines a static C string:
581
582 ```
583 const char hello::Greeter::Name_[] = "hello::Greeter";
584 ```
585
586 This is exploited by the definition of `mojo::ApplicationConnection::ConnectToSe rvice<T>`, which uses `T::Name_` as the name of the service to connect to. The t ype `T` in this context is inferred from the `InterfacePtr<T>*` argument. You ca n inspect the definition of `ConnectToService` in [//mojo/application/public/cpp /application\_connection.h](https://code.google.com/p/chromium/codesearch#chromi um/src/mojo/application/public/cpp/application_connection.h) for additional clar ity.
587
588 We could have instead written this code as:
589
590 ```
591 mojo::URLRequestPtr app_url = mojo::URLRequest::New();
592 app_url->url = "mojo::hello";
593
594 mojo::ServiceProviderPtr services;
595 application_impl()->shell()->ConnectToApplication(
596 app_url.Pass(), mojo::GetProxy(&services),
597 // We pass a null provider since we aren't exposing any of our own
598 // services to the target app.
599 mojo::ServiceProviderPtr());
600
601 mojo::InterfaceRequest<hello::Greeter> greeter_request =
602 mojo::GetProxy(&greeter_);
603 services->ConnectToService(hello::Greeter::Name_,
604 greeter_request.PassMessagePipe());
605 ```
606
607 The net result is the same, but 3-line version seems much nicer.
608
609 # Chromium Integration
610
611 Up until now we've been using `mojo_runner` to load and run `.mojo` binaries dyn amically. While this model is used by Mandoline and may eventually be used in Ch romium as well, Chromium is at the moment confined to running statically linked application code. This means we need some way to register applications with the browser's Mojo shell.
612
613 It also means that, rather than using the binary output of a `mojo_native_applic ation` target, some part of Chromium must link against the app's static library target (_e.g._, `"//components/hello:lib"`) and register a URL handler to teach the shell how to launch an instance of the app.
614
615 When registering an app URL in Chromium it probably makes sense to use the same mojo-scheme URL used for the app in Mandoline. For example the media renderer ap p is referenced by the `"mojo:media"` URL in both Mandoline and Chromium. In Man doline this resolves to a dynamically-loaded `.mojo` binary on disk, but in Chro mium it resolves to a static application loader linked into Chromium. The net re sult is the same in both cases: other apps can use the shell to connect to `"moj o:media"` and use its services.
616
617 This section explores different ways to register and connect to `"mojo:hello"` i n Chromium.
618
619 ## In-Process Applications
620
621 Applications can be set up to run within the browser process via `ContentBrowser Client::RegisterInProcessMojoApplications`. This method populates a mapping from URL to `base::Callback<scoped_ptr<mojo::ApplicationDelegate>()>` (_i.e._, a fac tory function which creates a new `mojo::ApplicationDelegate` instance), so regi stering a new app means adding an entry to this map.
622
623 Let's modify `ChromeContentBrowserClient::RegisterInProcessMojoApplications` (in `//chrome/browser/chrome_content_browser_client.cc`) by adding the following co de:
624
625 ```
626 apps->insert(std::make_pair(GURL("mojo:hello"),
627 base::Bind(&HelloApp::CreateApp)));
628 ```
629
630 you'll also want to add the following convenience method to your `HelloApp` defi nition in `//components/hello/hello_app.h`:
631
632 ```
633 static scoped_ptr<mojo::ApplicationDelegate> HelloApp::CreateApp() {
634 return scoped_ptr<mojo::ApplicationDelegate>(new HelloApp);
635 }
636 ```
637
638 This introduces a dependency from `//chrome/browser` on to `//components/hello:l ib`, which you can add to the `"browser"` target's deps in `//chrome/browser/BUI LD.gn`. You'll of course also need to include `"components/hello/hello_app.h"` i n `chrome_content_browser_client.cc`.
639
640 That's it! Now if an app comes to the shell asking to connect to `"mojo:hello"` and app is already running, it'll get connected to our `HelloApp` and have acces s to the `Greeter` service. If the app wasn't already running, it will first be launched on a new thread.
641
642 ## Connecting From the Browser
643
644 We've already seen how apps can connect to each other using their own private sh ell proxy, but the vast majority of Chromium code doesn't yet belong to a Mojo a pplication. So how do we use an app's services from arbitrary browser code? We u se `content::MojoAppConnection`, like this:
645
646 ```
647 #include "base/bind.h"
648 #include "base/logging.h"
649 #include "components/hello/public/interfaces/greeter.mojom.h"
650 #include "content/public/browser/mojo_app_connection.h"
651
652 void LogGreeting(const mojo::String& greeting) {
653 LOG(INFO) << greeting;
654 }
655
656 void GreetTheWorld() {
657 scoped_ptr<content::MojoAppConnection> connection =
658 content::MojoAppConnection::Create("mojo:hello",
659 content::kBrowserMojoAppUrl);
660 hello::GreeterPtr greeter;
661 connection->ConnectToService(&greeter);
662 greeter->Greet("world", base::Bind(&LogGreeting));
663 }
664 ```
665
666 A `content::MojoAppConnection`, while not thread-safe, may be created and safely used on any single browser thread.
667
668 You could add the above code to a new browsertest to convince yourself that it w orks. In fact you might want to take a peek at `MojoShellTest.TestBrowserConnect ion` (in [//content/browser/mojo\_shell\_browsertest.cc](https://code.google.com /p/chromium/codesearch#chromium/src/content/browser/mojo_shell_browsertest.cc)) which registers and tests an in-process Mojo app.
669
670 Finally, note that `MojoAppConnection::Create` takes two URLs. The first is the target app URL, and the second is the source URL. Since we're not really a Mojo app, but we are still trusted browser code, the shell will gladly use this URL a s the `requestor_url` when establishing an incoming connection to the target app . This allows browser code to masquerade as a Mojo app at the given URL. `conten t::kBrowserMojoAppUrl` (which is presently `"system:content_browser"`) is a reas onable default choice when a more specific app identity isn't required.
671
672 ## Out-of-Process Applications
673
674 If an app URL isn't registered for in-process loading, the shell assumes it must be an out-of-process application. If the shell doesn't already have a known ins tance of the app running, a new utility process is launched and the application request is passed onto it. Then if the app URL is registered in the utility proc ess, the app will be loaded there.
675
676 Similar to in-process registration, a URL mapping needs to be registered in `Con tentUtilityClient::RegisterMojoApplications`.
677
678 Once again you can take a peek at //content/browser/mojo\_shell\_browsertest.cc for an end-to-end example of testing an out-of-process Mojo app from browser cod e. Note that `content_browsertests` runs on `content_shell`, which uses `ShellCo ntentUtilityClient` as defined [//content/shell/utility/shell\_content\_utility\ _client.cc](https://code.google.com/p/chromium/codesearch#chromium/src/content/s hell/utility/shell_content_utility_client.cc). This code registers a common OOP test app.
679
680 ## Unsandboxed Out-of-Process Applications
681
682 By default new utility processes run in a sandbox. If you want your Mojo app to run out-of-process and unsandboxed (which you **probably do not**), you can regi ster its URL via `ContentBrowserClient::RegisterUnsandboxedOutOfProcessMojoAppli cations`.
683
684 ## Connecting From `RenderFrame`
685
686 We can also connect to Mojo apps from a `RenderFrame`. This is made possible by `RenderFrame`'s `GetServiceRegistry()` interface. The `ServiceRegistry` can be u sed to acquire a shell proxy and in turn connect to an app like so:
687
688 ```
689 void GreetWorld(content::RenderFrame* frame) {
690 mojo::ShellPtr shell;
691 frame->GetServiceRegistry()->ConnectToRemoteService(
692 mojo::GetProxy(&shell));
693
694 mojo::URLRequestPtr request = mojo::URLRequest::New();
695 request->url = "mojo:hello";
696
697 mojo::ServiceProviderPtr hello_services;
698 shell->ConnectToApplication(
699 request.Pass(), mojo::GetProxy(&hello_services), nullptr);
700
701 hello::GreeterPtr greeter;
702 hello_services->ConnectToService(
703 hello::Greeter::Name_, mojo::GetProxy(&greeter).PassMessagePipe());
704 }
705 ```
706
707 It's important to note that connections made through the frame's shell proxy wil l appear to come from the frame's `SiteInstance` URL. For example, if the frame has loaded `https://example.com/`, `HelloApp`'s incoming `mojo::ApplicationConne ction` in this case will have a remote application URL of `"https://example.com/ "`. This allows apps to expose their services to web frames on a per-origin basi s if needed.
708
709 ## Connecting From Java
710
711 TODO
712
713 ## Connecting From `JavaScript`
714
715 This is still a work in progress and might not really take shape until the Blink +Chromium merge. In the meantime there are some end-to-end WebUI examples in [// content/browser/webui/web\_ui\_mojo\_browsertest.cc](https://code.google.com/p/c hromium/codesearch#chromium/src/content/browser/webui/web_ui_mojo_browsertest.cc ). In particular, `WebUIMojoTest.ConnectToApplication` connects from a WebUI fra me to a test app running in a new utility process.
716
717 # FAQ
718
719 Nothing here yet!
OLDNEW
« no previous file with comments | « docs/mandriva_msttcorefonts.md ('k') | docs/ninja_build.md » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698