blob: 576ff330b53d825b69fcd1f93f1f0c474935983a [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
Darwin Huangb4bd2452019-10-08 22:56:0427can 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
Darwin Huangb4bd2452019-10-08 22:56:0434expect a reply. Replies are sent from the `Receiver` endpoint and received by the
35`Remote` endpoint.
Ken Rockotab035122019-02-06 00:35:2436***
37
Darwin Huangb4bd2452019-10-08 22:56:0438The `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
Darwin Huangb4bd2452019-10-08 22:56:0443Another 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
Darwin Huangb4bd2452019-10-08 22:56:0445corresponding 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
Darwin Huangb4bd2452019-10-08 22:56:0488using 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
Darwin Huangb4bd2452019-10-08 22:56:0490`Remote` 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
Darwin Huangb4bd2452019-10-08 22:56:0497// src/third_party/blink/example/public/ping_responder.h
Oksana Zhuravlova9f3b8ef2019-08-26 20:27:4098mojo::Remote<example::mojom::PingResponder> ping_responder;
99mojo::PendingReceiver<example::mojom::PingResponder> receiver =
100 ping_responder.BindNewPipeAndPassReceiver();
Ken Rockotab035122019-02-06 00:35:24101```
102
Darwin Huangb4bd2452019-10-08 22:56:04103In this example, ```ping_responder``` is the `Remote`, and ```receiver```
104is a `PendingReceiver`, which is a `Receiver` precursor that will eventually
105be turned into a `Receiver`. `BindNewPipeAndPassReceiver` is the most common way to create
Oksana Zhuravlova9f3b8ef2019-08-26 20:27:40106a message pipe: it yields the `PendingReceiver` as the return
Ken Rockotab035122019-02-06 00:35:24107value.
108
109*** aside
Darwin Huangb4bd2452019-10-08 22:56:04110NOTE: A `PendingReceiver` doesn't actually **do** anything. It is an
Ken Rockotab035122019-02-06 00:35:24111inert holder of a single message pipe endpoint. It exists only to make its
112endpoint more strongly-typed at compile-time, indicating that the endpoint
Darwin Huangb4bd2452019-10-08 22:56:04113expects to be bound by a `Receiver` of the same interface type.
Ken Rockotab035122019-02-06 00:35:24114***
115
116### Sending a Message
117
Darwin Huangb4bd2452019-10-08 22:56:04118Finally, we can call the `Ping()` method on our `Remote` to send a message:
Ken Rockotab035122019-02-06 00:35:24119
120```cpp
Darwin Huangb4bd2452019-10-08 22:56:04121// src/third_party/blink/example/public/ping_responder.h
Ken Rockotab035122019-02-06 00:35:24122ping_responder->Ping(base::BindOnce(&OnPong));
123```
124
125*** aside
Darwin Huangb4bd2452019-10-08 22:56:04126**IMPORTANT:** If we want to receive the response, we must keep the
Ken Rockotab035122019-02-06 00:35:24127`ping_responder` object alive until `OnPong` is invoked. After all,
128`ping_responder` *owns* its message pipe endpoint. If it's destroyed then so is
129the endpoint, and there will be nothing to receive the response message.
130***
131
132We're almost done! Of course, if everything were this easy, this document
133wouldn't need to exist. We've taken the hard problem of sending a message from
134a renderer process to the browser process, and transformed it into a problem
Oksana Zhuravlova9f3b8ef2019-08-26 20:27:40135where we just need to take the `receiver` object from above and pass it to the
Darwin Huangb4bd2452019-10-08 22:56:04136browser process somehow where it can be turned into a `Receiver` that dispatches
Ken Rockotab035122019-02-06 00:35:24137its received messages.
138
Darwin Huangb4bd2452019-10-08 22:56:04139### Sending a `PendingReceiver` to the Browser
Ken Rockotab035122019-02-06 00:35:24140
Darwin Huangb4bd2452019-10-08 22:56:04141It's worth noting that `PendingReceiver`s (and message pipe endpoints in general)
Ken Rockotab035122019-02-06 00:35:24142are just another type of object that can be freely sent over mojom messages.
Darwin Huangb4bd2452019-10-08 22:56:04143The most common way to get a `PendingReceiver` somewhere is to pass it as a
Ken Rockotab035122019-02-06 00:35:24144method argument on some other already-connected interface.
145
146One such interface which we always have connected between a renderer's
147`RenderFrameImpl` and its corresponding `RenderFrameHostImpl` in the browser
148is
Oksana Zhuravlova9f3b8ef2019-08-26 20:27:40149[`BrowserInterfaceBroker`](https://cs.chromium.org/chromium/src/third_party/blink/public/mojom/browser_interface_broker.mojom).
150This interface is a factory for acquiring other interfaces. Its `GetInterface`
151method takes a `GenericPendingReceiver`, which allows passing arbitrary
152interface receivers.
Ken Rockotab035122019-02-06 00:35:24153
154``` cpp
Oksana Zhuravlova9f3b8ef2019-08-26 20:27:40155interface BrowserInterfaceBroker {
156 GetInterface(mojo_base.mojom.GenericPendingReceiver receiver);
Ken Rockotab035122019-02-06 00:35:24157}
158```
Oksana Zhuravlova9f3b8ef2019-08-26 20:27:40159Since `GenericPendingReceiver` can be implicitly constructed from any specific
Darwin Huangb4bd2452019-10-08 22:56:04160`PendingReceiver`, it can call this method with the `receiver` object it created
Oksana Zhuravlova9f3b8ef2019-08-26 20:27:40161earlier via `BindNewPipeAndPassReceiver`:
Ken Rockotab035122019-02-06 00:35:24162
163``` cpp
164RenderFrame* my_frame = GetMyFrame();
Oksana Zhuravlovad4f1f5c2019-11-14 05:57:11165my_frame->GetBrowserInterfaceBroker().GetInterface(std::move(receiver));
Ken Rockotab035122019-02-06 00:35:24166```
167
Darwin Huangb4bd2452019-10-08 22:56:04168This will transfer the `PendingReceiver` endpoint to the browser process
Oksana Zhuravlova9f3b8ef2019-08-26 20:27:40169where it will be received by the corresponding `BrowserInterfaceBroker`
Ken Rockotab035122019-02-06 00:35:24170implementation. More on that below.
171
172### Implementing the Interface
173
Oksana Zhuravlova9f3b8ef2019-08-26 20:27:40174Finally, we need a browser-side implementation of our `PingResponder` interface.
Ken Rockotab035122019-02-06 00:35:24175
176```cpp
177#include "example/public/mojom/ping_responder.mojom.h"
178
179class PingResponderImpl : example::mojom::PingResponder {
180 public:
Oksana Zhuravlova9f3b8ef2019-08-26 20:27:40181 explicit PingResponderImpl(mojo::PendingReceiver<example::mojom::PingResponder> receiver)
182 : receiver_(this, std::move(receiver)) {}
Johanne6e768e92020-09-09 00:51:10183 PingResponderImpl(const PingResponderImpl&) = delete;
184 PingResponderImpl& operator=(const PingResponderImpl&) = delete;
Ken Rockotab035122019-02-06 00:35:24185
186 // example::mojom::PingResponder:
187 void Ping(PingCallback callback) override {
188 // Respond with a random 4, chosen by fair dice roll.
189 std::move(callback).Run(4);
190 }
191
192 private:
Charlie Hud4c0fe82019-10-08 19:48:13193 mojo::Receiver<example::mojom::PingResponder> receiver_;
Ken Rockotab035122019-02-06 00:35:24194};
195```
196
Oksana Zhuravlova9f3b8ef2019-08-26 20:27:40197`RenderFrameHostImpl` owns an implementation of `BrowserInterfaceBroker`.
198When this implementation receives a `GetInterface` method call, it calls
199the handler previously registered for this specific interface.
Ken Rockotab035122019-02-06 00:35:24200
201``` cpp
202// render_frame_host_impl.h
203class RenderFrameHostImpl
204 ...
Oksana Zhuravlova9f3b8ef2019-08-26 20:27:40205 void GetPingResponder(mojo::PendingReceiver<example::mojom::PingResponder> receiver);
Ken Rockotab035122019-02-06 00:35:24206 ...
207 private:
208 ...
209 std::unique_ptr<PingResponderImpl> ping_responder_;
210 ...
211};
212
213// render_frame_host_impl.cc
214void RenderFrameHostImpl::GetPingResponder(
Oksana Zhuravlova9f3b8ef2019-08-26 20:27:40215 mojo::PendingReceiver<example::mojom::PingResponder> receiver) {
216 ping_responder_ = std::make_unique<PingResponderImpl>(std::move(receiver));
217}
218
219// browser_interface_binders.cc
220void PopulateFrameBinders(RenderFrameHostImpl* host,
Robert Sesek5a5fbb82020-05-04 16:18:28221 mojo::BinderMap* map) {
Oksana Zhuravlova9f3b8ef2019-08-26 20:27:40222...
223 // Register the handler for PingResponder.
224 map->Add<example::mojom::PingResponder>(base::BindRepeating(
225 &RenderFrameHostImpl::GetPingResponder, base::Unretained(host)));
Ken Rockotab035122019-02-06 00:35:24226}
227```
228
229And we're done. This setup is sufficient to plumb a new interface connection
230between a renderer frame and its browser-side host object!
231
232Assuming we kept our `ping_responder` object alive in the renderer long enough,
233we would eventually see its `OnPong` callback invoked with the totally random
234value of `4`, as defined by the browser-side implementation above.
235
236## Services Overview &amp; Terminology
237The previous section only scratches the surface of how Mojo IPC is used in
238Chromium. While renderer-to-browser messaging is simple and possibly the most
239prevalent usage by sheer code volume, we are incrementally decomposing the
240codebase into a set of services with a bit more granularity than the traditional
241Content browser/renderer/gpu/utility process split.
242
243A **service** is a self-contained library of code which implements one or more
244related features or behaviors and whose interaction with outside code is done
Ken Rockot216eb5d2020-02-19 17:09:55245*exclusively* through Mojo interface connections, typically brokered by the
246browser process.
Ken Rockotab035122019-02-06 00:35:24247
Ken Rockot216eb5d2020-02-19 17:09:55248Each service defines and implements a main Mojo interface which can be used
249by the browser to manage an instance of the service.
Ken Rockotab035122019-02-06 00:35:24250
251## Example: Building a Simple Out-of-Process Service
252
Ken Rockot216eb5d2020-02-19 17:09:55253There are multiple steps typically involved to get a new service up and running
254in Chromium:
Ken Rockotab035122019-02-06 00:35:24255
Ken Rockot216eb5d2020-02-19 17:09:55256- Define the main service interface and implementation
257- Hook up the implementation in out-of-process code
258- Write some browser logic to launch a service process
Ken Rockotab035122019-02-06 00:35:24259
260This section walks through these steps with some brief explanations. For more
261thorough documentation of the concepts and APIs used herein, see the
Ken Rockotab035122019-02-06 00:35:24262[Mojo](/mojo/README.md) documentation.
263
264### Defining the Service
265
266Typically service definitions are placed in a `services` directory, either at
267the top level of the tree or within some subdirectory. In this example, we'll
268define a new service for use by Chrome specifically, so we'll define it within
269`//chrome/services`.
270
271We can create the following files. First some mojoms:
272
273``` cpp
Ken Rockot216eb5d2020-02-19 17:09:55274// src/chrome/services/math/public/mojom/math_service.mojom
Ken Rockotab035122019-02-06 00:35:24275module math.mojom;
276
Ken Rockot216eb5d2020-02-19 17:09:55277interface MathService {
Ken Rockotab035122019-02-06 00:35:24278 Divide(int32 dividend, int32 divisor) => (int32 quotient);
279};
280```
281
282``` python
283# src/chrome/services/math/public/mojom/BUILD.gn
Ken Rockota0cb6cf92019-03-26 16:40:42284import("//mojo/public/tools/bindings/mojom.gni")
Ken Rockotab035122019-02-06 00:35:24285
286mojom("mojom") {
287 sources = [
Ken Rockot216eb5d2020-02-19 17:09:55288 "math_service.mojom",
Ken Rockotab035122019-02-06 00:35:24289 ]
290}
291```
292
Ken Rockot216eb5d2020-02-19 17:09:55293Then the actual `MathService` implementation:
Ken Rockotab035122019-02-06 00:35:24294
295``` cpp
296// src/chrome/services/math/math_service.h
Ken Rockotab035122019-02-06 00:35:24297#include "base/macros.h"
Ken Rockot216eb5d2020-02-19 17:09:55298#include "chrome/services/math/public/mojom/math_service.mojom.h"
Ken Rockotab035122019-02-06 00:35:24299
300namespace math {
301
Ken Rockot216eb5d2020-02-19 17:09:55302class MathService : public mojom::MathService {
Ken Rockotab035122019-02-06 00:35:24303 public:
Ken Rockot216eb5d2020-02-19 17:09:55304 explicit MathService(mojo::PendingReceiver<mojom::MathService> receiver);
Ken Rockotab035122019-02-06 00:35:24305 ~MathService() override;
Johanne6e768e92020-09-09 00:51:10306 MathService(const MathService&) = delete;
307 MathService& operator=(const MathService&) = delete;
Ken Rockotab035122019-02-06 00:35:24308
309 private:
Ken Rockot216eb5d2020-02-19 17:09:55310 // mojom::MathService:
Ken Rockotab035122019-02-06 00:35:24311 void Divide(int32_t dividend,
312 int32_t divisor,
313 DivideCallback callback) override;
314
Ken Rockot216eb5d2020-02-19 17:09:55315 mojo::Receiver<mojom::MathService> receiver_;
Ken Rockotab035122019-02-06 00:35:24316};
317
318} // namespace math
319```
320
321``` cpp
322// src/chrome/services/math/math_service.cc
323#include "chrome/services/math/math_service.h"
324
325namespace math {
326
Ken Rockot216eb5d2020-02-19 17:09:55327MathService::MathService(mojo::PendingReceiver<mojom::MathService> receiver)
328 : receiver_(this, std::move(receiver)) {}
Ken Rockotab035122019-02-06 00:35:24329
330MathService::~MathService() = default;
331
Ken Rockotab035122019-02-06 00:35:24332void MathService::Divide(int32_t dividend,
333 int32_t divisor,
334 DivideCallback callback) {
335 // Respond with the quotient!
Oksana Zhuravlova0941c08d2019-05-03 20:46:33336 std::move(callback).Run(dividend / divisor);
Ken Rockotab035122019-02-06 00:35:24337}
338
339} // namespace math
340```
341
342``` python
343# src/chrome/services/math/BUILD.gn
344
345source_set("math") {
346 sources = [
Dominic Farolino982b79c2020-09-08 20:07:10347 "math_service.cc",
348 "math_service.h",
Ken Rockotab035122019-02-06 00:35:24349 ]
350
351 deps = [
352 "//base",
353 "//chrome/services/math/public/mojom",
Ken Rockotab035122019-02-06 00:35:24354 ]
355}
356```
357
Ken Rockot216eb5d2020-02-19 17:09:55358Now we have a fully defined `MathService` implementation that we can make
359available in- or out-of-process.
Ken Rockotab035122019-02-06 00:35:24360
361### Hooking Up the Service Implementation
362
Ken Rockot216eb5d2020-02-19 17:09:55363For an out-of-process Chrome service, we simply register a factory function
364in [`//chrome/utility/services.cc`](https://cs.chromium.org/chromium/src/chrome/utility/services.cc).
Ken Rockotab035122019-02-06 00:35:24365
366``` cpp
Ken Rockot216eb5d2020-02-19 17:09:55367auto RunMathService(mojo::PendingReceiver<math::mojom::MathService> receiver) {
368 return std::make_unique<math::MathService>(std::move(receiver));
Ken Rockotab035122019-02-06 00:35:24369}
Ken Rockot216eb5d2020-02-19 17:09:55370
Miriam Polzer49235d02020-11-13 17:19:29371void RegisterMainThreadServices(mojo::ServiceFactory& services) {
372 // Existing services...
373 services.Add(RunFilePatcher);
374 services.Add(RunUnzipper);
Ken Rockot216eb5d2020-02-19 17:09:55375
Miriam Polzer49235d02020-11-13 17:19:29376 // We add our own factory to this list
377 services.Add(RunMathService);
378 //...
Ken Rockotab035122019-02-06 00:35:24379```
380
Ken Rockot216eb5d2020-02-19 17:09:55381With this done, it is now possible for the browser process to launch new
382out-of-process instances of MathService.
Ken Rockotab035122019-02-06 00:35:24383
Ken Rockot216eb5d2020-02-19 17:09:55384### Launching the Service
385
386If you're running your service in-process, there's really nothing interesting
387left to do. You can instantiate the service implementation just like any other
388object, yet you can also talk to it via a Mojo Remote as if it were
389out-of-process.
390
391To launch an out-of-process service instance after the hookup performed in the
392previous section, use Content's
393[`ServiceProcessHost`](https://cs.chromium.org/chromium/src/content/public/browser/service_process_host.h?rcl=e7a1f6c9a24f3151c875598174a05167fb12c5d5&l=47)
394API:
Ken Rockotab035122019-02-06 00:35:24395
396``` cpp
Ken Rockot216eb5d2020-02-19 17:09:55397mojo::Remote<math::mojom::MathService> math_service =
398 content::ServiceProcessHost::Launch<math::mojom::MathService>(
399 content::ServiceProcessHost::LaunchOptions()
Ken Rockot216eb5d2020-02-19 17:09:55400 .WithDisplayName("Math!")
401 .Pass());
Ken Rockotab035122019-02-06 00:35:24402```
403
Ken Rockot216eb5d2020-02-19 17:09:55404Except in the case of crashes, the launched process will live as long as
405`math_service` lives. As a corollary, you can force the process to be torn
406down by destroying (or resetting) `math_service`.
Ken Rockotab035122019-02-06 00:35:24407
Ken Rockot216eb5d2020-02-19 17:09:55408We can now perform an out-of-process division:
Ken Rockotab035122019-02-06 00:35:24409
410``` cpp
Ken Rockot216eb5d2020-02-19 17:09:55411// NOTE: As a client, we do not have to wait for any acknowledgement or
412// confirmation of a connection. We can start queueing messages immediately and
413// they will be delivered as soon as the service is up and running.
414math_service->Divide(
Ken Rockotab035122019-02-06 00:35:24415 42, 6, base::BindOnce([](int32_t quotient) { LOG(INFO) << quotient; }));
416```
Oksana Zhuravlova0941c08d2019-05-03 20:46:33417*** aside
Mario Sanchez Prada7dead3e2019-12-20 18:46:38418NOTE: To ensure the execution of the response callback, the
Ken Rockot216eb5d2020-02-19 17:09:55419`mojo::Remote<math::mojom::MathService>` object must be kept alive (see
Oksana Zhuravlova0941c08d2019-05-03 20:46:33420[this section](/mojo/public/cpp/bindings/README.md#A-Note-About-Endpoint-Lifetime-and-Callbacks)
421and [this note from an earlier section](#sending-a-message)).
422***
Ken Rockotab035122019-02-06 00:35:24423
Alex Goughf18988f2020-05-15 00:51:02424### Using a non-standard sandbox
425
Alex Gough4aac4e92021-05-26 01:46:47426Ideally services will run inside the service process sandbox unless
427they need access to operating system resources. For services that need
428a custom sandbox, a new sandbox type must be defined in consultation
429with [email protected].
430
431All services must specify their sandbox by specialization of
432`GetServiceSandboxType()` in an appropriate `service_sandbox_type.h` such as
Alex Goughf18988f2020-05-15 00:51:02433[`//chrome/browser/service_sandbox_type.h`](https://cs.chromium.org/chromium/src/chrome/browser/service_sandbox_type.h)
434or
435[`//content/browser/service_sandbox_type.h`](https://cs.chromium.org/chromium/src/content/browser/service_sandbox_type.h)
436and included where `ServiceProcessHost::Launch()` is called.
437
Ken Rockotab035122019-02-06 00:35:24438## Content-Layer Services Overview
439
Ken Rockot216eb5d2020-02-19 17:09:55440### Interface Brokers
Ken Rockotab035122019-02-06 00:35:24441
Oksana Zhuravlovaee1afd12020-02-15 00:47:27442We define an explicit mojom interface with a persistent connection
443between a renderer's frame object and the corresponding
444`RenderFrameHostImpl` in the browser process.
Ken Rockotab035122019-02-06 00:35:24445This interface is called
Oksana Zhuravlova9f3b8ef2019-08-26 20:27:40446[`BrowserInterfaceBroker`](https://cs.chromium.org/chromium/src/third_party/blink/public/mojom/browser_interface_broker.mojom?rcl=09aa5ae71649974cae8ad4f889d7cd093637ccdb&l=11)
447and is fairly easy to work with: you add a new method on `RenderFrameHostImpl`:
Ken Rockotab035122019-02-06 00:35:24448
449``` cpp
450void RenderFrameHostImpl::GetGoatTeleporter(
Oksana Zhuravlova9f3b8ef2019-08-26 20:27:40451 mojo::PendingReceiver<magic::mojom::GoatTeleporter> receiver) {
452 goat_teleporter_receiver_.Bind(std::move(receiver));
Ken Rockotab035122019-02-06 00:35:24453}
454```
455
Oksana Zhuravlova9f3b8ef2019-08-26 20:27:40456and register this method in `PopulateFrameBinders` function in `browser_interface_binders.cc`,
457which maps specific interfaces to their handlers in respective hosts:
458
459``` cpp
460// //content/browser/browser_interface_binders.cc
461void PopulateFrameBinders(RenderFrameHostImpl* host,
Robert Sesek5a5fbb82020-05-04 16:18:28462 mojo::BinderMap* map) {
Oksana Zhuravlova9f3b8ef2019-08-26 20:27:40463...
464 map->Add<magic::mojom::GoatTeleporter>(base::BindRepeating(
465 &RenderFrameHostImpl::GetGoatTeleporter, base::Unretained(host)));
466}
467```
468
Oksana Zhuravlova291a21992021-05-12 00:00:02469It's also possible to bind an interface on a different sequence by specifying a task runner:
470
471``` cpp
472// //content/browser/browser_interface_binders.cc
473void PopulateFrameBinders(RenderFrameHostImpl* host,
474 mojo::BinderMap* map) {
475...
476 map->Add<magic::mojom::GoatTeleporter>(base::BindRepeating(
477 &RenderFrameHostImpl::GetGoatTeleporter, base::Unretained(host)),
478 GetIOThreadTaskRunner({}));
479}
480```
481
Oksana Zhuravlova22345af2020-03-18 18:45:21482For binding an embedder-specific document-scoped interface, override
483[`ContentBrowserClient::RegisterBrowserInterfaceBindersForFrame()`](https://cs.chromium.org/chromium/src/content/public/browser/content_browser_client.h?rcl=3eb14ce219e383daa0cd8d743f475f9d9ce8c81a&l=999)
484and add the binders to the provided map.
485
486*** aside
487NOTE: if BrowserInterfaceBroker cannot find a binder for the requested
488interface, it will call `ReportNoBinderForInterface()` on the relevant
489context host, which results in a `ReportBadMessage()` call on the host's
490receiver (one of the consequences is a termination of the renderer). To
491avoid this crash in tests (when content_shell doesn't bind some
492Chrome-specific interfaces, but the renderer requests them anyway),
493use the
494[`EmptyBinderForFrame`](https://cs.chromium.org/chromium/src/content/browser/browser_interface_binders.cc?rcl=12e73e76a6898cb6df6a361a98320a8936f37949&l=407)
495helper in `browser_interface_binders.cc`. However, it is recommended
496to have the renderer and browser sides consistent if possible.
497***
498
499TODO: add information about workers.
Oksana Zhuravlova9f3b8ef2019-08-26 20:27:40500
Ken Rockotab035122019-02-06 00:35:24501## Additional Support
502
503If this document was not helpful in some way, please post a message to your
504friendly
505[[email protected]](https://groups.google.com/a/chromium.org/forum/#!forum/chromium-mojo)
506or
507[[email protected]](https://groups.google.com/a/chromium.org/forum/#!forum/services-dev)
508mailing list.