Roll src/third_party/WebKit a3b4a2e:7441784 (svn 202551:202552)
[chromium-blink-merge.git] / docs / mojo_in_chromium.md
blobb9919e22414936149e81fb477ef67bf7ee6843aa
1 # Mojo in Chromium
3 **THIS DOCUIMENT IS A WORK IN PROGRESS.** As long as this notice exists, you
4 should probably ignore everything below it.
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++
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,
10 callback binding, and so on.
12 [TOC]
14 ## Should I Bother Reading This?
16 If you're planning to build a Chromium feature that needs IPC and you aren't
17 already using Mojo, you probably want to read this. **Legacy IPC** -- _i.e._,
18 `foo_messages.h` files, message filters, and the suite of `IPC_MESSAGE_*` macros
19 -- **is on the verge of deprecation.**
21 ## Why Mojo?
23 Mojo provides IPC primitives for pushing messages and data around between
24 transferrable endpoints which may or may not cross process boundaries; it
25 simplifies threading with regard to IPC; it standardizes message serialization
26 in a way that's resilient to versioning issues; and it can be used with relative
27 ease and consistency across a number of languages including C++, Java, and
28 `JavaScript` -- all languages which comprise a significant share of Chromium
29 code.
31 The messaging protocol doesn't strictly need to be used for IPC though, and
32 there are some higher-level reasons for this adoption and for the specific
33 approach to integration outlined in this document.
35 ### Code Health
37 At the moment we have fairly weak separation between components, with DEPS being
38 the strongest line of defense against increasing complexity.
40 A component Foo might hold a reference to some bit of component Bar's internal
41 state, or it might expect Bar to initialize said internal state in some
42 particular order. These sorts of problems are reasonably well-mitigated by the
43 code review process, but they can (and do) still slip through the cracks, and
44 they have a noticeable cumulative effect on complexity as the code base
45 continues to grow.
47 We think we can make a lasting positive impact on code health by establishing
48 more concrete boundaries between components, and this is something a library
49 like Mojo gives us an opportunity to do.
51 ### Modularity
53 In addition to code health -- which alone could be addressed in any number of
54 ways that don't involve Mojo -- this approach opens doors to build and
55 distribute parts of Chrome separately from the main binary.
57 While we're not currently taking advantage of this capability, doing so remains
58 a long-term goal due to prohibitive binary size constraints in emerging mobile
59 markets. Many open questions around the feasibility of this goal should be
60 answered by the experimental Mandoline project as it unfolds, but the Chromium
61 project can be technically prepared for such a transition in the meantime.
63 ### Mandoline
65 The Mandoline project is producing a potential replacement for `src/content`.
66 Because Mandoline components are Mojo apps, and Chromium is now capable of
67 loading Mojo apps (somethings we'll discuss later), Mojo apps can be shared
68 between both projects with minimal effort. Developing your feature as or within
69 a Mojo application can mean you're contributing to both Chromium and Mandoline.
71 ## Mojo Overview
73 This section provides a general overview of Mojo and some of its API features.
74 You can probably skip straight to
75 [Your First Mojo Application](#Your-First-Mojo-Application) if you just want to
76 get to some practical sample code.
78 The Mojo Embedder Development Kit (EDK) provides a suite of low-level IPC
79 primitives: **message pipes**, **data pipes**, and **shared buffers**. We'll
80 focus primarily on message pipes and the C++ bindings API in this document.
82 _TODO: Java and JS bindings APIs should also be covered here._
84 ### Message Pipes
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
88 by a **handle** -- a unique process-wide integer identifying the endpoint to the
89 EDK.
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
93 process or in two different processes.
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
97 class wrapper with each endpoint represented as a scoped handle type (see
98 members `handle0` and `handle1` and the definition of
99 `mojo::ScopedMessagePipeHandle`). In the same header you can find
100 `WriteMessageRaw` and `ReadMessageRaw` definitions. These are in theory all one
101 needs to begin pushing things from one endpoint to the other.
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
105 use bindings code generated from mojom interface definitions, along with the
106 public bindings API which mostly hides the underlying pipes.
108 ### Mojom Bindings
110 Mojom is the IDL for Mojo interfaces. When given a mojom file, the bindings
111 generator outputs a collection of bindings libraries for each supported
112 language. Mojom syntax is fairly straightforward (TODO: Link to a mojom language
113 spec?). Consider the example mojom file below:
116 // frobinator.mojom
117 module frob;
118 interface Frobinator {
119   Frobinate();
123 This can be used to generate bindings for a very simple `Frobinator` interface.
124 Bindings are generated at build time and will match the location of the mojom
125 source file itself, mapped into the generated output directory for your Chromium
126 build. In this case one can expect to find files named `frobinator.mojom.js`,
127 `frobinator.mojom.cc`, `frobinator.mojom.h`, _etc._
129 The C++ header (`frobinator.mojom.h`) generated from this mojom will define a
130 pure virtual class interface named `frob::Frobinator` with a pure virtual method
131 of signature `void Frobinate()`. Any class which implements this interface is
132 effectively a `Frobinator` service.
134 ### C++ Bindings API
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
138 familiar with. These complement generated bindings code and generally obviate
139 any need to use a `mojo::MessagePipe` directly.
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.
144 #### `mojo::InterfacePtr<T>`
146 Defined in `/third_party/mojo/src/mojo/public/cpp/bindings/interface_ptr.h`.
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
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
152 to any Mojo service.
154 For illustrative purposes only, we can create a message pipe and bind an
155 `InterfacePtr` to one end as follows:
158   mojo::MessagePipe pipe;
159   mojo::InterfacePtr<frob::Frobinator> frobinator;
160   frobinator.Bind(
161       mojo::InterfacePtrInfo<frob::Frobinator>(pipe.handle0.Pass(), 0u));
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
166 to do this though, because as you'll soon see there's a nicer way to establish
167 service pipes.
169 #### `mojo::InterfaceRequest<T>`
171 Defined in `/third_party/mojo/src/mojo/public/cpp/bindings/interface_request.h`.
173 `mojo::InterfaceRequest<T>` is a typed container for a message pipe endpoint
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
176 onto an endpoint without losing interface type information.
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
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
182 see later, a first-class concept in Mojom interface definitions.
184 As with `InterfacePtr<T>`, we can manually bind an `InterfaceRequest<T>` to a
185 pipe endpoint:
188 mojo::MessagePipe pipe;
190 mojo::InterfacePtr<frob::Frobinator> frobinator;
191 frobinator.Bind(
192     mojo::InterfacePtrInfo<frob::Frobinator>(pipe.handle0.Pass(), 0u));
194 mojo::InterfaceRequest<frob::Frobinator> frobinator_request;
195 frobinator_request.Bind(pipe.handle1.Pass());
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.
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.
203 #### `mojo::GetProxy<T>`
205 Defined in
206 `/third_party/mojo/src/mojo/public/cpp/bindings/interface`_request.h`.
208 `mojo::GetProxy<T>` is the function you will most commonly use to create a new
209 message pipe. Its signature is as follows:
212 template <typename T>
213 mojo::InterfaceRequest<T> GetProxy(mojo::InterfacePtr<T>* ptr);
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`
218 which it then returns. Equivalent to the sample code just above is the following
219 snippet:
222   mojo::InterfacePtr<frob::Frobinator> frobinator;
223   mojo::InterfaceRequest<frob::Frobinator> frobinator_request =
224       mojo::GetProxy(&frobinator);
227 #### `mojo::Binding<T>`
229 Defined in `/third_party/mojo/src/mojo/public/cpp/bindings/binding.h`.
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
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`
235 (which itself usually owns said `Binding` object), and its bound pipe is usually
236 taken from a passed `InterfaceRequest<T>`.
238 A common usage pattern looks something like this:
241 #include "components/frob/public/interfaces/frobinator.mojom.h"
242 #include "third_party/mojo/src/mojo/public/cpp/bindings/binding.h"
243 #include "third_party/mojo/src/mojo/public/cpp/bindings/interface_request.h"
245 class FrobinatorImpl : public frob::Frobinator {
246  public:
247   FrobinatorImpl(mojo::InterfaceRequest<frob::Frobinator> request)
248       : binding_(this, request.Pass()) {}
249   ~FrobinatorImpl() override {}
251  private:
252   // frob::Frobinator:
253   void Frobinate() override { /* ... */ }
255   mojo::Binding<frob::Frobinator> binding_;
259 And then we could write some code to test this:
262 // Fun fact: The bindings generator emits a type alias like this for every
263 // interface type. frob::FrobinatorPtr is an InterfacePtr<frob::Frobinator>.
264 frob::FrobinatorPtr frobinator;
265 scoped_ptr<FrobinatorImpl> impl(
266     new FrobinatorImpl(mojo::GetProxy(&frobinator)));
267 frobinator->Frobinate();
270 This will _eventually_ call `FrobinatorImpl::Frobinate()`. "Eventually," because
271 the sequence of events when `frobinator->Frobinate()` is called is roughly as
272 follows:
274 1.  A new message buffer is allocated and filled with an encoded 'Frobinate'
275     message.
276 1.  The EDK is asked to write this message to the pipe endpoint owned by the
277     `FrobinatorPtr`.
278 1.  If the call didn't happen on the Mojo IPC thread for this process, EDK hops
279     to the Mojo IPC thread.
280 1.  The EDK writes the message to the pipe. In this case the pipe endpoints live
281     in the same process, so this essentially a glorified `memcpy`. If they lived
282     in different processes this would be the point at which the data moved
283     across a real IPC channel.
284 1.  The EDK on the other end of the pipe is awoken on the Mojo IPC thread and
285     alerted to the message arrival.
286 1.  The EDK reads the message.
287 1.  If the bound receiver doesn't live on the Mojo IPC thread, the EDK hops to
288     the receiver's thread.
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
291     the `Frobinate` message.
292 1.  `FrobinatorImpl::Frobinate()` is called on the bound implementation.
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.
297 #### `mojo::StrongBinding<T>`
299 Defined in `third_party/mojo/src/mojo/public/cpp/bindings/strong_binding.h`.
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
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
305 servicing, but like all features with clever lifetime semantics, it should be
306 used with caution.
308 ## The Mojo Shell
310 Both Chromium and Mandoline run a central **shell** component which is used to
311 coordinate communication among all Mojo applications (see the next section for
312 an overview of Mojo applications.)
314 Every application receives a proxy to this shell upon initialization, and it is
315 exclusively through this proxy that an application can request connections to
316 other applications. The `mojo::Shell` interface provided by this proxy is
317 defined as follows:
320 module mojo;
321 interface Shell {
322   ConnectToApplication(URLRequest application_url,
323                        ServiceProvider&? services,
324                        ServiceProvider? exposed_services);
325   QuitApplication();
329 and as for the `mojo::ServiceProvider` interface:
332 module mojo;
333 interface ServiceProvider {
334   ConnectToService(string interface_name, handle<message_pipe> pipe);
338 Definitions for these interfaces can be found in
339 `/mojo/application/public/interfaces`. Also note that `mojo::URLRequest` is a
340 Mojo struct defined in
341 `/mojo/services/network/public/interfaces/url_loader.mojom`.
343 Note that there's some new syntax in the mojom for `ConnectToApplication` above.
344 The '?' signifies a nullable value and the '&' signifies an interface request
345 rather than an interface proxy.
347 The argument `ServiceProvider&? services` indicates that the caller should pass
348 an `InterfaceRequest<ServiceProvider>` as the second argument, but that it need
349 not be bound to a pipe (i.e., it can be "null" in which case it's ignored.)
351 The argument `ServiceProvider? exposed_services` indicates that the caller
352 should pass an `InterfacePtr<ServiceProvider>` as the third argument, but that
353 it may also be null.
355 `ConnectToApplication` asks the shell to establish a connection between the
356 caller and some other app the shell might know about. In the event that a
357 connection can be established -- which may involve the shell starting a new
358 instance of the target app -- the given `services` request (if not null) will be
359 bound to a service provider in the target app. The target app may in turn use
360 the passed `exposed_services` proxy (if not null) to request services from the
361 connecting app.
363 ### Mojo Applications
365 All code which runs in a Mojo environment, apart from the shell itself (see
366 above), belongs to one Mojo **application** or another**`**`**. The term
367 "application" in this context is a common source of confusion, but it's really a
368 simple concept. In essence an application is anything which implements the
369 following Mojom interface:
372 module mojo;
373 interface Application {
374   Initialize(Shell shell, string url);
375   AcceptConnection(string requestor_url,
376                    ServiceProvider&? services,
377                    ServiceProvider? exposed_services,
378                    string resolved_url);
379   OnQuitRequested() => (bool can_quit);
383 Of course, in Chromium and Mandoline environments this interface is obscured
384 from application code and applications should generally just implement
385 `mojo::ApplicationDelegate` (defined in
386 `/mojo/application/public/cpp/application_delegate.h`.) We'll see a concrete
387 example of this in the next section,
388 [Your First Mojo Application](#Your-First-Mojo-Application).
390 The takeaway here is that an application can be anything. It's not necessarily a
391 new process (though at the moment, it's at least a new thread). Applications can
392 connect to each other, and these connections are the mechanism through which
393 separate components expose services to each other.
395 **NOTE##: This is not true in Chromium today, but it should be eventually. For
396 some components (like render frames, or arbitrary browser process code) we
397 provide APIs which allow non-Mojo-app-code to masquerade as a Mojo app and
398 therefore connect to real Mojo apps through the shell.
400 ### Other IPC Primitives
402 Finally, it's worth making brief mention of the other types of IPC primitives
403 Mojo provides apart from message pipes. A **data pipe** is a unidirectional
404 channel for pushing around raw data in bulk, and a **shared buffer** is
405 (unsurprisingly) a shared memory primitive. Both of these objects use the same
406 type of transferable handle as message pipe endpoints, and can therefore be
407 transferred across message pipes, potentially to other processes.
409 ## Your First Mojo Application
411 In this section, we're going to build a simple Mojo application that can be run
412 in isolation using Mandoline's `mojo_runner` binary. After that we'll add a
413 service to the app and set up a test suite to connect and test that service.
415 ### Hello, world!
417 So, you're building a new Mojo app and it has to live somewhere. For the
418 foreseeable future we'll likely be treating `//components` as a sort of
419 top-level home for new Mojo apps in the Chromium tree. Any component application
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
422 make while working through this.
424 First create a new `//components/hello` directory. Inside this directory we're
425 going to add the following files:
427 **components/hello/main.cc**
429 #include "base/logging.h"
430 #include "third_party/mojo/src/mojo/public/c/system/main.h"
432 MojoResult MojoMain(MojoHandle shell_handle) {
433   LOG(ERROR) << "Hello, world!";
434   return MOJO_RESULT_OK;
438 **components/hello/BUILD.gn**
440 import("//mojo/public/mojo_application.gni")
442 mojo_native_application("hello") {
443   sources = [
444     "main.cc",
445   ]
446   deps = [
447     "//base",
448     "//mojo/environment:chromium",
449   ]
453 For the sake of this example you'll also want to add your component as a
454 dependency somewhere in your local checkout to ensure its build files are
455 generated. The easiest thing to do there is probably to add a dependency on
456 `"//components/hello"` in the `"gn_all"` target of the top-level `//BUILD.gn`.
458 Assuming you have a GN output directory at `out_gn/Debug`, you can build the
459 Mojo runner along with your shiny new app:
461     ninja -C out_gn/Debug mojo_runner components/hello
463 In addition to the `mojo_runner` executable, this will produce a new binary at
464 `out_gn/Debug/hello/hello.mojo`. This binary is essentially a shared library
465 which exports your `MojoMain` function.
467 `mojo_runner` takes an application URL as its only argument and runs the
468 corresponding application. In its current state it resolves `mojo`-scheme URLs
469 such that `"mojo:foo"` maps to the file `"foo/foo.mojo"` relative to the
470 `mojo_runner` path (_i.e._ your output directory.) This means you can run your
471 new app with the following command:
473     out_gn/Debug/mojo_runner mojo:hello
475 You should see our little `"Hello, world!"` error log followed by a hanging
476 application. You can `^C` to kill it.
478 ### Exposing Services
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
482 least one service to connecting applications.
484 Let's update `main.cc` with the following contents:
486 **components/hello/main.cc**
488 #include "components/hello/hello_app.h"
489 #include "mojo/application/public/cpp/application_runner.h"
490 #include "third_party/mojo/src/mojo/public/c/system/main.h"
492 MojoResult MojoMain(MojoHandle shell_handle) {
493   mojo::ApplicationRunner runner(new hello::HelloApp);
494   return runner.Run(shell_handle);
498 This is a pretty typical looking `MojoMain`. Most of the time this is all you
499 want -- a `mojo::ApplicationRunner` constructed over a
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:
503 **components/hello/public/interfaces/greeter.mojom**
505 module hello;
506 interface Greeter {
507   Greet(string name) => (string greeting);
511 Note the new arrow syntax on the `Greet` method. This indicates that the caller
512 expects a response from the service.
514 **components/hello/public/interfaces/BUILD.gn**
516 import("//third_party/mojo/src/mojo/public/tools/bindings/mojom.gni")
518 mojom("interfaces") {
519   sources = [
520     "greeter.mojom",
521   ]
525 **components/hello/hello_app.h**
527 #ifndef COMPONENTS_HELLO_HELLO_APP_H_
528 #define COMPONENTS_HELLO_HELLO_APP_H_
530 #include "base/macros.h"
531 #include "components/hello/public/interfaces/greeter.mojom.h"
532 #include "mojo/application/public/cpp/application_delegate.h"
533 #include "mojo/application/public/cpp/interface_factory.h"
535 namespace hello {
537 class HelloApp : public mojo::ApplicationDelegate,
538                  public mojo::InterfaceFactory<Greeter> {
539  public:
540   HelloApp();
541   ~HelloApp() override;
543  private:
544   // mojo::ApplicationDelegate:
545   bool ConfigureIncomingConnection(
546       mojo::ApplicationConnection* connection) override;
548   // mojo::InterfaceFactory<Greeter>:
549   void Create(mojo::ApplicationConnection* connection,
550               mojo::InterfaceRequest<Greeter> request) override;
552   DISALLOW_COPY_AND_ASSIGN(HelloApp);
555 }  // namespace hello
557 #endif  // COMPONENTS_HELLO_HELLO_APP_H_
561 **components/hello/hello_app.cc**
563 #include "base/macros.h"
564 #include "components/hello/hello_app.h"
565 #include "mojo/application/public/cpp/application_connection.h"
566 #include "third_party/mojo/src/mojo/public/cpp/bindings/interface_request.h"
567 #include "third_party/mojo/src/mojo/public/cpp/bindings/strong_binding.h"
569 namespace hello {
571 namespace {
573 class GreeterImpl : public Greeter {
574  public:
575   GreeterImpl(mojo::InterfaceRequest<Greeter> request)
576       : binding_(this, request.Pass()) {
577   }
579   ~GreeterImpl() override {}
581  private:
582   // Greeter:
583   void Greet(const mojo::String& name, const GreetCallback& callback) override {
584     callback.Run("Hello, " + std::string(name) + "!");
585   }
587   mojo::StrongBinding<Greeter> binding_;
589   DISALLOW_COPY_AND_ASSIGN(GreeterImpl);
592 }  // namespace
594 HelloApp::HelloApp() {
597 HelloApp::~HelloApp() {
600 bool HelloApp::ConfigureIncomingConnection(
601     mojo::ApplicationConnection* connection) {
602   connection->AddService<Greeter>(this);
603   return true;
606 void HelloApp::Create(
607     mojo::ApplicationConnection* connection,
608     mojo::InterfaceRequest<Greeter> request) {
609   new GreeterImpl(request.Pass());
612 }  // namespace hello
615 And finally we need to update our app's `BUILD.gn` to add some new sources and
616 dependencies:
618 **components/hello/BUILD.gn**
620 import("//mojo/public/mojo_application.gni")
622 source_set("lib") {
623   sources = [
624     "hello_app.cc",
625     "hello_app.h",
626   ]
627   deps = [
628     "//base",
629     "//components/hello/public/interfaces",
630     "//mojo/application/public/cpp",
631     "//mojo/environment:chromium",
632   ]
635 mojo_native_application("hello") {
636   sources = [
637     "main.cc",
638   ],
639   deps = [ ":lib" ]
643 Note that we build the bulk of our application sources as a static library
644 separate from the `MojoMain` definition. Following this convention is
645 particularly useful for Chromium integration, as we'll see later.
647 There's a lot going on here and it would be useful to familiarize yourself with
648 the definitions of `mojo::ApplicationDelegate`, `mojo::ApplicationConnection`,
649 and `mojo::InterfaceFactory<T>`. The TL;DR though is that if someone connects to
650 this app and requests a service named `"hello::Greeter"`, the app will create a
651 new `GreeterImpl` and bind it to that request pipe. From there the connecting
652 app can call `Greeter` interface methods and they'll be routed to that
653 `GreeterImpl` instance.
655 Although this appears to be a more interesting application, we need some way to
656 actually connect and test the behavior of our new service. Let's write an app
657 test!
659 ### App Tests
661 App tests run inside a test application, giving test code access to a shell
662 which can connect to one or more applications-under-test.
664 First let's introduce some test code:
666 **components/hello/hello_apptest.cc**
668 #include "base/bind.h"
669 #include "base/callback.h"
670 #include "base/logging.h"
671 #include "base/macros.h"
672 #include "base/run_loop.h"
673 #include "components/hello/public/interfaces/greeter.mojom.h"
674 #include "mojo/application/public/cpp/application_impl.h"
675 #include "mojo/application/public/cpp/application_test_base.h"
677 namespace hello {
678 namespace {
680 class HelloAppTest : public mojo::test::ApplicationTestBase {
681  public:
682   HelloAppTest() {}
683   ~HelloAppTest() override {}
685   void SetUp() override {
686     ApplicationTestBase::SetUp();
687     mojo::URLRequestPtr app_url = mojo::URLRequest::New();
688     app_url->url = "mojo:hello";
689     application_impl()->ConnectToService(app_url.Pass(), &greeter_);
690   }
692   Greeter* greeter() { return greeter_.get(); }
694  private:
695   GreeterPtr greeter_;
697   DISALLOW_COPY_AND_ASSIGN(HelloAppTest);
700 void ExpectGreeting(const mojo::String& expected_greeting,
701                     const base::Closure& continuation,
702                     const mojo::String& actual_greeting) {
703   EXPECT_EQ(expected_greeting, actual_greeting);
704   continuation.Run();
707 TEST_F(HelloAppTest, GreetWorld) {
708   base::RunLoop loop;
709   greeter()->Greet("world", base::Bind(&ExpectGreeting, "Hello, world!",
710                                        loop.QuitClosure()));
711   loop.Run();
714 }  // namespace
715 }  // namespace hello
718 We also need to add a new rule to `//components/hello/BUILD.gn`:
721 mojo_native_application("apptests") {
722   output_name = "hello_apptests"
723   testonly = true
724   sources = [
725     "hello_apptest.cc",
726   ]
727   deps = [
728     "//base",
729     "//mojo/application/public/cpp:test_support",
730   ]
731   public_deps = [
732     "//components/hello/public/interfaces",
733   ]
734   data_deps = [ ":hello" ]
738 Note that the `//components/hello:apptests` target does **not** have a binary
739 dependency on either `HelloApp` or `GreeterImpl` implementations; instead it
740 depends only on the component's public interface definitions.
742 The `data_deps` entry ensures that `hello.mojo` is up-to-date when `apptests` is
743 built. This is desirable because the test connects to `"mojo:hello"` which will
744 in turn load `hello.mojo` from disk.
746 You can now build the test suite:
748     ninja -C out_gn/Debug components/hello:apptests
750 and run it:
752     out_gn/Debug/mojo_runner mojo:hello_apptests
754 You should see one test (`HelloAppTest.GreetWorld`) passing.
756 One particularly interesting bit of code in this test is in the `SetUp` method:
758     mojo::URLRequestPtr app_url = mojo::URLRequest::New();
759     app_url->url = "mojo:hello";
760     application_impl()->ConnectToService(app_url.Pass(), &greeter_);
762 `ConnectToService` is a convenience method provided by `mojo::ApplicationImpl`,
763 and it's essentially a shortcut for calling out to the shell's
764 `ConnectToApplication` method with the given application URL (in this case
765 `"mojo:hello"`) and then connecting to a specific service provided by that app
766 via its `ServiceProvider`'s `ConnectToService` method.
768 Note that generated interface bindings include a constant string to identify
769 each interface by name; so for example the generated `hello::Greeter` type
770 defines a static C string:
772     const char hello::Greeter::Name_[] = "hello::Greeter";
774 This is exploited by the definition of
775 `mojo::ApplicationConnection::ConnectToService<T>`, which uses `T::Name_` as the
776 name of the service to connect to. The type `T` in this context is inferred from
777 the `InterfacePtr<T>*` argument. You can inspect the definition of
778 `ConnectToService` in `/mojo/application/public/cpp/application_connection.h`
779 for additional clarity.
781 We could have instead written this code as:
784 mojo::URLRequestPtr app_url = mojo::URLRequest::New();
785 app_url->url = "mojo::hello";
787 mojo::ServiceProviderPtr services;
788 application_impl()->shell()->ConnectToApplication(
789     app_url.Pass(), mojo::GetProxy(&services),
790     // We pass a null provider since we aren't exposing any of our own
791     // services to the target app.
792     mojo::ServiceProviderPtr());
794 mojo::InterfaceRequest<hello::Greeter> greeter_request =
795     mojo::GetProxy(&greeter_);
796 services->ConnectToService(hello::Greeter::Name_,
797                            greeter_request.PassMessagePipe());
800 The net result is the same, but 3-line version seems much nicer.
802 ## Chromium Integration
804 Up until now we've been using `mojo_runner` to load and run `.mojo` binaries
805 dynamically. While this model is used by Mandoline and may eventually be used in
806 Chromium as well, Chromium is at the moment confined to running statically
807 linked application code. This means we need some way to register applications
808 with the browser's Mojo shell.
810 It also means that, rather than using the binary output of a
811 `mojo_native_application` target, some part of Chromium must link against the
812 app's static library target (_e.g._, `"//components/hello:lib"`) and register a
813 URL handler to teach the shell how to launch an instance of the app.
815 When registering an app URL in Chromium it probably makes sense to use the same
816 mojo-scheme URL used for the app in Mandoline. For example the media renderer
817 app is referenced by the `"mojo:media"` URL in both Mandoline and Chromium. In
818 Mandoline this resolves to a dynamically-loaded `.mojo` binary on disk, but in
819 Chromium it resolves to a static application loader linked into Chromium. The
820 net result is the same in both cases: other apps can use the shell to connect to
821 `"mojo:media"` and use its services.
823 This section explores different ways to register and connect to `"mojo:hello"`
824 in Chromium.
826 ### In-Process Applications
828 Applications can be set up to run within the browser process via
829 `ContentBrowserClient::RegisterInProcessMojoApplications`. This method populates
830 a mapping from URL to `base::Callback<scoped_ptr<mojo::ApplicationDelegate>()>`
831 (_i.e._, a factory function which creates a new `mojo::ApplicationDelegate`
832 instance), so registering a new app means adding an entry to this map.
834 Let's modify `ChromeContentBrowserClient::RegisterInProcessMojoApplications`
835 (in `//chrome/browser/chrome_content_browser_client.cc`) by adding the following
836 code:
838     apps->insert(std::make_pair(GURL("mojo:hello"),
839                                 base::Bind(&HelloApp::CreateApp)));
841 you'll also want to add the following convenience method to your `HelloApp`
842 definition in `//components/hello/hello_app.h`:
844     static scoped_ptr<mojo::ApplicationDelegate> HelloApp::CreateApp() {
845       return scoped_ptr<mojo::ApplicationDelegate>(new HelloApp);
846     }
848 This introduces a dependency from `//chrome/browser` on to
849 `//components/hello:lib`, which you can add to the `"browser"` target's deps in
850 `//chrome/browser/BUILD.gn`. You'll of course also need to include
851 `"components/hello/hello_app.h"` in `chrome_content_browser_client.cc`.
853 That's it! Now if an app comes to the shell asking to connect to `"mojo:hello"`
854 and app is already running, it'll get connected to our `HelloApp` and have
855 access to the `Greeter` service. If the app wasn't already running, it will
856 first be launched on a new thread.
858 ### Connecting From the Browser
860 We've already seen how apps can connect to each other using their own private
861 shell proxy, but the vast majority of Chromium code doesn't yet belong to a Mojo
862 application. So how do we use an app's services from arbitrary browser code? We
863 use `content::MojoAppConnection`, like this:
866 #include "base/bind.h"
867 #include "base/logging.h"
868 #include "components/hello/public/interfaces/greeter.mojom.h"
869 #include "content/public/browser/mojo_app_connection.h"
871 void LogGreeting(const mojo::String& greeting) {
872   LOG(INFO) << greeting;
875 void GreetTheWorld() {
876   scoped_ptr<content::MojoAppConnection> connection =
877       content::MojoAppConnection::Create("mojo:hello",
878                                          content::kBrowserMojoAppUrl);
879   hello::GreeterPtr greeter;
880   connection->ConnectToService(&greeter);
881   greeter->Greet("world", base::Bind(&LogGreeting));
885 A `content::MojoAppConnection`, while not thread-safe, may be created and safely
886 used on any single browser thread.
888 You could add the above code to a new browsertest to convince yourself that it
889 works. In fact you might want to take a peek at
890 `MojoShellTest.TestBrowserConnection` (in
891 `/content/browser/mojo_shell_browsertest.cc`) which registers and tests an
892 in-process Mojo app.
894 Finally, note that `MojoAppConnection::Create` takes two URLs. The first is the
895 target app URL, and the second is the source URL. Since we're not really a Mojo
896 app, but we are still trusted browser code, the shell will gladly use this URL
897 as the `requestor_url` when establishing an incoming connection to the target
898 app. This allows browser code to masquerade as a Mojo app at the given URL.
899 `content::kBrowserMojoAppUrl` (which is presently `"system:content_browser"`) is
900 a reasonable default choice when a more specific app identity isn't required.
902 ### Out-of-Process Applications
904 If an app URL isn't registered for in-process loading, the shell assumes it must
905 be an out-of-process application. If the shell doesn't already have a known
906 instance of the app running, a new utility process is launched and the
907 application request is passed onto it. Then if the app URL is registered in the
908 utility process, the app will be loaded there.
910 Similar to in-process registration, a URL mapping needs to be registered in
911 `ContentUtilityClient::RegisterMojoApplications`.
913 Once again you can take a peek at `/content/browser/mojo_shell_browsertest.cc`
914 for an end-to-end example of testing an out-of-process Mojo app from browser
915 code. Note that `content_browsertests` runs on `content_shell`, which uses
916 `ShellContentUtilityClient` as defined
917 `/content/shell/utility/shell_content_utility_client.cc`. This code registers a
918 common OOP test app.
920 ## Unsandboxed Out-of-Process Applications
922 By default new utility processes run in a sandbox. If you want your Mojo app to
923 run out-of-process and unsandboxed (which you **probably do not**), you can
924 register its URL via
925 `ContentBrowserClient::RegisterUnsandboxedOutOfProcessMojoApplications`.
927 ## Connecting From `RenderFrame`
929 We can also connect to Mojo apps from a `RenderFrame`. This is made possible by
930 `RenderFrame`'s `GetServiceRegistry()` interface. The `ServiceRegistry` can be
931 used to acquire a shell proxy and in turn connect to an app like so:
934 void GreetWorld(content::RenderFrame* frame) {
935   mojo::ShellPtr shell;
936   frame->GetServiceRegistry()->ConnectToRemoteService(
937       mojo::GetProxy(&shell));
939   mojo::URLRequestPtr request = mojo::URLRequest::New();
940   request->url = "mojo:hello";
942   mojo::ServiceProviderPtr hello_services;
943   shell->ConnectToApplication(
944       request.Pass(), mojo::GetProxy(&hello_services), nullptr);
946   hello::GreeterPtr greeter;
947   hello_services->ConnectToService(
948       hello::Greeter::Name_, mojo::GetProxy(&greeter).PassMessagePipe());
952 It's important to note that connections made through the frame's shell proxy
953 will appear to come from the frame's `SiteInstance` URL. For example, if the
954 frame has loaded `https://example.com/`, `HelloApp`'s incoming
955 `mojo::ApplicationConnection` in this case will have a remote application URL of
956 `"https://example.com/"`. This allows apps to expose their services to web
957 frames on a per-origin basis if needed.
959 ### Connecting From Java
961 TODO
963 ### Connecting From `JavaScript`
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
967 in `/content/browser/webui/web_ui_mojo_browsertest.cc`. In particular,
968 `WebUIMojoTest.ConnectToApplication` connects from a WebUI frame to a test app
969 running in a new utility process.
971 ## FAQ
973 Nothing here yet!