blob: 17a24124a6526e8f75d1b6e2aa119a56c5ed552f [file] [log] [blame] [view]
# Intro to Mojo & Services
[TOC]
## Overview
This document contains the minimum amount of information needed for a developer
to start using Mojo effectively in Chromium, with example Mojo interface usage,
service definition and hookup, and a brief overview of the Content layer's core
services.
See other [Mojo & Services](/docs/README.md#Mojo-Services) documentation
for introductory guides, API references, and more.
## Mojo Terminology
A **message pipe** is a pair of **endpoints**. Each endpoint has a queue of
incoming messages, and writing a message at one endpoint effectively enqueues
that message on the other (**peer**) endpoint. Message pipes are thus
bidirectional.
A **mojom** file describes **interfaces**, which are strongly-typed collections
of **messages**. Each interface message is roughly analogous to a single proto
message, for developers who are familiar with Google protobufs.
Given a mojom interface and a message pipe, one of the endpoints
can be designated as an **InterfacePtr** and is used to *send* messages described by
the interface. The other endpoint can be designated as a **Binding** and is used
to *receive* interface messages.
*** aside
NOTE: The above generalization is a bit oversimplified. Remember that the
message pipe is still bidirectional, and it's possible for a mojom message to
expect a reply. Replies are sent from the Binding endpoint and received by the
InterfacePtr endpoint.
***
The Binding endpoint must be associated with (*i.e.* **bound** to) an
**implementation** of its mojom interface in order to process received messages.
A received message is dispatched as a scheduled task invoking the corresponding
interface method on the implementation object.
Another way to think about all this is simply that **an InterfacePtr makes
calls on a remote implementation of its interface associated with a
corresponding remote Binding.**
## Example: Defining a New Frame Interface
Let's apply this to Chrome. Suppose we want to send a "Ping" message from a
render frame to its corresponding `RenderFrameHostImpl` instance in the browser
process. We need to define a nice mojom interface for this purpose, create a
pipe to use that interface, and then plumb one end of the pipe to the right
place so the sent messages can be received and processed there. This section
goes through that process in detail.
### Defining the Interface
The first step involves creating a new `.mojom` file with an interface
definition, like so:
``` cpp
// src/example/public/mojom/ping_responder.mojom
module example.mojom;
interface PingResponder {
// Receives a "Ping" and responds with a random integer.
Ping() => (int32 random);
};
```
This should have a corresponding build rule to generate C++ bindings for the
definition here:
``` python
# src/example/public/mojom/BUILD.gn
import("//mojo/public/tools/bindings/mojom.gni")
mojom("mojom") {
sources = [ "ping_responder.mojom" ]
}
```
### Creating the Pipe
Now let's create a message pipe to use this interface.
*** aside
As a general rule and as a matter of convenience when
using Mojo, the *client* of an interface (*i.e.* the InterfacePtr side) is
typically the party who creates a new pipe. This is convenient because the
InterfacePtr may be used to start sending messages immediately without waiting
for the InterfaceRequest endpoint to be transferred or bound anywhere.
***
This code would be placed somewhere in the renderer:
```cpp
example::mojom::PingResponderPtr ping_responder;
example::mojom::PingResponderRequest request =
mojo::MakeRequest(&ping_responder);
```
In this example, ```ping_responder``` is the InterfacePtr, and ```request```
is an InterfaceRequest, which is a Binding precursor that will eventually
be turned into a Binding. `mojo::MakeRequest` is the most common way to create
a message pipe: it yields both endpoints as strongly-typed objects, with the
`InterfacePtr` as an output argument and the `InterfaceRequest` as the return
value.
*** aside
NOTE: Every mojom interface `T` generates corresponding C++ type aliases
`TPtr = InterfacePtr<T>` and `TRequest = InterfaceRequest<T>`. Chromium code
almost exclusively uses these aliases instead of writing out the more verbose
templated name.
Also note that an InterfaceRequest doesn't actually **do** anything. It is an
inert holder of a single message pipe endpoint. It exists only to make its
endpoint more strongly-typed at compile-time, indicating that the endpoint
expects to be bound by a Binding of the same interface type.
***
### Sending a Message
Finally, we can call the `Ping()` method on our InterfacePtr to send a message:
```cpp
ping_responder->Ping(base::BindOnce(&OnPong));
```
*** aside
**IMPORTANT:** If we want to receive the the response, we must keep the
`ping_responder` object alive until `OnPong` is invoked. After all,
`ping_responder` *owns* its message pipe endpoint. If it's destroyed then so is
the endpoint, and there will be nothing to receive the response message.
***
We're almost done! Of course, if everything were this easy, this document
wouldn't need to exist. We've taken the hard problem of sending a message from
a renderer process to the browser process, and transformed it into a problem
where we just need to take the `request` object from above and pass it to the
browser process somehow where it can be turned into a Binding that dispatches
its received messages.
### Sending an InterfaceRequest to the Browser
It's worth noting that InterfaceRequests (and message pipe endpoints in general)
are just another type of object that can be freely sent over mojom messages.
The most common way to get an InterfaceRequest somewhere is to pass it as a
method argument on some other already-connected interface.
One such interface which we always have connected between a renderer's
`RenderFrameImpl` and its corresponding `RenderFrameHostImpl` in the browser
is
[`DocumentInterfaceBroker`](https://cs.chromium.org/chromium/src/third_party/blink/public/mojom/frame/document_interface_broker.mojom).
We can update this definition to add support for our new PingResponder
interface:
``` cpp
interface DocumentInterfaceBroker {
...
GetPingResponder(PingResponder& responder);
}
```
The `&` syntax is not a reference! In mojom it denotes an InterfaceRequest.
Specifically in this case, the `GetPingResponder` takes a single
`PingResponderRequest` argument. If the `&` were omitted, this would instead
take a `PingResponderPtr`.
Now the renderer can call this method with the `request` object it created
earlier via `mojo::MakeRequest`:
``` cpp
RenderFrame* my_frame = GetMyFrame();
my_frame->GetDocumentInterfaceBroker()->GetPingResponder(std::move(request));
```
This will transfer the PingResponderRequest endpoint to the browser process
where it will be received by the corresponding `DocumentInterfaceBroker`
implementation. More on that below.
### Implementing the Interface
Finally, we need a browser-side implementation of our `PingResponder` interface
as well as an implementation of the new
`DocumentInterfaceBroker.GetPingResponder` message. Let's implement
`PingResponder` first:
```cpp
#include "example/public/mojom/ping_responder.mojom.h"
class PingResponderImpl : example::mojom::PingResponder {
public:
explicit PingResponderImpl(example::mojom::PingResponderRequest request)
: binding_(this, std::move(request)) {}
// example::mojom::PingResponder:
void Ping(PingCallback callback) override {
// Respond with a random 4, chosen by fair dice roll.
std::move(callback).Run(4);
}
private:
mojo::Binding<example::mojom::PingResponder> binding_;
DISALLOW_COPY_AND_ASSIGN(PingResponderImpl);
};
```
And conveniently `RenderFrameHostImpl` implements `DocumentInterfaceBroker`, and
any calls made on the object returned by
`RenderFrameImpl::GetDocumentInterfaceBroker()` will be routed directly to the
`RenderFrameHostImpl`. So the only thing left to do is update
`RenderFrameHostImpl` to implement `GetPingResponder`. If you forget to do this
the compiler will complain anyway, because generated mojom interface methods are
pure virtual methods in C++.
``` cpp
// render_frame_host_impl.h
class RenderFrameHostImpl
...
void GetPingResponder(example::mojom::PingResponderRequest request) override;
...
private:
...
std::unique_ptr<PingResponderImpl> ping_responder_;
...
};
// render_frame_host_impl.cc
void RenderFrameHostImpl::GetPingResponder(
example::mojom::PingResponderRequest request) {
ping_responder_ = std::make_unique<PingResponderImpl>(std::move(request));
}
```
And we're done. This setup is sufficient to plumb a new interface connection
between a renderer frame and its browser-side host object!
Assuming we kept our `ping_responder` object alive in the renderer long enough,
we would eventually see its `OnPong` callback invoked with the totally random
value of `4`, as defined by the browser-side implementation above.
## Services Overview &amp; Terminology
The previous section only scratches the surface of how Mojo IPC is used in
Chromium. While renderer-to-browser messaging is simple and possibly the most
prevalent usage by sheer code volume, we are incrementally decomposing the
codebase into a set of services with a bit more granularity than the traditional
Content browser/renderer/gpu/utility process split.
A **service** is a self-contained library of code which implements one or more
related features or behaviors and whose interaction with outside code is done
*exclusively* through Mojo interface connections facilitated by the **Service
Manager.**
The **Service Manager** is a component which can run in a dedicated process
or embedded within another process. Only one Service Manager exists globally
across the system, and in Chromium the browser process runs an embedded Service
Manager instance immediately on startup. The Service Manager spawns
**service instances** on-demand, and it routes each interface request from a
service instance to some destination instance of the Service Manager's choosing.
Each service instance implements the
[**`Service`**](https://cs.chromium.org/chromium/src/services/service_manager/public/cpp/service.h)
interface to receive incoming interface requests brokered by the Service
Manager, and each service instance has a
[**`Connector`**](https://cs.chromium.org/chromium/src/services/service_manager/public/cpp/connector.h)
it can use to issue interface requests to other services via the
Service Manager.
Every service has a **manifest** which declares some static metadata about the
service. This metadata is used by the Service Manager for various purposes,
including as a declaration of what interfaces are exposed to other services in
the system. This eases the security review process.
Inside its manifest every service declares its **service name**, used to
identify instances of the service in the most general sense. Names are free-form
and usually short strings which must be globally unique. Some services defined
in Chromium today include `"device"`, `"identity"`, and `"network"` services.
For more complete and in-depth coverage of the concepts covered here and other
related APIs, see the
[Service Manager documentation](/services/service_manager/README.md).
## Example: Building a Simple Out-of-Process Service
There are multiple steps required to get a new service up and running in
Chromium. You must:
- Define the `Service` implementation
- Define the service's manifest
- Tell Chromium's Service Manager about the manifest
- Tell Chromium how to instantiate the `Service` implementation when it's needed
This section walks through these steps with some brief explanations. For more
thorough documentation of the concepts and APIs used herein, see the
[Service Manager](/services/service_manager/README.md) and
[Mojo](/mojo/README.md) documentation.
### Defining the Service
Typically service definitions are placed in a `services` directory, either at
the top level of the tree or within some subdirectory. In this example, we'll
define a new service for use by Chrome specifically, so we'll define it within
`//chrome/services`.
We can create the following files. First some mojoms:
``` cpp
// src/chrome/services/math/public/mojom/constants.mojom
module math.mojom;
// These are not used by the implementation directly, but will be used in
// following sections.
const string kServiceName = "math";
const string kArithmeticCapability = "arithmetic";
```
``` cpp
// src/chrome/services/math/public/mojom/divider.mojom
module math.mojom;
interface Divider {
Divide(int32 dividend, int32 divisor) => (int32 quotient);
};
```
``` python
# src/chrome/services/math/public/mojom/BUILD.gn
import("//mojo/public/tools/bindings/mojom.gni")
mojom("mojom") {
sources = [
"constants.mojom",
"divider.mojom",
]
}
```
Then the actual `Service` implementation:
``` cpp
// src/chrome/services/math/math_service.h
#include "services/service_manager/public/cpp/service.h"
#include "base/macros.h"
#include "chrome/services/math/public/mojom/divider.mojom.h"
namespace math {
class MathService : public service_manager::Service,
public mojom::Divider {
public:
explicit MathService(service_manager::mojom::ServiceRequest request);
~MathService() override;
private:
// service_manager::Service:
void OnBindInterface(const service_manager::BindSourceInfo& source,
const std::string& interface_name,
mojo::ScopedMessagePipeHandle interface_pipe) override;
// mojom::Divider:
void Divide(int32_t dividend,
int32_t divisor,
DivideCallback callback) override;
service_manager::ServiceBinding service_binding_;
// You could also use a Binding. We use BindingSet to conveniently allow
// multiple clients to bind to the same instance of this class. See Mojo
// C++ Bindings documentation for more information.
mojo::BindingSet<mojom::Divider> divider_bindings_;
DISALLOW_COPY_AND_ASSIGN(MathService);
};
} // namespace math
```
``` cpp
// src/chrome/services/math/math_service.cc
#include "chrome/services/math/math_service.h"
namespace math {
MathService::MathService(service_manager::ServiceRequest request)
: service_binding_(this, std::move(request)) {}
MathService::~MathService() = default;
void MathService::OnBindInterface(
const service_manager::BindSourceInfo& source,
const std::string& interface_name,
mojo::ScopedMessagePipeHandle interface_pipe) {
// Note that services typically use a service_manager::BinderRegistry if they
// plan on handling many different interface request types.
if (interface_name == mojom::Divider::Name_) {
divider_bindings_.AddBinding(
this, mojom::DividerRequest(std::move(interface_pipe)));
}
}
void MathService::Divide(int32_t dividend,
int32_t divisor,
DivideCallback callback) {
// Respond with the quotient!
std::move(callback).Run(dividend / divisor);
}
} // namespace math
```
``` python
# src/chrome/services/math/BUILD.gn
source_set("math") {
sources = [
"math.cc",
"math.h",
]
deps = [
"//base",
"//chrome/services/math/public/mojom",
"//services/service_manager/public/cpp",
]
}
```
Now we have a fully defined `math` service implementation, including a nice
little `Divider` interface for clients to play with. Next we need to define the
service's manifest to declare how the service can be used.
### Defining the Manifest
Manifests are defined as
[`Manifest`](https://cs.chromium.org/chromium/src/services/service_manager/public/cpp/manifest.h)
objects, typically built using a
[`ManifestBuilder`](https://cs.chromium.org/chromium/src/services/service_manager/public/cpp/manifest_builder.h). As a general rule, services should define their manifest
in a dedicated `source_set` or `component` target under their `public/cpp`
subdirectory (typically referred to as the service's **C++ client library**).
We can create the following files for this purpose:
``` cpp
// src/chrome/services/math/public/cpp/manifest.h
#include "services/service_manager/public/cpp/manifest.h"
namespace math {
const service_manager::Manifest& GetManifest();
} // namespace math
```
``` cpp
// src/chrome/services/math/public/cpp/manifest.cc
#include "chrome/services/math/public/cpp/manifest.h"
#include "base/no_destructor.h"
#include "chrome/services/math/public/mojom/constants.mojom.h"
#include "chrome/services/math/public/mojom/divider.mojom.h"
#include "services/service_manager/public/cpp/manifest_builder.h"
namespace math {
const service_manager::Manifest& GetManifest() {
static base::NoDestructor<service_manager::Manifest> manifest{
service_manager::ManifestBuilder()
.WithServiceName(mojom::kServiceName)
.ExposeCapability(
mojom::kArithmeticCapability,
service_manager::Manifest::InterfaceList<mojom::Divider>())
.Build()};
return *manifest
}
} // namespace math
```
We also need to define a build target for our manifest sources:
``` python
# src/chrome/services/math/public/cpp/BUILD.gn
source_set("manifest") {
sources = [
"manifest.cc",
"manifest.h",
]
deps = [
"//base",
"//chrome/services/math/public/mojom",
"//services/service_manager/public/cpp",
]
}
```
The above `Manifest` definition declares that the service is named `math` and
that it **exposes** a single **capability** named `arithmetic` which allows
access to the `Divider` interface.
Another service may **require** this capability from its own manifest in order
for the Service Manager to grant it access to a `Divider`. We'll see this a
few sections below. First, let's get the manifest and service implementation
registered with Chromium's Service Manager.
### Registering the Manifest
For the most common out-of-process service cases, we register service manifests
by **packaging** them in Chrome. This can be done by augmenting the value
returned by
[`GetChromePackagedServiceManifests`](https://cs.chromium.org/chromium/src/chrome/app/chrome_packaged_service_manifests.cc?rcl=af43cabf3c01e28be437becb972a7eae44fd54e8&l=133).
We can add our manifest there:
``` cpp
// Deep within src/chrome/app/chrome_packaged_service_manifests.cc...
const std::vector<service_manager::Manifest>
GetChromePackagedServiceManifests() {
...
math::GetManifest(),
...
```
And don't forget to add a GN dependency from
[`//chrome/app:chrome_packaged_service_manifests`](https://cs.chromium.org/chromium/src/chrome/app/BUILD.gn?l=564&rcl=a77d5ba9c4621cfe14e7e1cd03bbae16904f269e) onto
`//chrome/services/math/public/cpp:manifest`!
We're almost done with service setup. The last step is to teach Chromium (and
thus the Service Manager) how to launch an instance of our beautiful `math`
service.
### Hooking Up the Service Implementation
There are two parts to this for an out-of-process Chrome service.
First, we need
to inform the embedded Service Manager that this service is an out-of-process
service. The goofiness of this part is a product of some legacy issues and it
should be eliminated soon, but for now it just means teaching the Service
Manager how to *label* the process it creates for this service (e.g. how the process will
appear in the system task manager). We modify
[`ChromeContentBrowserClient::RegisterOutOfProcessServices`](https://cs.chromium.org/chromium/src/chrome/browser/chrome_content_browser_client.cc?rcl=960886a7febcc2acccea7f797d3d5e03a344a12c&l=3766)
for this:
``` cpp
void ChromeContentBrowserClient::RegisterOutOfProcessServices(
OutOfProcessServicesMap* services) {
...
(*services)[math::mojom::kServiceName] =
base::BindRepeating([]() -> base::string16 {
return "Math Service";
});
...
}
```
And finally, since nearly all out-of-process services run in a "utility" process
today, we need to add a dependency on our actual `Service` implementation to
Chrome's service spawning code within the utility process.
For this step we just modify
[`ChromeContentUtilityClient::MaybeCreateMainThreadService`](https://cs.chromium.org/chromium/src/chrome/utility/chrome_content_utility_client.cc?rcl=7226adebd6e8d077d673a82acf1aab0790627178&l=261)
by adding a block of code as follows:
``` cpp
void ChromeContentUtilityClient::MaybeCreateMainThreadService(
const std::string& service_name,
service_manager::mojom::ServiceRequest request) {
...
if (service_name == math::mojom::kServiceName)
return std::make_unique<math::MathService>(std::move(request));
...
}
```
And we're done!
As one nice follow-up step, let's use our math service from the browser.
### Using the Service
We can grant the browser process access to our `Divider` interface by
**requiring** the `math` service's `arithmetic` capability within the
`content_browser` service manifest.
*** aside
NOTE: See the following section for an elaboration on what `content_browser` is.
For the sake of this example, it's magic.
***
For Chrome-specific features such as our glorious new `math` service, we can
amend the `content_browser` manifest by modifying
[GetChromeContentBrowserOverlayManifest](https://cs.chromium.org/chromium/src/chrome/app/chrome_content_browser_overlay_manifest.cc?rcl=38db90321e8e3627b2f3165cdb051fa8d668af48&l=100)
as follows:
``` cpp
// src/chrome/app/chrome_content_browser_overlay_manifest.cc
...
const service_manager::Manifest& GetChromeContentBrowserOverlayManifest() {
...
.RequireCapability(math::mojom::kServiceName,
math::mojom::kArithmeticCapability)
...
}
```
Finally, we can use the global `content_browser` instance's `Connector` to send
an interface request to our service. This is accessible from the main thread of
the browser process. Somewhere in `src/chrome/browser`, we can write:
``` cpp
// This gives us the global content_browser's Connector
service_manager::Connector* connector =
content::ServiceManagerConnection::GetForProcess()->GetConnector();
// Recall from the earlier Mojo section that mojo::MakeRequest creates a new
// message pipe for our interface. Connector passes the request endpoint to
// the Service Manager along with the name of our target service, "math".
math::mojom::DividerPtr divider;
connector->BindInterface(math::mojom::kServiceName,
mojo::MakeRequest(&divider));
// As a client, we do not have to wait for any acknowledgement or confirmation
// of a connection. We can start queueing messages immediately and they will be
// delivered as soon as the service is up and running.
divider->Divide(
42, 6, base::BindOnce([](int32_t quotient) { LOG(INFO) << quotient; }));
```
*** aside
NOTE: To ensure the execution of the response callback, the DividerPtr
object must be kept alive (see
[this section](/mojo/public/cpp/bindings/README.md#A-Note-About-Endpoint-Lifetime-and-Callbacks)
and [this note from an earlier section](#sending-a-message)).
***
This should successfully spawn a new process to run the `math` service if it's
not already running, then ask it to do a division, and ultimately log the result
after it's sent back to the browser process.
Finally it's worth reiterating that every service instance in the system has
its own `Connector` and there's no reason we have to limit ourselves to
`content_browser` as the client, as long as the appropriate manifest declares
that it requires our `arithmetic` capability.
If we did not update the `content_browser` manifest overlay as we did in this
example, the `Divide` call would never reach the `math` service (in fact the
service wouldn't even be started) and instead we'd get an error message (or in
developer builds, an assertion failure) informing us that the Service Manager
blocked the `BindInterface` call.
## Content-Layer Services Overview
Apart from very early initialization steps in the browser process, every bit of
logic in Chromium today is effectively running as part of one service instance
or another.
Although we continue to migrate parts of the browser's privileged
functionality to more granular services defined below the Content layer, the
main services defined in Chromium today continue to model the Content layer's
classical multiprocess architecture which defines a handful of
**process types**: browser, renderer, gpu, utility, and plugin processes. For
each of these process types, we now define corresponding services.
Manifest definitions for all of the following services can be found in
`//content/public/app`.
### The Browser Service
`content_browser` is defined to encapsulate general-purpose browser process
code. There are multiple instances of this service, all running within the
singular browser process. There is one shared global instance as well an
additional instance for each `BrowserContext` (*i.e.* per Chrome profile).
The global instance exists primarily so that arbitrary browser process code can
reach various system services conveniently via a global `Connector` instance
on the main thread.
Each instance associated with a `BrowserContext` is placed in an isolated
instance group specific to that `BrowserContext`. This limits the service
instances with which its `Connector` can make contact. These instances are
used primarily to facilitate the spawning of other isolated per-profile service
instances, such as renderers and plugins.
### The Renderer Service
A `content_renderer` instance is spawned in its own sandboxed process for every
site-isolated instance of Blink we require. Instances are placed in the same
instance group as the renderer's corresponding `BrowserContext`, *i.e.* the
profile which navigated to the site being rendered.
Most interfaces used by `content_renderer` are not brokered through the Service
Manager but instead are brokered through dedicated interfaces implemented by
`content_browser`, with which each renderer maintains persistent connections.
### The GPU Service
Only a single instance of `content_gpu` exists at a time and it always runs in
its own isolated, sandboxed process. This service hosts the code in content/gpu
and whatever else Content's embedder adds to that for GPU support.
### The Plugin Service
`content_plugin` hosts a plugin in an isolated process. Similarly to
`content_renderer` instances, each instance of `content_plugin` belongs to
an instance group associated with a specific `BrowserContext`, and in general
plugins get most of their functionality by talking directly to `content_browser`
rather than brokering interface requests through the Service Manager.
### The Utility Service
`content_utility` exists only nominally today, as there is no remaining API
surface within Content which would allow a caller to explicitly create an
instance of it. Instead, this service is used exclusively to bootstrap new
isolated processes in which other services will run.
## Exposing Interfaces Between Content Processes
Apart from the standard Service Manager APIs, the Content layer defines a number
of additional concepts for Content and its embedder to expose interfaces
specifically between Content processes in various contexts.
### Exposing Browser Interfaces to Renderer Documents and Workers
Documents and workers are somewhat of a special case since interface access
decisions often require browser-centric state that the Service Manager cannot
know about, such as details of the current `BrowserContext`, the origin of the
renderered content, installed extensions in the renderer, *etc.* For this
reason, interface brokering decisions are increasingly being made by the
browser.
There are two ways this is done: the Deprecated way and the New way.
#### The Deprecated Way: InterfaceProvider
This is built on the concept of **interface filters** and the
**`InterfaceProvider`** interface. It is **deprecated** and new features should
use [The New Way](#The-New-Way_Interface-Brokers) instead. This section only
briefly covers practical usage in Chromium.
The `content_browser` manifest exposes capabilities on a few named interface
filters, the main one being `"navigation:frame"`. There are others scoped to
different worker contexts, *e.g.* `"navigation:service_worker"`.
`RenderProcessHostImpl` or `RenderFrameHostImpl` sets up an `InterfaceProvider`
for each known execution context in the corresponding renderer, filtered through
the Service Manager according to one of the named filters.
The practical result of all this means the interface must be listed in the
`content_browser` manifest under the
`ExposeInterfaceFilterCapability_Deprecated("navigation:frame", "renderer", ...)`
entry, and a corresponding interface request handler must be registered with the
host's `registry_` in
[`RenderFrameHostImpl::RegisterMojoInterfaces`](https://cs.chromium.org/chromium/src/content/browser/frame_host/render_frame_host_impl.cc?rcl=0a23c78c57ecb2405837155aa0a0def7b5ba9c22&l=3971)
Similarly for worker contexts, an interface must be exposed by the `"renderer"`
capability on the corresponding interface filter
(*e.g.*, `"navigation:shared_worker"`) and a request handler must be registered
within
[`RendererInterfaceBinders::InitializeParameterizedBinderRegistry`](https://cs.chromium.org/chromium/src/content/browser/renderer_interface_binders.cc?rcl=0a23c78c57ecb2405837155aa0a0def7b5ba9c22&l=116).
The best way to understand all of this after reading this section is to look at
the linked code above and examine a few examples. They are fairly repetitive.
For additional convenience, here is also a link to the `content_browser`
[manifest](https://cs.chromium.org/chromium/src/content/public/app/content_browser_manifest.cc).
#### The New Way: Interface Brokers
*** aside
In classic Google tradition, the New Way is not entirely ready yet. As of this
writing, worker-scoped interfaces must still use the Old Way described above.
***
Rather than the confusing spaghetti of interface filter logic, we now define an
explicit mojom interface with a persistent connection between a renderer's
frame object and the corresponding `RenderFrameHostImpl` in the browser process.
This interface is called
[`DocumentInterfaceBroker`](https://cs.chromium.org/chromium/src/third_party/blink/public/mojom/frame/document_interface_broker.mojom?rcl=ea6921f717f21e9a72d321a15c4bf50d47d10310&l=11)
and is fairly easy to work with: you simply add a new factory method to the
interface definition:
``` cpp
interface DocumentInterfaceBroker {
...
GetGoatTeleporter(magic.mojom.GoatTeleporter& request);
};
```
and implement this new method on `RenderFrameHostImpl`, which is an
implementation (**the** production implementation) of
`DocumentInterfaceBroker`:
``` cpp
void RenderFrameHostImpl::GetGoatTeleporter(
magic::mojom::GoatTeleporterRequest request) {
goat_teleporter_binding_.Bind(std::move(request));
}
```
### Exposing Browser Interfaces to Render Processes
Sometimes (albeit rarely) it's useful to expose a browser interface directly to
a renderer process. This can be done as for any other interface exposed between
two services. In this specific instance, the `content_browser` manifest exposes
a capability named `"renderer"` which `content_renderer` requires. Any interface
listed as part of that capability can be accessed by a `content_renderer`
instance by using its own `Connector`. See below.
### Exposing Browser Interfaces to Content Child Processes
All Content child process types (renderer, GPU, and plugin) share a common API
to interface with the Service Manager. Their Service Manager connection is
initialized and maintained by `ChildThreadImpl` on process startup, and from
the main thread, you can access the process's `Connector` as follows:
``` cpp
auto* connector = content::ChildThread::Get()->GetConnector();
// For example...
connector->BindInterface(content::mojom::kBrowserServiceName,
std::move(some_request));
```
### Exposing Content Child Process Interfaces to the Browser
Content child processes may also expose interfaces to the browser, though this
is much less common and requires a fair bit of caution since the browser must be
careful to only call `Connector.BindInterface` in these cases with an exact
`service_manager::Identity` to avoid unexpected behavior.
Every child process provides a subclass of ChildThreadImpl, and this can be used
to install a new `ConnectionFilter` on the process's Service Manager connection
before starting to accept requests.
This behavior should really be considered deprecated, but for posterity, here is
how the GPU process does it:
1. [Disable Service Manager connection auto-start](https://cs.chromium.org/chromium/src/content/gpu/gpu_child_thread.cc?rcl=6b85a56334c0cd64b0e657934060de716714ca64&l=62)
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)
3. [Start the Service Manager connection manually](https://cs.chromium.org/chromium/src/content/gpu/gpu_child_thread.cc?rcl=6b85a56334c0cd64b0e657934060de716714ca64&l=257)
It's much more common instead for there to be some primordial interface
connection established by the child process which can then be used to facilitate
push communications from the browser, so please consider not duplicating this
behavior.
## Additional Support
If this document was not helpful in some way, please post a message to your
friendly
[chromium-mojo@chromium.org](https://groups.google.com/a/chromium.org/forum/#!forum/chromium-mojo)
or
[services-dev@chromium.org](https://groups.google.com/a/chromium.org/forum/#!forum/services-dev)
mailing list.