| 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 |