blob: 847a581fa20fc7f777a2526a1f47d158bcded344 [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
Dustin J. Mitchell68180352023-03-20 17:31:2762// src/example/public/mojom/pingable.mojom
Ken Rockotab035122019-02-06 00:35:2463module example.mojom;
64
Dustin J. Mitchell68180352023-03-20 17:31:2765interface Pingable {
Ken Rockotab035122019-02-06 00:35:2466 // 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") {
Dustin J. Mitchell68180352023-03-20 17:31:2778 sources = [ "pingable.mojom" ]
Ken Rockotab035122019-02-06 00:35:2479}
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
Dustin J. Mitchell68180352023-03-20 17:31:2797// src/third_party/blink/example/public/pingable.h
98mojo::Remote<example::mojom::Pingable> pingable;
99mojo::PendingReceiver<example::mojom::Pingable> receiver =
100 pingable.BindNewPipeAndPassReceiver();
Ken Rockotab035122019-02-06 00:35:24101```
102
Dustin J. Mitchell68180352023-03-20 17:31:27103In this example, ```pingable``` is the `Remote`, and ```receiver```
Darwin Huangb4bd2452019-10-08 22:56:04104is 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
Dustin J. Mitchell68180352023-03-20 17:31:27121// src/third_party/blink/example/public/pingable.h
122pingable->Ping(base::BindOnce(&OnPong));
Ken Rockotab035122019-02-06 00:35:24123```
124
125*** aside
Darwin Huangb4bd2452019-10-08 22:56:04126**IMPORTANT:** If we want to receive the response, we must keep the
Dustin J. Mitchell68180352023-03-20 17:31:27127`pingable` object alive until `OnPong` is invoked. After all,
128`pingable` *owns* its message pipe endpoint. If it's destroyed then so is
Ken Rockotab035122019-02-06 00:35:24129the 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
Dustin J. Mitchell68180352023-03-20 17:31:27174Finally, we need a browser-side implementation of our `Pingable` interface.
Ken Rockotab035122019-02-06 00:35:24175
176```cpp
Dustin J. Mitchell68180352023-03-20 17:31:27177#include "example/public/mojom/pingable.mojom.h"
Ken Rockotab035122019-02-06 00:35:24178
Dustin J. Mitchell68180352023-03-20 17:31:27179class PingableImpl : example::mojom::Pingable {
Ken Rockotab035122019-02-06 00:35:24180 public:
Dustin J. Mitchell68180352023-03-20 17:31:27181 explicit PingableImpl(mojo::PendingReceiver<example::mojom::Pingable> receiver)
Oksana Zhuravlova9f3b8ef2019-08-26 20:27:40182 : receiver_(this, std::move(receiver)) {}
Dustin J. Mitchell68180352023-03-20 17:31:27183 PingableImpl(const PingableImpl&) = delete;
184 PingableImpl& operator=(const PingableImpl&) = delete;
Ken Rockotab035122019-02-06 00:35:24185
Dustin J. Mitchell68180352023-03-20 17:31:27186 // example::mojom::Pingable:
Ken Rockotab035122019-02-06 00:35:24187 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:
Dustin J. Mitchell68180352023-03-20 17:31:27193 mojo::Receiver<example::mojom::Pingable> 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 ...
Dustin J. Mitchell68180352023-03-20 17:31:27205 void GetPingable(mojo::PendingReceiver<example::mojom::Pingable> receiver);
Ken Rockotab035122019-02-06 00:35:24206 ...
207 private:
208 ...
Dustin J. Mitchell68180352023-03-20 17:31:27209 std::unique_ptr<PingableImpl> pingable_;
Ken Rockotab035122019-02-06 00:35:24210 ...
211};
212
213// render_frame_host_impl.cc
Dustin J. Mitchell68180352023-03-20 17:31:27214void RenderFrameHostImpl::GetPingable(
215 mojo::PendingReceiver<example::mojom::Pingable> receiver) {
216 pingable_ = std::make_unique<PingableImpl>(std::move(receiver));
Oksana Zhuravlova9f3b8ef2019-08-26 20:27:40217}
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...
Dustin J. Mitchell68180352023-03-20 17:31:27223 // Register the handler for Pingable.
224 map->Add<example::mojom::Pingable>(base::BindRepeating(
225 &RenderFrameHostImpl::GetPingable, 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
Dustin J. Mitchell68180352023-03-20 17:31:27232Assuming we kept our `pingable` object alive in the renderer long enough,
Ken Rockotab035122019-02-06 00:35:24233we 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 Rockot216eb5d2020-02-19 17:09:55297#include "chrome/services/math/public/mojom/math_service.mojom.h"
Ken Rockotab035122019-02-06 00:35:24298
299namespace math {
300
Ken Rockot216eb5d2020-02-19 17:09:55301class MathService : public mojom::MathService {
Ken Rockotab035122019-02-06 00:35:24302 public:
Ken Rockot216eb5d2020-02-19 17:09:55303 explicit MathService(mojo::PendingReceiver<mojom::MathService> receiver);
Johanne6e768e92020-09-09 00:51:10304 MathService(const MathService&) = delete;
305 MathService& operator=(const MathService&) = delete;
Peter Boström2e6be142021-11-13 01:28:25306 ~MathService() override;
Ken Rockotab035122019-02-06 00:35:24307
308 private:
Ken Rockot216eb5d2020-02-19 17:09:55309 // mojom::MathService:
Ken Rockotab035122019-02-06 00:35:24310 void Divide(int32_t dividend,
311 int32_t divisor,
312 DivideCallback callback) override;
313
Ken Rockot216eb5d2020-02-19 17:09:55314 mojo::Receiver<mojom::MathService> receiver_;
Ken Rockotab035122019-02-06 00:35:24315};
316
317} // namespace math
318```
319
320``` cpp
321// src/chrome/services/math/math_service.cc
322#include "chrome/services/math/math_service.h"
323
324namespace math {
325
Ken Rockot216eb5d2020-02-19 17:09:55326MathService::MathService(mojo::PendingReceiver<mojom::MathService> receiver)
327 : receiver_(this, std::move(receiver)) {}
Ken Rockotab035122019-02-06 00:35:24328
329MathService::~MathService() = default;
330
Ken Rockotab035122019-02-06 00:35:24331void MathService::Divide(int32_t dividend,
332 int32_t divisor,
333 DivideCallback callback) {
334 // Respond with the quotient!
Oksana Zhuravlova0941c08d2019-05-03 20:46:33335 std::move(callback).Run(dividend / divisor);
Ken Rockotab035122019-02-06 00:35:24336}
337
338} // namespace math
339```
340
341``` python
342# src/chrome/services/math/BUILD.gn
343
344source_set("math") {
345 sources = [
Dominic Farolino982b79c2020-09-08 20:07:10346 "math_service.cc",
347 "math_service.h",
Ken Rockotab035122019-02-06 00:35:24348 ]
349
350 deps = [
351 "//base",
352 "//chrome/services/math/public/mojom",
Ken Rockotab035122019-02-06 00:35:24353 ]
354}
355```
356
Ken Rockot216eb5d2020-02-19 17:09:55357Now we have a fully defined `MathService` implementation that we can make
358available in- or out-of-process.
Ken Rockotab035122019-02-06 00:35:24359
360### Hooking Up the Service Implementation
361
Ken Rockot216eb5d2020-02-19 17:09:55362For an out-of-process Chrome service, we simply register a factory function
363in [`//chrome/utility/services.cc`](https://cs.chromium.org/chromium/src/chrome/utility/services.cc).
Ken Rockotab035122019-02-06 00:35:24364
365``` cpp
Ken Rockot216eb5d2020-02-19 17:09:55366auto RunMathService(mojo::PendingReceiver<math::mojom::MathService> receiver) {
367 return std::make_unique<math::MathService>(std::move(receiver));
Ken Rockotab035122019-02-06 00:35:24368}
Ken Rockot216eb5d2020-02-19 17:09:55369
Miriam Polzer49235d02020-11-13 17:19:29370void RegisterMainThreadServices(mojo::ServiceFactory& services) {
371 // Existing services...
372 services.Add(RunFilePatcher);
373 services.Add(RunUnzipper);
Ken Rockot216eb5d2020-02-19 17:09:55374
Miriam Polzer49235d02020-11-13 17:19:29375 // We add our own factory to this list
376 services.Add(RunMathService);
377 //...
Ken Rockotab035122019-02-06 00:35:24378```
379
Ken Rockot216eb5d2020-02-19 17:09:55380With this done, it is now possible for the browser process to launch new
381out-of-process instances of MathService.
Ken Rockotab035122019-02-06 00:35:24382
Ken Rockot216eb5d2020-02-19 17:09:55383### Launching the Service
384
385If you're running your service in-process, there's really nothing interesting
386left to do. You can instantiate the service implementation just like any other
387object, yet you can also talk to it via a Mojo Remote as if it were
388out-of-process.
389
390To launch an out-of-process service instance after the hookup performed in the
391previous section, use Content's
392[`ServiceProcessHost`](https://cs.chromium.org/chromium/src/content/public/browser/service_process_host.h?rcl=e7a1f6c9a24f3151c875598174a05167fb12c5d5&l=47)
393API:
Ken Rockotab035122019-02-06 00:35:24394
395``` cpp
Ken Rockot216eb5d2020-02-19 17:09:55396mojo::Remote<math::mojom::MathService> math_service =
397 content::ServiceProcessHost::Launch<math::mojom::MathService>(
Mateus Azis0c2ebb402022-03-10 01:19:55398 content::ServiceProcessHost::Options()
Ken Rockot216eb5d2020-02-19 17:09:55399 .WithDisplayName("Math!")
400 .Pass());
Ken Rockotab035122019-02-06 00:35:24401```
402
Ken Rockot216eb5d2020-02-19 17:09:55403Except in the case of crashes, the launched process will live as long as
404`math_service` lives. As a corollary, you can force the process to be torn
405down by destroying (or resetting) `math_service`.
Ken Rockotab035122019-02-06 00:35:24406
Ken Rockot216eb5d2020-02-19 17:09:55407We can now perform an out-of-process division:
Ken Rockotab035122019-02-06 00:35:24408
409``` cpp
Ken Rockot216eb5d2020-02-19 17:09:55410// NOTE: As a client, we do not have to wait for any acknowledgement or
411// confirmation of a connection. We can start queueing messages immediately and
412// they will be delivered as soon as the service is up and running.
413math_service->Divide(
Ken Rockotab035122019-02-06 00:35:24414 42, 6, base::BindOnce([](int32_t quotient) { LOG(INFO) << quotient; }));
415```
Oksana Zhuravlova0941c08d2019-05-03 20:46:33416*** aside
Mario Sanchez Prada7dead3e2019-12-20 18:46:38417NOTE: To ensure the execution of the response callback, the
Ken Rockot216eb5d2020-02-19 17:09:55418`mojo::Remote<math::mojom::MathService>` object must be kept alive (see
Oksana Zhuravlova0941c08d2019-05-03 20:46:33419[this section](/mojo/public/cpp/bindings/README.md#A-Note-About-Endpoint-Lifetime-and-Callbacks)
420and [this note from an earlier section](#sending-a-message)).
421***
Ken Rockotab035122019-02-06 00:35:24422
Alex Goughad69b6d2021-07-30 23:23:57423### Specifying a sandbox
Alex Goughf18988f2020-05-15 00:51:02424
Alex Goughad69b6d2021-07-30 23:23:57425All services must specify a sandbox. Ideally services will run inside the
426`kService` process sandbox unless they need access to operating system
427resources. For services that need a custom sandbox, a new sandbox type must be
428defined in consultation with [email protected].
Alex Gough4aac4e92021-05-26 01:46:47429
Alex Goughad69b6d2021-07-30 23:23:57430The preferred way to define the sandbox for your interface is by specifying a
431`[ServiceSandbox=type]` attribute on your `interface {}` in its `.mojom` file:
432
433```
Nina Satragno0810b572024-01-25 21:27:52434import "sandbox/policy/mojom/sandbox.mojom";
Alex Goughad69b6d2021-07-30 23:23:57435[ServiceSandbox=sandbox.mojom.Sandbox.kService]
436interface FakeService {
437 ...
438};
439```
440
441Valid values are those in
442[`//sandbox/policy/mojom/sandbox.mojom`](https://cs.chromium.org/chromium/src/sandbox/policy/mojom/sandbox.mojom). Note
443that the sandbox is only applied if the interface is launched
444out-of-process using `content::ServiceProcessHost::Launch()`.
445
Alex Goughec5693892021-10-12 00:55:44446As a last resort, dynamic or feature based mapping to an underlying platform
447sandbox can be achieved but requires plumbing through ContentBrowserClient
Andrey Kosyakov07716892024-09-19 03:31:13448(e.g. `ShouldSandboxNetworkService()`).
Alex Goughf18988f2020-05-15 00:51:02449
Ken Rockotab035122019-02-06 00:35:24450## Content-Layer Services Overview
451
Ken Rockot216eb5d2020-02-19 17:09:55452### Interface Brokers
Ken Rockotab035122019-02-06 00:35:24453
Oksana Zhuravlovaee1afd12020-02-15 00:47:27454We define an explicit mojom interface with a persistent connection
455between a renderer's frame object and the corresponding
456`RenderFrameHostImpl` in the browser process.
Ken Rockotab035122019-02-06 00:35:24457This interface is called
Oksana Zhuravlova9f3b8ef2019-08-26 20:27:40458[`BrowserInterfaceBroker`](https://cs.chromium.org/chromium/src/third_party/blink/public/mojom/browser_interface_broker.mojom?rcl=09aa5ae71649974cae8ad4f889d7cd093637ccdb&l=11)
459and is fairly easy to work with: you add a new method on `RenderFrameHostImpl`:
Ken Rockotab035122019-02-06 00:35:24460
461``` cpp
462void RenderFrameHostImpl::GetGoatTeleporter(
Oksana Zhuravlova9f3b8ef2019-08-26 20:27:40463 mojo::PendingReceiver<magic::mojom::GoatTeleporter> receiver) {
464 goat_teleporter_receiver_.Bind(std::move(receiver));
Ken Rockotab035122019-02-06 00:35:24465}
466```
467
Oksana Zhuravlova9f3b8ef2019-08-26 20:27:40468and register this method in `PopulateFrameBinders` function in `browser_interface_binders.cc`,
469which maps specific interfaces to their handlers in respective hosts:
470
471``` cpp
472// //content/browser/browser_interface_binders.cc
473void PopulateFrameBinders(RenderFrameHostImpl* host,
Robert Sesek5a5fbb82020-05-04 16:18:28474 mojo::BinderMap* map) {
Oksana Zhuravlova9f3b8ef2019-08-26 20:27:40475...
476 map->Add<magic::mojom::GoatTeleporter>(base::BindRepeating(
477 &RenderFrameHostImpl::GetGoatTeleporter, base::Unretained(host)));
478}
479```
480
Oksana Zhuravlova291a21992021-05-12 00:00:02481It's also possible to bind an interface on a different sequence by specifying a task runner:
482
483``` cpp
484// //content/browser/browser_interface_binders.cc
485void PopulateFrameBinders(RenderFrameHostImpl* host,
486 mojo::BinderMap* map) {
487...
488 map->Add<magic::mojom::GoatTeleporter>(base::BindRepeating(
489 &RenderFrameHostImpl::GetGoatTeleporter, base::Unretained(host)),
490 GetIOThreadTaskRunner({}));
491}
492```
493
Andrew Williamsf90bbdd32021-12-29 19:19:57494Workers also have `BrowserInterfaceBroker` connections between the renderer and
495the corresponding remote implementation in the browser process. Adding new
496worker-specific interfaces is similar to the steps detailed above for frames,
497with the following differences:
498 - For Dedicated Workers, add a new method to
499 [`DedicatedWorkerHost`](https://source.chromium.org/chromium/chromium/src/+/main:content/browser/worker_host/dedicated_worker_host.h)
500 and register it in
501 [`PopulateDedicatedWorkerBinders`](https://source.chromium.org/chromium/chromium/src/+/main:content/browser/browser_interface_binders.cc;l=1126;drc=e24e0a914ff0da18e78044ebad7518afe9e13847)
502 - For Shared Workers, add a new method to
503 [`SharedWorkerHost`](https://source.chromium.org/chromium/chromium/src/+/main:content/browser/worker_host/shared_worker_host.h)
504 and register it in
505 [`PopulateSharedWorkerBinders`](https://source.chromium.org/chromium/chromium/src/+/main:content/browser/browser_interface_binders.cc;l=1232;drc=e24e0a914ff0da18e78044ebad7518afe9e13847)
506 - For Service Workers, add a new method to
507 [`ServiceWorkerHost`](https://source.chromium.org/chromium/chromium/src/+/main:content/browser/service_worker/service_worker_host.h)
508 and register it in
509 [`PopulateServiceWorkerBinders`](https://source.chromium.org/chromium/chromium/src/+/main:content/browser/browser_interface_binders.cc;l=1326;drc=e24e0a914ff0da18e78044ebad7518afe9e13847)
510
511Interfaces can also be added at the process level using the
512`BrowserInterfaceBroker` connection between the Blink `Platform` object in the
513renderer and the corresponding `RenderProcessHost` object in the browser
514process. This allows any thread (including frame and worker threads) in the
515renderer to access the interface, but comes with additional overhead because
516the `BrowserInterfaceBroker` implementation used must be thread-safe. To add a
517new process-level interface, add a new method to `RenderProcessHostImpl` and
518register it using a call to
519[`AddUIThreadInterface`](https://source.chromium.org/chromium/chromium/src/+/main:content/browser/renderer_host/render_process_host_impl.h;l=918;drc=ec5eaba0e021b757d5cbbf2c27ac8f06809d81e9)
520in
521[`RenderProcessHostImpl::RegisterMojoInterfaces`](https://source.chromium.org/chromium/chromium/src/+/main:content/browser/renderer_host/render_process_host_impl.cc;l=2317;drc=a817d852ea2f2085624d64154ad847dfa3faaeb6).
522On the renderer side, use
523[`Platform::GetBrowserInterfaceBroker`](https://source.chromium.org/chromium/chromium/src/+/main:third_party/blink/public/platform/platform.h;l=781;drc=ee1482552c4c97b40f15605fe6a52565cfe74548)
524to retrieve the corresponding `BrowserInterfaceBroker` object to call
525`GetInterface` on.
526
Oksana Zhuravlova22345af2020-03-18 18:45:21527For binding an embedder-specific document-scoped interface, override
528[`ContentBrowserClient::RegisterBrowserInterfaceBindersForFrame()`](https://cs.chromium.org/chromium/src/content/public/browser/content_browser_client.h?rcl=3eb14ce219e383daa0cd8d743f475f9d9ce8c81a&l=999)
529and add the binders to the provided map.
530
531*** aside
532NOTE: if BrowserInterfaceBroker cannot find a binder for the requested
533interface, it will call `ReportNoBinderForInterface()` on the relevant
534context host, which results in a `ReportBadMessage()` call on the host's
535receiver (one of the consequences is a termination of the renderer). To
536avoid this crash in tests (when content_shell doesn't bind some
537Chrome-specific interfaces, but the renderer requests them anyway),
538use the
539[`EmptyBinderForFrame`](https://cs.chromium.org/chromium/src/content/browser/browser_interface_binders.cc?rcl=12e73e76a6898cb6df6a361a98320a8936f37949&l=407)
540helper in `browser_interface_binders.cc`. However, it is recommended
541to have the renderer and browser sides consistent if possible.
542***
543
Andrew Williamsf90bbdd32021-12-29 19:19:57544### Navigation-Associated Interfaces
545
546For cases where the ordering of messages from different frames is important,
547and when messages need to be ordered correctly with respect to the messages
548implementing navigation, navigation-associated interfaces can be used.
549Navigation-associated interfaces leverage connections from each frame to the
550corresponding `RenderFrameHostImpl` object and send messages from each
551connection over the same FIFO pipe that's used for messages relating to
552navigation. As a result, messages sent after a navigation are guaranteed to
553arrive in the browser process after the navigation-related messages, and the
554ordering of messages sent from different frames of the same document is
555preserved as well.
556
557To add a new navigation-associated interface, create a new method for
558`RenderFrameHostImpl` and register it with a call to
559`associated_registry_->AddInterface` in
560[`RenderFrameHostImpl::SetUpMojoConnection`](https://source.chromium.org/chromium/chromium/src/+/main:content/browser/renderer_host/render_frame_host_impl.cc;l=8365;drc=a817d852ea2f2085624d64154ad847dfa3faaeb6).
561From the renderer, use
562[`LocalFrame::GetRemoteNavigationAssociatedInterfaces`](https://source.chromium.org/chromium/chromium/src/+/main:third_party/blink/renderer/core/frame/local_frame.h;l=409;drc=19f17a30e102f811bc90a13f79e8ad39193a6403)
563to get an object to call
564`GetInterface` on (this call is similar to
565`BrowserInterfaceBroker::GetInterface` except that it takes a
566[pending associated receiver](https://chromium.googlesource.com/chromium/src/+/main/mojo/public/cpp/bindings/README.md#associated-interfaces)
567instead of a pending receiver).
Oksana Zhuravlova9f3b8ef2019-08-26 20:27:40568
Ken Rockotab035122019-02-06 00:35:24569## Additional Support
570
571If this document was not helpful in some way, please post a message to your
572friendly
573[[email protected]](https://groups.google.com/a/chromium.org/forum/#!forum/chromium-mojo)
574or
575[[email protected]](https://groups.google.com/a/chromium.org/forum/#!forum/services-dev)
576mailing list.