OLD | NEW |
1 **THIS DOCUIMENT IS A WORK IN PROGRESS.** As long as this notice exists, you sho
uld probably ignore everything below it. | 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. |
3 | 5 |
| 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. |
4 | 11 |
5 # Introduction | 12 [TOC] |
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 | 13 |
9 ## Should I Bother Reading This? | 14 ## Should I Bother Reading This? |
10 | 15 |
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.** | 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.** |
12 | 20 |
13 ## Why Mojo? | 21 ## Why Mojo? |
14 | 22 |
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. | 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. |
16 | 30 |
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. | 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. |
18 | 34 |
19 ### Code Health | 35 ### Code Health |
20 | 36 |
21 At the moment we have fairly weak separation between components, with DEPS being
the strongest line of defense against increasing complexity. | 37 At the moment we have fairly weak separation between components, with DEPS being |
| 38 the strongest line of defense against increasing complexity. |
22 | 39 |
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. | 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. |
24 | 46 |
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. | 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. |
26 | 50 |
27 ### Modularity | 51 ### Modularity |
28 | 52 |
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. | 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. |
30 | 56 |
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. | 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. |
32 | 62 |
33 ### Mandoline | 63 ### Mandoline |
34 | 64 |
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. | 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. |
36 | 70 |
37 # Mojo Overview | 71 ## Mojo Overview |
38 | 72 |
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. | 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. |
40 | 77 |
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. | 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. |
42 | 81 |
43 _TODO: Java and JS bindings APIs should also be covered here._ | 82 _TODO: Java and JS bindings APIs should also be covered here._ |
44 | 83 |
45 ## Message Pipes | 84 ### Message Pipes |
46 | 85 |
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. | 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. |
48 | 90 |
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. | 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. |
50 | 94 |
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. | 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. |
52 | 102 |
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. | 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. |
54 | 107 |
55 ## Mojom Bindings | 108 ### Mojom Bindings |
56 | 109 |
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: | 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: |
58 | 114 |
59 ``` | 115 ``` |
60 // frobinator.mojom | 116 // frobinator.mojom |
61 module frob; | 117 module frob; |
62 interface Frobinator { | 118 interface Frobinator { |
63 Frobinate(); | 119 Frobinate(); |
64 }; | 120 }; |
65 ``` | 121 ``` |
66 | 122 |
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._ | 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._ |
68 | 128 |
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. | 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. |
70 | 133 |
71 ## C++ Bindings API | 134 ### C++ Bindings API |
72 | 135 |
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. | 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. |
74 | 140 |
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. | 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. |
76 | 143 |
77 ### `mojo::InterfacePtr<T>` | 144 #### `mojo::InterfacePtr<T>` |
78 | 145 |
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). | 146 Defined in `/third_party/mojo/src/mojo/public/cpp/bindings/interface_ptr.h`. |
80 | 147 |
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. | 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. |
82 | 153 |
83 For illustrative purposes only, we can create a message pipe and bind an `Interf
acePtr` to one end as follows: | 154 For illustrative purposes only, we can create a message pipe and bind an |
| 155 `InterfacePtr` to one end as follows: |
84 | 156 |
85 ``` | 157 ``` |
86 mojo::MessagePipe pipe; | 158 mojo::MessagePipe pipe; |
87 mojo::InterfacePtr<frob::Frobinator> frobinator; | 159 mojo::InterfacePtr<frob::Frobinator> frobinator; |
88 frobinator.Bind( | 160 frobinator.Bind( |
89 mojo::InterfacePtrInfo<frob::Frobinator>(pipe.handle0.Pass(), 0u)); | 161 mojo::InterfacePtrInfo<frob::Frobinator>(pipe.handle0.Pass(), 0u)); |
90 ``` | 162 ``` |
91 | 163 |
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. | 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. |
93 | 168 |
94 ### `mojo::InterfaceRequest<T>` | 169 #### `mojo::InterfaceRequest<T>` |
95 | 170 |
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). | 171 Defined in `/third_party/mojo/src/mojo/public/cpp/bindings/interface_request.h`. |
97 | 172 |
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. | 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. |
99 | 177 |
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. | 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. |
101 | 183 |
102 As with `InterfacePtr<T>`, we can manually bind an `InterfaceRequest<T>` to a pi
pe endpoint: | 184 As with `InterfacePtr<T>`, we can manually bind an `InterfaceRequest<T>` to a |
| 185 pipe endpoint: |
103 | 186 |
104 ``` | 187 ``` |
105 mojo::MessagePipe pipe; | 188 mojo::MessagePipe pipe; |
106 | 189 |
107 mojo::InterfacePtr<frob::Frobinator> frobinator; | 190 mojo::InterfacePtr<frob::Frobinator> frobinator; |
108 frobinator.Bind( | 191 frobinator.Bind( |
109 mojo::InterfacePtrInfo<frob::Frobinator>(pipe.handle0.Pass(), 0u)); | 192 mojo::InterfacePtrInfo<frob::Frobinator>(pipe.handle0.Pass(), 0u)); |
110 | 193 |
111 mojo::InterfaceRequest<frob::Frobinator> frobinator_request; | 194 mojo::InterfaceRequest<frob::Frobinator> frobinator_request; |
112 frobinator_request.Bind(pipe.handle1.Pass()); | 195 frobinator_request.Bind(pipe.handle1.Pass()); |
113 ``` | 196 ``` |
114 | 197 |
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. | 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. |
116 | 202 |
117 ### `mojo::GetProxy<T>` | 203 #### `mojo::GetProxy<T>` |
118 | 204 |
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). | 205 Defined in |
| 206 `/third_party/mojo/src/mojo/public/cpp/bindings/interface`_request.h`. |
120 | 207 |
121 `mojo::GetProxy<T>` is the function you will most commonly use to create a new m
essage pipe. Its signature is as follows: | 208 `mojo::GetProxy<T>` is the function you will most commonly use to create a new |
| 209 message pipe. Its signature is as follows: |
122 | 210 |
123 ``` | 211 ``` |
124 template <typename T> | 212 template <typename T> |
125 mojo::InterfaceRequest<T> GetProxy(mojo::InterfacePtr<T>* ptr); | 213 mojo::InterfaceRequest<T> GetProxy(mojo::InterfacePtr<T>* ptr); |
126 ``` | 214 ``` |
127 | 215 |
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: | 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: |
129 | 220 |
130 ``` | 221 ``` |
131 mojo::InterfacePtr<frob::Frobinator> frobinator; | 222 mojo::InterfacePtr<frob::Frobinator> frobinator; |
132 mojo::InterfaceRequest<frob::Frobinator> frobinator_request = | 223 mojo::InterfaceRequest<frob::Frobinator> frobinator_request = |
133 mojo::GetProxy(&frobinator); | 224 mojo::GetProxy(&frobinator); |
134 ``` | 225 ``` |
135 | 226 |
136 ### `mojo::Binding<T>` | 227 #### `mojo::Binding<T>` |
137 | 228 |
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). | 229 Defined in `/third_party/mojo/src/mojo/public/cpp/bindings/binding.h`. |
139 | 230 |
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>`. | 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>`. |
141 | 237 |
142 A common usage pattern looks something like this: | 238 A common usage pattern looks something like this: |
143 | 239 |
144 ``` | 240 ``` |
145 #include "components/frob/public/interfaces/frobinator.mojom.h" | 241 #include "components/frob/public/interfaces/frobinator.mojom.h" |
146 #include "third_party/mojo/src/mojo/public/cpp/bindings/binding.h" | 242 #include "third_party/mojo/src/mojo/public/cpp/bindings/binding.h" |
147 #include "third_party/mojo/src/mojo/public/cpp/bindings/interface_request.h" | 243 #include "third_party/mojo/src/mojo/public/cpp/bindings/interface_request.h" |
148 | 244 |
149 class FrobinatorImpl : public frob::Frobinator { | 245 class FrobinatorImpl : public frob::Frobinator { |
150 public: | 246 public: |
151 FrobinatorImpl(mojo::InterfaceRequest<frob::Frobinator> request) | 247 FrobinatorImpl(mojo::InterfaceRequest<frob::Frobinator> request) |
152 : binding_(this, request.Pass()) {} | 248 : binding_(this, request.Pass()) {} |
153 ~FrobinatorImpl() override {} | 249 ~FrobinatorImpl() override {} |
154 | 250 |
155 private: | 251 private: |
156 // frob::Frobinator: | 252 // frob::Frobinator: |
157 void Frobinate() override { /* ... */ } | 253 void Frobinate() override { /* ... */ } |
158 | 254 |
159 mojo::Binding<frob::Frobinator> binding_; | 255 mojo::Binding<frob::Frobinator> binding_; |
160 }; | 256 }; |
161 ``` | 257 ``` |
162 | 258 |
163 And then we could write some code to test this: | 259 And then we could write some code to test this: |
164 | 260 |
165 ``` | 261 ``` |
166 // Fun fact: The bindings generator emits a type alias like this for every | 262 // Fun fact: The bindings generator emits a type alias like this for every |
167 // interface type. frob::FrobinatorPtr is an InterfacePtr<frob::Frobinator>. | 263 // interface type. frob::FrobinatorPtr is an InterfacePtr<frob::Frobinator>. |
168 frob::FrobinatorPtr frobinator; | 264 frob::FrobinatorPtr frobinator; |
169 scoped_ptr<FrobinatorImpl> impl( | 265 scoped_ptr<FrobinatorImpl> impl( |
170 new FrobinatorImpl(mojo::GetProxy(&frobinator))); | 266 new FrobinatorImpl(mojo::GetProxy(&frobinator))); |
171 frobinator->Frobinate(); | 267 frobinator->Frobinate(); |
172 ``` | 268 ``` |
173 | 269 |
174 This will _eventually_ call `FrobinatorImpl::Frobinate()`. "Eventually," because
the sequence of events when `frobinator->Frobinate()` is called is roughly as f
ollows: | 270 This will _eventually_ call `FrobinatorImpl::Frobinate()`. "Eventually," because |
| 271 the sequence of events when `frobinator->Frobinate()` is called is roughly as |
| 272 follows: |
175 | 273 |
176 1. A new message buffer is allocated and filled with an encoded 'Frobinate' me
ssage. | 274 1. A new message buffer is allocated and filled with an encoded 'Frobinate' |
177 1. The EDK is asked to write this message to the pipe endpoint owned by the `F
robinatorPtr`. | 275 message. |
178 1. If the call didn't happen on the Mojo IPC thread for this process, EDK hops
to the Mojo IPC thread. | 276 1. The EDK is asked to write this message to the pipe endpoint owned by the |
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. | 277 `FrobinatorPtr`. |
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. | 278 1. If the call didn't happen on the Mojo IPC thread for this process, EDK hops |
181 1. The EDK reads the message. | 279 to the Mojo IPC thread. |
182 1. If the bound receiver doesn't live on the Mojo IPC thread, the EDK hops to
the receiver's thread. | 280 1. The EDK writes the message to the pipe. In this case the pipe endpoints live |
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. | 281 in the same process, so this essentially a glorified `memcpy`. If they lived |
184 1. `FrobinatorImpl::Frobinate()` is called on the bound implementation. | 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. |
185 | 293 |
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. | 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. |
187 | 296 |
188 ### `mojo::StrongBinding<T>` | 297 #### `mojo::StrongBinding<T>` |
189 | 298 |
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). | 299 Defined in `third_party/mojo/src/mojo/public/cpp/bindings/strong_binding.h`. |
191 | 300 |
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. | 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. |
193 | 307 |
194 ## The Mojo Shell | 308 ## The Mojo Shell |
195 | 309 |
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.) | 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.) |
197 | 313 |
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: | 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: |
199 | 318 |
200 ``` | 319 ``` |
201 module mojo; | 320 module mojo; |
202 interface Shell { | 321 interface Shell { |
203 ConnectToApplication(URLRequest application_url, | 322 ConnectToApplication(URLRequest application_url, |
204 ServiceProvider&? services, | 323 ServiceProvider&? services, |
205 ServiceProvider? exposed_services); | 324 ServiceProvider? exposed_services); |
206 QuitApplication(); | 325 QuitApplication(); |
207 }; | 326 }; |
208 ``` | 327 ``` |
209 | 328 |
210 and as for the `mojo::ServiceProvider` interface: | 329 and as for the `mojo::ServiceProvider` interface: |
211 | 330 |
212 ``` | 331 ``` |
213 module mojo; | 332 module mojo; |
214 interface ServiceProvider { | 333 interface ServiceProvider { |
215 ConnectToService(string interface_name, handle<message_pipe> pipe); | 334 ConnectToService(string interface_name, handle<message_pipe> pipe); |
216 }; | 335 }; |
217 ``` | 336 ``` |
218 | 337 |
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). | 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`. |
220 | 342 |
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. | 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. |
222 | 346 |
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.) | 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.) |
224 | 350 |
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. | 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. |
226 | 354 |
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. | 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. |
228 | 362 |
229 ## Mojo Applications | 363 ### Mojo Applications |
230 | 364 |
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: | 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: |
232 | 370 |
233 ``` | 371 ``` |
234 module mojo; | 372 module mojo; |
235 interface Application { | 373 interface Application { |
236 Initialize(Shell shell, string url); | 374 Initialize(Shell shell, string url); |
237 AcceptConnection(string requestor_url, | 375 AcceptConnection(string requestor_url, |
238 ServiceProvider&? services, | 376 ServiceProvider&? services, |
239 ServiceProvider? exposed_services, | 377 ServiceProvider? exposed_services, |
240 string resolved_url); | 378 string resolved_url); |
241 OnQuitRequested() => (bool can_quit); | 379 OnQuitRequested() => (bool can_quit); |
242 }; | 380 }; |
243 ``` | 381 ``` |
244 | 382 |
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). | 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). |
246 | 389 |
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. | 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. |
248 | 394 |
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. | 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. |
250 | 399 |
251 ## Other IPC Primitives | 400 ### Other IPC Primitives |
252 | 401 |
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. | 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. |
254 | 408 |
255 # Your First Mojo Application | 409 ## Your First Mojo Application |
256 | 410 |
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. | 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. |
258 | 414 |
259 ## Hello, world! | 415 ### Hello, world! |
260 | 416 |
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. | 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. |
262 | 423 |
263 First create a new `//components/hello` directory. Inside this directory we're g
oing to add the following files: | 424 First create a new `//components/hello` directory. Inside this directory we're |
| 425 going to add the following files: |
264 | 426 |
265 **components/hello/main.cc** | 427 **components/hello/main.cc** |
266 ``` | 428 ``` |
267 #include "base/logging.h" | 429 #include "base/logging.h" |
268 #include "third_party/mojo/src/mojo/public/c/system/main.h" | 430 #include "third_party/mojo/src/mojo/public/c/system/main.h" |
269 | 431 |
270 MojoResult MojoMain(MojoHandle shell_handle) { | 432 MojoResult MojoMain(MojoHandle shell_handle) { |
271 LOG(ERROR) << "Hello, world!"; | 433 LOG(ERROR) << "Hello, world!"; |
272 return MOJO_RESULT_OK; | 434 return MOJO_RESULT_OK; |
273 }; | 435 }; |
274 ``` | 436 ``` |
275 | 437 |
276 | |
277 **components/hello/BUILD.gn** | 438 **components/hello/BUILD.gn** |
278 ``` | 439 ``` |
279 import("//mojo/public/mojo_application.gni") | 440 import("//mojo/public/mojo_application.gni") |
280 | 441 |
281 mojo_native_application("hello") { | 442 mojo_native_application("hello") { |
282 sources = [ | 443 sources = [ |
283 "main.cc", | 444 "main.cc", |
284 ] | 445 ] |
285 deps = [ | 446 deps = [ |
286 "//base", | 447 "//base", |
287 "//mojo/environment:chromium", | 448 "//mojo/environment:chromium", |
288 ] | 449 ] |
289 } | 450 } |
290 ``` | 451 ``` |
291 | 452 |
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`. | 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`. |
293 | 457 |
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: | 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: |
295 | 460 |
296 ``` | |
297 ninja -C out_gn/Debug mojo_runner components/hello | 461 ninja -C out_gn/Debug mojo_runner components/hello |
298 ``` | |
299 | 462 |
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. | 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. |
301 | 466 |
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: | 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: |
303 | 472 |
304 ``` | |
305 out_gn/Debug/mojo_runner mojo:hello | 473 out_gn/Debug/mojo_runner mojo:hello |
306 ``` | |
307 | 474 |
308 You should see our little `"Hello, world!"` error log followed by a hanging appl
ication. You can `^C` to kill it. | 475 You should see our little `"Hello, world!"` error log followed by a hanging |
| 476 application. You can `^C` to kill it. |
309 | 477 |
310 ## Exposing Services | 478 ### Exposing Services |
311 | 479 |
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. | 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. |
313 | 483 |
314 Let's update `main.cc` with the following contents: | 484 Let's update `main.cc` with the following contents: |
315 | 485 |
316 **components/hello/main.cc** | 486 **components/hello/main.cc** |
317 ``` | 487 ``` |
318 #include "components/hello/hello_app.h" | 488 #include "components/hello/hello_app.h" |
319 #include "mojo/application/public/cpp/application_runner.h" | 489 #include "mojo/application/public/cpp/application_runner.h" |
320 #include "third_party/mojo/src/mojo/public/c/system/main.h" | 490 #include "third_party/mojo/src/mojo/public/c/system/main.h" |
321 | 491 |
322 MojoResult MojoMain(MojoHandle shell_handle) { | 492 MojoResult MojoMain(MojoHandle shell_handle) { |
323 mojo::ApplicationRunner runner(new hello::HelloApp); | 493 mojo::ApplicationRunner runner(new hello::HelloApp); |
324 return runner.Run(shell_handle); | 494 return runner.Run(shell_handle); |
325 }; | 495 }; |
326 ``` | 496 ``` |
327 | 497 |
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: | 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: |
329 | 502 |
330 **components/hello/public/interfaces/greeter.mojom** | 503 **components/hello/public/interfaces/greeter.mojom** |
331 ``` | 504 ``` |
332 module hello; | 505 module hello; |
333 interface Greeter { | 506 interface Greeter { |
334 Greet(string name) => (string greeting); | 507 Greet(string name) => (string greeting); |
335 }; | 508 }; |
336 ``` | 509 ``` |
337 | 510 |
338 Note the new arrow syntax on the `Greet` method. This indicates that the caller
expects a response from the service. | 511 Note the new arrow syntax on the `Greet` method. This indicates that the caller |
| 512 expects a response from the service. |
339 | 513 |
340 **components/hello/public/interfaces/BUILD.gn** | 514 **components/hello/public/interfaces/BUILD.gn** |
341 ``` | 515 ``` |
342 import("//third_party/mojo/src/mojo/public/tools/bindings/mojom.gni") | 516 import("//third_party/mojo/src/mojo/public/tools/bindings/mojom.gni") |
343 | 517 |
344 mojom("interfaces") { | 518 mojom("interfaces") { |
345 sources = [ | 519 sources = [ |
346 "greeter.mojom", | 520 "greeter.mojom", |
347 ] | 521 ] |
348 } | 522 } |
349 ``` | 523 ``` |
350 | 524 |
351 **components/hello/hello\_app.h** | 525 **components/hello/hello_app.h** |
352 ``` | 526 ``` |
353 #ifndef COMPONENTS_HELLO_HELLO_APP_H_ | 527 #ifndef COMPONENTS_HELLO_HELLO_APP_H_ |
354 #define COMPONENTS_HELLO_HELLO_APP_H_ | 528 #define COMPONENTS_HELLO_HELLO_APP_H_ |
355 | 529 |
356 #include "base/macros.h" | 530 #include "base/macros.h" |
357 #include "components/hello/public/interfaces/greeter.mojom.h" | 531 #include "components/hello/public/interfaces/greeter.mojom.h" |
358 #include "mojo/application/public/cpp/application_delegate.h" | 532 #include "mojo/application/public/cpp/application_delegate.h" |
359 #include "mojo/application/public/cpp/interface_factory.h" | 533 #include "mojo/application/public/cpp/interface_factory.h" |
360 | 534 |
361 namespace hello { | 535 namespace hello { |
(...skipping 15 matching lines...) Expand all Loading... |
377 | 551 |
378 DISALLOW_COPY_AND_ASSIGN(HelloApp); | 552 DISALLOW_COPY_AND_ASSIGN(HelloApp); |
379 }; | 553 }; |
380 | 554 |
381 } // namespace hello | 555 } // namespace hello |
382 | 556 |
383 #endif // COMPONENTS_HELLO_HELLO_APP_H_ | 557 #endif // COMPONENTS_HELLO_HELLO_APP_H_ |
384 ``` | 558 ``` |
385 | 559 |
386 | 560 |
387 **components/hello/hello\_app.cc** | 561 **components/hello/hello_app.cc** |
388 ``` | 562 ``` |
389 #include "base/macros.h" | 563 #include "base/macros.h" |
390 #include "components/hello/hello_app.h" | 564 #include "components/hello/hello_app.h" |
391 #include "mojo/application/public/cpp/application_connection.h" | 565 #include "mojo/application/public/cpp/application_connection.h" |
392 #include "third_party/mojo/src/mojo/public/cpp/bindings/interface_request.h" | 566 #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" | 567 #include "third_party/mojo/src/mojo/public/cpp/bindings/strong_binding.h" |
394 | 568 |
395 namespace hello { | 569 namespace hello { |
396 | 570 |
397 namespace { | 571 namespace { |
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
431 | 605 |
432 void HelloApp::Create( | 606 void HelloApp::Create( |
433 mojo::ApplicationConnection* connection, | 607 mojo::ApplicationConnection* connection, |
434 mojo::InterfaceRequest<Greeter> request) { | 608 mojo::InterfaceRequest<Greeter> request) { |
435 new GreeterImpl(request.Pass()); | 609 new GreeterImpl(request.Pass()); |
436 } | 610 } |
437 | 611 |
438 } // namespace hello | 612 } // namespace hello |
439 ``` | 613 ``` |
440 | 614 |
441 And finally we need to update our app's `BUILD.gn` to add some new sources and d
ependencies: | 615 And finally we need to update our app's `BUILD.gn` to add some new sources and |
| 616 dependencies: |
442 | 617 |
443 **components/hello/BUILD.gn** | 618 **components/hello/BUILD.gn** |
444 ``` | 619 ``` |
445 import("//mojo/public/mojo_application.gni") | 620 import("//mojo/public/mojo_application.gni") |
446 | 621 |
447 source_set("lib") { | 622 source_set("lib") { |
448 sources = [ | 623 sources = [ |
449 "hello_app.cc", | 624 "hello_app.cc", |
450 "hello_app.h", | 625 "hello_app.h", |
451 ] | 626 ] |
452 deps = [ | 627 deps = [ |
453 "//base", | 628 "//base", |
454 "//components/hello/public/interfaces", | 629 "//components/hello/public/interfaces", |
455 "//mojo/application/public/cpp", | 630 "//mojo/application/public/cpp", |
456 "//mojo/environment:chromium", | 631 "//mojo/environment:chromium", |
457 ] | 632 ] |
458 } | 633 } |
459 | 634 |
460 mojo_native_application("hello") { | 635 mojo_native_application("hello") { |
461 sources = [ | 636 sources = [ |
462 "main.cc", | 637 "main.cc", |
463 ], | 638 ], |
464 deps = [ ":lib" ] | 639 deps = [ ":lib" ] |
465 } | 640 } |
466 ``` | 641 ``` |
467 | 642 |
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. | 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. |
469 | 646 |
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. | 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. |
471 | 654 |
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! | 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! |
473 | 658 |
474 ## App Tests | 659 ### App Tests |
475 | 660 |
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. | 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. |
477 | 663 |
478 First let's introduce some test code: | 664 First let's introduce some test code: |
479 | 665 |
480 **components/hello/hello\_apptest.cc** | 666 **components/hello/hello_apptest.cc** |
481 ``` | 667 ``` |
482 #include "base/bind.h" | 668 #include "base/bind.h" |
483 #include "base/callback.h" | 669 #include "base/callback.h" |
484 #include "base/logging.h" | 670 #include "base/logging.h" |
485 #include "base/macros.h" | 671 #include "base/macros.h" |
486 #include "base/run_loop.h" | 672 #include "base/run_loop.h" |
487 #include "components/hello/public/interfaces/greeter.mojom.h" | 673 #include "components/hello/public/interfaces/greeter.mojom.h" |
488 #include "mojo/application/public/cpp/application_impl.h" | 674 #include "mojo/application/public/cpp/application_impl.h" |
489 #include "mojo/application/public/cpp/application_test_base.h" | 675 #include "mojo/application/public/cpp/application_test_base.h" |
490 | 676 |
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
525 loop.Run(); | 711 loop.Run(); |
526 } | 712 } |
527 | 713 |
528 } // namespace | 714 } // namespace |
529 } // namespace hello | 715 } // namespace hello |
530 ``` | 716 ``` |
531 | 717 |
532 We also need to add a new rule to `//components/hello/BUILD.gn`: | 718 We also need to add a new rule to `//components/hello/BUILD.gn`: |
533 | 719 |
534 ``` | 720 ``` |
535 mojo_native_application("apptests") { | 721 mojo_native_application("apptests") { |
536 output_name = "hello_apptests" | 722 output_name = "hello_apptests" |
537 testonly = true | 723 testonly = true |
538 sources = [ | 724 sources = [ |
539 "hello_apptest.cc", | 725 "hello_apptest.cc", |
540 ] | 726 ] |
541 deps = [ | 727 deps = [ |
542 "//base", | 728 "//base", |
543 "//mojo/application/public/cpp:test_support", | 729 "//mojo/application/public/cpp:test_support", |
544 ] | 730 ] |
545 public_deps = [ | 731 public_deps = [ |
546 "//components/hello/public/interfaces", | 732 "//components/hello/public/interfaces", |
547 ] | 733 ] |
548 data_deps = [ ":hello" ] | 734 data_deps = [ ":hello" ] |
549 } | 735 } |
550 ``` | 736 ``` |
551 | 737 |
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. | 738 Note that the `//components/hello:apptests` target does **not** have a binary |
553 | 739 dependency on either `HelloApp` or `GreeterImpl` implementations; instead it |
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. | 740 depends only on the component's public interface definitions. |
| 741 |
| 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. |
555 | 745 |
556 You can now build the test suite: | 746 You can now build the test suite: |
557 | 747 |
558 ``` | 748 ninja -C out_gn/Debug components/hello:apptests |
559 ninja -C out_gn/Debug components/hello:apptests | |
560 ``` | |
561 | 749 |
562 and run it: | 750 and run it: |
563 | 751 |
564 ``` | 752 out_gn/Debug/mojo_runner mojo:hello_apptests |
565 out_gn/Debug/mojo_runner mojo:hello_apptests | |
566 ``` | |
567 | 753 |
568 You should see one test (`HelloAppTest.GreetWorld`) passing. | 754 You should see one test (`HelloAppTest.GreetWorld`) passing. |
569 | 755 |
570 One particularly interesting bit of code in this test is in the `SetUp` method: | 756 One particularly interesting bit of code in this test is in the `SetUp` method: |
571 | 757 |
572 ``` | |
573 mojo::URLRequestPtr app_url = mojo::URLRequest::New(); | 758 mojo::URLRequestPtr app_url = mojo::URLRequest::New(); |
574 app_url->url = "mojo:hello"; | 759 app_url->url = "mojo:hello"; |
575 application_impl()->ConnectToService(app_url.Pass(), &greeter_); | 760 application_impl()->ConnectToService(app_url.Pass(), &greeter_); |
576 ``` | 761 |
577 | 762 `ConnectToService` is a convenience method provided by `mojo::ApplicationImpl`, |
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. | 763 and it's essentially a shortcut for calling out to the shell's |
579 | 764 `ConnectToApplication` method with the given application URL (in this case |
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: | 765 `"mojo:hello"`) and then connecting to a specific service provided by that app |
581 | 766 via its `ServiceProvider`'s `ConnectToService` method. |
582 ``` | 767 |
| 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: |
| 771 |
583 const char hello::Greeter::Name_[] = "hello::Greeter"; | 772 const char hello::Greeter::Name_[] = "hello::Greeter"; |
584 ``` | 773 |
585 | 774 This is exploited by the definition of |
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. | 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. |
587 | 780 |
588 We could have instead written this code as: | 781 We could have instead written this code as: |
589 | 782 |
590 ``` | 783 ``` |
591 mojo::URLRequestPtr app_url = mojo::URLRequest::New(); | 784 mojo::URLRequestPtr app_url = mojo::URLRequest::New(); |
592 app_url->url = "mojo::hello"; | 785 app_url->url = "mojo::hello"; |
593 | 786 |
594 mojo::ServiceProviderPtr services; | 787 mojo::ServiceProviderPtr services; |
595 application_impl()->shell()->ConnectToApplication( | 788 application_impl()->shell()->ConnectToApplication( |
596 app_url.Pass(), mojo::GetProxy(&services), | 789 app_url.Pass(), mojo::GetProxy(&services), |
597 // We pass a null provider since we aren't exposing any of our own | 790 // We pass a null provider since we aren't exposing any of our own |
598 // services to the target app. | 791 // services to the target app. |
599 mojo::ServiceProviderPtr()); | 792 mojo::ServiceProviderPtr()); |
600 | 793 |
601 mojo::InterfaceRequest<hello::Greeter> greeter_request = | 794 mojo::InterfaceRequest<hello::Greeter> greeter_request = |
602 mojo::GetProxy(&greeter_); | 795 mojo::GetProxy(&greeter_); |
603 services->ConnectToService(hello::Greeter::Name_, | 796 services->ConnectToService(hello::Greeter::Name_, |
604 greeter_request.PassMessagePipe()); | 797 greeter_request.PassMessagePipe()); |
605 ``` | 798 ``` |
606 | 799 |
607 The net result is the same, but 3-line version seems much nicer. | 800 The net result is the same, but 3-line version seems much nicer. |
608 | 801 |
609 # Chromium Integration | 802 ## Chromium Integration |
610 | 803 |
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. | 804 Up until now we've been using `mojo_runner` to load and run `.mojo` binaries |
612 | 805 dynamically. While this model is used by Mandoline and may eventually be used in |
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. | 806 Chromium as well, Chromium is at the moment confined to running statically |
614 | 807 linked application code. This means we need some way to register applications |
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. | 808 with the browser's Mojo shell. |
616 | 809 |
617 This section explores different ways to register and connect to `"mojo:hello"` i
n Chromium. | 810 It also means that, rather than using the binary output of a |
618 | 811 `mojo_native_application` target, some part of Chromium must link against the |
619 ## In-Process Applications | 812 app's static library target (_e.g._, `"//components/hello:lib"`) and register a |
620 | 813 URL handler to teach the shell how to launch an instance of the app. |
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. | 814 |
622 | 815 When registering an app URL in Chromium it probably makes sense to use the same |
623 Let's modify `ChromeContentBrowserClient::RegisterInProcessMojoApplications` (in
`//chrome/browser/chrome_content_browser_client.cc`) by adding the following co
de: | 816 mojo-scheme URL used for the app in Mandoline. For example the media renderer |
624 | 817 app is referenced by the `"mojo:media"` URL in both Mandoline and Chromium. In |
625 ``` | 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. |
| 822 |
| 823 This section explores different ways to register and connect to `"mojo:hello"` |
| 824 in Chromium. |
| 825 |
| 826 ### In-Process Applications |
| 827 |
| 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. |
| 833 |
| 834 Let's modify `ChromeContentBrowserClient::RegisterInProcessMojoApplications` |
| 835 (in `//chrome/browser/chrome_content_browser_client.cc`) by adding the following |
| 836 code: |
| 837 |
626 apps->insert(std::make_pair(GURL("mojo:hello"), | 838 apps->insert(std::make_pair(GURL("mojo:hello"), |
627 base::Bind(&HelloApp::CreateApp))); | 839 base::Bind(&HelloApp::CreateApp))); |
628 ``` | 840 |
629 | 841 you'll also want to add the following convenience method to your `HelloApp` |
630 you'll also want to add the following convenience method to your `HelloApp` defi
nition in `//components/hello/hello_app.h`: | 842 definition in `//components/hello/hello_app.h`: |
631 | 843 |
632 ``` | |
633 static scoped_ptr<mojo::ApplicationDelegate> HelloApp::CreateApp() { | 844 static scoped_ptr<mojo::ApplicationDelegate> HelloApp::CreateApp() { |
634 return scoped_ptr<mojo::ApplicationDelegate>(new HelloApp); | 845 return scoped_ptr<mojo::ApplicationDelegate>(new HelloApp); |
635 } | 846 } |
636 ``` | 847 |
637 | 848 This introduces a dependency from `//chrome/browser` on to |
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`. | 849 `//components/hello:lib`, which you can add to the `"browser"` target's deps in |
639 | 850 `//chrome/browser/BUILD.gn`. You'll of course also need to include |
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. | 851 `"components/hello/hello_app.h"` in `chrome_content_browser_client.cc`. |
641 | 852 |
642 ## Connecting From the Browser | 853 That's it! Now if an app comes to the shell asking to connect to `"mojo:hello"` |
643 | 854 and app is already running, it'll get connected to our `HelloApp` and have |
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: | 855 access to the `Greeter` service. If the app wasn't already running, it will |
645 | 856 first be launched on a new thread. |
646 ``` | 857 |
647 #include "base/bind.h" | 858 ### Connecting From the Browser |
648 #include "base/logging.h" | 859 |
649 #include "components/hello/public/interfaces/greeter.mojom.h" | 860 We've already seen how apps can connect to each other using their own private |
650 #include "content/public/browser/mojo_app_connection.h" | 861 shell proxy, but the vast majority of Chromium code doesn't yet belong to a Mojo |
651 | 862 application. So how do we use an app's services from arbitrary browser code? We |
652 void LogGreeting(const mojo::String& greeting) { | 863 use `content::MojoAppConnection`, like this: |
653 LOG(INFO) << greeting; | 864 |
654 } | 865 ``` |
655 | 866 #include "base/bind.h" |
656 void GreetTheWorld() { | 867 #include "base/logging.h" |
657 scoped_ptr<content::MojoAppConnection> connection = | 868 #include "components/hello/public/interfaces/greeter.mojom.h" |
658 content::MojoAppConnection::Create("mojo:hello", | 869 #include "content/public/browser/mojo_app_connection.h" |
659 content::kBrowserMojoAppUrl); | 870 |
660 hello::GreeterPtr greeter; | 871 void LogGreeting(const mojo::String& greeting) { |
661 connection->ConnectToService(&greeter); | 872 LOG(INFO) << greeting; |
662 greeter->Greet("world", base::Bind(&LogGreeting)); | 873 } |
663 } | 874 |
664 ``` | 875 void GreetTheWorld() { |
665 | 876 scoped_ptr<content::MojoAppConnection> connection = |
666 A `content::MojoAppConnection`, while not thread-safe, may be created and safely
used on any single browser thread. | 877 content::MojoAppConnection::Create("mojo:hello", |
667 | 878 content::kBrowserMojoAppUrl); |
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. | 879 hello::GreeterPtr greeter; |
669 | 880 connection->ConnectToService(&greeter); |
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. | 881 greeter->Greet("world", base::Bind(&LogGreeting)); |
671 | 882 } |
672 ## Out-of-Process Applications | 883 ``` |
673 | 884 |
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. | 885 A `content::MojoAppConnection`, while not thread-safe, may be created and safely |
675 | 886 used on any single browser thread. |
676 Similar to in-process registration, a URL mapping needs to be registered in `Con
tentUtilityClient::RegisterMojoApplications`. | 887 |
677 | 888 You could add the above code to a new browsertest to convince yourself that it |
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. | 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. |
| 893 |
| 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. |
| 901 |
| 902 ### Out-of-Process Applications |
| 903 |
| 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. |
| 909 |
| 910 Similar to in-process registration, a URL mapping needs to be registered in |
| 911 `ContentUtilityClient::RegisterMojoApplications`. |
| 912 |
| 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. |
679 | 919 |
680 ## Unsandboxed Out-of-Process Applications | 920 ## Unsandboxed Out-of-Process Applications |
681 | 921 |
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`. | 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`. |
683 | 926 |
684 ## Connecting From `RenderFrame` | 927 ## Connecting From `RenderFrame` |
685 | 928 |
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: | 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: |
687 | 932 |
688 ``` | 933 ``` |
689 void GreetWorld(content::RenderFrame* frame) { | 934 void GreetWorld(content::RenderFrame* frame) { |
690 mojo::ShellPtr shell; | 935 mojo::ShellPtr shell; |
691 frame->GetServiceRegistry()->ConnectToRemoteService( | 936 frame->GetServiceRegistry()->ConnectToRemoteService( |
692 mojo::GetProxy(&shell)); | 937 mojo::GetProxy(&shell)); |
693 | 938 |
694 mojo::URLRequestPtr request = mojo::URLRequest::New(); | 939 mojo::URLRequestPtr request = mojo::URLRequest::New(); |
695 request->url = "mojo:hello"; | 940 request->url = "mojo:hello"; |
696 | 941 |
697 mojo::ServiceProviderPtr hello_services; | 942 mojo::ServiceProviderPtr hello_services; |
698 shell->ConnectToApplication( | 943 shell->ConnectToApplication( |
699 request.Pass(), mojo::GetProxy(&hello_services), nullptr); | 944 request.Pass(), mojo::GetProxy(&hello_services), nullptr); |
700 | 945 |
701 hello::GreeterPtr greeter; | 946 hello::GreeterPtr greeter; |
702 hello_services->ConnectToService( | 947 hello_services->ConnectToService( |
703 hello::Greeter::Name_, mojo::GetProxy(&greeter).PassMessagePipe()); | 948 hello::Greeter::Name_, mojo::GetProxy(&greeter).PassMessagePipe()); |
704 } | 949 } |
705 ``` | 950 ``` |
706 | 951 |
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. | 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. |
708 | 958 |
709 ## Connecting From Java | 959 ### Connecting From Java |
710 | 960 |
711 TODO | 961 TODO |
712 | 962 |
713 ## Connecting From `JavaScript` | 963 ### Connecting From `JavaScript` |
714 | 964 |
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. | 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. |
716 | 970 |
717 # FAQ | 971 ## FAQ |
718 | 972 |
719 Nothing here yet! | 973 Nothing here yet! |
OLD | NEW |