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