Index: docs/mojo_in_chromium.md |
diff --git a/docs/mojo_in_chromium.md b/docs/mojo_in_chromium.md |
deleted file mode 100644 |
index c9e71c8dae35f6820cca345214d35f110d0bc556..0000000000000000000000000000000000000000 |
--- a/docs/mojo_in_chromium.md |
+++ /dev/null |
@@ -1,342 +0,0 @@ |
-# Mojo in Chromium |
- |
-This document is intended to serve as a Mojo primer for Chromium developers. No |
-prior knowledge of Mojo is assumed. |
- |
-[TOC] |
- |
-## Should I Bother Reading This? |
- |
-If you're planning to build a Chromium feature that needs IPC and you aren't |
-already using Mojo, YES! **Legacy IPC is deprecated.** |
- |
-## Why Mojo? |
- |
-TL;DR: The long-term intent is to refactor Chromium into a large set of smaller |
-services. |
- |
-We can be smarter about: |
- |
- * Which services we bring up or don't |
- * How we isolate these services to improve security and stability |
- * Which binary features we ship to one user or another |
- |
-A more robust messaging layer opens the door for a number of interesting |
-possibilities; in particular it allows us to integrate a large number of |
-components without link-time interdependencies, and it breaks down the growing |
-number of interesting cross-language boundaries across the codebase. |
- |
-Much has been learned from using Chromium IPC and maintaining Chromium |
-dependencies in anger over the past several years and we feel there's now a |
-significant opportunity to make life easier for developers, and to help them |
-build more and better features, faster, and with much less cost to users. |
- |
-## Mojo Overview |
- |
-The Mojo system API provides a small suite of low-level IPC primitives: |
-**message pipes**, **data pipes**, and **shared buffers**. On top of this API |
-we've built higher-level bindings APIs to simplify messaging for consumers |
-writing C++, Java, or JavaScript code. |
- |
-This document focuses primarily on using C++ bindings with message pipes, which |
-is likely to be the most common usage encountered by Chromium developers. |
- |
-### Message Pipes |
- |
-A message pipe is a lightweight primitive for reliable bidirectional transfer of |
-relatively small packets of data. Unsurprisingly a pipe has two endpoints, and |
-either endpoint may be transferred over another message pipe. |
- |
-Because we bootstrap a primordial message pipe between the browser process and |
-each child process, this in turn means that you can create a new pipe and |
-ultimately send either end to any process, and the two ends will still be |
-able to talk to each other seamlessly and exclusively. Goodbye, routing IDs! |
- |
-While message pipes can carry arbitrary packets of unstructured data we |
-generally use them in conjunction with generated bindings to ensure a |
-consistent, well-defined, versioned message structure on all endpoints. |
- |
-### Mojom |
- |
-Mojom is the IDL for Mojo interfaces. Given a `.mojom` file, the bindings |
-generator outputs bindings for all three of the currently supported languages. |
- |
-For example: |
- |
-``` |
-// src/components/frob/public/interfaces/frobinator.mojom |
-module frob.mojom; |
- |
-interface Frobinator { |
- Frobinate(); |
-}; |
-``` |
- |
-would generate the following outputs: |
- |
-``` |
-out/Debug/gen/components/frob/public/interfaces/frobinator.mojom.cc |
-out/Debug/gen/components/frob/public/interfaces/frobinator.mojom.h |
-out/Debug/gen/components/frob/public/interfaces/frobinator.mojom.js |
-out/Debug/gen/components/frob/public/interfaces/frobinator.mojom.srcjar |
-... |
-``` |
- |
-The generated code hides away all the details of serializing and deserializing |
-messages on either end of a pipe. |
- |
-The C++ header (`frobinator.mojom.h`) defines an abstract class for each |
-mojom interface specified. Namespaces are derived from the `module` name. |
- |
-**NOTE:** Chromium convention for component `foo`'s module name is `foo.mojom`. |
-This means all mojom-generated C++ typenames for component `foo` will live in |
-the `foo::mojom` namespace to avoid collisions with non-generated typenames. |
- |
-In this example the generated `frob::mojom::Frobinator` has a single |
-pure virtual function: |
- |
-```cpp |
-namespace frob { |
- |
-class Frobinator { |
- public: |
- virtual void Frobinate() = 0; |
-}; |
- |
-} // namespace frob |
-``` |
- |
-To create a `Frobinator` service, one simply implements `foo::Frobinator` and |
-provides a means of binding pipes to it. |
- |
-### Binding to Pipes |
- |
-Let's look at some sample code: |
- |
-```cpp |
-// src/components/frob/frobinator_impl.cc |
- |
-#include "components/frob/public/interfaces/frobinator.mojom.h" |
-#include "mojo/public/cpp/bindings/binding.h" |
-#include "mojo/public/cpp/bindings/interface_request.h" |
- |
-namespace frob { |
- |
-class FrobinatorImpl : public mojom::Frobinator { |
- public: |
- FrobinatorImpl(mojom::FrobinatorRequest request) |
- : binding_(this, std::move(request)) {} |
- ~FrobinatorImpl() override {} |
- |
- // mojom::Frobinator: |
- void Frobinate() override { DLOG(INFO) << "I can't stop frobinating!"; } |
- |
- private: |
- mojo::Binding<mojom::Frobinator> binding_; |
-}; |
- |
-} // namespace frob |
-``` |
- |
-The first thing to note is that `mojo::Binding<T>` *binds* one end of a message |
-pipe to an implementation of a service. This means it watches that end of the |
-pipe for incoming messages; it knows how to decode messages for interface `T`, |
-and it dispatches them to methods on the bound `T` implementation. |
- |
-`mojom::FrobinatorRequest` is a generated type alias for |
-`mojo::InterfaceRequest<mojom::Frobinator>` and is essentially semantic sugar |
-for a strongly-typed message pipe endpoint. A common way to create new message |
-pipes is via the `GetProxy` call defined in `interface_request.h`: |
- |
-```cpp |
-mojom::FrobinatorPtr proxy; |
-mojom::FrobinatorRequest request = mojo::GetProxy(&proxy); |
-``` |
- |
-This creates a new message pipe with one end owned by `proxy` and the other end |
-owned by `request`. It has the nice property of attaching common type |
-information to each end of the pipe. |
- |
-Note that `InterfaceRequest<T>` doesn't actually **do** anything. It just scopes |
-a pipe endpoint and associates it with an interface type at compile time. As |
-such, other typed service binding primitives such as `mojo::Binding<T>` take |
-these objects as input when they need an endpoint to bind to. |
- |
-`mojom::FrobinatorPtr` is a generated type alias for |
-`mojo::InterfacePtr<mojom::Frobinator>`. An `InterfacePtr<T>` scopes a message |
-pipe endpoint as well, but it also internally implements every method on `T` by |
-serializing a corresponding message and writing it to the pipe. |
- |
-Hence we can put this together to talk to a `FrobinatorImpl` over a pipe: |
- |
-```cpp |
-frob:mojom::FrobinatorPtr frobinator; |
-frob::FrobinatorImpl impl(GetProxy(&frobinator)); |
- |
-// Tada! |
-frobinator->Frobinate(); |
-``` |
- |
-Behind the scenes this serializes a message corresponding to the `Frobinate` |
-request and writes it to one end of the pipe. Eventually (and incidentally, |
-very soon after), `impl`'s internal `mojo::Binding` will decode this message and |
-dispatch a call to `impl.Frobinate()`. |
- |
-**NOTE:** In this example the service and client are in the same process, and |
-this works just fine. If they were in different processes (see the example below |
-in [Exposing Services in Chromium](#Exposing-Services-in-Chromium)), the call |
-to `Frobinate()` would look exactly the same! |
- |
-### Responding to Requests |
- |
-A common idiom in Chromium IPC is to keep track of IPC requests with some kind |
-of opaque identifier (i.e. an integer *request ID*) so that you can later |
-respond to a specific request using some nominally related message in the other |
-direction. |
- |
-This is baked into mojom interface definitions. We can extend our `Frobinator` |
-service like so: |
- |
-``` |
-module frob.mojom; |
- |
-interface Frobinator { |
- Frobinate(); |
- GetFrobinationLevels() => (int min, int max); |
-}; |
-``` |
- |
-and update our implementation: |
- |
-```cpp |
-class FrobinatorImpl : public mojom::Frobinator { |
- public: |
- // ... |
- |
- // mojom::Frobinator: |
- void Frobinate() override { /* ... */ } |
- void GetFrobinationLevels(const GetFrobinationLevelsCallback& callback) { |
- callback.Run(1, 42); |
- } |
-}; |
-``` |
- |
-When the service implementation runs `callback`, the response arguments are |
-serialized and sent back over the pipe. The proxy on the other end knows how to |
-read this response and will in turn dispatch it to a callback on that end: |
- |
-```cpp |
-void ShowLevels(int min, int max) { |
- DLOG(INFO) << "Frobinator min=" << min << " max=" << max; |
-} |
- |
-// ... |
- |
- mojom::FrobinatorPtr frobinator; |
- FrobinatorImpl impl(GetProxy(&frobinator)); |
- |
- frobinator->GetFrobinatorLevels(base::Bind(&ShowLevels)); |
-``` |
- |
-This does what you'd expect. |
- |
-## Exposing Services in Chromium |
- |
-There are a number of ways one might expose services across various surfaces of |
-the browser. One common approach now is to use a |
-[`content::ServiceRegistry` (link)](https://goo.gl/uEhx06). These come in |
-pairs generally spanning a process boundary, and they provide primitive service |
-registration and connection interfaces. For one example, [every |
-`RenderFrameHost` has a `ServiceRegistry`](https://goo.gl/4YR3j5), as does |
-[every corresponding `RenderFrame`](https://goo.gl/YhrgXa). These registries are |
-intertwined. |
- |
-The gist is that you can add a service to the local side of the registry -- it's |
-just a mapping from interface name to factory function -- or you can connect by |
-name to services registered on the remote side. |
- |
-**NOTE:** In this context the "factory function" is simply a callback which |
-takes a pipe endpoint and does something with it. It's expected that you'll |
-either bind it to a service implementation of some kind or you will close it, effectively rejecting the connection request. |
- |
-We can build a simple browser-side `FrobinatorImpl` service that has access to a |
-`BrowserContext` for any frame which connects to it: |
- |
-```cpp |
-#include "base/macros.h" |
-#include "components/frob/public/interfaces/frobinator.mojom.h" |
-#include "content/public/browser/browser_context.h" |
-#include "mojo/public/cpp/system/interface_request.h" |
-#include "mojo/public/cpp/system/strong_binding.h" |
- |
-namespace frob { |
- |
-class FrobinatorImpl : public mojom::Frobinator { |
- public: |
- FrobinatorImpl(content::BrowserContext* context, |
- mojom::FrobinatorRequest request) |
- : context_(context), binding_(this, std::move(request)) {} |
- ~FrobinatorImpl() override {} |
- |
- // A factory function to use in conjunction with ServiceRegistry. |
- static void Create(content::BrowserContext* context, |
- mojom::FrobinatorRequest request) { |
- // See comment below for why this doesn't leak. |
- new FrobinatorImpl(context, std::move(request)); |
- } |
- |
- private: |
- // mojom::Frobinator: |
- void Frobinate() override { /* ... */ } |
- |
- content::BrowserContext* context_; |
- |
- // A StrongBinding is just like a Binding, except that it takes ownership of |
- // its bound implementation and deletes itself (and the impl) if and when the |
- // bound pipe encounters an error or is closed on the other end. |
- mojo::StrongBinding<mojom::Frobinator> binding_; |
- |
- DISALLOW_COPY_AND_ASSIGN(FrobinatorImpl); |
-}; |
- |
-} // namespace frob |
-``` |
- |
-Now somewhere in the browser we register the Frobinator service with each |
-`RenderFrameHost` ([this](https://goo.gl/HEFn63) is a popular spot): |
- |
-```cpp |
-frame_host->GetServiceRegistry()->AddService<frob::mojom::Frobinator>( |
- base::Bind( |
- &frob::FrobinatorImpl::Create, |
- base::Unretained(frame_host->GetProcess()->GetBrowserContext()))); |
-``` |
- |
-And in the render process we can now do something like: |
- |
-```cpp |
-mojom::FrobinatorPtr frobinator; |
-render_frame->GetServiceRegistry()->ConnectToRemoteService( |
- mojo::GetProxy(&frobinator)); |
- |
-// It's IPC! |
-frobinator->Frobinate(); |
-``` |
- |
-There are now plenty of concrete examples of Mojo usage in the Chromium tree. |
-Poke around at existing mojom files and see how their implementions are built |
-and connected. |
- |
-## Mojo in Blink |
- |
-*TODO* |
- |
-This is a work in progress. TL;DR: We'll also soon begin using Mojo services |
-from Blink so that the platform layer can consume browser services |
-directly via Mojo. The long-term goal there is to eliminate `content/renderer`. |
- |
-## Questions, Discussion, etc. |
- |
-A good place to find highly concentrated doses of people who know and care |
-about Mojo in Chromium would be the [chromium-mojo](https://goo.gl/A4ebWB) |
-mailing list[.](https://goo.gl/L70ihQ) |