OLD | NEW |
1 # Mojo in Chromium | 1 # Mojo in Chromium |
2 | 2 |
3 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 |
4 prior knowledge of Mojo is assumed. | 4 prior knowledge of Mojo is assumed. |
5 | 5 |
6 [TOC] | 6 [TOC] |
7 | 7 |
8 ## Should I Bother Reading This? | 8 ## Should I Bother Reading This? |
9 | 9 |
10 If you're planning to build a Chromium feature that needs IPC and you aren't | 10 If you're planning to build a Chromium feature that needs IPC and you aren't |
(...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
88 The C++ header (`frobinator.mojom.h`) defines an abstract class for each | 88 The C++ header (`frobinator.mojom.h`) defines an abstract class for each |
89 mojom interface specified. Namespaces are derived from the `module` name. | 89 mojom interface specified. Namespaces are derived from the `module` name. |
90 | 90 |
91 **NOTE:** Chromium convention for component `foo`'s module name is `foo.mojom`. | 91 **NOTE:** Chromium convention for component `foo`'s module name is `foo.mojom`. |
92 This means all mojom-generated C++ typenames for component `foo` will live in | 92 This means all mojom-generated C++ typenames for component `foo` will live in |
93 the `foo::mojom` namespace to avoid collisions with non-generated typenames. | 93 the `foo::mojom` namespace to avoid collisions with non-generated typenames. |
94 | 94 |
95 In this example the generated `frob::mojom::Frobinator` has a single | 95 In this example the generated `frob::mojom::Frobinator` has a single |
96 pure virtual function: | 96 pure virtual function: |
97 | 97 |
98 ``` | 98 ```cpp |
99 namespace frob { | 99 namespace frob { |
100 | 100 |
101 class Frobinator { | 101 class Frobinator { |
102 public: | 102 public: |
103 virtual void Frobinate() = 0; | 103 virtual void Frobinate() = 0; |
104 }; | 104 }; |
105 | 105 |
106 } // namespace frob | 106 } // namespace frob |
107 ``` | 107 ``` |
108 | 108 |
109 To create a `Frobinator` service, one simply implements `foo::Frobinator` and | 109 To create a `Frobinator` service, one simply implements `foo::Frobinator` and |
110 provides a means of binding pipes to it. | 110 provides a means of binding pipes to it. |
111 | 111 |
112 ### Binding to Pipes | 112 ### Binding to Pipes |
113 | 113 |
114 Let's look at some sample code: | 114 Let's look at some sample code: |
115 | 115 |
116 ``` | 116 ```cpp |
117 // src/components/frob/frobinator_impl.cc | 117 // src/components/frob/frobinator_impl.cc |
118 | 118 |
119 #include "components/frob/public/interfaces/frobinator.mojom.h" | 119 #include "components/frob/public/interfaces/frobinator.mojom.h" |
120 #include "mojo/public/cpp/bindings/binding.h" | 120 #include "mojo/public/cpp/bindings/binding.h" |
121 #include "mojo/public/cpp/bindings/interface_request.h" | 121 #include "mojo/public/cpp/bindings/interface_request.h" |
122 | 122 |
123 namespace frob { | 123 namespace frob { |
124 | 124 |
125 class FrobinatorImpl : public mojom::Frobinator { | 125 class FrobinatorImpl : public mojom::Frobinator { |
126 public: | 126 public: |
(...skipping 14 matching lines...) Expand all Loading... |
141 The first thing to note is that `mojo::Binding<T>` *binds* one end of a message | 141 The first thing to note is that `mojo::Binding<T>` *binds* one end of a message |
142 pipe to an implementation of a service. This means it watches that end of the | 142 pipe to an implementation of a service. This means it watches that end of the |
143 pipe for incoming messages; it knows how to decode messages for interface `T`, | 143 pipe for incoming messages; it knows how to decode messages for interface `T`, |
144 and it dispatches them to methods on the bound `T` implementation. | 144 and it dispatches them to methods on the bound `T` implementation. |
145 | 145 |
146 `mojom::FrobinatorRequest` is a generated type alias for | 146 `mojom::FrobinatorRequest` is a generated type alias for |
147 `mojo::InterfaceRequest<mojom::Frobinator>` and is essentially semantic sugar | 147 `mojo::InterfaceRequest<mojom::Frobinator>` and is essentially semantic sugar |
148 for a strongly-typed message pipe endpoint. A common way to create new message | 148 for a strongly-typed message pipe endpoint. A common way to create new message |
149 pipes is via the `GetProxy` call defined in `interface_request.h`: | 149 pipes is via the `GetProxy` call defined in `interface_request.h`: |
150 | 150 |
151 ``` | 151 ```cpp |
152 mojom::FrobinatorPtr proxy; | 152 mojom::FrobinatorPtr proxy; |
153 mojom::FrobinatorRequest request = mojo::GetProxy(&proxy); | 153 mojom::FrobinatorRequest request = mojo::GetProxy(&proxy); |
154 ``` | 154 ``` |
155 | 155 |
156 This creates a new message pipe with one end owned by `proxy` and the other end | 156 This creates a new message pipe with one end owned by `proxy` and the other end |
157 owned by `request`. It has the nice property of attaching common type | 157 owned by `request`. It has the nice property of attaching common type |
158 information to each end of the pipe. | 158 information to each end of the pipe. |
159 | 159 |
160 Note that `InterfaceRequest<T>` doesn't actually **do** anything. It just scopes | 160 Note that `InterfaceRequest<T>` doesn't actually **do** anything. It just scopes |
161 a pipe endpoint and associates it with an interface type at compile time. As | 161 a pipe endpoint and associates it with an interface type at compile time. As |
162 such, other typed service binding primitives such as `mojo::Binding<T>` take | 162 such, other typed service binding primitives such as `mojo::Binding<T>` take |
163 these objects as input when they need an endpoint to bind to. | 163 these objects as input when they need an endpoint to bind to. |
164 | 164 |
165 `mojom::FrobinatorPtr` is a generated type alias for | 165 `mojom::FrobinatorPtr` is a generated type alias for |
166 `mojo::InterfacePtr<mojom::Frobinator>`. An `InterfacePtr<T>` scopes a message | 166 `mojo::InterfacePtr<mojom::Frobinator>`. An `InterfacePtr<T>` scopes a message |
167 pipe endpoint as well, but it also internally implements every method on `T` by | 167 pipe endpoint as well, but it also internally implements every method on `T` by |
168 serializing a corresponding message and writing it to the pipe. | 168 serializing a corresponding message and writing it to the pipe. |
169 | 169 |
170 Hence we can put this together to talk to a `FrobinatorImpl` over a pipe: | 170 Hence we can put this together to talk to a `FrobinatorImpl` over a pipe: |
171 | 171 |
172 ``` | 172 ```cpp |
173 frob:mojom::FrobinatorPtr frobinator; | 173 frob:mojom::FrobinatorPtr frobinator; |
174 frob::FrobinatorImpl impl(GetProxy(&frobinator)); | 174 frob::FrobinatorImpl impl(GetProxy(&frobinator)); |
175 | 175 |
176 // Tada! | 176 // Tada! |
177 frobinator->Frobinate(); | 177 frobinator->Frobinate(); |
178 ``` | 178 ``` |
179 | 179 |
180 Behind the scenes this serializes a message corresponding to the `Frobinate` | 180 Behind the scenes this serializes a message corresponding to the `Frobinate` |
181 request and writes it to one end of the pipe. Eventually (and incidentally, | 181 request and writes it to one end of the pipe. Eventually (and incidentally, |
182 very soon after), `impl`'s internal `mojo::Binding` will decode this message and | 182 very soon after), `impl`'s internal `mojo::Binding` will decode this message and |
(...skipping 18 matching lines...) Expand all Loading... |
201 module frob.mojom; | 201 module frob.mojom; |
202 | 202 |
203 interface Frobinator { | 203 interface Frobinator { |
204 Frobinate(); | 204 Frobinate(); |
205 GetFrobinationLevels() => (int min, int max); | 205 GetFrobinationLevels() => (int min, int max); |
206 }; | 206 }; |
207 ``` | 207 ``` |
208 | 208 |
209 and update our implementation: | 209 and update our implementation: |
210 | 210 |
211 ``` | 211 ```cpp |
212 class FrobinatorImpl : public mojom::Frobinator { | 212 class FrobinatorImpl : public mojom::Frobinator { |
213 public: | 213 public: |
214 // ... | 214 // ... |
215 | 215 |
216 // mojom::Frobinator: | 216 // mojom::Frobinator: |
217 void Frobinate() override { /* ... */ } | 217 void Frobinate() override { /* ... */ } |
218 void GetFrobinationLevels(const GetFrobinationLevelsCallback& callback) { | 218 void GetFrobinationLevels(const GetFrobinationLevelsCallback& callback) { |
219 callback.Run(1, 42); | 219 callback.Run(1, 42); |
220 } | 220 } |
221 }; | 221 }; |
222 ``` | 222 ``` |
223 | 223 |
224 When the service implementation runs `callback`, the response arguments are | 224 When the service implementation runs `callback`, the response arguments are |
225 serialized and sent back over the pipe. The proxy on the other end knows how to | 225 serialized and sent back over the pipe. The proxy on the other end knows how to |
226 read this response and will in turn dispatch it to a callback on that end: | 226 read this response and will in turn dispatch it to a callback on that end: |
227 | 227 |
228 ``` | 228 ```cpp |
229 void ShowLevels(int min, int max) { | 229 void ShowLevels(int min, int max) { |
230 DLOG(INFO) << "Frobinator min=" << min << " max=" << max; | 230 DLOG(INFO) << "Frobinator min=" << min << " max=" << max; |
231 } | 231 } |
232 | 232 |
233 // ... | 233 // ... |
234 | 234 |
235 mojom::FrobinatorPtr frobinator; | 235 mojom::FrobinatorPtr frobinator; |
236 FrobinatorImpl impl(GetProxy(&frobinator)); | 236 FrobinatorImpl impl(GetProxy(&frobinator)); |
237 | 237 |
238 frobinator->GetFrobinatorLevels(base::Bind(&ShowLevels)); | 238 frobinator->GetFrobinatorLevels(base::Bind(&ShowLevels)); |
(...skipping 16 matching lines...) Expand all Loading... |
255 just a mapping from interface name to factory function -- or you can connect by | 255 just a mapping from interface name to factory function -- or you can connect by |
256 name to services registered on the remote side. | 256 name to services registered on the remote side. |
257 | 257 |
258 **NOTE:** In this context the "factory function" is simply a callback which | 258 **NOTE:** In this context the "factory function" is simply a callback which |
259 takes a pipe endpoint and does something with it. It's expected that you'll | 259 takes a pipe endpoint and does something with it. It's expected that you'll |
260 either bind it to a service implementation of some kind or you will close it, ef
fectively rejecting the connection request. | 260 either bind it to a service implementation of some kind or you will close it, ef
fectively rejecting the connection request. |
261 | 261 |
262 We can build a simple browser-side `FrobinatorImpl` service that has access to a | 262 We can build a simple browser-side `FrobinatorImpl` service that has access to a |
263 `BrowserContext` for any frame which connects to it: | 263 `BrowserContext` for any frame which connects to it: |
264 | 264 |
265 ``` | 265 ```cpp |
266 #include "base/macros.h" | 266 #include "base/macros.h" |
267 #include "components/frob/public/interfaces/frobinator.mojom.h" | 267 #include "components/frob/public/interfaces/frobinator.mojom.h" |
268 #include "content/public/browser/browser_context.h" | 268 #include "content/public/browser/browser_context.h" |
269 #include "mojo/public/cpp/system/interface_request.h" | 269 #include "mojo/public/cpp/system/interface_request.h" |
270 #include "mojo/public/cpp/system/strong_binding.h" | 270 #include "mojo/public/cpp/system/strong_binding.h" |
271 | 271 |
272 namespace frob { | 272 namespace frob { |
273 | 273 |
274 class FrobinatorImpl : public mojom::Frobinator { | 274 class FrobinatorImpl : public mojom::Frobinator { |
275 public: | 275 public: |
(...skipping 22 matching lines...) Expand all Loading... |
298 | 298 |
299 DISALLOW_COPY_AND_ASSIGN(FrobinatorImpl); | 299 DISALLOW_COPY_AND_ASSIGN(FrobinatorImpl); |
300 }; | 300 }; |
301 | 301 |
302 } // namespace frob | 302 } // namespace frob |
303 ``` | 303 ``` |
304 | 304 |
305 Now somewhere in the browser we register the Frobinator service with each | 305 Now somewhere in the browser we register the Frobinator service with each |
306 `RenderFrameHost` ([this](https://goo.gl/HEFn63) is a popular spot): | 306 `RenderFrameHost` ([this](https://goo.gl/HEFn63) is a popular spot): |
307 | 307 |
308 ``` | 308 ```cpp |
309 frame_host->GetServiceRegistry()->AddService<frob::mojom::Frobinator>( | 309 frame_host->GetServiceRegistry()->AddService<frob::mojom::Frobinator>( |
310 base::Bind( | 310 base::Bind( |
311 &frob::FrobinatorImpl::Create, | 311 &frob::FrobinatorImpl::Create, |
312 base::Unretained(frame_host->GetProcess()->GetBrowserContext()))); | 312 base::Unretained(frame_host->GetProcess()->GetBrowserContext()))); |
313 ``` | 313 ``` |
314 | 314 |
315 And in the render process we can now do something like: | 315 And in the render process we can now do something like: |
316 | 316 |
317 ``` | 317 ```cpp |
318 mojom::FrobinatorPtr frobinator; | 318 mojom::FrobinatorPtr frobinator; |
319 render_frame->GetServiceRegistry()->ConnectToRemoteService( | 319 render_frame->GetServiceRegistry()->ConnectToRemoteService( |
320 mojo::GetProxy(&frobinator)); | 320 mojo::GetProxy(&frobinator)); |
321 | 321 |
322 // It's IPC! | 322 // It's IPC! |
323 frobinator->Frobinate(); | 323 frobinator->Frobinate(); |
324 ``` | 324 ``` |
325 | 325 |
326 There are now plenty of concrete examples of Mojo usage in the Chromium tree. | 326 There are now plenty of concrete examples of Mojo usage in the Chromium tree. |
327 Poke around at existing mojom files and see how their implementions are built | 327 Poke around at existing mojom files and see how their implementions are built |
328 and connected. | 328 and connected. |
329 | 329 |
330 ## Mojo in Blink | 330 ## Mojo in Blink |
331 | 331 |
332 *TODO* | 332 *TODO* |
333 | 333 |
334 This is a work in progress. TL;DR: We'll also soon begin using Mojo services | 334 This is a work in progress. TL;DR: We'll also soon begin using Mojo services |
335 from Blink so that the platform layer can consume browser services | 335 from Blink so that the platform layer can consume browser services |
336 directly via Mojo. The long-term goal there is to eliminate `content/renderer`. | 336 directly via Mojo. The long-term goal there is to eliminate `content/renderer`. |
337 | 337 |
338 ## Questions, Discussion, etc. | 338 ## Questions, Discussion, etc. |
339 | 339 |
340 A good place to find highly concentrated doses of people who know and care | 340 A good place to find highly concentrated doses of people who know and care |
341 about Mojo in Chromium would be the [chromium-mojo](https://goo.gl/A4ebWB) | 341 about Mojo in Chromium would be the [chromium-mojo](https://goo.gl/A4ebWB) |
342 mailing list[.](https://goo.gl/L70ihQ) | 342 mailing list[.](https://goo.gl/L70ihQ) |
OLD | NEW |