blob: b1254c588e4d3a55784c349f431ccfff7eb178ec [file] [log] [blame] [view]
Ken Rockotab035122019-02-06 00:35:241# Servicifying Chromium Features
blundell77afe7a62017-05-02 09:08:492
3[TOC]
4
Ken Rockotab035122019-02-06 00:35:245## Overview
blundell77afe7a62017-05-02 09:08:496
Ken Rockotab035122019-02-06 00:35:247Much to the dismay of Chromium developers, practicing linguists, and keyboard
8operators everywhere, the term **servicificificification** [sic] has been
9egregiously smuggled into the Chromium parlance.
blundell77afe7a62017-05-02 09:08:4910
Ken Rockotab035122019-02-06 00:35:2411Lots of Chromium code is contained in reasonably well-isolated component
12libraries with some occasionally fuzzy boundaries and often a surprising number
13of gnarly runtime interdependencies among a complex graph of components. Y
14implements one of Z's delegate interfaces, while X implements one of Y's
15delegate interfaces, and now it's possible for some ridiculous bug to creep in
16where W calls into Z at the wrong time and causes a crash in X. Yikes.
blundell77afe7a62017-05-02 09:08:4917
Ken Rockotab035122019-02-06 00:35:2418Servicification embodies the ongoing process of **servicifying** Chromium
19features and subsystems, or refactoring these collections of library code into
20services with well-defined public API boundaries and very strong runtime
21isolation via Mojo interfaces.
blundell77afe7a62017-05-02 09:08:4922
Ken Rockotab035122019-02-06 00:35:2423The primary goals are to improve maintainability and extensibility of the system
24over time, while also allowing for more flexible runtime configuration. For
25example, with the Network Service in place we can now run the entire network
26stack either inside or outside of the browser process with the flip of a
27command-line switch. Client code using the Network Service stays the same,
28independent of that switch.
Oksana Zhuravlovac6e0f952018-09-25 03:25:0429
Ken Rockotab035122019-02-06 00:35:2430This document focuses on helpful guidelines and patterns for servicifying parts
Ken Rockot216eb5d2020-02-19 17:09:5531of Chromium.
blundell77afe7a62017-05-02 09:08:4932
Ken Rockotab035122019-02-06 00:35:2433Also see general [Mojo & Services](/docs/README.md#Mojo-Services)
34documentation for other introductory guides, API references, *etc.*
blundell77afe7a62017-05-02 09:08:4935
Ken Rockotab035122019-02-06 00:35:2436## Setting Up The Service
blundell77afe7a62017-05-02 09:08:4937
Ken Rockot216eb5d2020-02-19 17:09:5538This section briefly covers early decisions and implementation concerns when
39introducing a new service.
Ken Rockotd2ed25a2018-11-06 22:25:3740
Ken Rockotab035122019-02-06 00:35:2441### Where in the Tree?
blundell77afe7a62017-05-02 09:08:4942
Ken Rockotab035122019-02-06 00:35:2443Based on the
44[service development guidelines](/services/README.md), any service which could
45be reasonably justified as a core system service in a hypothetical,
46well-designed operating system may belong in the top-level `//services`
47directory. If that sounds super hand-wavy and unclear, that's because it is!
48There isn't really a great universal policy here, so when in doubt, contact your
49favorite local
50[[email protected]](https://groups.google.com/a/chromium.org/forum#!forum/services-dev)
51mailing list and start a friendly discussion.
blundell77afe7a62017-05-02 09:08:4952
Ken Rockotab035122019-02-06 00:35:2453Other common places where developers place services, and why:
blundell77afe7a62017-05-02 09:08:4954
Ken Rockotab035122019-02-06 00:35:2455- `//components/services` for services which haven't yet made the cut for
56 `//services` but which are either used by Content directly or by multiple
57 Content embedders.
58- `//chrome/services` for services which are used exclusively within Chrome and
59 not shared with other Content embedders.
60- `//chromeos/services` for services which are used on Chrome OS by more than
61 just Chrome itself (for example, if the `ash` service must also connect to
62 them for use in system UI).
blundell77afe7a62017-05-02 09:08:4963
Ken Rockot216eb5d2020-02-19 17:09:5564### Launching Service Processes
blundell77afe7a62017-05-02 09:08:4965
Ken Rockot216eb5d2020-02-19 17:09:5566Content provides a simple
67[`ServiceProcessHost`](https://cs.chromium.org/chromium/src/content/public/browser/service_process_host.h?rcl=723edf64a56ef6058e886afc67adc786bea39e78&l=47)
68API to launch a new Service Process. The Mojo Remote corresponding to each
69process launch is effectively a lifetime control for the launched process.
Ken Rockotab035122019-02-06 00:35:2470
Ken Rockot216eb5d2020-02-19 17:09:5571You may choose to maintain only a single concurrent instance of your service
72at a time, similar to the Network or Storage services. In this case, typically
73you will have some browser code maintain a lazy Mojo Remote to the service
74process, and any clients of the service will have their connections brokered
75through this interface.
Ken Rockotab035122019-02-06 00:35:2476
Ken Rockot216eb5d2020-02-19 17:09:5577In other cases you may want to manage multiple independent service processes.
78The Data Decoder service, for example, allows for arbitrary browser code
79to launch a unique isolated instance to process a single decode operation or
80a batch of related operations (e.g. to decode a bunch of different objects
81from the same untrusted origin).
Ken Rockotab035122019-02-06 00:35:2482
Ken Rockot216eb5d2020-02-19 17:09:5583Insofar as the browser can use ServiceProcessLauncher however it likes, and the
84corresponding Mojo Remotes can be owned just like any other object, developers
85are free to manage their service instances however they like.
Ken Rockotab035122019-02-06 00:35:2486
Ken Rockot216eb5d2020-02-19 17:09:5587### Hooking Up the Service Implementation
Ken Rockotab035122019-02-06 00:35:2488
Ken Rockot216eb5d2020-02-19 17:09:5589For out-of-process service launching, Content uses its "utility" process type.
Ken Rockotab035122019-02-06 00:35:2490
Ken Rockot216eb5d2020-02-19 17:09:5591For services known to content, this is accomplished by adding an appropriate
92factory function to
93[`//content/utility/services.cc`](https://cs.chromium.org/chromium/src/content/utility/services.cc)
Ken Rockotab035122019-02-06 00:35:2494
Ken Rockot216eb5d2020-02-19 17:09:5595For other services known only to Chrome, we have a similar file at
96[`//chrome/utility/services.cc`](https://cs.chromium.org/chromium/src/chrome/utility/services.cc).
Ken Rockotab035122019-02-06 00:35:2497
Ken Rockot216eb5d2020-02-19 17:09:5598Once an appropriate service factory is registered for your main service
99interface in one of these places, `ServiceProcessHost::Launch` can be used to
100acquire a new isolated instance from within the browser process.
Ken Rockotab035122019-02-06 00:35:24101
Ken Rockot216eb5d2020-02-19 17:09:55102To run a service in-process, you can simply instantiate your service
103implementation (e.g. on a background thread) like you would any other object,
104and you can then bind a Mojo Remote which is connected to that instance.
Ken Rockotab035122019-02-06 00:35:24105
Ken Rockot216eb5d2020-02-19 17:09:55106This is useful if you want to avoid the overhead of extra processes in some
107scenarios, and it allows the detail of where and how the service runs to be
108fully hidden behind management of the main interface's Mojo Remote.
Ken Rockotab035122019-02-06 00:35:24109
110## Incremental Servicification
111
112For large Chromium features it is not feasible to convert an entire subsystem
113to a service all at once. As a result, it may be necessary for the subsystem
114to spend a considerable amount of time (weeks or months) split between the old
115implementation and your beautiful, sparkling new service implementation.
blundell77afe7a62017-05-02 09:08:49116
117In creating your service, you likely have two goals:
118
Ken Rockotab035122019-02-06 00:35:24119- Making the service available to its consumers
blundell77afe7a62017-05-02 09:08:49120- Making the service self-contained
121
122Those two goals are not the same, and to some extent are at tension:
123
124- To satisfy the first, you need to build out the API surface of the service to
125 a sufficient degree for the anticipated use cases.
126
127- To satisfy the second, you need to convert all clients of the code that you
128 are servicifying to instead use the service, and then fold that code into the
129 internal implementation of the service.
130
131Whatever your goals, you will need to proceed incrementally if your project is
132at all non-trivial (as they basically all are given the nature of the effort).
133You should explicitly decide what your approach to incremental bringup and
Ken Rockotab035122019-02-06 00:35:24134conversion will be. Here are some approaches that have been taken for various
blundell77afe7a62017-05-02 09:08:49135services:
136
137- Build out your service depending directly on existing code,
138 convert the clients of that code 1-by-1, and fold the existing code into the
139 service implementation when complete ([Identity Service](https://docs.google.com/document/d/1EPLEJTZewjiShBemNP5Zyk3b_9sgdbrZlXn7j1fubW0/edit)).
140- Build out the service with new code and make the existing code
141 into a client library of the service. In that fashion, all consumers of the
142 existing code get converted transparently ([Preferences Service](https://docs.google.com/document/d/1JU8QUWxMEXWMqgkvFUumKSxr7Z-nfq0YvreSJTkMVmU/edit#heading=h.19gc5b5u3e3x)).
143- Build out the new service piece-by-piece by picking a given
144 bite-size piece of functionality and entirely servicifying that functionality
145 ([Device Service](https://docs.google.com/document/d/1_1Vt4ShJCiM3fin-leaZx00-FoIPisOr8kwAKsg-Des/edit#heading=h.c3qzrjr1sqn7)).
146
147These all have tradeoffs:
148
Ken Rockotd2ed25a2018-11-06 22:25:37149- The first lets you incrementally validate your API and implementation, but
blundell77afe7a62017-05-02 09:08:49150 leaves the service depending on external code for a long period of time.
151- The second can create a self-contained service more quickly, but leaves
152 all the existing clients in place as potential cleanup work.
153- The third ensures that you're being honest as you go, but delays having
154 the breadth of the service API up and going.
155
156Which makes sense depends both on the nature of the existing code and on
157the priorities for doing the servicification. The first two enable making the
158service available for new use cases sooner at the cost of leaving legacy code in
159place longer, while the last is most suitable when you want to be very exacting
160about doing the servicification cleanly as you go.
161
Ken Rockotab035122019-02-06 00:35:24162## Platform-Specific Issues: Android
blundell77afe7a62017-05-02 09:08:49163
Ken Rockotd2ed25a2018-11-06 22:25:37164As you servicify code running on Android, you might find that you need to port
Ken Rockotab035122019-02-06 00:35:24165interfaces that are served in Java. Here is an
166[example CL](https://codereview.chromium.org/2643713002) that gives a basic
blundell77afe7a62017-05-02 09:08:49167pattern to follow in doing this.
168
169You also might need to register JNI in your service. That is simple to set
170up, as illustrated in [this CL](https://codereview.chromium.org/2690963002).
171(Note that that CL is doing more than *just* enabling the Device Service to
172register JNI; you should take the register_jni.cc file added there as your
173starting point to examine the pattern to follow).
174
175Finally, it is possible that your feature will have coupling to UI process state
176(e.g., the Activity) via Android system APIs. To handle this challenging
177issue, see the section on [Coupling to UI](#Coupling-to-UI).
178
Ken Rockotab035122019-02-06 00:35:24179## Platform-Specific Issues: iOS
180
181*** aside
182**WARNING:** Some of this content is obsolete and needs to be updated. When in
183doubt, look approximately near the recommended bits of code and try to find
184relevant prior art.
185***
blundell77afe7a62017-05-02 09:08:49186
Ken Rockot216eb5d2020-02-19 17:09:55187Services are supported on iOS insofar as Mojo is supported. However, Chrome on
188iOS is strictly single-process, and all services thus must run in-process on
189iOS.
Colin Blundell08b84ab2017-09-04 16:10:04190
191If you have a use case or need for services on iOS, contact
Ken Rockotab035122019-02-06 00:35:24192[email protected]. For general information on the motivations and vision for
193supporting services on iOS, see the high-level
194[servicification design doc](https://docs.google.com/document/d/15I7sQyQo6zsqXVNAlVd520tdGaS8FCicZHrN0yRu-oU/edit).
195In particular, search for the mentions of iOS within the doc.
blundell77afe7a62017-05-02 09:08:49196
197## Client-Specific Issues
198
blundell77afe7a62017-05-02 09:08:49199#### Mocking Interface Impls in JS
Kent Tamura59ffb022018-11-27 05:30:56200It is a common pattern in Blink's web tests to mock a remote Mojo interface
Ken Rockotab035122019-02-06 00:35:24201in JS so that native Blink code requests interfaces from the test JS rather
202than whatever would normally service them in the browser process.
203
204The current way to set up that sort of thing looks like
205[this](https://cs.chromium.org/chromium/src/third_party/blink/web_tests/battery-status/resources/mock-battery-monitor.js?rcl=be6e0001855f7f1cfc26205d0ff5a2b5b324fcbd&l=19).
206
blundell77afe7a62017-05-02 09:08:49207#### Feature Impls That Depend on Blink Headers
208In the course of servicifying a feature that has Blink as a client, you might
209encounter cases where the feature implementation has dependencies on Blink
210public headers (e.g., defining POD structs that are used both by the client and
211by the feature implementation). These dependencies pose a challenge:
212
Ken Rockotd2ed25a2018-11-06 22:25:37213- Services should not depend on Blink, as this is a dependency inversion (Blink
blundell77afe7a62017-05-02 09:08:49214is a client of services).
215- However, Blink is very careful about accepting dependencies from Chromium.
216
217To meet this challenge, you have two options:
218
2191. Move the code in question from C++ to mojom (e.g., if it is simple structs).
Ken Rockotd2ed25a2018-11-06 22:25:372202. Move the code into the service's C++ client library, being very explicit
Ken Rockotab035122019-02-06 00:35:24221 about its usage by Blink. See
222 [this CL](https://codereview.chromium.org/2415083002) for a basic pattern to
223 follow.
blundell77afe7a62017-05-02 09:08:49224
225#### Frame-Scoped Connections
226You must think carefully about the scoping of the connection being made
227from Blink. In particular, some feature requests are necessarily scoped to a
228frame in the context of Blink (e.g., geolocation, where permission to access the
229interface is origin-scoped). Servicifying these features is then challenging, as
230Blink has no frame-scoped connection to arbitrary services (by design, as
231arbitrary services have no knowledge of frames or even a notion of what a frame
232is).
233
Ken Rockotab035122019-02-06 00:35:24234After a
235[long discussion](https://groups.google.com/a/chromium.org/forum/#!topic/services-dev/CSnDUjthAuw),
blundell77afe7a62017-05-02 09:08:49236the policy that we have adopted for this challenge is the following:
237
238CURRENT
239
240- The renderer makes a request through its frame-scoped connection to the
241 browser.
242- The browser obtains the necessary permissions before directly servicing the
243 request.
244
245AFTER SERVICIFYING THE FEATURE IN QUESTION
246
247- The renderer makes a request through its frame-scoped connection to the
248 browser.
249- The browser obtains the necessary permissions before forwarding the
250 request on to the underlying service that hosts the feature.
251
252Notably, from the renderer's POV essentially nothing changes here.
253
blundell77afe7a62017-05-02 09:08:49254## Strategies for Challenges to Decoupling from //content
255
256### Coupling to UI
257
258Some feature implementations have hard constraints on coupling to UI on various
259platforms. An example is NFC on Android, which requires the Activity of the view
260in which the requesting client is hosted in order to access the NFC platform
261APIs. This coupling is at odds with the vision of servicification, which is to
262make the service physically isolatable. However, when it occurs, we need to
263accommodate it.
264
265The high-level decision that we have reached is to scope the coupling to the
266feature *and* platform in question (rather than e.g. introducing a
267general-purpose FooServiceDelegate), in order to make it completely explicit
268what requires the coupling and to avoid the coupling creeping in scope.
269
270The basic strategy to support this coupling while still servicifying the feature
271in question is to inject a mechanism of mapping from an opaque "context ID" to
272the required context. The embedder (e.g., //content) maintains this map, and the
Ken Rockotab035122019-02-06 00:35:24273service makes use of it. The embedder also serves as an intermediary: it
blundell77afe7a62017-05-02 09:08:49274provides a connection that is appropriately context-scoped to clients. When
275clients request the feature in question, the embedder forwards the request on
276along with the appropriate context ID. The service impl can then map that
277context ID back to the needed context on-demand using the mapping functionality
278injected into the service impl.
279
Ken Rockotab035122019-02-06 00:35:24280To make this more concrete, see
281[this CL](https://codereview.chromium.org/2734943003).
blundell77afe7a62017-05-02 09:08:49282
Ken Rockotab035122019-02-06 00:35:24283### Shutdown of Singletons
blundell77afe7a62017-05-02 09:08:49284
285You might find that your feature includes singletons that are shut down as part
286of //content's shutdown process. As part of decoupling the feature
287implementation entirely from //content, the shutdown of these singletons must be
288either ported into your service or eliminated:
289
290- In general, as Chromium is moving away from graceful shutdown, the first
291 question to analyze is: Do the singletons actually need to be shut down at
292 all?
Ken Rockotd2ed25a2018-11-06 22:25:37293- If you need to preserve shutdown of the singleton, the naive approach is to
blundell77afe7a62017-05-02 09:08:49294 move the shutdown of the singleton to the destructor of your service
Ken Rockotd2ed25a2018-11-06 22:25:37295- However, you should carefully examine when your service is destroyed compared
296 to when the previous code was executing, and ensure that any differences
blundell77afe7a62017-05-02 09:08:49297 introduced do not impact correctness.
298
Ken Rockotab035122019-02-06 00:35:24299See
300[this thread](https://groups.google.com/a/chromium.org/forum/#!topic/services-dev/Y9FKZf9n1ls)
301for more discussion of this issue.
blundell77afe7a62017-05-02 09:08:49302
Ken Rockotab035122019-02-06 00:35:24303## Additional Support
blundell77afe7a62017-05-02 09:08:49304
Ken Rockotab035122019-02-06 00:35:24305If this document was not helpful in some way, please post a message to your
306friendly local
307[[email protected]](https://groups.google.com/a/chromium.org/forum/#!forum/chromium-mojo)
308or
309[[email protected]](https://groups.google.com/a/chromium.org/forum/#!forum/services-dev)
310mailing list.