Update Mojo and services documentation
This is a large update to all Mojo and services documentation in the
tree. Here are the changes in a nutshell:
- Images for Mojo docs are upstreamed instead of being pulled from
docs.google.com
- Various minor updates, corrections, clarifications in core Mojo
docs
- Consolidation of documents in the tree.
- Refresh of all service and Service Manager related documentation,
removing lots of outdated information, adding clarifying definitions
and examples of core concepts
As of this CL, the relevant documentation in the tree is pared down
to:
- The mojo/ subtree itself
- services/README.md - service guidelines
- services/service_manager/README.md - general service manager
and service API documentation, examples, etc
- docs/mojo_and_services.md - intro to mojo & services for
chromium developers
- docs/mojo_ipc_conversion.md - advice for converting legacy IPCs
to mojo interfaces
- docs/servicification.md - advice for servicifying chromium
features specifically
Specifically this wipes out content/public/common/services.md,
ipc/README.md, services/service_manager/service_manifests.md, and
services/api_standards.md. Any still-relevant content that was in
these docs has been merged into one of the docs listed above.
Finally, the presence in docs/README.md has been cleaned up a bit.
A new section for "Mojo & Services" is added with links to the above
list of documents.
Change-Id: I294a32025afdca62441d3605da51d714f3aebd00
TBR: [email protected]
Reviewed-on: https://chromium-review.googlesource.com/c/1441640
Commit-Queue: Ken Rockot <[email protected]>
Reviewed-by: Oksana Zhuravlova <[email protected]>
Cr-Commit-Position: refs/heads/master@{#629384}
diff --git a/docs/README.md b/docs/README.md
index 933f296..9939e5c6 100644
--- a/docs/README.md
+++ b/docs/README.md
@@ -340,7 +340,20 @@
install Chromium OS on VMWare.
* [User Data Directory](user_data_dir.md) - How the user data and cache
directories are determined on all platforms.
-* [Mojo](../mojo/README.md) - IPC mechanism used by services.
+
+### Mojo & Services
+* [Intro to Mojo & Services](mojo_and_services.md) - Quick introduction
+ to Mojo and services in Chromium, with examples
+* [Mojo API Reference](/mojo/README.md) - Detailed reference documentation for
+ all things Mojo
+* [The Service Manager & Services](/services/service_manager/README.md) -
+ Services system overview, API references, example services
+* [Service Development Guidelines](/services/README.md) - Guidelines for
+ service development in the Chromium tree
+* [Servicifying Chromium Features](servicification.md) - General advice for
+ integrating new and existing subsystems into Chromium as services
+* [Converting Legacy IPC to Mojo](mojo_ipc_conversion.md) - Tips and common
+ patterns for practical IPC conversion work
### Probably Obsolete
* [TPM Quick Reference](tpm_quick_ref.md) - Trusted Platform Module notes.
diff --git a/docs/images/mojo_binding_and_dispatch.png b/docs/images/mojo_binding_and_dispatch.png
new file mode 100644
index 0000000..06a0da7
--- /dev/null
+++ b/docs/images/mojo_binding_and_dispatch.png
Binary files differ
diff --git a/docs/images/mojo_message.png b/docs/images/mojo_message.png
new file mode 100644
index 0000000..be819052
--- /dev/null
+++ b/docs/images/mojo_message.png
Binary files differ
diff --git a/docs/images/mojo_pipe.png b/docs/images/mojo_pipe.png
new file mode 100644
index 0000000..06b2477
--- /dev/null
+++ b/docs/images/mojo_pipe.png
Binary files differ
diff --git a/docs/images/mojo_stack.png b/docs/images/mojo_stack.png
new file mode 100644
index 0000000..f36afdc
--- /dev/null
+++ b/docs/images/mojo_stack.png
Binary files differ
diff --git a/docs/images/mojo_sync_call_deadlock.png b/docs/images/mojo_sync_call_deadlock.png
new file mode 100644
index 0000000..e890c849
--- /dev/null
+++ b/docs/images/mojo_sync_call_deadlock.png
Binary files differ
diff --git a/docs/images/mojo_sync_call_flow.png b/docs/images/mojo_sync_call_flow.png
new file mode 100644
index 0000000..ad6fd15
--- /dev/null
+++ b/docs/images/mojo_sync_call_flow.png
Binary files differ
diff --git a/docs/mojo_and_services.md b/docs/mojo_and_services.md
new file mode 100644
index 0000000..18c5d3c
--- /dev/null
+++ b/docs/mojo_and_services.md
@@ -0,0 +1,855 @@
+# 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() => (int 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 & 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!
+ 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:packaged_service_manifests` 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(÷r));
+
+// 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; }));
+```
+
+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
+[[email protected]](https://groups.google.com/a/chromium.org/forum/#!forum/chromium-mojo)
+or
+[[email protected]](https://groups.google.com/a/chromium.org/forum/#!forum/services-dev)
+mailing list.
diff --git a/docs/mojo_guide.md b/docs/mojo_guide.md
deleted file mode 100644
index c5ec846..0000000
--- a/docs/mojo_guide.md
+++ /dev/null
@@ -1,157 +0,0 @@
-# Mojo For Chromium Developers
-
-## Overview
-
-This document contains the minimum amount of information needed for a developer
-to start using Mojo in Chromium. For more detailed documentation on the C++
-bindings, see [this link](/mojo/public/cpp/bindings/README.md).
-
-## Terminology
-
-A **message pipe** is a pair of **endpoints**. Each endpoint has a queue of
-incoming messages, and writing a message to one endpoint effectively enqueues
-that message on the other endpoint. Message pipes are thus bidirectional.
-
-A **mojom** file describes **interfaces** which describe strongly typed message
-structures, similar to proto files.
-
-Given a **mojom interface** and a **message pipe**, the two **endpoints**
-can be given the labels **InterfacePtr** and **Binding**. This now describes a
-strongly typed **message pipe** which transports messages described by the
-**mojom interface**. The **InterfacePtr** is the **endpoint** which "sends"
-messages, and the **Binding** "receives" messages. Note that the **message
-pipe** itself is still bidirectional, and it's possible for a message to have a
-response callback, which the **InterfacePtr** would receive.
-
-Another way to think of this is that an **InterfacePtr** is capable of making
-remote calls on an implementation of the mojom interface associated with the
-**Binding**.
-
-The **Binding** itself is just glue that wires the endpoint's message queue up
-to some implementation of the interface provided by the developer.
-
-## Example
-
-Let's apply this to Chrome. Let's say we want to send a "Ping" message from a
-Browser to a Renderer. First we need to define the mojom interface.
-
-```
-module example.mojom;
-interface PingResponder {
- // Receives a "Ping" and responds with a random integer.
- Ping() => (int random);
-};
-```
-
-Now let's make a MessagePipe.
-```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 shortly
-be turned into a **Binding**. Now we can send our Ping message.
-
-```cpp
-auto callback = base::Bind(&OnPong);
-ping_responder->Ping(callback);
-```
-
-Important aside: If we want to receive the the response, we must keep the object
-```ping_responder``` alive. After all, it's just a wrapper around a **Message
-Pipe endpoint**, if it were to go away, there'd be nothing left to receive the
-response.
-
-We're 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 the Browser to
-a Renderer, and transformed it into a problem where we just need to take the
-```request``` object, pass it to the Renderer, turn it into a **Binding**, and
-implement the interface.
-
-In Chrome, processes host services, and the services themselves are connected to
-a Service Manager via **message pipes**. It's easy to pass ```request``` to the
-appropriate Renderer using the Service Manager, but this requires explicitly
-declaring our intentions via manifest files. For this example, we'll use the
-content_browser service [manifest
-file](https://cs.chromium.org/chromium/src/content/public/app/mojo/content_browser_manifest.json)
-and the content_renderer service [manifest
-file](https://cs.chromium.org/chromium/src/content/public/app/mojo/content_renderer_manifest.json).
-
-```js
-content_renderer_manifest.json:
-...
- "interface_provider_specs": {
- "service_manager:connector": {
- "provides": {
- "cool_ping_feature": [
- "example::mojom::PingResponder"
- ]
- },
- },
-...
-```
-
-```js
-content_browser_manifest.json:
-...
- "interface_provider_specs": {
- "service_manager:connector": {
- "requires": {
- "content_renderer": [ "cool_ping_feature" ],
- },
- },
- },
-...
-```
-
-These changes indicate that the content_renderer service provides the interface
-PingResponder, under the **capability** named "cool_ping_feature". And the
-content_browser services intends to use this feature.
-```content::BindInterface``` is a helper function that takes ```request``` and
-sends it to the renderer process via the Service Manager.
-
-```cpp
-content::RenderProcessHost* host = GetRenderProcessHost();
-content::BindInterface(host, std::move(request));
-```
-
-Putting this all together for the browser process:
-```cpp
-example::mojom::PingResponderPtr ping_responder; // Make sure to keep this alive! Otherwise the response will never be received.
-example::mojom::PingResponderRequest request = mojo::MakeRequest(&ping_responder);
-ping_responder->Ping(base::BindOnce(&OnPong));
-content::RenderProcessHost* host = GetRenderProcessHost();
-content::BindInterface(host, std::move(request));
-```
-
-In the Renderer process, we need to write an implementation for PingResponder,
-and ensure that a **Binding** is created using the transported ```request```. In a
-standalone Mojo service, this would require us to implement
-```service_manager::Service::OnBindInterface()```. In Chrome, this is abstracted
-behind ```content::ConnectionFilters``` and
-```service_manager::BinderRegistry```. This is typically done in
-```RenderThreadImpl::Init```.
-
-```cpp
-class PingResponderImpl : mojom::PingResponder {
- void BindToInterface(example::mojom::PingResponderRequest request) {
- binding_.reset(
- new mojo::Binding<mojom::MemlogClient>(this, std::move(request)));
- }
- void Ping(PingCallback callback) { std::move(callback).Run(4); }
- std::unique_ptr<mojo::Binding<mojom::PingResponder>> binding_;
-};
-
-RenderThreadImpl::Init() {
-...
- this->ping_responder = std::make_unique<PingResponderImpl>();
- auto registry = base::MakeUnique<service_manager::BinderRegistry>();
-
- // This makes the assumption that |this->ping_responder| will outlive |registry|.
- registry->AddInterface(base::Bind(&PingResponderImpl::BindToInterface), base::Unretained(this->ping_responder.get()));
-
- GetServiceManagerConnection()->AddConnectionFilter(
- base::MakeUnique<SimpleConnectionFilter>(std::move(registry)));
-...
-```
diff --git a/docs/mojo_ipc_conversion.md b/docs/mojo_ipc_conversion.md
new file mode 100644
index 0000000..2a4c81d
--- /dev/null
+++ b/docs/mojo_ipc_conversion.md
@@ -0,0 +1,374 @@
+# Converting Legacy IPC to Mojo
+
+[TOC]
+
+## Overview
+
+A number of IPC messages sent (primarily between the browser and renderer
+processes) are still defined using Chrome's old IPC system in `//ipc`. This
+system uses
+[`base::Pickle`](https://cs.chromium.org/chromium/src/base/pickle.h?rcl=8b7842262ee1239b1f3ae20b9c851748ef0b9a8b&l=128)
+as the basis for message serialization and is supported by a number if `IPC_*`
+preprocessor macros defined in `//ipc` and used around the source tree.
+
+There is an ongoing, distributed effort to get these messages converted to Mojo
+interface messages. Messages that still need to be converted are tracked in two
+spreadsheets:
+
+- [Chrome IPC to Mojo migration](https://docs.google.com/spreadsheets/d/1pGWX_wxGdjAVtQOmlDDfhuIc3Pbwg9FtvFXAXYu7b7c/edit#gid=0) for non-web platform messages
+- [Mojoifying Platform Features](https://docs.google.com/spreadsheets/d/1VIINt17Dg2cJjPpoJ_HY3HI0uLpidql-1u8pBJtpbGk/edit#gid=1603373208) for web platform messages
+
+This document is concerned primarily with rote conversion of legacy IPC messages
+to Mojo interface messages. If you are considering more holistic refactoring and
+better isolation of an entire subsystem of the browser, you may consider
+[servicifying](servicification.md) the feature instead of merely converting its
+IPCs.
+
+See other [Mojo & Services](/docs/README.md#Mojo-Services) documentation
+for introductory guides, API references, and more.
+
+## Legacy IPC Concepts
+
+Each Content child process has a single **`IPC::Channel`** implementation going
+between it and the browser process, and this is used as the sole two-way FIFO
+to send legacy IPC messages between the processes.
+
+There are two fundamental types of legacy IPC messages: **control** messages,
+defined via `IPC_MESSAGE_CONTROLn` macros (where `n` is some small integer) and
+**routed** messages defined via `IPC_MESSAGE_ROUTEDn` macros.
+
+Control messages generally go between a browser-side process host (*e.g.*,
+`RenderProcessHost` or `GpuProcessHost`) and the child-side `ChildThreadImpl`
+subclass. All of these classes implement `IPC::Sender` and thus have a `Send`
+method for sending a control message to their remote counterpart, and they
+implement `IPC::Listener` to receive incoming control messages via
+`OnMessageReceived`.
+
+Routed messages are relegated to **routes** which have arbitrary meaning
+determined by their use within a given process. For example, renderers use
+routes to isolate messages scoped to individual render frames, and so such
+routed messages will travel between a `RenderFrameHostImpl` and its
+corresponding `RenderFrameImpl`, both of which also implement `IPC::Sender` and
+`IPC::Listener`.
+
+## Mojo Interfaces as Routes
+
+Routed messages in the old IPC system always carry a **routing ID** to identify
+to the receiving endpoint which routed object (*e.g.* which `RenderFrameImpl`
+or `RenderViewImpl` or whatever) the message is targeting. Each endpoint is thus
+required to do some additional book-keeping to track what each routing ID means.
+
+Mojo interfaces obviate the need for routing IDs, as new "routes" can be
+established by simply creating a new interface pipe and passing one endpoint to
+something which knows how to bind it.
+
+When thinking about an IPC message conversion to Mojo, it's important to
+consider whether the message is a control message or a routed message, as this
+determines where you might find an existing Mojo interface to carry your
+message, or where you will want to add a new end-to-end Mojo interface for that
+purpose. This can mean the difference between a single per-process interface
+going between each `RenderProcessHostImpl` and its corresponding
+`RenderThreadImpl`, vs a per-frame interface going between each
+`RenderFrameHostImpl` and its corresponding `RenderFrameImpl`.
+
+## Ordering Considerations
+
+One **very important** consideration when doing IPC conversions is the relative
+ordering of IPC-driven operations. With the old IPC system, because every
+message between two processes is globally ordered, it is quite easy for parts
+of the system to (intentionally or often unintentionally) rely on strict
+ordering guarantees.
+
+For example, imagine a `WebContentsObserver` in the browser processes observes
+a frame navigation and immediately sends an IPC message to the frame to
+configure some new behavior. The implementation may be inadvertently relying on
+this message arriving *before* some other tangentially related message sent to
+the same frame shortly after the same navigation event.
+
+Mojo does not (and in fact cannot) make any strict ordering guarantees between
+separate message pipes, as message pipes may be freely moved across process
+boundaries and thus cannot necessarily share a common FIFO at all times.
+
+If the two messages described above were moved to separate Mojo interfaces on
+separate message pipes, renderer behavior could break as the first message may
+arrive after the second message.
+
+The best solution to this problem is to rethink the IPC surface and/or
+implementation on either side to eliminate ordering dependencies between two
+interfaces that otherwise seem to be logically distinct. Failing that, Mojo's
+solution to this problem is to support
+[**associated interfaces**](/mojo/public/tools/bindings/README.md#Associated-Interfaces).
+In a nutshell, these allow multiple distinct interfaces to be multiplexed over
+a shared message pipe.
+
+## Channel-Associated Interfaces
+
+The previous section mentions **associated interfaces** as a general-purpose
+solution for establishing a mutual FIFO between multiple logical Mojo interfaces
+by having them share a single message pipe.
+
+In Chrome, the `IPC::Channel` which carries all legacy IPC messages between
+two processes is itself a Mojo message pipe. We provide a mechanism for
+associating arbitrary Mojo interfaces with this pipe, which means messages can
+be converted to Mojo while preserving strict FIFO with respect to other legacy
+IPC messages. Such interfaces are designated in Chrome parlance as
+**Channel-associated interfaces**.
+
+*** aside
+**NOTE:** Channel-associated interface acquisition is not constrained by the
+Service Manager in any way, so security reviewers need to be careful to inspect
+new additions and uses of such interfaces.
+***
+
+Usage of Channel-associated interfaces should be rare but is considered a
+reasonable intermediate solution for incremental IPC conversions where it would
+be too risky or noisy to convert a large IPC surface all at once, but it would
+also be impossible to split the IPC surface between legacy IPC and a dedicated
+Mojo interface pipe without introducing timing bugs.
+
+At this point in Chrome's development, practical usage of Channel-associated
+interfaces is restricted to the `IPC::Channel` between the browser process and
+a renderer process, as this is the most complex IPC surface with the most
+implicit ordering dependencies. A few simple APIs exist to support this.
+
+`RenderProcessHostImpl` owns an `IPC::Channel` to its corresponding
+`RenderThreadImpl` in the render process. This object has a
+`GetRemoteAssociatedInterfaces` method which can be used to pass arbitrary
+associated interface requests:
+
+``` cpp
+magic::mojom::GoatTeleporterAssociatedPtr teleporter;
+channel_->GetRemoteAssociatedInterfaces()->GetInterface(&teleporter);
+
+// These messages are all guaranteed to arrive in the same order they were sent.
+channel_->Send(new FooMsg_SomeLegacyIPC);
+teleporter->TeleportAllGoats();
+channel_->Send(new FooMsg_AnotherLegacyIPC);
+```
+
+Likewise, `ChildThreadImpl` has an `IPC::Channel` that can be used in the same
+way to send such messages back to the browser.
+
+To receive and bind incoming Channel-associated interface requests, the above
+objects also implement `IPC::Listener::OnAssociatedInterfaceRequest`.
+
+For supplementation of routed messages, both `RenderFrameHostImpl` and
+`RenderFrameImpl` define a `GetRemoteAssociatedInterfaces` method which works
+like the one on `IPC::Channel`, and both objects also implement
+`IPC::Listener::OnAssociatedInterfaceRequest` for processing incoming associated
+interface requests specific to their own frame.
+
+There are some example conversion CLs which use Channel-associated interfaces
+[here](https://codereview.chromium.org/2381493003) and
+[here](https://codereview.chromium.org/2400313002).
+
+## Deciding How to Approach a Conversion
+
+There are a few questions you should ask before embarking upon any IPC message
+conversion journey, and there are many potential approaches to consider. The
+right one depends on context.
+
+Note that this section assumes the message is traveling between the browser
+process and a renderer process. Other cases are rare and developers may wish to
+consult
+[[email protected]](https://groups.google.com/a/chromium.org/forum/#!forum/chromium-mojo)
+before proceeding with them. Otherwise, apply the following basic algorithm to
+decide how to proceed:
+
+- General note: If the message is a reply to some other message (typically these
+ take a "request ID" argument), see the note about message replies at the
+ bottom of this section.
+- Consider whether or not the message makes sense as part of the IPC surface of
+ a new or existing service somewhere in `//services` or `//chrome/services`,
+ *etc.* This is less and less likely to be the case as time goes on, as many
+ remaining IPC conversions are quite narrowly dealing with specific
+ browser/renderer details rather than the browser's supporting subsystems. If
+ defining a new service, you may wish to consult some of the other
+ [Mojo & Services documentation](/docs/README.md#Mojo-Services) first.
+- If the message is an `IPC_MESSAGE_CONTROL` message:
+ - If there are likely to be strict ordering requirements between this
+ message and other legacy IPC or Channel-associated interface messages,
+ consider using a new or existing
+ [Channel-associated interface](#Channel-Associated-Interfaces) between
+ `RenderProcessHostImpl` and `RenderThreadImpl`.
+ - If the message is sent from a renderer to the browser:
+ - If an existing interface is bound by `RenderProcessHostImpl` and
+ requested through `RenderThread`'s Connector and seems to be a good
+ fit for the message, add the equivalent Mojo message to that
+ interface.
+ - If no such interface exists, consider adding one for this message and
+ any related messages.
+ - If the message is sent from the browser to a renderer:
+ - If an existing interface is bound by `RenderThreadImpl` and requested
+ through a `BrowserContext` Connector referencing a specific
+ `RenderProcessHost` [identity](https://cs.chromium.org/chromium/src/content/public/browser/render_process_host.h?rcl=1497b88b7d6400a2a5cced258df03d53800d7848&l=327),
+ and the interface seems to be a good fit for the message, add the
+ equivalent Mojo message to that interface.
+ - If no such interface exists, consider adding one for this message and
+ any related messages.
+- If the message is an `IPC_MESSAGE_ROUTED` message:
+ - Determine what the routing endpoints are. If they are
+ `RenderFrameHostImpl` and `RenderFrameImpl`:
+ - If there are likely to be strict ordering requirements between this
+ message and other legacy IPC or Channel-associated interface messages,
+ consider using a new or existing
+ [Channel-associated interface](#Channel-Associated-Interfaces) between
+ `RenderFrameHostImpl` and `RenderFrameImpl`.
+ - If the message is sent from a renderer to the browser:
+ - If an existing interface is bound by `RenderFrameHostImpl` and
+ acquired either via `RenderFrame::GetRemoteInterfaces` or
+ `RenderFrame::GetDocumentInterfaceBroker` and the interface seems
+ to be a good fit for this message, add the equivalent Mojo message
+ to that interface.
+ - If no such interface exists, consider adding one and exposing it
+ via a new getter method on `DocumentInterfaceBroker`. See the
+ [simple example](/docs/mojo_and_services.md#Example_Defining-a-New-Frame-Interface)
+ earlier in this document.
+ - If the message is sent from the browser to a renderer, consider
+ adding a Mojo equivalent to the `content.mojom.Frame` interface
+ defined
+ [here](https://cs.chromium.org/chromium/src/content/common/frame.mojom?rcl=138b66744ee9ee853cbb0ae8437b71eaa1fafaa9&l=42).
+ - If the routing endpoints are **not** frame objects (for example, they may
+ be `RenderView`/`RenderViewHost` objects), this is a special case which
+ does not yet have an easy conversion approach readily available. Contact
+ [[email protected]](https://groups.google.com/a/chromium.org/forum#!forum/chromium-mojo)
+ to propose or discuss options.
+
+### Dealing With Replies
+
+If the message is a **reply**, meaning it has a "request ID" which correlates it
+to a prior message in the opposite direction, consider converting the
+**request** message following the algorithm above. Unlike with legacy IPC, Mojo
+messages support replies as a first-class concept. So for example if you have:
+
+``` cpp
+IPC_CONTROL_MESSAGE2(FooHostMsg_DoTheThing,
+ int /* request_id */,
+ std::string /* name */);
+IPC_CONTROL_MESSAGE2(FooMsg_DidTheThing,
+ int /* request_id */,
+ bool /* success */);
+```
+
+You should consider defining an interface `Foo` which is bound in
+`RenderProcessHostImpl` and acquired from `RenderThreadImpl`, with the following
+mojom definition:
+
+``` cpp
+interface Foo {
+ DoTheThing(string name) => (bool success);
+};
+```
+
+## Repurposing `IPC::ParamTraits` and `IPC_STRUCT*` Invocations
+
+Occasionally it is useful to do partial IPC conversions, where you want to
+convert a message to a Mojo interface method but you don't want to necessarily
+convert every structure passed by the message. In this case, you can leverage
+Mojo's
+[type-mapping](https://chromium.googlesource.com/chromium/src/+/master/mojo/public/cpp/bindings/README.md#Type-Mapping)
+system to repurpose existing `IPC::ParamTraits`.
+
+*** aside
+**NOTE**: Although in some cases `IPC::ParamTraits<T>` specializations are
+defined manually in library code, the `IPC_STRUCT*` macro helpers also define
+`IPC::ParamTraits<T>` specializations under the hood. All advice in this section
+pertains to both kinds of definitions.
+***
+
+If a mojom struct is declared without a struct body and is tagged with
+`[Native]`, and a corresponding typemap is provided for the struct, the emitted
+C++ bindings will -- as if by magic -- replace the mojom type with the
+typemapped C++ type and will internally use the existing `IPC::ParamTraits<T>`
+specialization for that type in order to serialize and deserialize the struct.
+
+For example, given the
+[`resource_messages.h`](https://cs.chromium.org/chromium/src/content/common/resource_messages.h?rcl=2e7a430d8d88222c04ab3ffb0a143fa85b3cec5b&l=215) header
+which defines an IPC mapping for `content::ResourceRequest`:
+
+``` cpp
+IPC_STRUCT_TRAITS_BEGIN(content::ResourceRequest)
+ IPC_STRUCT_TRAITS_MEMBER(method)
+ IPC_STRUCT_TRAITS_MEMBER(url)
+ // ...
+IPC_STRUCT_TRAITS_END()
+```
+
+and the
+[`resource_request.h`](https://cs.chromium.org/chromium/src/content/common/resource_request.h?rcl=dce9e476a525e4ff0304787935dc1a8c38392ac8&l=32) header
+which actually defines the `content::ResourceRequest` type:
+
+``` cpp
+namespace content {
+
+struct CONTENT_EXPORT ResourceRequest {
+ // ...
+};
+
+} // namespace content
+```
+
+we can declare a corresponding "native" mojom struct:
+
+``` cpp
+module content.mojom;
+
+[Native]
+struct URLRequest;
+```
+
+and add a typemap like
+[`url_request.typemap`](https://cs.chromium.org/chromium/src/content/common/url_request.typemap?rcl=4b5963fa744a706398f8f06a4cbbf70d7fa3213d)
+to define how to map between them:
+
+``` python
+mojom = "//content/public/common/url_loader.mojom"
+public_headers = [ "//content/common/resource_request.h" ]
+traits_headers = [ "//content/common/resource_messages.h" ]
+...
+type_mappings = [ "content.mojom.URLRequest=content::ResourceRequest" ]
+```
+
+Note specifically that public_headers includes the definition of the native C++
+type, and traits_headers includes the definition of the legacy IPC traits.
+
+As a result of all this, other mojom files can now reference
+`content.mojom.URLRequest` as a type for method parameters and other struct
+fields, and the generated C++ bindings will represent those values exclusively
+as `content::ResourceRequest` objects.
+
+This same basic approach can be used to leverage existing `IPC_ENUM_TRAITS` for
+invocations for `[Native]` mojom enum aliases.
+
+*** aside
+**NOTE:** Use of `[Native]` mojom definitions is strictly limited to C++
+bindings. If a mojom message depends on such definitions, it cannot be sent or
+received by other language bindings. This feature also depends on continued
+support for legacy IPC serialization and all uses of it should therefore be
+treated as technical debt.
+***
+
+## Typemaps For Content and Blink Types
+
+Using typemapping for messages that go between Blink and content browser code
+can sometimes be tricky due to things like dependency cycles or confusion over
+the correct place for some definition
+to live. There are some example CLs provided here, but feel free to also contact
+[[email protected]](https://groups.google.com/a/chromium.org/forum/#!forum/chromium-mojo)
+with specific details if you encounter trouble.
+
+[This CL](https://codereview.chromium.org/2363533002) introduces a Mojom
+definition and typemap for `ui::WindowOpenDisposition` as a precursor to the
+IPC conversion below.
+
+The [follow-up CL](https://codereview.chromium.org/2363573002) uses that
+definition along with several other new typemaps (including native typemaps as
+described above) to convert the relatively large `ViewHostMsg_CreateWindow`
+message to Mojo.
+
+## Additional Support
+
+If this document was not helpful in some way, please post a message to your
+friendly
+[[email protected]](https://groups.google.com/a/chromium.org/forum/#!forum/chromium-mojo)
+mailing list.
diff --git a/docs/servicification.md b/docs/servicification.md
index 2a0c67b..d24dcd3 100644
--- a/docs/servicification.md
+++ b/docs/servicification.md
@@ -1,102 +1,197 @@
-# Servicification Strategies
-
-This document captures strategies, hints, and best practices for solving typical
-challenges enountered when converting existing Chromium
-code to services. It is assumed that you have already read the high-level
-documentation on [what a service is](/services).
-
-If you're looking for Mojo documentation, please see the [general
-Mojo documentation](/mojo) and/or the [documentation on converting Chrome IPC to
-Mojo](/ipc).
-
-Note that throughout the below document we link to CLs to illustrate the
-strategies being made. Over the course of time code tends to shift, so it is
-likely that the code on trunk does not exactly match what it was at the time of
-the CLs. When necessary, use the CLs as a starting point for examining the
-current state of the codebase with respect to these issues (e.g., exactly where
-a service is embedded within the content layer).
+# Servicifying Chromium Features
[TOC]
-## Questions to Answer When Getting Started
+## Overview
-For the basic nuts and bolts of how to create a new service, see [the
-documentation on adding a new service](/services#Adding-a-new-service). This
-section gives questions that you should answer in order to shape the design of
-your service, as well as hints as to which answers make sense given your
-situation.
+Much to the dismay of Chromium developers, practicing linguists, and keyboard
+operators everywhere, the term **servicificificification** [sic] has been
+egregiously smuggled into the Chromium parlance.
-### Is your service global or per-BrowserContext?
-The Service Manager can either:
+Lots of Chromium code is contained in reasonably well-isolated component
+libraries with some occasionally fuzzy boundaries and often a surprising number
+of gnarly runtime interdependencies among a complex graph of components. Y
+implements one of Z's delegate interfaces, while X implements one of Y's
+delegate interfaces, and now it's possible for some ridiculous bug to creep in
+where W calls into Z at the wrong time and causes a crash in X. Yikes.
-- create one service instance per instance group or
-- field all connection requests for a given service via the same instance
+Servicification embodies the ongoing process of **servicifying** Chromium
+features and subsystems, or refactoring these collections of library code into
+services with well-defined public API boundaries and very strong runtime
+isolation via Mojo interfaces.
-Which of these policies the Service Manager employs is determined by the
-contents of your service manifest: the former is the default, while the latter
-is selected by informing the Service Manager that your service has the
-"instance_sharing" option value set to "shared_across_instance_groups"
-([example](https://cs.chromium.org/chromium/src/services/device/manifest.json)).
+The primary goals are to improve maintainability and extensibility of the system
+over time, while also allowing for more flexible runtime configuration. For
+example, with the Network Service in place we can now run the entire network
+stack either inside or outside of the browser process with the flip of a
+command-line switch. Client code using the Network Service stays the same,
+independent of that switch.
-Service manifests are described in more detail in this
-[document](https://chromium.googlesource.com/chromium/src/+/master/services/service_manager/service_manifests.md).
+This document focuses on helpful guidelines and patterns for servicifying parts
+of Chromium, taking into account some nuances in how Chromium models its core
+services as well as how it embeds and configures the Service Manager. Readers
+are strongly encouraged to first read some basic
+[Service Manager documentation](/services/service_manager/README.md), as it will
+likely make the contents of this document easier to digest.
-In practice, there is one instance group per-BrowserContext, so the question
-becomes: Is your Service a global or keyed by BrowserContext? In considering
-this question, there is one obvious hint: If you are converting per-Profile
-classes (e.g., KeyedServices), then your service is almost certainly going to
-want an instance per BrowserContext. More generally, if you envision needing to
-use *any* state related to the profile (e.g., you need to store files in the
-user's home directory), then your service should have an instance
-per-BrowserContext.
+Also see general [Mojo & Services](/docs/README.md#Mojo-Services)
+documentation for other introductory guides, API references, *etc.*
-Conversely, your service could be a good fit for being global if it is a utility
-that is unconcerned with the identity of the requesting client (e.g., the [data
-decoder service](/services/data_decoder), which simply decodes untrusted data in
-a separate process.
+## Setting Up The Service
-### Will you embed your service in //content, //chrome, or neither?
+There are three big things you must decide when building and hooking up a shiny
+new service:
-At the start (and potentially even long-term), your service will likely not
-actually run in its own process but will rather be embedded in the browser
-process. This is especially true in the common case where you are converting
-existing browser-process code.
+- Where should the service live in the tree?
+- Do you need an instance of your service per BrowserContext?
+- Can Content depend on your service, or must Content embedders like Chrome do
+ so independently?
-You then have a question: Where should it be embedded? The answer to this
-question hinges on the nature and location of the code that you are converting:
+This section aims to help you understand and answer those questions.
-- //content is the obvious choice if you are converting existing //content code
- (e.g., the Device Service). Global services
- are embedded by [content::ServiceManagerContext](https://cs.chromium.org/chromium/src/content/browser/service_manager/service_manager_context.cc?type=cs&q=CreateDeviceService),
- while per-BrowserContext services are naturally embedded by [content::BrowserContext](https://cs.chromium.org/chromium/src/content/browser/browser_context.cc?type=cs&q=CreateFileService).
+### Where in the Tree?
-- If your service is converting existing //chrome code, then you will need
- to embed your service in //chrome rather than //content. Global services
- are embedded by [ChromeContentBrowserClient](https://cs.chromium.org/chromium/src/chrome/browser/chrome_content_browser_client.cc?type=cs&q=CreateMediaService),
- while per-Profile services are embedded by [ProfileImpl](https://cs.chromium.org/chromium/src/chrome/browser/profiles/profile_impl.cc?type=cs&q=CreateIdentityService).
+Based on the
+[service development guidelines](/services/README.md), any service which could
+be reasonably justified as a core system service in a hypothetical,
+well-designed operating system may belong in the top-level `//services`
+directory. If that sounds super hand-wavy and unclear, that's because it is!
+There isn't really a great universal policy here, so when in doubt, contact your
+favorite local
+[[email protected]](https://groups.google.com/a/chromium.org/forum#!forum/services-dev)
+mailing list and start a friendly discussion.
-- If you are looking to convert all or part of a component (i.e., a feature in
- //components) into a service, the question arises of whether your new service
- is worthy of being in //services (i.e., is it a foundational service?). If
- not, then it can be placed in //components/services. See this
- [document](https://docs.google.com/document/d/1Zati5ZohwjUM0vz5qj6sWg5r-_I0iisUoSoAMNdd7C8/edit#) for discussion of this point.
+Other common places where developers place services, and why:
-### If your service is embedded in the browser process, what is its threading model?
+- `//components/services` for services which haven't yet made the cut for
+ `//services` but which are either used by Content directly or by multiple
+ Content embedders.
+- `//chrome/services` for services which are used exclusively within Chrome and
+ not shared with other Content embedders.
+- `//chromeos/services` for services which are used on Chrome OS by more than
+ just Chrome itself (for example, if the `ash` service must also connect to
+ them for use in system UI).
-If your service is embedded in the browser process, it will run on the IO thread
-by default. You can change that by specifying a task runner as part of the
-information for constructing your service. In particular, if the code that you
-are converting is UI-thread code, then you likely want your service running on
-the UI thread. Look at the changes to profile_impl.cc in [this
-CL](https://codereview.chromium.org/2753753007) to see an example of setting the
-task runner that a service should be run on as part of the factory for creating
-the service.
+### Inside Content or Not?
-### What is your approach for incremental conversion?
+The next decision you need to make is whether or not Content will wire in your
+service directly -- that is, whether or not your service is necessary to support
+some subsystem Content makes available to either the web platform or to Content
+embedders like Chrome, Android WebView, Cast Shell, and various third-party
+applications.
+
+For example, Content cannot function at all without the Network Service being
+available, because Content depends heavily on the Network Service to issue and
+process all of its network requests (imagine that, right?). As such, the
+Network Service is wired up to the Service Manager from within Content directly.
+In general, services which will be wired up in Content must live either in
+`//services` or `//components/services` but ideally the former.
+
+Conversely there are a large number of services used only by Chrome today,
+such as the `unzip` service which safely performs sandboxed unpacking of
+compressed archive files on behalf of clients in the browser process. These
+can always be placed in `//chrome/services`.
+
+### Per-BrowserContext or Not?
+
+Now that you've decided on a source location for your service and you know
+whether it will be wired into Content or hooked up by Content embedder code, all
+that's left left is to decide whether or not you want an instance of your service
+per BrowserContext (*i.e.* per user profile in Chrome).
+
+The alternative is for you to manage your own instance arity, either as a
+singleton service (quite common) or as a service which supports multiple
+instances that are *not* each intrinsically tied to a BrowserContext. Most
+services choose this path because BrowserContext coupling is typically
+unnecessary.
+
+As a general rule, if you're porting a subsystem which today relies heavily
+on `BrowserContextKeyedService`, it's likely that you want your service
+instances to have a 1:1 correspondence with BrowserContext instances.
+
+### Putting It All Together
+
+Let's get down to brass tacks. You're a developer of action. You've made all the
+important choices you need to make and you've even built a small and extremely
+well-tested prototype service with the help of
+[this glorious guide](/services/service_manager/README.md#Services). Now you
+want to get it working in Chromium while suffering as little pain as possible.
+
+You're not going to believe it, but this section was written *just for YOU*.
+
+For services which are **are not** isolated per BrowserContext and which **can**
+be wired directly into Content:
+
+ - Include your service's manifest in the `content_packaged_services` manifest
+ directly, similar to
+ [these ones](https://cs.chromium.org/chromium/src/content/public/app/content_packaged_services_manifest.cc?rcl=0e8ac57eec2acfaa6f44b06eaa2fa667fe84a293&l=63).
+ - If you want to run your service embedded in the browser process, follow the
+ examples using `RegisterInProcessService`
+ [here](https://cs.chromium.org/chromium/src/content/browser/service_manager/service_manager_context.cc?rcl=0e8ac57eec2acfaa6f44b06eaa2fa667fe84a293&l=589).
+ - If you want to run your service out-of-process, update
+ `out_of_process_services`
+ [like so](https://cs.chromium.org/chromium/src/content/browser/service_manager/service_manager_context.cc?rcl=0e8ac57eec2acfaa6f44b06eaa2fa667fe84a293&l=642)
+ and hook up your actual private `Service` implementation exactly like the
+ many examples
+ [here](https://cs.chromium.org/chromium/src/content/utility/utility_service_factory.cc?rcl=2bdcc80a55c72a26ffe9778681f98dc4b6a565c0&l=114).
+
+For services which are **are** isolated per BrowserContext and which **can**
+be wired directly into Content:
+
+- Include your service's manifest in the `content_browser` manifest directly,
+ similar to
+ [these ones](https://cs.chromium.org/chromium/src/content/public/app/content_browser_manifest.cc?rcl=a651619623a7b56d0c21083463ef8e61bf0a6058&l=277).
+- If you want to run your service embedded in the browser process, follow the
+ example
+ [here](https://cs.chromium.org/chromium/src/content/browser/browser_context.cc?rcl=a651619623a7b56d0c21083463ef8e61bf0a6058&l=250)
+- If you want to run your service out-of-process, you are doing something that
+ hasn't been done yet and you will need to build a new thing.
+
+For services which **are not** isolated per BrowserContext but which **can not**
+be wired directly into Content:
+
+- Include your service's manifest in Chrome's `content_packaged_services`
+ manifest overlay similar to
+ [these ones](https://cs.chromium.org/chromium/src/chrome/app/chrome_packaged_service_manifests.cc?rcl=a651619623a7b56d0c21083463ef8e61bf0a6058&l=135)
+- If you want to run your service embedded in the browser process, follow the
+ examples in `ChromeContentBrowserClient::HandleServiceRequest`
+ [here](https://cs.chromium.org/chromium/src/chrome/browser/chrome_content_browser_client.cc?rcl=a651619623a7b56d0c21083463ef8e61bf0a6058&l=3891)
+- If you want to run your service out-of-process, modify
+ `ChromeContentBrowserClient::RegisterOutOfProcessServices` like the examples
+ [here](https://cs.chromium.org/chromium/src/chrome/browser/chrome_content_browser_client.cc?rcl=a651619623a7b56d0c21083463ef8e61bf0a6058&l=3785)
+ and hook up your `Service` implementation in
+ `ChromeContentUtilityClient::HandleServiceRequest` like the ones
+ [here](https://cs.chromium.org/chromium/src/chrome/utility/chrome_content_utility_client.cc?rcl=a651619623a7b56d0c21083463ef8e61bf0a6058&l=237).
+
+For services which **are** isolated per BrowserContext but which **can not** be
+wired directly into Content:
+
+- Include your service's manifest in Chrome's `content_browser` manifest overlay
+ similar to
+ [these ones](https://cs.chromium.org/chromium/src/chrome/app/chrome_content_browser_overlay_manifest.cc?rcl=a651619623a7b56d0c21083463ef8e61bf0a6058&l=247)
+- If you want to run your service embedded in the browser process, follow the
+ examples in `ProfileImpl::HandleServiceRequest`
+ [here](https://cs.chromium.org/chromium/src/chrome/browser/profiles/profile_impl.cc?rcl=350aea1a0242c2ea8610c9f755acee085c74ea7d&l=1263)
+- If you want to run your service out-of-process, you are doing something that
+ hasn't been done yet and you will need to build a new thing.
+
+*** aside
+The non-Content examples above are obviously specific to Chrome as the embedder,
+but Chrome's additions to supported services are all facilitated through the
+common `ContentBrowserClient` and `ContentUtilityClient` APIs that all embedders
+can implement. Mimicking what Chrome does should be sufficient for any embedder.
+***
+
+## Incremental Servicification
+
+For large Chromium features it is not feasible to convert an entire subsystem
+to a service all at once. As a result, it may be necessary for the subsystem
+to spend a considerable amount of time (weeks or months) split between the old
+implementation and your beautiful, sparkling new service implementation.
In creating your service, you likely have two goals:
-- Making the service available to other services
+- Making the service available to its consumers
- Making the service self-contained
Those two goals are not the same, and to some extent are at tension:
@@ -111,7 +206,7 @@
Whatever your goals, you will need to proceed incrementally if your project is
at all non-trivial (as they basically all are given the nature of the effort).
You should explicitly decide what your approach to incremental bringup and
-conversion will be. Here some approaches that have been taken for various
+conversion will be. Here are some approaches that have been taken for various
services:
- Build out your service depending directly on existing code,
@@ -139,11 +234,11 @@
place longer, while the last is most suitable when you want to be very exacting
about doing the servicification cleanly as you go.
-## Platform-Specific Issues
+## Platform-Specific Issues: Android
-### Android
As you servicify code running on Android, you might find that you need to port
-interfaces that are served in Java. Here is an [example CL](https://codereview.chromium.org/2643713002) that gives a basic
+interfaces that are served in Java. Here is an
+[example CL](https://codereview.chromium.org/2643713002) that gives a basic
pattern to follow in doing this.
You also might need to register JNI in your service. That is simple to set
@@ -156,50 +251,60 @@
(e.g., the Activity) via Android system APIs. To handle this challenging
issue, see the section on [Coupling to UI](#Coupling-to-UI).
-### iOS
+## Platform-Specific Issues: iOS
+
+*** aside
+**WARNING:** Some of this content is obsolete and needs to be updated. When in
+doubt, look approximately near the recommended bits of code and try to find
+relevant prior art.
+***
Services are supported on iOS, with the usage model in //ios/web being very
close to the usage model in //content. More specifically:
* To embed a global service in the browser service, override
- [WebClient::RegisterServices](https://cs.chromium.org/chromium/src/ios/web/public/web_client.h?q=WebClient::Register&sq=package:chromium&l=136). For an
- example usage, see
+ [WebClient::RegisterServices](https://cs.chromium.org/chromium/src/ios/web/public/web_client.h?q=WebClient::Register&sq=package:chromium&l=136). For an example usage, see
[ShellWebClient](https://cs.chromium.org/chromium/src/ios/web/shell/shell_web_client.mm?q=ShellWebClient::RegisterS&sq=package:chromium&l=91)
- and the related integration test that [connects to the embedded service](https://cs.chromium.org/chromium/src/ios/web/shell/test/service_manager_egtest.mm?q=service_manager_eg&sq=package:chromium&l=89).
+ and the related integration test that
+ [connects to the embedded service](https://cs.chromium.org/chromium/src/ios/web/shell/test/service_manager_egtest.mm?q=service_manager_eg&sq=package:chromium&l=89).
* To embed a per-BrowserState service, override
[BrowserState::RegisterServices](https://cs.chromium.org/chromium/src/ios/web/public/browser_state.h?q=BrowserState::RegisterServices&sq=package:chromium&l=89). For an
example usage, see
[ShellBrowserState](https://cs.chromium.org/chromium/src/ios/web/shell/shell_browser_state.mm?q=ShellBrowserState::RegisterServices&sq=package:chromium&l=48)
- and the related integration test that [connects to the embedded service](https://cs.chromium.org/chromium/src/ios/web/shell/test/service_manager_egtest.mm?q=service_manager_eg&sq=package:chromium&l=110).
+ and the related integration test that
+ [connects to the embedded service](https://cs.chromium.org/chromium/src/ios/web/shell/test/service_manager_egtest.mm?q=service_manager_eg&sq=package:chromium&l=110).
* To register a per-frame Mojo interface, override
- [WebClient::BindInterfaceRequestFromMainFrame](https://cs.chromium.org/chromium/src/ios/web/public/web_client.h?q=WebClient::BindInterfaceRequestFromMainFrame&sq=package:chromium&l=148). For an
- example usage, see
+ [WebClient::BindInterfaceRequestFromMainFrame](https://cs.chromium.org/chromium/src/ios/web/public/web_client.h?q=WebClient::BindInterfaceRequestFromMainFrame&sq=package:chromium&l=148).
+ For an example usage, see
[ShellWebClient](https://cs.chromium.org/chromium/src/ios/web/shell/shell_web_client.mm?type=cs&q=ShellWebClient::BindInterfaceRequestFromMainFrame&sq=package:chromium&l=115)
- and the related integration test that [connects to the interface](https://cs.chromium.org/chromium/src/ios/web/shell/test/service_manager_egtest.mm?q=service_manager_eg&sq=package:chromium&l=130). Note that this is the
- equivalent of [ContentBrowserClient::BindInterfaceRequestFromFrame()](https://cs.chromium.org/chromium/src/content/public/browser/content_browser_client.h?type=cs&q=ContentBrowserClient::BindInterfaceRequestFromFrame&sq=package:chromium&l=667), as on iOS all operation "in the content area" is implicitly
- operating in the context of the page's main frame.
+ and the related integration test that
+ [connects to the interface](https://cs.chromium.org/chromium/src/ios/web/shell/test/service_manager_egtest.mm?q=service_manager_eg&sq=package:chromium&l=130).
+ Note that this is the equivalent of
+ [ContentBrowserClient::BindInterfaceRequestFromFrame()](https://cs.chromium.org/chromium/src/content/public/browser/content_browser_client.h?type=cs&q=ContentBrowserClient::BindInterfaceRequestFromFrame&sq=package:chromium&l=667),
+ as on iOS all operation "in the content area" is implicitly operating in the
+ context of the page's main frame.
If you have a use case or need for services on iOS, contact
[email protected]. For general information on the motivations and vision for supporting services on iOS, see the high-level [servicification design doc](https://docs.google.com/document/d/15I7sQyQo6zsqXVNAlVd520tdGaS8FCicZHrN0yRu-oU/edit) (in particular, search for the mentions
-of iOS within the doc).
[email protected]. For general information on the motivations and vision for
+supporting services on iOS, see the high-level
+[servicification design doc](https://docs.google.com/document/d/15I7sQyQo6zsqXVNAlVd520tdGaS8FCicZHrN0yRu-oU/edit).
+In particular, search for the mentions of iOS within the doc.
## Client-Specific Issues
-### Services and Blink
-Connecting to services directly from Blink is fully supported. [This
-CL](https://codereview.chromium.org/2698083007) gives a basic example of
-connecting to an arbitrary service by name from Blink (look at the change to
-SensorProviderProxy.cpp as a starting point).
-
-Below, we go through strategies for some common challenges encountered when
-servicifying features that have Blink as a client.
-
#### Mocking Interface Impls in JS
It is a common pattern in Blink's web tests to mock a remote Mojo interface
-in JS. [This CL](https://codereview.chromium.org/2643713002) illustrates the
-basic pattern for porting such mocking of an interface hosted by
-//content/browser to an interface hosted by an arbitrary service (see the
-changes to mock-battery-monitor.js).
+in JS so that native Blink code requests interfaces from the test JS rather
+than whatever would normally service them in the browser process.
+
+The current way to set up that sort of thing looks like
+[this](https://cs.chromium.org/chromium/src/third_party/blink/web_tests/battery-status/resources/mock-battery-monitor.js?rcl=be6e0001855f7f1cfc26205d0ff5a2b5b324fcbd&l=19).
+
+*** aside
+**NOTE:** The above approach to mocking in JS no longer applies when using
+the new recommended `DocumentInterfaceBroker` approach to exposing interfaces
+to documents. New JS mocking support is in development for this.
+***
#### Feature Impls That Depend on Blink Headers
In the course of servicifying a feature that has Blink as a client, you might
@@ -215,7 +320,9 @@
1. Move the code in question from C++ to mojom (e.g., if it is simple structs).
2. Move the code into the service's C++ client library, being very explicit
- about its usage by Blink. See [this CL](https://codereview.chromium.org/2415083002) for a basic pattern to follow.
+ about its usage by Blink. See
+ [this CL](https://codereview.chromium.org/2415083002) for a basic pattern to
+ follow.
#### Frame-Scoped Connections
You must think carefully about the scoping of the connection being made
@@ -226,8 +333,8 @@
arbitrary services have no knowledge of frames or even a notion of what a frame
is).
-After a [long
-discussion](https://groups.google.com/a/chromium.org/forum/#!topic/services-dev/CSnDUjthAuw),
+After a
+[long discussion](https://groups.google.com/a/chromium.org/forum/#!topic/services-dev/CSnDUjthAuw),
the policy that we have adopted for this challenge is the following:
CURRENT
@@ -246,9 +353,6 @@
Notably, from the renderer's POV essentially nothing changes here.
-In the longer term, this will still be the basic model, only with "the browser"
-replaced by "the Navigation Service" or "the web permissions broker".
-
## Strategies for Challenges to Decoupling from //content
### Coupling to UI
@@ -268,16 +372,17 @@
The basic strategy to support this coupling while still servicifying the feature
in question is to inject a mechanism of mapping from an opaque "context ID" to
the required context. The embedder (e.g., //content) maintains this map, and the
-service makes use of it. The embedder also serves as an intermediary: It
+service makes use of it. The embedder also serves as an intermediary: it
provides a connection that is appropriately context-scoped to clients. When
clients request the feature in question, the embedder forwards the request on
along with the appropriate context ID. The service impl can then map that
context ID back to the needed context on-demand using the mapping functionality
injected into the service impl.
-To make this more concrete, see [this CL](https://codereview.chromium.org/2734943003).
+To make this more concrete, see
+[this CL](https://codereview.chromium.org/2734943003).
-### Shutdown of singletons
+### Shutdown of Singletons
You might find that your feature includes singletons that are shut down as part
of //content's shutdown process. As part of decoupling the feature
@@ -293,29 +398,15 @@
to when the previous code was executing, and ensure that any differences
introduced do not impact correctness.
-See [this thread](https://groups.google.com/a/chromium.org/forum/#!topic/services-dev/Y9FKZf9n1ls) for more discussion of this issue.
+See
+[this thread](https://groups.google.com/a/chromium.org/forum/#!topic/services-dev/Y9FKZf9n1ls)
+for more discussion of this issue.
-### Tests that muck with service internals
-It is often the case that browsertests reach directly into what will become part
-of the internal service implementation to either inject mock/fake state or to
-monitor private state.
+## Additional Support
-This poses a challenge: As part of servicification, *no* code outside the
-service impl should depend on the service impl. Thus, these dependencies need to
-be removed. The question is how to do so while preserving testing coverage.
-
-To answer this question, there are several different strategies. These
-strategies are not mutually-exclusive; they can and should be combined to
-preserve the full breadth of coverage.
-
-- Blink client-side behavior can be tested via [web tests](https://codereview.chromium.org/2731953003)
-- To test service impl behavior, create [service tests](https://codereview.chromium.org/2774783003).
-- To preserve tests of end-to-end behavior (e.g., that when Blink makes a
- request via a Web API in JS, the relevant feature impl receives a connection
- request), we are planning on introducing the ability to register mock
- implementations with the Service Manager.
-
-To emphasize one very important point: it is in general necessary to leave
-*some* test of end-to-end functionality, as otherwise it is too easy for bustage
-to slip in via e.g. changes to how services are registered. See [this thread](https://groups.google.com/a/chromium.org/forum/#!topic/services-dev/lJCKAElWz-E)
-for further discussion of this point.
+If this document was not helpful in some way, please post a message to your
+friendly local
+[[email protected]](https://groups.google.com/a/chromium.org/forum/#!forum/chromium-mojo)
+or
+[[email protected]](https://groups.google.com/a/chromium.org/forum/#!forum/services-dev)
+mailing list.