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

Side by Side Diff: docs/mojo_in_chromium.md

Issue 1641053003: [mojo] Revisit the Mojo in Chromium overview (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 4 years, 10 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 | « no previous file | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
4 should probably ignore everything below it.
5
6 This document is intended to serve as a Mojo primer for Chromium developers. No 3 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++ 4 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 5 and be familiar with Chromium's multi-process architecture as well as common
9 concepts used throughout Chromium such as smart pointers, message loops, 6 concepts used throughout Chromium such as smart pointers, message loops,
10 callback binding, and so on. 7 callback binding, and so on.
11 8
12 [TOC] 9 [TOC]
13 10
14 ## Should I Bother Reading This? 11 ## Should I Bother Reading This?
15 12
16 If you're planning to build a Chromium feature that needs IPC and you aren't 13 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._, 14 already using Mojo, YES! **Legacy IPC is deprecated.**
18 `foo_messages.h` files, message filters, and the suite of `IPC_MESSAGE_*` macros
19 -- **is on the verge of deprecation.**
20 15
21 ## Why Mojo? 16 ## Why Mojo?
22 17
23 Mojo provides IPC primitives for pushing messages and data around between 18 TL;DR: The long-term intent is to refactor Chromium into a large set of smaller
24 transferrable endpoints which may or may not cross process boundaries; it 19 services.
25 simplifies threading with regard to IPC; it standardizes message serialization 20
26 in a way that's resilient to versioning issues; and it can be used with relative 21 We can be smarter about:
27 ease and consistency across a number of languages including C++, Java, and 22
28 `JavaScript` -- all languages which comprise a significant share of Chromium 23 * Which services we bring up or don't
29 code. 24 * How we isolate these services to improve security and stability
30 25 * Which binary features we ship to one user or another
31 The messaging protocol doesn't strictly need to be used for IPC though, and 26
32 there are some higher-level reasons for this adoption and for the specific 27 A more robust messaging layer opens the door for a number of interesting
33 approach to integration outlined in this document. 28 possibilities; in particular it allows us to integrate a large number of
34 29 components without link-time interdependencies, and it breaks down the growing
35 ### Code Health 30 number of interesting cross-language boundaries across the codebase.
36 31
37 At the moment we have fairly weak separation between components, with DEPS being 32 Much has been learned from using Chromium IPC and maintaining Chromium
38 the strongest line of defense against increasing complexity. 33 dependencies in anger over the past several years and we feel there's now a
39 34 significant opportunity to make life easier for developers, and to help them
40 A component Foo might hold a reference to some bit of component Bar's internal 35 build more and better features, faster, and with much less cost to users.
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.
46
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.
50
51 ### Modularity
52
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.
56
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.
62
63 ### Mandoline
64
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.
70 36
71 ## Mojo Overview 37 ## Mojo Overview
72 38
73 This section provides a general overview of Mojo and some of its API features. 39 The Mojo system API provides a small suite of low-level IPC primitives:
74 You can probably skip straight to 40 **message pipes**, **data pipes**, and **shared buffers**. On top of this API
75 [Your First Mojo Application](#Your-First-Mojo-Application) if you just want to 41 we've built higher-level bindings APIs to simplify messaging for consumers
76 get to some practical sample code. 42 writing C++, Java, or JavaScript code.
77 43
78 The Mojo Embedder Development Kit (EDK) provides a suite of low-level IPC 44 This document focuses primarily on using C++ bindings with message pipes, which
79 primitives: **message pipes**, **data pipes**, and **shared buffers**. We'll 45 is likely to be the most common usage encountered by Chromium developers.
80 focus primarily on message pipes and the C++ bindings API in this document.
81
82 _TODO: Java and JS bindings APIs should also be covered here._
83 46
84 ### Message Pipes 47 ### Message Pipes
85 48
86 A message pipe is a lightweight primitive for reliable, bidirectional, queued 49 A message pipe is a lightweight primitive for reliable bidirectional transfer of
87 transfer of relatively small packets of data. Every pipe endpoint is identified 50 relatively small packets of data. Unsurprisingly a pipe has two endpoints, and
88 by a **handle** -- a unique process-wide integer identifying the endpoint to the 51 either endpoint may be transferred over another message pipe.
89 EDK. 52
90 53 Because we bootstrap a primordial message pipe between the browser process and
91 A single message across a pipe consists of a binary payload and an array of zero 54 each child process, this in turn means that you can create a new pipe and
92 or more handles to be transferred. A pipe's endpoints may live in the same 55 ultimately send either end to any any process, and the two ends will still be
93 process or in two different processes. 56 able to talk to each other seamlessly and exclusively. Goodbye, routing IDs!
94 57
95 Pipes are easy to create. The `mojo::MessagePipe` type (see 58 While message pipes can carry arbitrary packets of unstructured data, we
96 `/third_party/mojo/src/mojo/public/cpp/system/message_pipe.h`) provides a nice 59 generally use them in conjunction with generated bindings to ensure a
97 class wrapper with each endpoint represented as a scoped handle type (see 60 consistent, well-defined, versioned message structure on all endpoints.
98 members `handle0` and `handle1` and the definition of 61
99 `mojo::ScopedMessagePipeHandle`). In the same header you can find 62 ### Mojom
100 `WriteMessageRaw` and `ReadMessageRaw` definitions. These are in theory all one 63
101 needs to begin pushing things from one endpoint to the other. 64 Mojom is the IDL for Mojo interfaces. Given a `.mojom` file, the bindings
102 65 generator outputs bindings for all three of the currently supported languages.
103 While it's worth being aware of `mojo::MessagePipe` and the associated raw I/O 66
104 functions, you will rarely if ever have a use for them. Instead you'll typically 67 For example:
105 use bindings code generated from mojom interface definitions, along with the 68
106 public bindings API which mostly hides the underlying pipes. 69 ```
107 70 // src/components/frob/public/interfaces/frobinator.mojom
108 ### Mojom Bindings 71 module frob.mojom;
109 72
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:
114
115 ```
116 // frobinator.mojom
117 module frob;
118 interface Frobinator { 73 interface Frobinator {
119 Frobinate(); 74 Frobinate();
120 }; 75 };
121 ``` 76 ```
122 77
123 This can be used to generate bindings for a very simple `Frobinator` interface. 78 would generate the following outputs:
124 Bindings are generated at build time and will match the location of the mojom 79
125 source file itself, mapped into the generated output directory for your Chromium 80 ```
126 build. In this case one can expect to find files named `frobinator.mojom.js`, 81 out/Debug/gen/components/frob/public/interfaces/frobinator.mojom.cc
127 `frobinator.mojom.cc`, `frobinator.mojom.h`, _etc._ 82 out/Debug/gen/components/frob/public/interfaces/frobinator.mojom.h
128 83 out/Debug/gen/components/frob/public/interfaces/frobinator.mojom.js
129 The C++ header (`frobinator.mojom.h`) generated from this mojom will define a 84 out/Debug/gen/components/frob/public/interfaces/frobinator.mojom.srcjar
130 pure virtual class interface named `frob::Frobinator` with a pure virtual method 85 ...
131 of signature `void Frobinate()`. Any class which implements this interface is 86 ```
132 effectively a `Frobinator` service. 87
133 88 The generated code hides away all the details of serializing and deserializing
134 ### C++ Bindings API 89 messages on either end of a pipe.
135 90
136 Before we see an example implementation and usage of the Frobinator, there are a 91 The C++ header (`frobinator.mojom.h`) defines an abstract class for each
137 handful of interesting bits in the public C++ bindings API you should be 92 mojom interface specified. Namespaces are derived from the `module` name.
138 familiar with. These complement generated bindings code and generally obviate 93
139 any need to use a `mojo::MessagePipe` directly. 94 **NOTE:** Chromium convention for component `foo`'s module name is `foo.mojom`.
140 95 This means all mojom-generated C++ typenames for component `foo` will live in
141 In all of the cases below, `T` is the type of a generated bindings class 96 the `foo::mojom` namespace to avoid collisions with non-generated typenames.
142 interface, such as the `frob::Frobinator` discussed above. 97
143 98 In this example the generated `frob::mojom::Frobinator` has a single
144 #### `mojo::InterfacePtr<T>` 99 pure virtual function:
145 100
146 Defined in `/third_party/mojo/src/mojo/public/cpp/bindings/interface_ptr.h`. 101 ```
147 102 namespace frob {
148 `mojo::InterfacePtr<T>` is a typed proxy for a service of type `T`, which can be 103
149 bound to a message pipe endpoint. This class implements every interface method 104 class Frobinator {
150 on `T` by serializing a message (encoding the method call and its arguments) and 105 public:
151 writing it to the pipe (if bound.) This is the standard way for C++ code to talk 106 virtual void Frobinate() = 0;
152 to any Mojo service. 107 };
153 108
154 For illustrative purposes only, we can create a message pipe and bind an 109 } // namespace frob
155 `InterfacePtr` to one end as follows: 110 ```
156 111
157 ```cpp 112 To create a `Frobinator` service, one simply implements `foo::Frobinator` and
158 mojo::MessagePipe pipe; 113 provides a means of binding pipes to it.
159 mojo::InterfacePtr<frob::Frobinator> frobinator; 114
160 frobinator.Bind( 115 ### Binding to Pipes
161 mojo::InterfacePtrInfo<frob::Frobinator>(pipe.handle0.Pass(), 0u)); 116
162 ``` 117 Let's look at some sample code:
163 118
164 You could then call `frobinator->Frobinate()` and read the encoded `Frobinate` 119 ```
165 message from the other side of the pipe (`handle1`.) You most likely don't want 120 // src/components/frob/frobinator_impl.cc
166 to do this though, because as you'll soon see there's a nicer way to establish 121
167 service pipes.
168
169 #### `mojo::InterfaceRequest<T>`
170
171 Defined in `/third_party/mojo/src/mojo/public/cpp/bindings/interface_request.h`.
172
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.
177
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.
183
184 As with `InterfacePtr<T>`, we can manually bind an `InterfaceRequest<T>` to a
185 pipe endpoint:
186
187 ```cpp
188 mojo::MessagePipe pipe;
189
190 mojo::InterfacePtr<frob::Frobinator> frobinator;
191 frobinator.Bind(
192 mojo::InterfacePtrInfo<frob::Frobinator>(pipe.handle0.Pass(), 0u));
193
194 mojo::InterfaceRequest<frob::Frobinator> frobinator_request;
195 frobinator_request.Bind(pipe.handle1.Pass());
196 ```
197
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.
202
203 #### `mojo::GetProxy<T>`
204
205 Defined in
206 `/third_party/mojo/src/mojo/public/cpp/bindings/interface`_request.h`.
207
208 `mojo::GetProxy<T>` is the function you will most commonly use to create a new
209 message pipe. Its signature is as follows:
210
211 ```cpp
212 template <typename T>
213 mojo::InterfaceRequest<T> GetProxy(mojo::InterfacePtr<T>* ptr);
214 ```
215
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:
220
221 ```cpp
222 mojo::InterfacePtr<frob::Frobinator> frobinator;
223 mojo::InterfaceRequest<frob::Frobinator> frobinator_request =
224 mojo::GetProxy(&frobinator);
225 ```
226
227 #### `mojo::Binding<T>`
228
229 Defined in `/third_party/mojo/src/mojo/public/cpp/bindings/binding.h`.
230
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>`.
237
238 A common usage pattern looks something like this:
239
240 ```cpp
241 #include "components/frob/public/interfaces/frobinator.mojom.h" 122 #include "components/frob/public/interfaces/frobinator.mojom.h"
242 #include "third_party/mojo/src/mojo/public/cpp/bindings/binding.h" 123 #include "mojo/public/cpp/bindings/binding.h"
243 #include "third_party/mojo/src/mojo/public/cpp/bindings/interface_request.h" 124 #include "mojo/public/cpp/bindings/interface_request.h"
244 125
245 class FrobinatorImpl : public frob::Frobinator { 126 namespace frob {
127
128 class FrobinatorImpl : public mojom::Frobinator {
246 public: 129 public:
247 FrobinatorImpl(mojo::InterfaceRequest<frob::Frobinator> request) 130 FrobinatorImpl(mojo::InterfaceRequest<mojom::Frobinator> request)
248 : binding_(this, request.Pass()) {} 131 : binding_(this, std::move(request)) {}
249 ~FrobinatorImpl() override {} 132 ~FrobinatorImpl() override {}
250 133
134 // mojom::Frobinator:
135 void Frobinate() override { DLOG(INFO) << "I can't stop frobinating!"; }
136
251 private: 137 private:
252 // frob::Frobinator: 138 mojo::Binding<mojom::Frobinator> binding_;
139 };
140
141 } // namespace frob
142 ```
143
144 The first thing to note is that `mojo::Binding<T>` *binds* one end of a message
145 pipe to an implementation of a service. This means it watches that end of the
146 pipe for incoming messages; it knows how to decode messages for interface `T`,
147 and it dispatches them to methods on the bound `T` implementation.
148
149 `mojo::InterfaceRequest<T>` is essentially semantic sugar for a strongly-typed
150 message pipe endpoint. A common way to create new message pipes is via the
151 `GetProxy` call defined in `interface_request.h`:
152
153 ```
154 mojom::FrobinatorPtr proxy;
155 mojo::InterfaceRequest<mojom::Frobinator> request = mojo::GetProxy(&proxy);
156 ```
157
158 This creates a new message pipe with one end owned by `proxy` and the other end
159 owned by `request`. It has the nice property of attaching common type
160 information to each end of the pipe.
161
162 Note that `InterfaceRequest<T>` doesn't actually **do** anything. It just scopes
163 a pipe endpoint and associates it with an interface type at compile time. As
164 such, other typed service binding primitives such as `mojo::Binding<T>` take
165 these objects as input when they need an endpoint to bind to.
166
167 `mojom::FrobinatorPtr` is a generated type alias for
168 `mojo::InterfacePtr<mojom::Frobinator>`. An `InterfacePtr<T>` scopes a message
169 pipe endpoint as well, but it also internally implements every method on `T` by
170 serializing a corresponding message and writing it to the pipe.
171
172 Hence we can put this together to talk to a `FrobinatorImpl` over a pipe:
173
174 ```
175 frob:mojom::FrobinatorPtr frobinator;
176 frob::FrobinatorImpl impl(GetProxy(&frobinator));
177
178 // Tada!
179 frobinator->Frobinate();
180 ```
181
182 Behind the scenes this serializes a message corresponding to the `Frobinate`
183 request and writes it to one end of the pipe. Eventually (and, incidentally,
184 very soon after), `impl`'s internal `mojo::Binding` will decode this message and
185 dispatch a call to `impl.Frobinate()`.
186
187 ### Responding to Requests
188
189 A common idiom in Chromium IPC is to keep track of IPC requests with some kind
190 of opaque identifier (i.e. an integer *request ID*) so that you can later
191 respond to a specific request using some nominally related message in the other
192 direction.
193
194 This is baked into mojom interface definitions. We can extend our `Frobinator`
195 service like so:
196
197 ```
198 module frob.mojom;
199
200 interface Frobinator {
201 Frobinate();
202 GetFrobinationLevels() => (int min, int max);
203 };
204 ```
205
206 and update our implementation:
207
208 ```
209 class FrobinatorImpl : public mojom::Frobinator {
210 public:
211 // ...
212
213 // mojom::Frobinator:
253 void Frobinate() override { /* ... */ } 214 void Frobinate() override { /* ... */ }
254 215 void GetFrobinationLevels(const GetFrobinationLevelsCallback& callback) {
255 mojo::Binding<frob::Frobinator> binding_; 216 callback.Run(1, 42);
256 }; 217 }
257 ``` 218 };
258 219 ```
259 And then we could write some code to test this: 220
260 221 When the service implementation runs `callback`, the response arguments are
261 ```cpp 222 serialized and sent back over the pipe. The proxy on the other end knows how to
262 // Fun fact: The bindings generator emits a type alias like this for every 223 read this response and will in turn dispatch it to a callback on that end:
263 // interface type. frob::FrobinatorPtr is an InterfacePtr<frob::Frobinator>. 224
264 frob::FrobinatorPtr frobinator; 225 ```
265 scoped_ptr<FrobinatorImpl> impl( 226 void ShowLevels(int min, int max) {
266 new FrobinatorImpl(mojo::GetProxy(&frobinator))); 227 DLOG(INFO) << "Frobinator min=" << min << " max=" << max;
228 }
229
230 // ...
231
232 mojom::FrobinatorPtr frobinator;
233 FrobinatorImpl impl(GetProxy(&frobinator));
234
235 frobinator->GetFrobinatorLevels(base::Bind(&ShowLevels));
236 ```
237
238 This does what you'd expect.
239
240 ## Exposing Services in Chromium
241
242 There are a number of ways one might expose services across various surfaces of
243 the browser. One common approach now is to use a
244 [`content::ServiceRegistry` (link)](https://goo.gl/uEhx06). These come in
245 pairs generally spanning a process boundary, and they provide primitive service
246 registration and connection interfaces. For one example, [every
247 `RenderFrameHost` has a `ServiceRegistry`](https://goo.gl/4YR3j5), as does
248 [every corresponding `RenderFrame`](https://goo.gl/YhrgXa). These registries are
249 intertwined.
250
251 The gist is that you can add a service to the local side of the registry -- it's
252 just a mapping from interface name to factory function -- or you can connect by
253 name to services registered on the remote side.
254
255 **NOTE:** In this context the "factory function" is simply a callback which
256 takes a pipe endpoint and does something with it. It's expected that you'll
257 either bind it to a service implementation of some kind or you will close it, ef fectively rejecting the connection request.
258
259 We can build a simple browser-side `FrobinatorImpl` service that has access to a
260 `BrowserContext` for any frame which connects to it:
261
262 ```
263 #include "base/macros.h"
264 #include "components/frob/public/interfaces/frobinator.mojom.h"
265 #include "content/public/browser/browser_context.h"
266 #inlcude "mojo/public/cpp/system/interface_request.h"
267 #inlcude "mojo/public/cpp/system/message_pipe.h"
268 #inlcude "mojo/public/cpp/system/strong_binding.h"
269
270 namespace frob {
271
272 class FrobinatorImpl : public mojom::Frobinator {
273 public:
274 FrobinatorImpl(content::BrowserContext* context,
275 mojo::InterfaceRequest<mojom::Frobinator> request)
276 : context_(context), binding_(this, std::move(request)) {}
277 ~FrobinatorImpl() override {}
278
279 // A factory function to use in conjunction with ServiceRegistry.
280 static void Create(content::BrowserContext* context,
281 mojo::InterfaceRequest<mojom::Frobinator> request) {
282 // See comment below for why this doesn't leak.
283 new FrobinatorImpl(context,
284 mojo::MakeRequest<mojom::Frobinator>(std::move(pipe)));
285 }
286
287 private:
288 // mojom::Frobinator:
289 void Frobinate() override { /* ... */ }
290
291 content::BrowserContext* context_;
292
293 // A StrongBinding is just like a Binding, except that it takes ownership of
294 // its bound implementation and deletes itself (and the impl) if and when the
295 // bound pipe encounters an error or is closed on the other end.
296 mojo::StrongBinding<mojom::Frobinator> binding_;
297
298 DISALLOW_COPY_AND_ASSIGN(FrobinatorImpl);
299 };
300
301 } // namespace frob
302 ```
303
304 Now somewhere in the browser we register the Frobinator service with each
305 `RenderFrameHost` ([this](https://goo.gl/HEFn63) is a popular spot):
306
307 ```
308 frame_host->GetServiceRegistry()->AddService<frob::mojom::Frobinator>(
309 base::Bind(
310 &frob::FrobinatorImpl::Create,
311 base::Unretained(frame_host->GetProcess()->GetBrowserContext())));
312 ```
313
314 And in the render process we can now do something like:
315
316 ```
317 mojom::FrobinatorPtr frobinator;
318 render_frame->GetServiceRegistry()->ConnectToRemoteService(
319 mojo::GetProxy(&frobinator));
320
321 // It's IPC!
267 frobinator->Frobinate(); 322 frobinator->Frobinate();
268 ``` 323 ```
269 324
270 This will _eventually_ call `FrobinatorImpl::Frobinate()`. "Eventually," because 325 There are now plenty of concrete examples of Mojo usage in the Chromium tree.
271 the sequence of events when `frobinator->Frobinate()` is called is roughly as 326 Poke around at existing mojom files and see how their implementions are built
272 follows: 327 and connected.
273 328
274 1. A new message buffer is allocated and filled with an encoded 'Frobinate' 329 ## Mojo in Blink
275 message. 330
276 1. The EDK is asked to write this message to the pipe endpoint owned by the 331 *TODO*
277 `FrobinatorPtr`. 332
278 1. If the call didn't happen on the Mojo IPC thread for this process, EDK hops 333 This is a work in progress. TL;DR: We'll also soon begin using Mojo services
279 to the Mojo IPC thread. 334 from Blink so that the platform layer can consume browser services
280 1. The EDK writes the message to the pipe. In this case the pipe endpoints live 335 directly via Mojo. The long-term goal there is to eliminate `content/renderer`.
281 in the same process, so this essentially a glorified `memcpy`. If they lived 336
282 in different processes this would be the point at which the data moved 337 ## Questions, Discussion, etc.
283 across a real IPC channel. 338
284 1. The EDK on the other end of the pipe is awoken on the Mojo IPC thread and 339 A good place to find highly concentrated doses of people who know and care
285 alerted to the message arrival. 340 about Mojo in Chromium would be the [chromium-mojo](https://goo.gl/A4ebWB)
286 1. The EDK reads the message. 341 mailing list[.](https://goo.gl/L70ihQ)
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.
293
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.
296
297 #### `mojo::StrongBinding<T>`
298
299 Defined in `third_party/mojo/src/mojo/public/cpp/bindings/strong_binding.h`.
300
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.
307
308 ## The Mojo Shell
309
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.)
313
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:
318
319 ```
320 module mojo;
321 interface Shell {
322 ConnectToApplication(URLRequest application_url,
323 ServiceProvider&? services,
324 ServiceProvider? exposed_services);
325 QuitApplication();
326 };
327 ```
328
329 and as for the `mojo::ServiceProvider` interface:
330
331 ```
332 module mojo;
333 interface ServiceProvider {
334 ConnectToService(string interface_name, handle<message_pipe> pipe);
335 };
336 ```
337
338 Definitions for these interfaces can be found in
339 `/mojo/shell/public/interfaces`. Also note that `mojo::URLRequest` is a
340 Mojo struct defined in
341 `/mojo/services/network/public/interfaces/url_loader.mojom`.
342
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.
346
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.)
350
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.
354
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.
362
363 ### Mojo Applications
364
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:
370
371 ```
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);
380 };
381 ```
382
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/shell/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).
389
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.
394
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.
399
400 ### Other IPC Primitives
401
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.
408
409 ## Your First Mojo Application
410
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.
414
415 ### Hello, world!
416
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.
423
424 First create a new `//components/hello` directory. Inside this directory we're
425 going to add the following files:
426
427 **components/hello/main.cc**
428
429 ```cpp
430 #include "base/logging.h"
431 #include "third_party/mojo/src/mojo/public/c/system/main.h"
432
433 MojoResult MojoMain(MojoHandle shell_handle) {
434 LOG(ERROR) << "Hello, world!";
435 return MOJO_RESULT_OK;
436 };
437 ```
438
439 **components/hello/BUILD.gn**
440
441 ```
442 import("//mojo/public/mojo_application.gni")
443
444 mojo_native_application("hello") {
445 sources = [
446 "main.cc",
447 ]
448 deps = [
449 "//base",
450 "//mojo/environment:chromium",
451 ]
452 }
453 ```
454
455 For the sake of this example you'll also want to add your component as a
456 dependency somewhere in your local checkout to ensure its build files are
457 generated. The easiest thing to do there is probably to add a dependency on
458 `"//components/hello"` in the `"gn_all"` target of the top-level `//BUILD.gn`.
459
460 Assuming you have a GN output directory at `out_gn/Debug`, you can build the
461 Mojo runner along with your shiny new app:
462
463 ninja -C out_gn/Debug mojo_runner components/hello
464
465 In addition to the `mojo_runner` executable, this will produce a new binary at
466 `out_gn/Debug/hello/hello.mojo`. This binary is essentially a shared library
467 which exports your `MojoMain` function.
468
469 `mojo_runner` takes an application URL as its only argument and runs the
470 corresponding application. In its current state it resolves `mojo`-scheme URLs
471 such that `"mojo:foo"` maps to the file `"foo/foo.mojo"` relative to the
472 `mojo_runner` path (_i.e._ your output directory.) This means you can run your
473 new app with the following command:
474
475 out_gn/Debug/mojo_runner mojo:hello
476
477 You should see our little `"Hello, world!"` error log followed by a hanging
478 application. You can `^C` to kill it.
479
480 ### Exposing Services
481
482 An app that prints `"Hello, world!"` isn't terribly interesting. At a bare
483 minimum your app should implement `mojo::ApplicationDelegate` and expose at
484 least one service to connecting applications.
485
486 Let's update `main.cc` with the following contents:
487
488 **components/hello/main.cc**
489
490 ```cpp
491 #include "components/hello/hello_app.h"
492 #include "mojo/shell/public/cpp/application_runner.h"
493 #include "third_party/mojo/src/mojo/public/c/system/main.h"
494
495 MojoResult MojoMain(MojoHandle shell_handle) {
496 mojo::ApplicationRunner runner(new hello::HelloApp);
497 return runner.Run(shell_handle);
498 };
499 ```
500
501 This is a pretty typical looking `MojoMain`. Most of the time this is all you
502 want -- a `mojo::ApplicationRunner` constructed over a
503 `mojo::ApplicationDelegate` instance, `Run()` with the pipe handle received from
504 the shell. We'll add some new files to the app as well:
505
506 **components/hello/public/interfaces/greeter.mojom**
507
508 ```
509 module hello;
510 interface Greeter {
511 Greet(string name) => (string greeting);
512 };
513 ```
514
515 Note the new arrow syntax on the `Greet` method. This indicates that the caller
516 expects a response from the service.
517
518 **components/hello/public/interfaces/BUILD.gn**
519
520 ```
521 import("//third_party/mojo/src/mojo/public/tools/bindings/mojom.gni")
522
523 mojom("interfaces") {
524 sources = [
525 "greeter.mojom",
526 ]
527 }
528 ```
529
530 **components/hello/hello_app.h**
531
532 ```cpp
533 #ifndef COMPONENTS_HELLO_HELLO_APP_H_
534 #define COMPONENTS_HELLO_HELLO_APP_H_
535
536 #include "base/macros.h"
537 #include "components/hello/public/interfaces/greeter.mojom.h"
538 #include "mojo/shell/public/cpp/application_delegate.h"
539 #include "mojo/shell/public/cpp/interface_factory.h"
540
541 namespace hello {
542
543 class HelloApp : public mojo::ApplicationDelegate,
544 public mojo::InterfaceFactory<Greeter> {
545 public:
546 HelloApp();
547 ~HelloApp() override;
548
549 private:
550 // mojo::ApplicationDelegate:
551 bool ConfigureIncomingConnection(
552 mojo::ApplicationConnection* connection) override;
553
554 // mojo::InterfaceFactory<Greeter>:
555 void Create(mojo::ApplicationConnection* connection,
556 mojo::InterfaceRequest<Greeter> request) override;
557
558 DISALLOW_COPY_AND_ASSIGN(HelloApp);
559 };
560
561 } // namespace hello
562
563 #endif // COMPONENTS_HELLO_HELLO_APP_H_
564 ```
565
566
567 **components/hello/hello_app.cc**
568
569 ```cpp
570 #include "base/macros.h"
571 #include "components/hello/hello_app.h"
572 #include "mojo/shell/public/cpp/application_connection.h"
573 #include "third_party/mojo/src/mojo/public/cpp/bindings/interface_request.h"
574 #include "third_party/mojo/src/mojo/public/cpp/bindings/strong_binding.h"
575
576 namespace hello {
577
578 namespace {
579
580 class GreeterImpl : public Greeter {
581 public:
582 GreeterImpl(mojo::InterfaceRequest<Greeter> request)
583 : binding_(this, request.Pass()) {
584 }
585
586 ~GreeterImpl() override {}
587
588 private:
589 // Greeter:
590 void Greet(const mojo::String& name, const GreetCallback& callback) override {
591 callback.Run("Hello, " + std::string(name) + "!");
592 }
593
594 mojo::StrongBinding<Greeter> binding_;
595
596 DISALLOW_COPY_AND_ASSIGN(GreeterImpl);
597 };
598
599 } // namespace
600
601 HelloApp::HelloApp() {
602 }
603
604 HelloApp::~HelloApp() {
605 }
606
607 bool HelloApp::ConfigureIncomingConnection(
608 mojo::ApplicationConnection* connection) {
609 connection->AddService<Greeter>(this);
610 return true;
611 }
612
613 void HelloApp::Create(
614 mojo::ApplicationConnection* connection,
615 mojo::InterfaceRequest<Greeter> request) {
616 new GreeterImpl(request.Pass());
617 }
618
619 } // namespace hello
620 ```
621
622 And finally we need to update our app's `BUILD.gn` to add some new sources and
623 dependencies:
624
625 **components/hello/BUILD.gn**
626
627 ```
628 import("//mojo/public/mojo_application.gni")
629
630 source_set("lib") {
631 sources = [
632 "hello_app.cc",
633 "hello_app.h",
634 ]
635 deps = [
636 "//base",
637 "//components/hello/public/interfaces",
638 "//mojo/environment:chromium",
639 "//mojo/shell/public/cpp",
640 ]
641 }
642
643 mojo_native_application("hello") {
644 sources = [
645 "main.cc",
646 ],
647 deps = [ ":lib" ]
648 }
649 ```
650
651 Note that we build the bulk of our application sources as a static library
652 separate from the `MojoMain` definition. Following this convention is
653 particularly useful for Chromium integration, as we'll see later.
654
655 There's a lot going on here and it would be useful to familiarize yourself with
656 the definitions of `mojo::ApplicationDelegate`, `mojo::ApplicationConnection`,
657 and `mojo::InterfaceFactory<T>`. The TL;DR though is that if someone connects to
658 this app and requests a service named `"hello::Greeter"`, the app will create a
659 new `GreeterImpl` and bind it to that request pipe. From there the connecting
660 app can call `Greeter` interface methods and they'll be routed to that
661 `GreeterImpl` instance.
662
663 Although this appears to be a more interesting application, we need some way to
664 actually connect and test the behavior of our new service. Let's write an app
665 test!
666
667 ### App Tests
668
669 App tests run inside a test application, giving test code access to a shell
670 which can connect to one or more applications-under-test.
671
672 First let's introduce some test code:
673
674 **components/hello/hello_apptest.cc**
675
676 ```cpp
677 #include "base/bind.h"
678 #include "base/callback.h"
679 #include "base/logging.h"
680 #include "base/macros.h"
681 #include "base/run_loop.h"
682 #include "components/hello/public/interfaces/greeter.mojom.h"
683 #include "mojo/shell/public/cpp/application_impl.h"
684 #include "mojo/shell/public/cpp/application_test_base.h"
685
686 namespace hello {
687 namespace {
688
689 class HelloAppTest : public mojo::test::ApplicationTestBase {
690 public:
691 HelloAppTest() {}
692 ~HelloAppTest() override {}
693
694 void SetUp() override {
695 ApplicationTestBase::SetUp();
696 mojo::URLRequestPtr app_url = mojo::URLRequest::New();
697 app_url->url = "mojo:hello";
698 application_impl()->ConnectToService(app_url.Pass(), &greeter_);
699 }
700
701 Greeter* greeter() { return greeter_.get(); }
702
703 private:
704 GreeterPtr greeter_;
705
706 DISALLOW_COPY_AND_ASSIGN(HelloAppTest);
707 };
708
709 void ExpectGreeting(const mojo::String& expected_greeting,
710 const base::Closure& continuation,
711 const mojo::String& actual_greeting) {
712 EXPECT_EQ(expected_greeting, actual_greeting);
713 continuation.Run();
714 };
715
716 TEST_F(HelloAppTest, GreetWorld) {
717 base::RunLoop loop;
718 greeter()->Greet("world", base::Bind(&ExpectGreeting, "Hello, world!",
719 loop.QuitClosure()));
720 loop.Run();
721 }
722
723 } // namespace
724 } // namespace hello
725 ```
726
727 We also need to add a new rule to `//components/hello/BUILD.gn`:
728
729 ```
730 mojo_native_application("apptests") {
731 output_name = "hello_apptests"
732 testonly = true
733 sources = [
734 "hello_apptest.cc",
735 ]
736 deps = [
737 "//base",
738 "//mojo/shell/public/cpp:test_support",
739 ]
740 public_deps = [
741 "//components/hello/public/interfaces",
742 ]
743 data_deps = [ ":hello" ]
744 }
745 ```
746
747 Note that the `//components/hello:apptests` target does **not** have a binary
748 dependency on either `HelloApp` or `GreeterImpl` implementations; instead it
749 depends only on the component's public interface definitions.
750
751 The `data_deps` entry ensures that `hello.mojo` is up-to-date when `apptests` is
752 built. This is desirable because the test connects to `"mojo:hello"` which will
753 in turn load `hello.mojo` from disk.
754
755 You can now build the test suite:
756
757 ninja -C out_gn/Debug components/hello:apptests
758
759 and run it:
760
761 out_gn/Debug/mojo_runner mojo:hello_apptests
762
763 You should see one test (`HelloAppTest.GreetWorld`) passing.
764
765 One particularly interesting bit of code in this test is in the `SetUp` method:
766
767 mojo::URLRequestPtr app_url = mojo::URLRequest::New();
768 app_url->url = "mojo:hello";
769 application_impl()->ConnectToService(app_url.Pass(), &greeter_);
770
771 `ConnectToService` is a convenience method provided by `mojo::ApplicationImpl`,
772 and it's essentially a shortcut for calling out to the shell's
773 `ConnectToApplication` method with the given application URL (in this case
774 `"mojo:hello"`) and then connecting to a specific service provided by that app
775 via its `ServiceProvider`'s `ConnectToService` method.
776
777 Note that generated interface bindings include a constant string to identify
778 each interface by name; so for example the generated `hello::Greeter` type
779 defines a static C string:
780
781 const char hello::Greeter::Name_[] = "hello::Greeter";
782
783 This is exploited by the definition of
784 `mojo::ApplicationConnection::ConnectToService<T>`, which uses `T::Name_` as the
785 name of the service to connect to. The type `T` in this context is inferred from
786 the `InterfacePtr<T>*` argument. You can inspect the definition of
787 `ConnectToService` in `/mojo/shell/public/cpp/application_connection.h`
788 for additional clarity.
789
790 We could have instead written this code as:
791
792 ```cpp
793 mojo::URLRequestPtr app_url = mojo::URLRequest::New();
794 app_url->url = "mojo::hello";
795
796 mojo::ServiceProviderPtr services;
797 application_impl()->shell()->ConnectToApplication(
798 app_url.Pass(), mojo::GetProxy(&services),
799 // We pass a null provider since we aren't exposing any of our own
800 // services to the target app.
801 mojo::ServiceProviderPtr());
802
803 mojo::InterfaceRequest<hello::Greeter> greeter_request =
804 mojo::GetProxy(&greeter_);
805 services->ConnectToService(hello::Greeter::Name_,
806 greeter_request.PassMessagePipe());
807 ```
808
809 The net result is the same, but 3-line version seems much nicer.
810
811 ## Chromium Integration
812
813 Up until now we've been using `mojo_runner` to load and run `.mojo` binaries
814 dynamically. While this model is used by Mandoline and may eventually be used in
815 Chromium as well, Chromium is at the moment confined to running statically
816 linked application code. This means we need some way to register applications
817 with the browser's Mojo shell.
818
819 It also means that, rather than using the binary output of a
820 `mojo_native_application` target, some part of Chromium must link against the
821 app's static library target (_e.g._, `"//components/hello:lib"`) and register a
822 URL handler to teach the shell how to launch an instance of the app.
823
824 When registering an app URL in Chromium it probably makes sense to use the same
825 mojo-scheme URL used for the app in Mandoline. For example the media renderer
826 app is referenced by the `"mojo:media"` URL in both Mandoline and Chromium. In
827 Mandoline this resolves to a dynamically-loaded `.mojo` binary on disk, but in
828 Chromium it resolves to a static application loader linked into Chromium. The
829 net result is the same in both cases: other apps can use the shell to connect to
830 `"mojo:media"` and use its services.
831
832 This section explores different ways to register and connect to `"mojo:hello"`
833 in Chromium.
834
835 ### In-Process Applications
836
837 Applications can be set up to run within the browser process via
838 `ContentBrowserClient::RegisterInProcessMojoApplications`. This method populates
839 a mapping from URL to `base::Callback<scoped_ptr<mojo::ApplicationDelegate>()>`
840 (_i.e._, a factory function which creates a new `mojo::ApplicationDelegate`
841 instance), so registering a new app means adding an entry to this map.
842
843 Let's modify `ChromeContentBrowserClient::RegisterInProcessMojoApplications`
844 (in `//chrome/browser/chrome_content_browser_client.cc`) by adding the following
845 code:
846
847 ```cpp
848 apps->insert(std::make_pair(GURL("mojo:hello"),
849 base::Bind(&HelloApp::CreateApp)));
850 ```
851
852 you'll also want to add the following convenience method to your `HelloApp`
853 definition in `//components/hello/hello_app.h`:
854
855 ```cpp
856 static scoped_ptr<mojo::ApplicationDelegate> HelloApp::CreateApp() {
857 return scoped_ptr<mojo::ApplicationDelegate>(new HelloApp);
858 }
859 ```
860
861 This introduces a dependency from `//chrome/browser` on to
862 `//components/hello:lib`, which you can add to the `"browser"` target's deps in
863 `//chrome/browser/BUILD.gn`. You'll of course also need to include
864 `"components/hello/hello_app.h"` in `chrome_content_browser_client.cc`.
865
866 That's it! Now if an app comes to the shell asking to connect to `"mojo:hello"`
867 and app is already running, it'll get connected to our `HelloApp` and have
868 access to the `Greeter` service. If the app wasn't already running, it will
869 first be launched on a new thread.
870
871 ### Connecting From the Browser
872
873 We've already seen how apps can connect to each other using their own private
874 shell proxy, but the vast majority of Chromium code doesn't yet belong to a Mojo
875 application. So how do we use an app's services from arbitrary browser code? We
876 use `content::MojoAppConnection`, like this:
877
878 ```cpp
879 #include "base/bind.h"
880 #include "base/logging.h"
881 #include "components/hello/public/interfaces/greeter.mojom.h"
882 #include "content/public/browser/mojo_app_connection.h"
883
884 void LogGreeting(const mojo::String& greeting) {
885 LOG(INFO) << greeting;
886 }
887
888 void GreetTheWorld() {
889 scoped_ptr<content::MojoAppConnection> connection =
890 content::MojoAppConnection::Create("mojo:hello",
891 content::kBrowserMojoAppUrl);
892 hello::GreeterPtr greeter;
893 connection->ConnectToService(&greeter);
894 greeter->Greet("world", base::Bind(&LogGreeting));
895 }
896 ```
897
898 A `content::MojoAppConnection`, while not thread-safe, may be created and safely
899 used on any single browser thread.
900
901 You could add the above code to a new browsertest to convince yourself that it
902 works. In fact you might want to take a peek at
903 `MojoShellTest.TestBrowserConnection` (in
904 `/content/browser/mojo_shell_browsertest.cc`) which registers and tests an
905 in-process Mojo app.
906
907 Finally, note that `MojoAppConnection::Create` takes two URLs. The first is the
908 target app URL, and the second is the source URL. Since we're not really a Mojo
909 app, but we are still trusted browser code, the shell will gladly use this URL
910 as the `requestor_url` when establishing an incoming connection to the target
911 app. This allows browser code to masquerade as a Mojo app at the given URL.
912 `content::kBrowserMojoAppUrl` (which is presently `"system:content_browser"`) is
913 a reasonable default choice when a more specific app identity isn't required.
914
915 ### Out-of-Process Applications
916
917 If an app URL isn't registered for in-process loading, the shell assumes it must
918 be an out-of-process application. If the shell doesn't already have a known
919 instance of the app running, a new utility process is launched and the
920 application request is passed onto it. Then if the app URL is registered in the
921 utility process, the app will be loaded there.
922
923 Similar to in-process registration, a URL mapping needs to be registered in
924 `ContentUtilityClient::RegisterMojoApplications`.
925
926 Once again you can take a peek at `/content/browser/mojo_shell_browsertest.cc`
927 for an end-to-end example of testing an out-of-process Mojo app from browser
928 code. Note that `content_browsertests` runs on `content_shell`, which uses
929 `ShellContentUtilityClient` as defined
930 `/content/shell/utility/shell_content_utility_client.cc`. This code registers a
931 common OOP test app.
932
933 ## Unsandboxed Out-of-Process Applications
934
935 By default new utility processes run in a sandbox. If you want your Mojo app to
936 run out-of-process and unsandboxed (which you **probably do not**), you can
937 register its URL via
938 `ContentBrowserClient::RegisterUnsandboxedOutOfProcessMojoApplications`.
939
940 ## Connecting From `RenderFrame`
941
942 We can also connect to Mojo apps from a `RenderFrame`. This is made possible by
943 `RenderFrame`'s `GetServiceRegistry()` interface. The `ServiceRegistry` can be
944 used to acquire a shell proxy and in turn connect to an app like so:
945
946 ```cpp
947 void GreetWorld(content::RenderFrame* frame) {
948 mojo::ShellPtr shell;
949 frame->GetServiceRegistry()->ConnectToRemoteService(
950 mojo::GetProxy(&shell));
951
952 mojo::URLRequestPtr request = mojo::URLRequest::New();
953 request->url = "mojo:hello";
954
955 mojo::ServiceProviderPtr hello_services;
956 shell->ConnectToApplication(
957 request.Pass(), mojo::GetProxy(&hello_services), nullptr);
958
959 hello::GreeterPtr greeter;
960 hello_services->ConnectToService(
961 hello::Greeter::Name_, mojo::GetProxy(&greeter).PassMessagePipe());
962 }
963 ```
964
965 It's important to note that connections made through the frame's shell proxy
966 will appear to come from the frame's `SiteInstance` URL. For example, if the
967 frame has loaded `https://example.com/`, `HelloApp`'s incoming
968 `mojo::ApplicationConnection` in this case will have a remote application URL of
969 `"https://example.com/"`. This allows apps to expose their services to web
970 frames on a per-origin basis if needed.
971
972 ### Connecting From Java
973
974 TODO
975
976 ### Connecting From `JavaScript`
977
978 This is still a work in progress and might not really take shape until the
979 Blink+Chromium merge. In the meantime there are some end-to-end WebUI examples
980 in `/content/browser/webui/web_ui_mojo_browsertest.cc`. In particular,
981 `WebUIMojoTest.ConnectToApplication` connects from a WebUI frame to a test app
982 running in a new utility process.
983
984 ## FAQ
985
986 Nothing here yet!
OLDNEW
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698