Ken Rockot | ab03512 | 2019-02-06 00:35:24 | [diff] [blame] | 1 | # Intro to Mojo & Services |
| 2 | |
| 3 | [TOC] |
| 4 | |
| 5 | ## Overview |
| 6 | |
| 7 | This document contains the minimum amount of information needed for a developer |
| 8 | to start using Mojo effectively in Chromium, with example Mojo interface usage, |
| 9 | service definition and hookup, and a brief overview of the Content layer's core |
| 10 | services. |
| 11 | |
| 12 | See other [Mojo & Services](/docs/README.md#Mojo-Services) documentation |
| 13 | for introductory guides, API references, and more. |
| 14 | |
| 15 | ## Mojo Terminology |
| 16 | |
| 17 | A **message pipe** is a pair of **endpoints**. Each endpoint has a queue of |
| 18 | incoming messages, and writing a message at one endpoint effectively enqueues |
| 19 | that message on the other (**peer**) endpoint. Message pipes are thus |
| 20 | bidirectional. |
| 21 | |
| 22 | A **mojom** file describes **interfaces**, which are strongly-typed collections |
| 23 | of **messages**. Each interface message is roughly analogous to a single proto |
| 24 | message, for developers who are familiar with Google protobufs. |
| 25 | |
| 26 | Given a mojom interface and a message pipe, one of the endpoints |
Darwin Huang | b4bd245 | 2019-10-08 22:56:04 | [diff] [blame^] | 27 | can be designated as a **`Remote`** and is used to *send* messages described by |
| 28 | the interface. The other endpoint can be designated as a **`Receiver`** and is used |
Ken Rockot | ab03512 | 2019-02-06 00:35:24 | [diff] [blame] | 29 | to *receive* interface messages. |
| 30 | |
| 31 | *** aside |
| 32 | NOTE: The above generalization is a bit oversimplified. Remember that the |
| 33 | message pipe is still bidirectional, and it's possible for a mojom message to |
Darwin Huang | b4bd245 | 2019-10-08 22:56:04 | [diff] [blame^] | 34 | expect a reply. Replies are sent from the `Receiver` endpoint and received by the |
| 35 | `Remote` endpoint. |
Ken Rockot | ab03512 | 2019-02-06 00:35:24 | [diff] [blame] | 36 | *** |
| 37 | |
Darwin Huang | b4bd245 | 2019-10-08 22:56:04 | [diff] [blame^] | 38 | The `Receiver` endpoint must be associated with (*i.e.* **bound** to) an |
Ken Rockot | ab03512 | 2019-02-06 00:35:24 | [diff] [blame] | 39 | **implementation** of its mojom interface in order to process received messages. |
| 40 | A received message is dispatched as a scheduled task invoking the corresponding |
| 41 | interface method on the implementation object. |
| 42 | |
Darwin Huang | b4bd245 | 2019-10-08 22:56:04 | [diff] [blame^] | 43 | Another way to think about all this is simply that **a `Remote` makes |
Ken Rockot | ab03512 | 2019-02-06 00:35:24 | [diff] [blame] | 44 | calls on a remote implementation of its interface associated with a |
Darwin Huang | b4bd245 | 2019-10-08 22:56:04 | [diff] [blame^] | 45 | corresponding remote `Receiver`.** |
Ken Rockot | ab03512 | 2019-02-06 00:35:24 | [diff] [blame] | 46 | |
| 47 | ## Example: Defining a New Frame Interface |
| 48 | |
| 49 | Let's apply this to Chrome. Suppose we want to send a "Ping" message from a |
| 50 | render frame to its corresponding `RenderFrameHostImpl` instance in the browser |
| 51 | process. We need to define a nice mojom interface for this purpose, create a |
| 52 | pipe to use that interface, and then plumb one end of the pipe to the right |
| 53 | place so the sent messages can be received and processed there. This section |
| 54 | goes through that process in detail. |
| 55 | |
| 56 | ### Defining the Interface |
| 57 | |
| 58 | The first step involves creating a new `.mojom` file with an interface |
| 59 | definition, like so: |
| 60 | |
| 61 | ``` cpp |
| 62 | // src/example/public/mojom/ping_responder.mojom |
| 63 | module example.mojom; |
| 64 | |
| 65 | interface PingResponder { |
| 66 | // Receives a "Ping" and responds with a random integer. |
Ken Rockot | a0cb6cf9 | 2019-03-26 16:40:42 | [diff] [blame] | 67 | Ping() => (int32 random); |
Ken Rockot | ab03512 | 2019-02-06 00:35:24 | [diff] [blame] | 68 | }; |
| 69 | ``` |
| 70 | |
| 71 | This should have a corresponding build rule to generate C++ bindings for the |
| 72 | definition here: |
| 73 | |
| 74 | ``` python |
| 75 | # src/example/public/mojom/BUILD.gn |
Ken Rockot | a0cb6cf9 | 2019-03-26 16:40:42 | [diff] [blame] | 76 | import("//mojo/public/tools/bindings/mojom.gni") |
Ken Rockot | ab03512 | 2019-02-06 00:35:24 | [diff] [blame] | 77 | mojom("mojom") { |
| 78 | sources = [ "ping_responder.mojom" ] |
| 79 | } |
| 80 | ``` |
| 81 | |
| 82 | ### Creating the Pipe |
| 83 | |
| 84 | Now let's create a message pipe to use this interface. |
| 85 | |
| 86 | *** aside |
| 87 | As a general rule and as a matter of convenience when |
Darwin Huang | b4bd245 | 2019-10-08 22:56:04 | [diff] [blame^] | 88 | using Mojo, the *client* of an interface (*i.e.* the `Remote` side) is |
Ken Rockot | ab03512 | 2019-02-06 00:35:24 | [diff] [blame] | 89 | typically the party who creates a new pipe. This is convenient because the |
Darwin Huang | b4bd245 | 2019-10-08 22:56:04 | [diff] [blame^] | 90 | `Remote` may be used to start sending messages immediately without waiting |
Ken Rockot | ab03512 | 2019-02-06 00:35:24 | [diff] [blame] | 91 | for the InterfaceRequest endpoint to be transferred or bound anywhere. |
| 92 | *** |
| 93 | |
| 94 | This code would be placed somewhere in the renderer: |
| 95 | |
| 96 | ```cpp |
Darwin Huang | b4bd245 | 2019-10-08 22:56:04 | [diff] [blame^] | 97 | // src/third_party/blink/example/public/ping_responder.h |
Oksana Zhuravlova | 9f3b8ef | 2019-08-26 20:27:40 | [diff] [blame] | 98 | mojo::Remote<example::mojom::PingResponder> ping_responder; |
| 99 | mojo::PendingReceiver<example::mojom::PingResponder> receiver = |
| 100 | ping_responder.BindNewPipeAndPassReceiver(); |
Ken Rockot | ab03512 | 2019-02-06 00:35:24 | [diff] [blame] | 101 | ``` |
| 102 | |
Darwin Huang | b4bd245 | 2019-10-08 22:56:04 | [diff] [blame^] | 103 | In this example, ```ping_responder``` is the `Remote`, and ```receiver``` |
| 104 | is a `PendingReceiver`, which is a `Receiver` precursor that will eventually |
| 105 | be turned into a `Receiver`. `BindNewPipeAndPassReceiver` is the most common way to create |
Oksana Zhuravlova | 9f3b8ef | 2019-08-26 20:27:40 | [diff] [blame] | 106 | a message pipe: it yields the `PendingReceiver` as the return |
Ken Rockot | ab03512 | 2019-02-06 00:35:24 | [diff] [blame] | 107 | value. |
| 108 | |
| 109 | *** aside |
Darwin Huang | b4bd245 | 2019-10-08 22:56:04 | [diff] [blame^] | 110 | NOTE: A `PendingReceiver` doesn't actually **do** anything. It is an |
Ken Rockot | ab03512 | 2019-02-06 00:35:24 | [diff] [blame] | 111 | inert holder of a single message pipe endpoint. It exists only to make its |
| 112 | endpoint more strongly-typed at compile-time, indicating that the endpoint |
Darwin Huang | b4bd245 | 2019-10-08 22:56:04 | [diff] [blame^] | 113 | expects to be bound by a `Receiver` of the same interface type. |
Ken Rockot | ab03512 | 2019-02-06 00:35:24 | [diff] [blame] | 114 | *** |
| 115 | |
| 116 | ### Sending a Message |
| 117 | |
Darwin Huang | b4bd245 | 2019-10-08 22:56:04 | [diff] [blame^] | 118 | Finally, we can call the `Ping()` method on our `Remote` to send a message: |
Ken Rockot | ab03512 | 2019-02-06 00:35:24 | [diff] [blame] | 119 | |
| 120 | ```cpp |
Darwin Huang | b4bd245 | 2019-10-08 22:56:04 | [diff] [blame^] | 121 | // src/third_party/blink/example/public/ping_responder.h |
Ken Rockot | ab03512 | 2019-02-06 00:35:24 | [diff] [blame] | 122 | ping_responder->Ping(base::BindOnce(&OnPong)); |
| 123 | ``` |
| 124 | |
| 125 | *** aside |
Darwin Huang | b4bd245 | 2019-10-08 22:56:04 | [diff] [blame^] | 126 | **IMPORTANT:** If we want to receive the response, we must keep the |
Ken Rockot | ab03512 | 2019-02-06 00:35:24 | [diff] [blame] | 127 | `ping_responder` object alive until `OnPong` is invoked. After all, |
| 128 | `ping_responder` *owns* its message pipe endpoint. If it's destroyed then so is |
| 129 | the endpoint, and there will be nothing to receive the response message. |
| 130 | *** |
| 131 | |
| 132 | We're almost done! Of course, if everything were this easy, this document |
| 133 | wouldn't need to exist. We've taken the hard problem of sending a message from |
| 134 | a renderer process to the browser process, and transformed it into a problem |
Oksana Zhuravlova | 9f3b8ef | 2019-08-26 20:27:40 | [diff] [blame] | 135 | where we just need to take the `receiver` object from above and pass it to the |
Darwin Huang | b4bd245 | 2019-10-08 22:56:04 | [diff] [blame^] | 136 | browser process somehow where it can be turned into a `Receiver` that dispatches |
Ken Rockot | ab03512 | 2019-02-06 00:35:24 | [diff] [blame] | 137 | its received messages. |
| 138 | |
Darwin Huang | b4bd245 | 2019-10-08 22:56:04 | [diff] [blame^] | 139 | ### Sending a `PendingReceiver` to the Browser |
Ken Rockot | ab03512 | 2019-02-06 00:35:24 | [diff] [blame] | 140 | |
Darwin Huang | b4bd245 | 2019-10-08 22:56:04 | [diff] [blame^] | 141 | It's worth noting that `PendingReceiver`s (and message pipe endpoints in general) |
Ken Rockot | ab03512 | 2019-02-06 00:35:24 | [diff] [blame] | 142 | are just another type of object that can be freely sent over mojom messages. |
Darwin Huang | b4bd245 | 2019-10-08 22:56:04 | [diff] [blame^] | 143 | The most common way to get a `PendingReceiver` somewhere is to pass it as a |
Ken Rockot | ab03512 | 2019-02-06 00:35:24 | [diff] [blame] | 144 | method argument on some other already-connected interface. |
| 145 | |
| 146 | One such interface which we always have connected between a renderer's |
| 147 | `RenderFrameImpl` and its corresponding `RenderFrameHostImpl` in the browser |
| 148 | is |
Oksana Zhuravlova | 9f3b8ef | 2019-08-26 20:27:40 | [diff] [blame] | 149 | [`BrowserInterfaceBroker`](https://cs.chromium.org/chromium/src/third_party/blink/public/mojom/browser_interface_broker.mojom). |
| 150 | This interface is a factory for acquiring other interfaces. Its `GetInterface` |
| 151 | method takes a `GenericPendingReceiver`, which allows passing arbitrary |
| 152 | interface receivers. |
Ken Rockot | ab03512 | 2019-02-06 00:35:24 | [diff] [blame] | 153 | |
| 154 | ``` cpp |
Oksana Zhuravlova | 9f3b8ef | 2019-08-26 20:27:40 | [diff] [blame] | 155 | interface BrowserInterfaceBroker { |
| 156 | GetInterface(mojo_base.mojom.GenericPendingReceiver receiver); |
Ken Rockot | ab03512 | 2019-02-06 00:35:24 | [diff] [blame] | 157 | } |
| 158 | ``` |
Oksana Zhuravlova | 9f3b8ef | 2019-08-26 20:27:40 | [diff] [blame] | 159 | Since `GenericPendingReceiver` can be implicitly constructed from any specific |
Darwin Huang | b4bd245 | 2019-10-08 22:56:04 | [diff] [blame^] | 160 | `PendingReceiver`, it can call this method with the `receiver` object it created |
Oksana Zhuravlova | 9f3b8ef | 2019-08-26 20:27:40 | [diff] [blame] | 161 | earlier via `BindNewPipeAndPassReceiver`: |
Ken Rockot | ab03512 | 2019-02-06 00:35:24 | [diff] [blame] | 162 | |
| 163 | ``` cpp |
| 164 | RenderFrame* my_frame = GetMyFrame(); |
Oksana Zhuravlova | 9f3b8ef | 2019-08-26 20:27:40 | [diff] [blame] | 165 | my_frame->GetBrowserInterfaceBrokerProxy()->GetInterface(std::move(receiver)); |
Ken Rockot | ab03512 | 2019-02-06 00:35:24 | [diff] [blame] | 166 | ``` |
| 167 | |
Darwin Huang | b4bd245 | 2019-10-08 22:56:04 | [diff] [blame^] | 168 | This will transfer the `PendingReceiver` endpoint to the browser process |
Oksana Zhuravlova | 9f3b8ef | 2019-08-26 20:27:40 | [diff] [blame] | 169 | where it will be received by the corresponding `BrowserInterfaceBroker` |
Ken Rockot | ab03512 | 2019-02-06 00:35:24 | [diff] [blame] | 170 | implementation. More on that below. |
| 171 | |
| 172 | ### Implementing the Interface |
| 173 | |
Oksana Zhuravlova | 9f3b8ef | 2019-08-26 20:27:40 | [diff] [blame] | 174 | Finally, we need a browser-side implementation of our `PingResponder` interface. |
Ken Rockot | ab03512 | 2019-02-06 00:35:24 | [diff] [blame] | 175 | |
| 176 | ```cpp |
| 177 | #include "example/public/mojom/ping_responder.mojom.h" |
| 178 | |
| 179 | class PingResponderImpl : example::mojom::PingResponder { |
| 180 | public: |
Oksana Zhuravlova | 9f3b8ef | 2019-08-26 20:27:40 | [diff] [blame] | 181 | explicit PingResponderImpl(mojo::PendingReceiver<example::mojom::PingResponder> receiver) |
| 182 | : receiver_(this, std::move(receiver)) {} |
Ken Rockot | ab03512 | 2019-02-06 00:35:24 | [diff] [blame] | 183 | |
| 184 | // example::mojom::PingResponder: |
| 185 | void Ping(PingCallback callback) override { |
| 186 | // Respond with a random 4, chosen by fair dice roll. |
| 187 | std::move(callback).Run(4); |
| 188 | } |
| 189 | |
| 190 | private: |
Charlie Hu | d4c0fe8 | 2019-10-08 19:48:13 | [diff] [blame] | 191 | mojo::Receiver<example::mojom::PingResponder> receiver_; |
Ken Rockot | ab03512 | 2019-02-06 00:35:24 | [diff] [blame] | 192 | |
| 193 | DISALLOW_COPY_AND_ASSIGN(PingResponderImpl); |
| 194 | }; |
| 195 | ``` |
| 196 | |
Oksana Zhuravlova | 9f3b8ef | 2019-08-26 20:27:40 | [diff] [blame] | 197 | `RenderFrameHostImpl` owns an implementation of `BrowserInterfaceBroker`. |
| 198 | When this implementation receives a `GetInterface` method call, it calls |
| 199 | the handler previously registered for this specific interface. |
Ken Rockot | ab03512 | 2019-02-06 00:35:24 | [diff] [blame] | 200 | |
| 201 | ``` cpp |
| 202 | // render_frame_host_impl.h |
| 203 | class RenderFrameHostImpl |
| 204 | ... |
Oksana Zhuravlova | 9f3b8ef | 2019-08-26 20:27:40 | [diff] [blame] | 205 | void GetPingResponder(mojo::PendingReceiver<example::mojom::PingResponder> receiver); |
Ken Rockot | ab03512 | 2019-02-06 00:35:24 | [diff] [blame] | 206 | ... |
| 207 | private: |
| 208 | ... |
| 209 | std::unique_ptr<PingResponderImpl> ping_responder_; |
| 210 | ... |
| 211 | }; |
| 212 | |
| 213 | // render_frame_host_impl.cc |
| 214 | void RenderFrameHostImpl::GetPingResponder( |
Oksana Zhuravlova | 9f3b8ef | 2019-08-26 20:27:40 | [diff] [blame] | 215 | mojo::PendingReceiver<example::mojom::PingResponder> receiver) { |
| 216 | ping_responder_ = std::make_unique<PingResponderImpl>(std::move(receiver)); |
| 217 | } |
| 218 | |
| 219 | // browser_interface_binders.cc |
| 220 | void PopulateFrameBinders(RenderFrameHostImpl* host, |
| 221 | service_manager::BinderMap* map) { |
| 222 | ... |
| 223 | // Register the handler for PingResponder. |
| 224 | map->Add<example::mojom::PingResponder>(base::BindRepeating( |
| 225 | &RenderFrameHostImpl::GetPingResponder, base::Unretained(host))); |
Ken Rockot | ab03512 | 2019-02-06 00:35:24 | [diff] [blame] | 226 | } |
| 227 | ``` |
| 228 | |
| 229 | And we're done. This setup is sufficient to plumb a new interface connection |
| 230 | between a renderer frame and its browser-side host object! |
| 231 | |
| 232 | Assuming we kept our `ping_responder` object alive in the renderer long enough, |
| 233 | we would eventually see its `OnPong` callback invoked with the totally random |
| 234 | value of `4`, as defined by the browser-side implementation above. |
| 235 | |
| 236 | ## Services Overview & Terminology |
| 237 | The previous section only scratches the surface of how Mojo IPC is used in |
| 238 | Chromium. While renderer-to-browser messaging is simple and possibly the most |
| 239 | prevalent usage by sheer code volume, we are incrementally decomposing the |
| 240 | codebase into a set of services with a bit more granularity than the traditional |
| 241 | Content browser/renderer/gpu/utility process split. |
| 242 | |
| 243 | A **service** is a self-contained library of code which implements one or more |
| 244 | related features or behaviors and whose interaction with outside code is done |
| 245 | *exclusively* through Mojo interface connections facilitated by the **Service |
| 246 | Manager.** |
| 247 | |
| 248 | The **Service Manager** is a component which can run in a dedicated process |
| 249 | or embedded within another process. Only one Service Manager exists globally |
| 250 | across the system, and in Chromium the browser process runs an embedded Service |
| 251 | Manager instance immediately on startup. The Service Manager spawns |
| 252 | **service instances** on-demand, and it routes each interface request from a |
| 253 | service instance to some destination instance of the Service Manager's choosing. |
| 254 | |
| 255 | Each service instance implements the |
| 256 | [**`Service`**](https://cs.chromium.org/chromium/src/services/service_manager/public/cpp/service.h) |
| 257 | interface to receive incoming interface requests brokered by the Service |
| 258 | Manager, and each service instance has a |
| 259 | [**`Connector`**](https://cs.chromium.org/chromium/src/services/service_manager/public/cpp/connector.h) |
| 260 | it can use to issue interface requests to other services via the |
| 261 | Service Manager. |
| 262 | |
| 263 | Every service has a **manifest** which declares some static metadata about the |
| 264 | service. This metadata is used by the Service Manager for various purposes, |
| 265 | including as a declaration of what interfaces are exposed to other services in |
| 266 | the system. This eases the security review process. |
| 267 | |
| 268 | Inside its manifest every service declares its **service name**, used to |
| 269 | identify instances of the service in the most general sense. Names are free-form |
| 270 | and usually short strings which must be globally unique. Some services defined |
| 271 | in Chromium today include `"device"`, `"identity"`, and `"network"` services. |
| 272 | |
| 273 | For more complete and in-depth coverage of the concepts covered here and other |
| 274 | related APIs, see the |
| 275 | [Service Manager documentation](/services/service_manager/README.md). |
| 276 | |
| 277 | ## Example: Building a Simple Out-of-Process Service |
| 278 | |
| 279 | There are multiple steps required to get a new service up and running in |
| 280 | Chromium. You must: |
| 281 | |
| 282 | - Define the `Service` implementation |
| 283 | - Define the service's manifest |
| 284 | - Tell Chromium's Service Manager about the manifest |
| 285 | - Tell Chromium how to instantiate the `Service` implementation when it's needed |
| 286 | |
| 287 | This section walks through these steps with some brief explanations. For more |
| 288 | thorough documentation of the concepts and APIs used herein, see the |
| 289 | [Service Manager](/services/service_manager/README.md) and |
| 290 | [Mojo](/mojo/README.md) documentation. |
| 291 | |
| 292 | ### Defining the Service |
| 293 | |
| 294 | Typically service definitions are placed in a `services` directory, either at |
| 295 | the top level of the tree or within some subdirectory. In this example, we'll |
| 296 | define a new service for use by Chrome specifically, so we'll define it within |
| 297 | `//chrome/services`. |
| 298 | |
| 299 | We can create the following files. First some mojoms: |
| 300 | |
| 301 | ``` cpp |
| 302 | // src/chrome/services/math/public/mojom/constants.mojom |
| 303 | module math.mojom; |
| 304 | |
| 305 | // These are not used by the implementation directly, but will be used in |
| 306 | // following sections. |
| 307 | const string kServiceName = "math"; |
| 308 | const string kArithmeticCapability = "arithmetic"; |
| 309 | ``` |
| 310 | |
| 311 | ``` cpp |
| 312 | // src/chrome/services/math/public/mojom/divider.mojom |
| 313 | module math.mojom; |
| 314 | |
| 315 | interface Divider { |
| 316 | Divide(int32 dividend, int32 divisor) => (int32 quotient); |
| 317 | }; |
| 318 | ``` |
| 319 | |
| 320 | ``` python |
| 321 | # src/chrome/services/math/public/mojom/BUILD.gn |
Ken Rockot | a0cb6cf9 | 2019-03-26 16:40:42 | [diff] [blame] | 322 | import("//mojo/public/tools/bindings/mojom.gni") |
Ken Rockot | ab03512 | 2019-02-06 00:35:24 | [diff] [blame] | 323 | |
| 324 | mojom("mojom") { |
| 325 | sources = [ |
| 326 | "constants.mojom", |
| 327 | "divider.mojom", |
| 328 | ] |
| 329 | } |
| 330 | ``` |
| 331 | |
| 332 | Then the actual `Service` implementation: |
| 333 | |
| 334 | ``` cpp |
| 335 | // src/chrome/services/math/math_service.h |
| 336 | #include "services/service_manager/public/cpp/service.h" |
| 337 | |
| 338 | #include "base/macros.h" |
| 339 | #include "chrome/services/math/public/mojom/divider.mojom.h" |
| 340 | |
| 341 | namespace math { |
| 342 | |
| 343 | class MathService : public service_manager::Service, |
| 344 | public mojom::Divider { |
| 345 | public: |
| 346 | explicit MathService(service_manager::mojom::ServiceRequest request); |
| 347 | ~MathService() override; |
| 348 | |
| 349 | private: |
| 350 | // service_manager::Service: |
| 351 | void OnBindInterface(const service_manager::BindSourceInfo& source, |
| 352 | const std::string& interface_name, |
| 353 | mojo::ScopedMessagePipeHandle interface_pipe) override; |
| 354 | |
| 355 | // mojom::Divider: |
| 356 | void Divide(int32_t dividend, |
| 357 | int32_t divisor, |
| 358 | DivideCallback callback) override; |
| 359 | |
| 360 | service_manager::ServiceBinding service_binding_; |
| 361 | |
Oksana Zhuravlova | 9f3b8ef | 2019-08-26 20:27:40 | [diff] [blame] | 362 | // You could also use a Receiver. We use ReceiverSet to conveniently allow |
Ken Rockot | ab03512 | 2019-02-06 00:35:24 | [diff] [blame] | 363 | // multiple clients to bind to the same instance of this class. See Mojo |
| 364 | // C++ Bindings documentation for more information. |
Oksana Zhuravlova | 9f3b8ef | 2019-08-26 20:27:40 | [diff] [blame] | 365 | mojo::ReceiverSet<mojom::Divider> divider_receivers_; |
Ken Rockot | ab03512 | 2019-02-06 00:35:24 | [diff] [blame] | 366 | |
| 367 | DISALLOW_COPY_AND_ASSIGN(MathService); |
| 368 | }; |
| 369 | |
| 370 | } // namespace math |
| 371 | ``` |
| 372 | |
| 373 | ``` cpp |
| 374 | // src/chrome/services/math/math_service.cc |
| 375 | #include "chrome/services/math/math_service.h" |
| 376 | |
| 377 | namespace math { |
| 378 | |
| 379 | MathService::MathService(service_manager::ServiceRequest request) |
| 380 | : service_binding_(this, std::move(request)) {} |
| 381 | |
| 382 | MathService::~MathService() = default; |
| 383 | |
| 384 | void MathService::OnBindInterface( |
| 385 | const service_manager::BindSourceInfo& source, |
| 386 | const std::string& interface_name, |
| 387 | mojo::ScopedMessagePipeHandle interface_pipe) { |
| 388 | // Note that services typically use a service_manager::BinderRegistry if they |
| 389 | // plan on handling many different interface request types. |
| 390 | if (interface_name == mojom::Divider::Name_) { |
Oksana Zhuravlova | 9f3b8ef | 2019-08-26 20:27:40 | [diff] [blame] | 391 | divider_receivers_.Add( |
| 392 | this, mojo::PendingReceiver<mojom::Divider>(std::move(interface_pipe))); |
Ken Rockot | ab03512 | 2019-02-06 00:35:24 | [diff] [blame] | 393 | } |
| 394 | } |
| 395 | |
| 396 | void MathService::Divide(int32_t dividend, |
| 397 | int32_t divisor, |
| 398 | DivideCallback callback) { |
| 399 | // Respond with the quotient! |
Oksana Zhuravlova | 0941c08d | 2019-05-03 20:46:33 | [diff] [blame] | 400 | std::move(callback).Run(dividend / divisor); |
Ken Rockot | ab03512 | 2019-02-06 00:35:24 | [diff] [blame] | 401 | } |
| 402 | |
| 403 | } // namespace math |
| 404 | ``` |
| 405 | |
| 406 | ``` python |
| 407 | # src/chrome/services/math/BUILD.gn |
| 408 | |
| 409 | source_set("math") { |
| 410 | sources = [ |
| 411 | "math.cc", |
| 412 | "math.h", |
| 413 | ] |
| 414 | |
| 415 | deps = [ |
| 416 | "//base", |
| 417 | "//chrome/services/math/public/mojom", |
| 418 | "//services/service_manager/public/cpp", |
| 419 | ] |
| 420 | } |
| 421 | ``` |
| 422 | |
| 423 | Now we have a fully defined `math` service implementation, including a nice |
| 424 | little `Divider` interface for clients to play with. Next we need to define the |
| 425 | service's manifest to declare how the service can be used. |
| 426 | |
| 427 | ### Defining the Manifest |
| 428 | Manifests are defined as |
| 429 | [`Manifest`](https://cs.chromium.org/chromium/src/services/service_manager/public/cpp/manifest.h) |
| 430 | objects, typically built using a |
| 431 | [`ManifestBuilder`](https://cs.chromium.org/chromium/src/services/service_manager/public/cpp/manifest_builder.h). As a general rule, services should define their manifest |
| 432 | in a dedicated `source_set` or `component` target under their `public/cpp` |
| 433 | subdirectory (typically referred to as the service's **C++ client library**). |
| 434 | |
| 435 | We can create the following files for this purpose: |
| 436 | |
| 437 | ``` cpp |
| 438 | // src/chrome/services/math/public/cpp/manifest.h |
| 439 | #include "services/service_manager/public/cpp/manifest.h" |
| 440 | |
| 441 | namespace math { |
| 442 | |
| 443 | const service_manager::Manifest& GetManifest(); |
| 444 | |
| 445 | } // namespace math |
| 446 | ``` |
| 447 | |
| 448 | ``` cpp |
| 449 | // src/chrome/services/math/public/cpp/manifest.cc |
| 450 | #include "chrome/services/math/public/cpp/manifest.h" |
| 451 | |
| 452 | #include "base/no_destructor.h" |
| 453 | #include "chrome/services/math/public/mojom/constants.mojom.h" |
| 454 | #include "chrome/services/math/public/mojom/divider.mojom.h" |
| 455 | #include "services/service_manager/public/cpp/manifest_builder.h" |
| 456 | |
| 457 | namespace math { |
| 458 | |
| 459 | const service_manager::Manifest& GetManifest() { |
| 460 | static base::NoDestructor<service_manager::Manifest> manifest{ |
| 461 | service_manager::ManifestBuilder() |
| 462 | .WithServiceName(mojom::kServiceName) |
| 463 | .ExposeCapability( |
| 464 | mojom::kArithmeticCapability, |
| 465 | service_manager::Manifest::InterfaceList<mojom::Divider>()) |
| 466 | .Build()}; |
| 467 | return *manifest |
| 468 | } |
| 469 | |
| 470 | } // namespace math |
| 471 | ``` |
| 472 | |
| 473 | We also need to define a build target for our manifest sources: |
| 474 | |
| 475 | ``` python |
| 476 | # src/chrome/services/math/public/cpp/BUILD.gn |
| 477 | |
| 478 | source_set("manifest") { |
| 479 | sources = [ |
| 480 | "manifest.cc", |
| 481 | "manifest.h", |
| 482 | ] |
| 483 | |
| 484 | deps = [ |
| 485 | "//base", |
| 486 | "//chrome/services/math/public/mojom", |
| 487 | "//services/service_manager/public/cpp", |
| 488 | ] |
| 489 | } |
| 490 | ``` |
| 491 | |
| 492 | The above `Manifest` definition declares that the service is named `math` and |
| 493 | that it **exposes** a single **capability** named `arithmetic` which allows |
| 494 | access to the `Divider` interface. |
| 495 | |
| 496 | Another service may **require** this capability from its own manifest in order |
| 497 | for the Service Manager to grant it access to a `Divider`. We'll see this a |
| 498 | few sections below. First, let's get the manifest and service implementation |
| 499 | registered with Chromium's Service Manager. |
| 500 | |
| 501 | ### Registering the Manifest |
| 502 | |
| 503 | For the most common out-of-process service cases, we register service manifests |
| 504 | by **packaging** them in Chrome. This can be done by augmenting the value |
| 505 | returned by |
| 506 | [`GetChromePackagedServiceManifests`](https://cs.chromium.org/chromium/src/chrome/app/chrome_packaged_service_manifests.cc?rcl=af43cabf3c01e28be437becb972a7eae44fd54e8&l=133). |
| 507 | |
| 508 | We can add our manifest there: |
| 509 | |
| 510 | ``` cpp |
| 511 | // Deep within src/chrome/app/chrome_packaged_service_manifests.cc... |
| 512 | const std::vector<service_manager::Manifest> |
| 513 | GetChromePackagedServiceManifests() { |
| 514 | ... |
| 515 | math::GetManifest(), |
| 516 | ... |
| 517 | ``` |
| 518 | |
| 519 | And don't forget to add a GN dependency from |
Oksana Zhuravlova | 0941c08d | 2019-05-03 20:46:33 | [diff] [blame] | 520 | [`//chrome/app:chrome_packaged_service_manifests`](https://cs.chromium.org/chromium/src/chrome/app/BUILD.gn?l=564&rcl=a77d5ba9c4621cfe14e7e1cd03bbae16904f269e) onto |
Ken Rockot | ab03512 | 2019-02-06 00:35:24 | [diff] [blame] | 521 | `//chrome/services/math/public/cpp:manifest`! |
| 522 | |
| 523 | We're almost done with service setup. The last step is to teach Chromium (and |
| 524 | thus the Service Manager) how to launch an instance of our beautiful `math` |
| 525 | service. |
| 526 | |
| 527 | ### Hooking Up the Service Implementation |
| 528 | |
| 529 | There are two parts to this for an out-of-process Chrome service. |
| 530 | |
| 531 | First, we need |
| 532 | to inform the embedded Service Manager that this service is an out-of-process |
| 533 | service. The goofiness of this part is a product of some legacy issues and it |
| 534 | should be eliminated soon, but for now it just means teaching the Service |
| 535 | Manager how to *label* the process it creates for this service (e.g. how the process will |
| 536 | appear in the system task manager). We modify |
| 537 | [`ChromeContentBrowserClient::RegisterOutOfProcessServices`](https://cs.chromium.org/chromium/src/chrome/browser/chrome_content_browser_client.cc?rcl=960886a7febcc2acccea7f797d3d5e03a344a12c&l=3766) |
| 538 | for this: |
| 539 | |
| 540 | ``` cpp |
| 541 | void ChromeContentBrowserClient::RegisterOutOfProcessServices( |
| 542 | OutOfProcessServicesMap* services) { |
| 543 | ... |
| 544 | |
| 545 | (*services)[math::mojom::kServiceName] = |
| 546 | base::BindRepeating([]() -> base::string16 { |
| 547 | return "Math Service"; |
| 548 | }); |
| 549 | |
| 550 | ... |
| 551 | } |
| 552 | ``` |
| 553 | |
| 554 | And finally, since nearly all out-of-process services run in a "utility" process |
| 555 | today, we need to add a dependency on our actual `Service` implementation to |
| 556 | Chrome's service spawning code within the utility process. |
| 557 | |
| 558 | For this step we just modify |
| 559 | [`ChromeContentUtilityClient::MaybeCreateMainThreadService`](https://cs.chromium.org/chromium/src/chrome/utility/chrome_content_utility_client.cc?rcl=7226adebd6e8d077d673a82acf1aab0790627178&l=261) |
| 560 | by adding a block of code as follows: |
| 561 | |
| 562 | ``` cpp |
Mohamed Heikal | a841c4f0 | 2019-06-10 19:50:40 | [diff] [blame] | 563 | std::unique_ptr<service_manager::Service> ChromeContentUtilityClient::MaybeCreateMainThreadService( |
Ken Rockot | ab03512 | 2019-02-06 00:35:24 | [diff] [blame] | 564 | const std::string& service_name, |
| 565 | service_manager::mojom::ServiceRequest request) { |
| 566 | ... |
| 567 | |
| 568 | if (service_name == math::mojom::kServiceName) |
| 569 | return std::make_unique<math::MathService>(std::move(request)); |
| 570 | |
| 571 | ... |
| 572 | } |
| 573 | ``` |
| 574 | |
| 575 | And we're done! |
| 576 | |
| 577 | As one nice follow-up step, let's use our math service from the browser. |
| 578 | |
| 579 | ### Using the Service |
| 580 | |
| 581 | We can grant the browser process access to our `Divider` interface by |
| 582 | **requiring** the `math` service's `arithmetic` capability within the |
| 583 | `content_browser` service manifest. |
| 584 | |
| 585 | *** aside |
| 586 | NOTE: See the following section for an elaboration on what `content_browser` is. |
| 587 | For the sake of this example, it's magic. |
| 588 | *** |
| 589 | |
| 590 | For Chrome-specific features such as our glorious new `math` service, we can |
| 591 | amend the `content_browser` manifest by modifying |
| 592 | [GetChromeContentBrowserOverlayManifest](https://cs.chromium.org/chromium/src/chrome/app/chrome_content_browser_overlay_manifest.cc?rcl=38db90321e8e3627b2f3165cdb051fa8d668af48&l=100) |
| 593 | as follows: |
| 594 | |
| 595 | ``` cpp |
| 596 | // src/chrome/app/chrome_content_browser_overlay_manifest.cc |
| 597 | |
| 598 | ... |
| 599 | const service_manager::Manifest& GetChromeContentBrowserOverlayManifest() { |
| 600 | ... |
| 601 | .RequireCapability(math::mojom::kServiceName, |
| 602 | math::mojom::kArithmeticCapability) |
| 603 | ... |
| 604 | } |
| 605 | ``` |
| 606 | |
| 607 | Finally, we can use the global `content_browser` instance's `Connector` to send |
| 608 | an interface request to our service. This is accessible from the main thread of |
| 609 | the browser process. Somewhere in `src/chrome/browser`, we can write: |
| 610 | |
| 611 | ``` cpp |
Ken Rockot | 70f4408 | 2019-06-20 21:47:38 | [diff] [blame] | 612 | // This gives us the system Connector for the browser process, which has access |
| 613 | // to most service interfaces. |
| 614 | service_manager::Connector* connector = content::GetSystemConnector(); |
Ken Rockot | ab03512 | 2019-02-06 00:35:24 | [diff] [blame] | 615 | |
| 616 | // Recall from the earlier Mojo section that mojo::MakeRequest creates a new |
| 617 | // message pipe for our interface. Connector passes the request endpoint to |
| 618 | // the Service Manager along with the name of our target service, "math". |
| 619 | math::mojom::DividerPtr divider; |
| 620 | connector->BindInterface(math::mojom::kServiceName, |
| 621 | mojo::MakeRequest(÷r)); |
| 622 | |
| 623 | // As a client, we do not have to wait for any acknowledgement or confirmation |
| 624 | // of a connection. We can start queueing messages immediately and they will be |
| 625 | // delivered as soon as the service is up and running. |
| 626 | divider->Divide( |
| 627 | 42, 6, base::BindOnce([](int32_t quotient) { LOG(INFO) << quotient; })); |
| 628 | ``` |
Oksana Zhuravlova | 0941c08d | 2019-05-03 20:46:33 | [diff] [blame] | 629 | *** aside |
| 630 | NOTE: To ensure the execution of the response callback, the DividerPtr |
| 631 | object must be kept alive (see |
| 632 | [this section](/mojo/public/cpp/bindings/README.md#A-Note-About-Endpoint-Lifetime-and-Callbacks) |
| 633 | and [this note from an earlier section](#sending-a-message)). |
| 634 | *** |
Ken Rockot | ab03512 | 2019-02-06 00:35:24 | [diff] [blame] | 635 | |
| 636 | This should successfully spawn a new process to run the `math` service if it's |
| 637 | not already running, then ask it to do a division, and ultimately log the result |
| 638 | after it's sent back to the browser process. |
| 639 | |
| 640 | Finally it's worth reiterating that every service instance in the system has |
| 641 | its own `Connector` and there's no reason we have to limit ourselves to |
| 642 | `content_browser` as the client, as long as the appropriate manifest declares |
| 643 | that it requires our `arithmetic` capability. |
| 644 | |
| 645 | If we did not update the `content_browser` manifest overlay as we did in this |
| 646 | example, the `Divide` call would never reach the `math` service (in fact the |
| 647 | service wouldn't even be started) and instead we'd get an error message (or in |
| 648 | developer builds, an assertion failure) informing us that the Service Manager |
| 649 | blocked the `BindInterface` call. |
| 650 | |
| 651 | ## Content-Layer Services Overview |
| 652 | |
| 653 | Apart from very early initialization steps in the browser process, every bit of |
| 654 | logic in Chromium today is effectively running as part of one service instance |
| 655 | or another. |
| 656 | |
| 657 | Although we continue to migrate parts of the browser's privileged |
| 658 | functionality to more granular services defined below the Content layer, the |
| 659 | main services defined in Chromium today continue to model the Content layer's |
| 660 | classical multiprocess architecture which defines a handful of |
| 661 | **process types**: browser, renderer, gpu, utility, and plugin processes. For |
| 662 | each of these process types, we now define corresponding services. |
| 663 | |
| 664 | Manifest definitions for all of the following services can be found in |
| 665 | `//content/public/app`. |
| 666 | |
| 667 | ### The Browser Service |
| 668 | |
| 669 | `content_browser` is defined to encapsulate general-purpose browser process |
| 670 | code. There are multiple instances of this service, all running within the |
| 671 | singular browser process. There is one shared global instance as well an |
| 672 | additional instance for each `BrowserContext` (*i.e.* per Chrome profile). |
| 673 | |
| 674 | The global instance exists primarily so that arbitrary browser process code can |
| 675 | reach various system services conveniently via a global `Connector` instance |
| 676 | on the main thread. |
| 677 | |
| 678 | Each instance associated with a `BrowserContext` is placed in an isolated |
| 679 | instance group specific to that `BrowserContext`. This limits the service |
| 680 | instances with which its `Connector` can make contact. These instances are |
| 681 | used primarily to facilitate the spawning of other isolated per-profile service |
| 682 | instances, such as renderers and plugins. |
| 683 | |
| 684 | ### The Renderer Service |
| 685 | |
| 686 | A `content_renderer` instance is spawned in its own sandboxed process for every |
| 687 | site-isolated instance of Blink we require. Instances are placed in the same |
| 688 | instance group as the renderer's corresponding `BrowserContext`, *i.e.* the |
| 689 | profile which navigated to the site being rendered. |
| 690 | |
| 691 | Most interfaces used by `content_renderer` are not brokered through the Service |
| 692 | Manager but instead are brokered through dedicated interfaces implemented by |
| 693 | `content_browser`, with which each renderer maintains persistent connections. |
| 694 | |
| 695 | ### The GPU Service |
| 696 | |
| 697 | Only a single instance of `content_gpu` exists at a time and it always runs in |
| 698 | its own isolated, sandboxed process. This service hosts the code in content/gpu |
| 699 | and whatever else Content's embedder adds to that for GPU support. |
| 700 | |
| 701 | ### The Plugin Service |
| 702 | |
| 703 | `content_plugin` hosts a plugin in an isolated process. Similarly to |
| 704 | `content_renderer` instances, each instance of `content_plugin` belongs to |
| 705 | an instance group associated with a specific `BrowserContext`, and in general |
| 706 | plugins get most of their functionality by talking directly to `content_browser` |
| 707 | rather than brokering interface requests through the Service Manager. |
| 708 | |
| 709 | ### The Utility Service |
| 710 | |
| 711 | `content_utility` exists only nominally today, as there is no remaining API |
| 712 | surface within Content which would allow a caller to explicitly create an |
| 713 | instance of it. Instead, this service is used exclusively to bootstrap new |
| 714 | isolated processes in which other services will run. |
| 715 | |
| 716 | ## Exposing Interfaces Between Content Processes |
| 717 | |
| 718 | Apart from the standard Service Manager APIs, the Content layer defines a number |
| 719 | of additional concepts for Content and its embedder to expose interfaces |
| 720 | specifically between Content processes in various contexts. |
| 721 | |
| 722 | ### Exposing Browser Interfaces to Renderer Documents and Workers |
| 723 | |
| 724 | Documents and workers are somewhat of a special case since interface access |
| 725 | decisions often require browser-centric state that the Service Manager cannot |
| 726 | know about, such as details of the current `BrowserContext`, the origin of the |
| 727 | renderered content, installed extensions in the renderer, *etc.* For this |
| 728 | reason, interface brokering decisions are increasingly being made by the |
| 729 | browser. |
| 730 | |
| 731 | There are two ways this is done: the Deprecated way and the New way. |
| 732 | |
| 733 | #### The Deprecated Way: InterfaceProvider |
| 734 | |
| 735 | This is built on the concept of **interface filters** and the |
| 736 | **`InterfaceProvider`** interface. It is **deprecated** and new features should |
| 737 | use [The New Way](#The-New-Way_Interface-Brokers) instead. This section only |
| 738 | briefly covers practical usage in Chromium. |
| 739 | |
| 740 | The `content_browser` manifest exposes capabilities on a few named interface |
| 741 | filters, the main one being `"navigation:frame"`. There are others scoped to |
| 742 | different worker contexts, *e.g.* `"navigation:service_worker"`. |
| 743 | `RenderProcessHostImpl` or `RenderFrameHostImpl` sets up an `InterfaceProvider` |
| 744 | for each known execution context in the corresponding renderer, filtered through |
| 745 | the Service Manager according to one of the named filters. |
| 746 | |
| 747 | The practical result of all this means the interface must be listed in the |
| 748 | `content_browser` manifest under the |
| 749 | `ExposeInterfaceFilterCapability_Deprecated("navigation:frame", "renderer", ...)` |
| 750 | entry, and a corresponding interface request handler must be registered with the |
| 751 | host's `registry_` in |
| 752 | [`RenderFrameHostImpl::RegisterMojoInterfaces`](https://cs.chromium.org/chromium/src/content/browser/frame_host/render_frame_host_impl.cc?rcl=0a23c78c57ecb2405837155aa0a0def7b5ba9c22&l=3971) |
| 753 | |
| 754 | Similarly for worker contexts, an interface must be exposed by the `"renderer"` |
| 755 | capability on the corresponding interface filter |
| 756 | (*e.g.*, `"navigation:shared_worker"`) and a request handler must be registered |
| 757 | within |
| 758 | [`RendererInterfaceBinders::InitializeParameterizedBinderRegistry`](https://cs.chromium.org/chromium/src/content/browser/renderer_interface_binders.cc?rcl=0a23c78c57ecb2405837155aa0a0def7b5ba9c22&l=116). |
| 759 | |
| 760 | The best way to understand all of this after reading this section is to look at |
| 761 | the linked code above and examine a few examples. They are fairly repetitive. |
| 762 | For additional convenience, here is also a link to the `content_browser` |
| 763 | [manifest](https://cs.chromium.org/chromium/src/content/public/app/content_browser_manifest.cc). |
| 764 | |
| 765 | #### The New Way: Interface Brokers |
| 766 | |
Ken Rockot | ab03512 | 2019-02-06 00:35:24 | [diff] [blame] | 767 | Rather than the confusing spaghetti of interface filter logic, we now define an |
| 768 | explicit mojom interface with a persistent connection between a renderer's |
| 769 | frame object and the corresponding `RenderFrameHostImpl` in the browser process. |
| 770 | This interface is called |
Oksana Zhuravlova | 9f3b8ef | 2019-08-26 20:27:40 | [diff] [blame] | 771 | [`BrowserInterfaceBroker`](https://cs.chromium.org/chromium/src/third_party/blink/public/mojom/browser_interface_broker.mojom?rcl=09aa5ae71649974cae8ad4f889d7cd093637ccdb&l=11) |
| 772 | and is fairly easy to work with: you add a new method on `RenderFrameHostImpl`: |
Ken Rockot | ab03512 | 2019-02-06 00:35:24 | [diff] [blame] | 773 | |
| 774 | ``` cpp |
| 775 | void RenderFrameHostImpl::GetGoatTeleporter( |
Oksana Zhuravlova | 9f3b8ef | 2019-08-26 20:27:40 | [diff] [blame] | 776 | mojo::PendingReceiver<magic::mojom::GoatTeleporter> receiver) { |
| 777 | goat_teleporter_receiver_.Bind(std::move(receiver)); |
Ken Rockot | ab03512 | 2019-02-06 00:35:24 | [diff] [blame] | 778 | } |
| 779 | ``` |
| 780 | |
Oksana Zhuravlova | 9f3b8ef | 2019-08-26 20:27:40 | [diff] [blame] | 781 | and register this method in `PopulateFrameBinders` function in `browser_interface_binders.cc`, |
| 782 | which maps specific interfaces to their handlers in respective hosts: |
| 783 | |
| 784 | ``` cpp |
| 785 | // //content/browser/browser_interface_binders.cc |
| 786 | void PopulateFrameBinders(RenderFrameHostImpl* host, |
| 787 | service_manager::BinderMap* map) { |
| 788 | ... |
| 789 | map->Add<magic::mojom::GoatTeleporter>(base::BindRepeating( |
| 790 | &RenderFrameHostImpl::GetGoatTeleporter, base::Unretained(host))); |
| 791 | } |
| 792 | ``` |
| 793 | |
| 794 | |
Ken Rockot | ab03512 | 2019-02-06 00:35:24 | [diff] [blame] | 795 | ### Exposing Browser Interfaces to Render Processes |
| 796 | |
| 797 | Sometimes (albeit rarely) it's useful to expose a browser interface directly to |
| 798 | a renderer process. This can be done as for any other interface exposed between |
| 799 | two services. In this specific instance, the `content_browser` manifest exposes |
| 800 | a capability named `"renderer"` which `content_renderer` requires. Any interface |
| 801 | listed as part of that capability can be accessed by a `content_renderer` |
| 802 | instance by using its own `Connector`. See below. |
| 803 | |
| 804 | ### Exposing Browser Interfaces to Content Child Processes |
| 805 | |
| 806 | All Content child process types (renderer, GPU, and plugin) share a common API |
| 807 | to interface with the Service Manager. Their Service Manager connection is |
| 808 | initialized and maintained by `ChildThreadImpl` on process startup, and from |
| 809 | the main thread, you can access the process's `Connector` as follows: |
| 810 | |
| 811 | ``` cpp |
| 812 | auto* connector = content::ChildThread::Get()->GetConnector(); |
| 813 | |
| 814 | // For example... |
Oksana Zhuravlova | 9f3b8ef | 2019-08-26 20:27:40 | [diff] [blame] | 815 | connector->Connect(content::mojom::kBrowserServiceName, |
| 816 | std::move(some_receiver)); |
Ken Rockot | ab03512 | 2019-02-06 00:35:24 | [diff] [blame] | 817 | ``` |
| 818 | |
| 819 | ### Exposing Content Child Process Interfaces to the Browser |
| 820 | |
| 821 | Content child processes may also expose interfaces to the browser, though this |
| 822 | is much less common and requires a fair bit of caution since the browser must be |
| 823 | careful to only call `Connector.BindInterface` in these cases with an exact |
| 824 | `service_manager::Identity` to avoid unexpected behavior. |
| 825 | |
| 826 | Every child process provides a subclass of ChildThreadImpl, and this can be used |
| 827 | to install a new `ConnectionFilter` on the process's Service Manager connection |
| 828 | before starting to accept requests. |
| 829 | |
| 830 | This behavior should really be considered deprecated, but for posterity, here is |
| 831 | how the GPU process does it: |
| 832 | |
| 833 | 1. [Disable Service Manager connection auto-start](https://cs.chromium.org/chromium/src/content/gpu/gpu_child_thread.cc?rcl=6b85a56334c0cd64b0e657934060de716714ca64&l=62) |
| 834 | 2. [Register a new ConnectionFilter impl to handle certain interface requests](https://cs.chromium.org/chromium/src/content/gpu/gpu_child_thread.cc?rcl=6b85a56334c0cd64b0e657934060de716714ca64&l=255) |
| 835 | 3. [Start the Service Manager connection manually](https://cs.chromium.org/chromium/src/content/gpu/gpu_child_thread.cc?rcl=6b85a56334c0cd64b0e657934060de716714ca64&l=257) |
| 836 | |
| 837 | It's much more common instead for there to be some primordial interface |
| 838 | connection established by the child process which can then be used to facilitate |
| 839 | push communications from the browser, so please consider not duplicating this |
| 840 | behavior. |
| 841 | |
| 842 | ## Additional Support |
| 843 | |
| 844 | If this document was not helpful in some way, please post a message to your |
| 845 | friendly |
| 846 | [[email protected]](https://groups.google.com/a/chromium.org/forum/#!forum/chromium-mojo) |
| 847 | or |
| 848 | [[email protected]](https://groups.google.com/a/chromium.org/forum/#!forum/services-dev) |
| 849 | mailing list. |