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