Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1145)

Side by Side Diff: services/service_manager/README.md

Issue 2783223004: Adds lots of Mojo documentation (Closed)
Patch Set: Created 3 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« ipc/README.md ('K') | « services/README.md ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 # Service Manager User Guide 1 # Service Manager User Guide
2 2
3 [TOC]
4
3 ## What is the Service Manager? 5 ## What is the Service Manager?
4 6
5 The Service Manager is a tool that brokers connections and capabilities between 7 The **Service Manager** is a tool that brokers connections and capabilities
6 and manages instances of components, referred to henceforth as “services”. 8 between -- and manages instances of -- system components referred to henceforth
9 as **services**.
7 10
8 The Service Manager performs the following functions: 11 The Service Manager performs the following functions:
9 12
10 * Brokering connections between services, including communicating policies such 13 * Brokers interface requests between service instances, enforcing static
11 as capabilities (which include access to interfaces), user identity, etc. 14 capability policies declared by the services involved.
12 * Launching and managing the lifecycle services and processes (though services 15 * Launches and manages the lifecycle of services and processes.
13 may also create their own processes and tell the Service Manager about them). 16 * Isolates service instances and interface requests among them according to
14 * Tracks running services, and provides an API that allows services to 17 user identity.
15 understand what’s running. 18 * Tracks running service instances and exposes privileged APIs for querying
19 system state.
16 20
17 The Service Manager presents a series of Mojo interfaces to services, though in 21 The Service Manager presents a series of Mojo
18 practice interacting with the Service is made simpler with a client library. 22 [interfaces](https://cs.chromium.org/chromium/src/services/service_manager/publi c/interfaces)
19 Currently, there is only a client library written in C++, since that meets the 23 to services, though in practice most interaction with the Service Manager is
20 needs of most of the use cases in Chrome. 24 made simpler by using its corresponding
25 [C++ client library](https://cs.chromium.org/chromium/src/services/service_manag er/public/cpp).
21 26
22 ## Details 27 ## Mojo Recap
23
24 ### Mojo Recap
25 28
26 The Mojo system provides two key components of interest here - a lightweight 29 The Mojo system provides two key components of interest here - a lightweight
27 message pipe concept allowing two endpoints to communicate, and a bindings layer 30 message pipe concept allowing two endpoints to communicate, and a bindings layer
28 that allows interfaces to be described to bind to those endpoints, with 31 that allows interfaces to be described to bind to those endpoints, with
29 ergonomic bindings for languages used in Chrome. 32 ergonomic bindings for languages used in Chrome.
30 33
31 Mojo message pipes are designed to be lightweight and may be read from/written 34 Mojo message pipes are designed to be lightweight and may be read from/written
32 to and passed around from one process to the next. In most situations however 35 to and passed around from one process to another. In most situations a developer
33 the developer won’t interact with the pipes directly, rather with a generated 36 won't interact with the pipes directly, but rather with bindings types generated
34 types encapsulating a bound interface. 37 to encapsulate a bound interface. To use the bindings, a developer defines their
35 38 interface in the [Mojom IDL format](/mojo/public/tools/bindings). With some
36 To use the bindings, a developer defines their interface in the Mojo IDL format, 39 build magic, the generated definitions can then be referenced from C++,
37 **mojom**. With some build magic, the generated headers can then be included and 40 JavaScript and Java code.
38 used from C++, JS and Java. 41
39 42 See the [Mojo documentation](/mojo) for a complete overview, detailed
40 It is important to note here that Mojo Interfaces have fully qualified 43 explanations, and API references.
41 identifiers in string form, generated from the module path and interface name: 44
42 “**`module.path.InterfaceName`**”. This is how interfaces are referenced in 45 ## Services
43 Service Manifests, and how they will be referenced throughout this document. 46
44 47 A **service** is a collection of one or more private implementations of public
45 This would be a good place for me to refer to this in-depth Mojo User Guide, 48 Mojo interfaces which are reachable via the Service Manager. Every service is
46 which spells all of this out in great detail. 49 comprised of the following pieces:
47 50
48 ### Services 51 * A set of public Mojo interface definitions
49 52 * A **service manifest** declarating arbitrarily named capabilities which are
50 A Service is any bit of code the Service Manager knows about. This could be a 53 each comprised of one or more exposed Mojo interfaces.
51 unique process, or just a bit of code run in some existing process. 54 * Private implementation code which responds to lifecycle events and incoming
52 55 interface requests, all driven by the Service Manager.
53 The Service Manager disambiguates services by their **Identity**. Every service 56
54 has its own unique Identity. From the Service Manager’s perspective, a service’s 57 The Service Manager is responsible for starting new service instances on-demand,
55 Identity is represented by the tuple of the its Name, UserId and Instance Name. 58 and a given service many have any number of concurrently running instances. The
56 The Name is a formatted string that superficially represents a scheme:host pair, 59 Service Manager disambiguates service instances by their unique
57 but actually isn’t a URL. More on the structure of these names later. The UserId 60 **identity**. A service's identity is represented by the 3-tuple of the its
58 is a string GUID, representing the user the service is run as. The Instance Name 61 **service name**, **user ID**, and **instance qualifier**:
59 is a string, typically (but not necessarily) derived from the Name, which can be 62
60 used to allow multiple instances of a service to exist for the same Name,UserId 63 * The service name is a free-form -- typically short -- string identifying the
61 pair. In Chrome an example of this would be multiple instances of the renderer 64 the specific service being run in the instance.
62 or the same profile. 65 * The user ID is a GUID string representing the identity of a user in the system .
63 66 Every running service instance is associated with a specific user ID.
64 A Service implements the Mojo interface service_manager.mojom.Service, which is 67 * Finally, the instance qualifier is an arbitrary free-form string used to
65 the primary means the Service Manager has of communicating with its service. 68 disambiguate multiple instances of a service for the same user.
66 Service has two methods: OnStart(), called once at when the Service Manager 69
67 first learns about the service, and OnConnect(), which the Service Manager calls 70 As long as a service instance is running it must maintain an implementation of
68 every time some other service tries to connect to this one. 71 the
69 72 [`service_manager.mojom.Service`](https://cs.chromium.org/chromium/src/services/ service_manager/public/interfaces/service.mojom)
70 Services have a link back to the Service Manager too, primarily in the form of 73 interface. Typically this is done in C++ code by implementing the C++ client
71 the service_manager.mojom.Connector interface. The Connector allows services to 74 library's
72 open connections to other services. 75 [`service_manager::Service`](https://cs.chromium.org/chromium/src/services/servi ce_manager/public/cpp/service.h)
73 76 interface. This interface is driven by messages from the Service Manager and is
74 A unique connection from the Service Manager to a service is called an 77 used to receive incoming interface requests the Service Manager brokers from
75 “instance,” each with its own unique identifier, called an instance id. Every 78 other services.
76 instance has a unique Identity. It is possible to locate an existing instance 79
77 purely using its Identity. 80 Every service instance also has an outgoing link back to the Service Manager
78 81 which it can use to make interface requests to other services in the system.
79 Services define their own lifetimes. Services in processes started by other 82 This is the
80 services (rather than the Service Manager) may even outlive the connection with 83 [`service_manager.mojom.Connector`](https://cs.chromium.org/chromium/src/service s/service_manager/public/interfaces/connector.mojom)
81 the Service Manager. For processes launched by the Service Manager, when a 84 interface, and it's commonly used via the C++ client library's
82 service wishes to terminate it closes the Service pipe with the Service Manager 85 [`service_manager::Connector`](https://cs.chromium.org/chromium/src/services/ser vice_manager/public/cpp/connector.h)
83 and the Service Manager destroys its corresponding instance and asks the process 86 class.
84 to exit. 87
85 88 ## A Simple Service Example
86 #### A simple Service example 89
87 90 This section walks through the creation of a simple skeleton service.
88 Consider this simple application that implements the Service interface: 91
89 92 ### Private Implementation
90 **my_service.cc:** 93
91 94 Consider this implementation of the `service_manager::Service` interface:
92 #include "services/service_manager/public/c/main.h" 95
93 #include "services/service_manager/public/cpp/service.h" 96 **`//services//my_service/my_service.h`**
94 #include "services/service_manager/public/cpp/service_runner.h" 97 ``` cpp
95 98 #include "base/macros.h"
96 class MyService : public service_manager::Service { 99 #include "services/service_manager/public/cpp/service.h"
97 public: 100
98 MyService() {} 101 namespace my_service {
99 ~MyService() override {} 102
100 103 class MyService : public service_manager::Service {
101 // Overridden from service_manager::Service: 104 public:
102 void OnStart() override { 105 MyService();
103 } 106 ~MyService() override;
104 bool OnConnect(const service_manager::ServiceInfo& remote_info, 107
105 service_manager::InterfaceRegistry* registry) override { 108 // service_manager::Service:
106 return true; 109 void OnStart() override;
107 } 110 void OnBindInterface(const service_manager::ServiceInfo& remote_info,
108 }; 111 const std::string& interface_name,
109 112 mojo::ScopedMessagePipeHandle handle) override;
110 MojoResult ServiceMain(MojoHandle service_request_handle) { 113 private:
111 return service_manager::ServiceRunner(new MyService).Run( 114 DISALLOW_COPY_AND_ASSIGN(MyService);
112 service_request_handle); 115 };
113 } 116
114 117 } // namespace my_service
115 **manifest.json:** 118 ```
116 119
117 { 120 **`//services//my_service/my_service.cc`**
118 "name": "my_service", 121 ``` cpp
119 "display_name": "My Service", 122 #include "services/my_service/my_service.h"
120 "inteface_provider_spec": { 123
121 "service_manager:connector": {} 124 namespace my_service {
125
126 MyService::MyService() = default;
127
128 MyService::~MyService() = default;
129
130 void MyService::OnStart() {
131 }
132
133 void MyService::OnBindInterface(const service_manager::ServiceInfo& remote_info,
134 const std::string& interface_name,
135 mojo::ScopedMessagePipeHandle handle) {
136 }
137
138 } // namespace my_service
139 ```
140
141 ### Main Entry Point
142
143 While services do not need to define a main entry point -- *e.g.* they may only
144 intend to be embedded in other running processes -- for the sake of completeness
145 we also define a `ServiceMain` definition so that the service can be run in its
146 own process:
147
148 **`//services/my_service/my_service_main.cc`**
149 ``` cpp
150 #include "services/my_service/my_service.h"
151 #include "services/service_manager/public/c/main.h"
152 #include "services/service_manager/public/cpp/service_runner.h"
153
154 MojoResult ServiceMain(MojoHandle service_request_handle) {
155 return service_manager::ServiceRunner(new MyService).Run(
156 service_request_handle);
157 }
158 ```
159
160 ### Manifest
161
162 A static manifest is provided to the Service Manager by each service to declare
163 the capabilities exposed and required by the service:
164
165 **`//services/my_service/manifest.json`**
166 ``` json
167 {
168 "name": "my_service",
169 "display_name": "My Service",
170 "interface_provider_spec": {
171 "service_manager:connector": {}
172 }
173 }
174 ```
175
176 See [Service Manifests](#Service-Manifests) for more information.
177
178 ### Build Targets
179
180 Finally some build targets corresponding to the above things:
181
182 **`//services/my_service/BUILD.gn`**
183 ``` python
184 import("//services/service_manager/public/cpp/service.gni")
185 import("//services/service_manager/public/service_manifest.gni")
186
187 source_set("lib") {
188 public = [ "my_service.h" ]
189 sources = [ "my_service.cc" ]
190
191 public_deps = [
192 "//base",
193 "//services/service_manager/public/cpp",
194 ]
195 }
196
197 service("my_service") {
198 sources = [
199 "my_service_main.cc",
200 ]
201 deps = [
202 ":lib",
203 "//services/service_manager/public/c",
204 ]
205 }
206
207 service_manifest("manifest") {
208 name = "my_service"
209 source = "manifest.json"
210 }
211 ```
212
213 Building the `my_service` target produces a `my_service.service` (or on Windows,
214 `my_service.service.exe`) binary in the output directory. This can be run as
215 a standalone executable, but it will exit immediately without doing anything
216 interesting, because it won't have a `Service` pipe to drive it. The Service
217 Manager knows how to provide such a pipe when launching a service executable.
218
219 This service doesn't do much of anything. It will simply run forever (or at
220 least until the Service Manager itself shuts down), ignoring all incoming
221 messages. Before we expand on the definition of this service, let's look at some
222 of the details of the `service_manager::Service` interface.
223
224 ### OnStart
225
226 The `Service` implementation is guaranteed to receive a single `OnStart()`
227 invocation from the Service Manager before anything else hapens. Once this
228 method is called, the implementation can access it
229 `service_manager::ServiceContext` via `context()`. This object itself exposes a
230 few values:
231
232 * `service_info()` is a `service_manager::ServiceInfo` structure describing the
233 running service from the Service Manager's perspective. This includes the
234 `service_manager::Identity` which uniquely identifies the running instance,
235 as well as the `service_manager::InterfaceProviderSpec` describing the
236 capability specifications outlined in the service's manifest.
237 * `identity()` is a shortcut to the `Identity` stored in the
238 `ServiceInfo`.
239 * `connector()` is a `service_manager::Connector` which can be used to make
240 outgoing interface requests to other services.
241
242 For example, we could modify `MyService` to connect out to logger service on
243 startup:
244
245 ``` cpp
246 void MyService::OnStart() {
247 logger::mojom::LoggerPtr logger;
248 context()->connector()->BindInterface("logger", &logger);
249 logger->Log("Started MyService!");
250 }
251 ```
252
253 ### OnBindInterface
254
255 The `OnBindInterface` method on `service_manager::Service` is invoked by the
256 Service Manager any time another service instance uses its own `Connector` to
257 request an interface from this `my_service` instance. The Service Manager only
258 invokes this method once it has already validated that the request meets the
259 mutual constraints specified in each involved service's manifest.
260
261 The arguments to `OnBindInterface` are as follows:
262
263 * `remote_info` is the `service_manager::ServiceInfo` corresponding to the
264 remote service which is requesting this interface. The information in this
265 structure is provided authoritatively by the Service Manager and can be
266 trusted in any context.
267 * `interface_name` is the (`std::string`) name of the interface being requested
268 by the remote service. The Service Manager has already validated that the
269 remote service requires at least one capability which exposes this interface
270 from the local service.
271 * `handle` is the `mojo::ScopedMessagePipeHandle` of an interface pipe which
272 the remote service expects us to bind to a concrete implementation of
273 the requested interface.
274
275 The Service Manager client library provides a
276 `service_manager::InterfaceRegistry` class definition which can make it easier
277 for services to bind incoming interface requests. Typesafe binding callbacks are
278 added to an `InterfaceRegistry` ahead of time, and the incoming arguments to
279 `OnBindInterface` can be forwarded to the registry, which will bind the message
280 pipe if it knows how. For example, we could modify our `MyService`
281 implementation as follows:
282
283 ``` cpp
284 namespace {
285
286 void BindDatabase(my_service::mojom::DatabaseRequest request) {
287 mojo::MakeStrongBinding(base::MakeUnique<my_service::DatabaseImpl>(),
288 std::move(request));
289 }
290
291 } // namespace
292
293 MyService::MyService() {
294 // Imagine |registry_| is added as a member of MyService, with type
295 // service_manager::InterfaceRegistry.
296
297 // The |my_service::mojom::Database| interface type is inferred by the
298 // compiler in the AddInterface call, and this effectively adds the bound
299 // function to an internal map keyed on the interface name, i.e.
300 // "my_service::mojom::Database" in this case.
301 registry_.AddInterface(base::Bind(&BindDatabase));
302 }
303
304 void MyService::OnBindInterface(const service_manager::ServiceInfo& remote_info,
305 const std::string& interface_name,
306 mojo::ScopedMessagePipeHandle handle) {
307 registry_.BindInterface(interface_name, std::move(handle));
308 }
309 ```
310
311 For more details regarding the definition of Mojom interfaces, implementing them
312 in C++, and working with C++ types like `InterfaceRequest`, see the
313 [Mojom IDL and Bindings Generator](/mojo/public/tools/bindings) and
314 [Mojo C++ Bindings API](/mojo/public/cpp/bindings) documentation.
315
316 ## Service Manifests
317
318 If some service were to come along and attempt to connect to `my_servce` and
319 bind the `my_service::mojom::Database` interface, we might see the Service
320 Manager spit out an error log complaining that `InterfaceProviderSpec` prevented
321 a connection to `my_service`.
322
323 In order for the interface to be reachable by other services, we must first fix
324 its manifest's **interface provider spec**. The interface provider spec is
325 a dictionary keyed by **interface provider name**, with each value representing
326 the **capability spec** for that provider.
327
328 Each capability spec defines an optional `"provides"` key and an optional
329 `"requires"` key.
330
331 The `provides` key value is a dictionary which is itself keyed by arbitrary
332 free-form strings (capability names, implicitly scoped to the manifest's own
333 service) whose values are lists of Mojom interface names exposed as part of that
334 capability.
335
336 The `requires` key value is also a dictionary, but it's one which is keyed by
337 remote service name. Each value is a list of capabilities required from the
338 corresponding remote service.
339
340 Finally, every interface provider spec (often exclusively) contains one standard
341 capability spec named "service_manager:connector". This is the capability spec
342 enforced when inter-service connections are made from a service's `Connector`
343 interface.
344
345 Let's update the `my_service` manifest as follows:
346
347 **`//services/my_service/manifest.json`**
348 ``` json
349 {
350 "name": "my_service",
351 "display_name": "My Service",
352 "interface_provider_spec": {
353 "service_manager:connector": {
354 "provides": {
355 "database": [
356 "my_service::mojom::Database"
357 ]
122 } 358 }
123 } 359 }
124 360 }
125 **BUILD.gn:** 361 }
126 362 ```
127 import("//services/service_manager/public/cpp/service.gni") 363
128 import("//services/service_manager/public/service_manifest.gni") 364 This means that `my_service` has defined a `database` capability comprised
129 365 solely of the `my_service::mojom::Database` interface. Any service which
130 service("my_service") { 366 requires this capability can bind that interface from `my_service`.
131 sources = [ "my_service.cc" ] 367
132 deps = [ "//base", "//services/service_manager/public/cpp" ] 368 For the sake of this example, let's define another service manifest:
133 } 369
134 370 **`//services/other_service/manifest.json`**
135 service_manifest("manifest") { 371 ``` json
136 name = "my_service" 372 {
137 source = "manifest.json" 373 "name": "other_service",
138 } 374 "display_name": "Other Service",
139 375 "interface_provider_spec": {
140 What does all this do? Building the app target produces two files in the output 376 "service_manager:connector": {
141 directory: Packages/my_service/my_service.library and 377 "requires": {
142 Packages/my_service/manifest.json. app.library is a DSO loaded by the Service 378 "my_service": [ "database" ]
143 Manager in its own process when another service connects to the
144 service:my_service name. This is not the only way (nor even the most likely one)
145 you can implement a Service, but it's the simplest and easiest to reason about.
146
147 This service doesn't do much. Its implementation of OnStart() is empty, and its
148 implementation of OnConnect just returns true to allow the inbound connection to
149 complete. Let's study the parameters to these methods though, since they'll be
150 important as we begin to do more in our service.
151
152 ##### OnStart Parameters
153
154 ###### const service_manager::ServiceInfo& info
155 ServiceInfo is a struct containing two fields, Identity and
156 InterfaceProviderSpec. The Identity field identifies this Service instance in
157 the Service Manager, and contains three components - the service name, the user
158 id the instance is run as, and an instance qualifier. The InterfaceProviderSpec
159 contains the definitions of the capabilities exposed and consumed by this
160 service that are statically declared in its manifest.
161
162 ##### OnConnect Parameters
163
164 ###### const service_manager::ServiceInfo& remote_info
165 Like the ServiceInfo parameter passed to OnStart, but defines the remote Service
166 that initiated the connection. The Service Manager client library uses this
167 information to limit what capabilities are exposed to the remote via the
168 InterfaceRegistry parameter.
169
170 ###### service_manager::InterfaceRegistry* registry
171 An object the local service uses to expose interfaces to be consumed by the
172 remote. This object is constructed by the Service Manager client library and
173 uses the InterfaceProviderSpecs of both the local and the remote service to
174 limit which interfaces can be bound by the remote. This object implements
175 service_manager::mojom::InterfaceProvider, which encapsulates the physical link
176 between the two services. The InterfaceRegistry is owned by the ServiceContext,
177 and will outlive the underlying pipe.
178
179 The service can decide to block the connection outright by returning false from
180 this method. In that scenario the underlying pipe will be closed and the remote
181 end will see an error and have the chance to recover.
182
183 Before we add any functionality to our service, such as exposing an interface,
184 we should look at how we connect to another service and bind an interface from
185 it. This will lay the groundwork to understanding how to export an interface.
186
187 ### Connecting
188
189 Once we have a Connector, we can connect to other services and bind interfaces
190 from them. In the trivial app above we can do this directly in OnStart:
191
192 void OnStart(const service_manager::ServiceInfo& info) override {
193 std::unique_ptr<service_manager::Connection> connection =
194 connector()->Connect("service:other_service");
195 mojom::SomeInterfacePtr some_interface;
196 connection->GetInterface(&some_interface);
197 some_interface->Foo();
198 }
199
200 This assumes an interface called 'mojo.SomeInterface' with a method 'Foo()'
201 exported by another service identified by the name 'service:other_service'.
202
203 What is happening here? Let's look line-by-line
204
205
206 std::unique_ptr<service_manager::Connection> connection =
207 connector->Connect("service:other_service");
208
209 This asks the Service Manager to open a connection to the service named
210 'service:other_service'. The Connect() method returns a Connection object simila r
211 to the one received by OnConnect() - in fact this Connection object binds the
212 other ends of the pipes of the Connection object received by OnConnect in the
213 remote service. This time, the caller of Connect() takes ownership of the
214 Connection, and when it is destroyed the connection (and the underlying pipes)
215 is closed. A note on this later.
216
217 mojom::SomeInterfacePtr some_interface;
218
219 This is a shorthand from the mojom bindings generator, producing an
220 instantiation of a mojo::InterfacePtr<mojom::SomeInterface>. At this point the
221 InterfacePtr is unbound (has no pipe handle), and calling is_bound() on it will
222 return false. Before we can call any methods, we need to bind it to a Mojo
223 message pipe. This is accomplished on the following line:
224
225 connection->GetInterface(&some_interface);
226
227 Calling this method allocates a Mojo message pipe, binds the client handle to
228 the provided InterfacePtr, and sends the server handle to the remote service,
229 where it will eventually (asynchronously) be bound to an object implementing the
230 requested interface. Now that our InterfacePtr has been bound, we can start
231 calling methods on it:
232
233 some_interface->Foo();
234
235 Now an important note about lifetimes. At this point the Connection returned by
236 Connect() goes out of scope, and is destroyed. This closes the underlying
237 InterfaceProvider pipes with the remote service. But Mojo methods are
238 asynchronous. Does this mean that the call to Foo() above is lost? No. Before
239 closing, queued writes to the pipe are flushed.
240
241 ### Implementing an Interface
242
243 Let's look at how to implement an interface now from a service and expose it to
244 inbound connections from other services. To do this we'll need to implement
245 OnConnect() in our Service implementation, and implement a couple of other
246 interfaces. For the sake of this example, we'll imagine now we're writing the
247 'service:other_service' service, implementing the interface defined in this
248 mojom:
249
250 **some_interface.mojom:**
251
252 module mojom;
253
254 interface SomeInterface {
255 Foo();
256 };
257
258 To build this mojom we need to invoke the mojom gn template from
259 `//mojo/public/tools/bindings/mojom.gni`. Once we do that and look at the
260 output, we can see that the C++ class mojom::SomeInterface is generated and can
261 be #included from the same path as the .mojom file at some_interface.mojom.h.
262 In our implementation of the service:other_service, we'll need to derive
263 from this class to implement the interface. But that's not enough. We'll also ha ve
264 to find a way to bind inbound requests to bind this interface to the object that
265 implements it. Let's look at a snippet of a class that does all of this:
266
267 **other_service.cc:**
268
269 class Service : public service_manager::Service,
270 public service_manager::InterfaceFactory<mojom::SomeInterfac e>,
271 public mojom::SomeInterface {
272 public:
273 ..
274
275 // Overridden from service_manager::Service:
276 bool OnConnect(const service_manager::ServiceInfo& remote_info,
277 service_manager::InterfaceRegistry* registry) override {
278 registry->AddInterface<mojom::SomeInterface>(this);
279 return true;
280 }
281
282 // Overridden from service_manager::InterfaceFactory<mojom::SomeInterface> :
283 void Create(const service_manager::Identity& remote_identity,
284 mojom::SomeInterfaceRequest request) override {
285 bindings_.AddBinding(this, std::move(request));
286 }
287
288 // Overridden from mojom::SomeInterface:
289 void Foo() override { /* .. */ }
290
291 mojo::BindingSet<mojom::SomeInterface> bindings_;
292 };
293
294 Let's study what's going on, starting with the obvious - we derive from
295 `mojom::SomeInterface` and implement `Foo()`. How do we bind this implementation
296 to a pipe handle from a connected service? First we have to advertise the
297 interface to the service via the registry provided at the incoming connection.
298 This is accomplished in OnConnect():
299
300 registry->AddInterface<mojom::SomeInterface>(this);
301
302 This adds the `mojom.SomeInterface` interface name to the inbound
303 InterfaceRegistry, and tells it to consult this object when it needs to
304 construct an implementation to bind. Why this object? Well in addition to
305 Service and SomeInterface, we also implement an instantiation of the generic
306 interface InterfaceFactory. InterfaceFactory is the missing piece - it binds a
307 request for SomeInterface (in the form of a message pipe server handle) to the
308 object that implements the interface (this). This is why we implement Create():
309
310 bindings_.AddBinding(this, std::move(request));
311
312 In this case, this single instance binds requests for this interface from all
313 connected services, so we use a mojo::BindingSet to hold them all.
314 Alternatively, we could construct an object per request, and use mojo::Binding.
315
316 ### Statically Declaring Capabilities
317
318 While the code above looks like it should work, if we were to type it all in,
319 build it and run it it still wouldn't. In fact, if we ran it, we'd see this
320 error in the console:
321
322 `InterfaceProviderSpec prevented connection from: service:my_service to service: other_service`
323
324 The answer lies in an omission in one of the files I didn't discuss earlier, the
325 manifest.json, specifically the empty 'interface_provider_specs' dictionary.
326
327 When held, a capability controls some behavior in a service, including the
328 ability to bind specific interfaces. At a primitive level, a simple way to think
329 about a capability is the ability to bind a pipe and communicate over it.
330
331 At the top level, the Service Manager implements the delegation of capabilities
332 in accordance with rules spelled out in each service's manifest.
333
334 Each service produces a manifest file with some typical metadata about itself,
335 and an 'interface_provider_spec'. An interface_provider_spec describes
336 capabilities offered by the service and those consumed from other services.
337 Let's study a fairly complete interface_provider_spec from another service's
338 manifest:
339
340 "interface_provider_specs": {
341 "service_manager:connector": {
342 "provides": {
343 "web": ["if1", "if2"],
344 "uid": []
345 },
346 "requires": {
347 "*": ["c1", "c2"],
348 "service:foo": ["c3"]
349 }
350 } 379 }
351 } 380 }
352 381 }
353 At the top level of the interface_provider_spec dictionary are one or more 382 }
354 sub-dictionaries, each corresponding to an individual InterfaceProviderSpec 383 ```
355 definition. In all cases, there is a dictionary called 384
356 "service_manager:connector". The name here means that the spec is meaningful to 385 Now if `other_service` attempts to bind the database interface:
357 the Service Manager, and relates to the service_manager::mojom::InterfaceProvide r 386
358 pair expressed via the Connector interface. This is the spec that controls what 387 ``` cpp
359 capabilities are exposed between services via the Connect()/OnConnect() methods. 388 void OtherService::OnStart() {
360 389 my_service::mojom::DatabasePtr database;
361 Within each spec definition there are two sub-dictionaries: 390 context()->connector()->BindInterface("my_service", &database);
362 391 database->AddTable(...);
363 #### Provided Capabilities 392 }
364 393 ```
365 The provides dictionary enumerates the capabilities provided by the service. A 394
366 capability is an alias, either to some special behavior exposed by the service 395 The Service Manager will approve of the request and forward it on to the
367 to remote services that request that capability, or to a set of interfaces 396 `my_service` instance's `OnBindInterface` method.
368 exposed by the service to remote services. In the former case, in the 397
369 dictionary we provide an empty array as the value of the capability key, in the 398 ## Testing
370 latter case we provide an array with a list of the fully qualified Mojo 399
371 interface names (module.path.InterfaceName). A special case of array is one that 400 Now that we've built a simple service it's time to write a test for it.
372 contains the single entry "*", which means 'all interfaces'. 401 The Service Manager client library provides a test fixture base class in
373 402 [`service_manager::test::ServiceTest`](https://cs.chromium.org/chromium/src/serv ices/service_manager/public/cpp/service_test.h) that makes writing service integ ration tests straightforward. This test fixture
374 Let's consider our previous example the `service:other_service`, which we want 403 runs an in-process Service Manager on a background thread which allows test
375 our `service:my_service` to connect to, and bind mojom::SomeInterface. Every 404 service instances to be injected at runtime.
376 interface that a service provides that is intended to be reachable via 405
377 Connect()/OnConnect() must be statically declared in the manifest as exported 406 Let's look at a simple test of our service:
378 in the providing service's manifest as part of a named capability. A capability 407
379 name is just a string that provider and consumer agree upon. Here's what 408 **`//services/my_service/my_service_unittest.cc`**
380 `service:other_service`'s manifest must then look like: 409 ``` cpp
381 410 #include "base/bind.h"
382 { 411 #include "base/run_loop.h"
383 "name": "service:other_service", 412 #include "services/service_manager/public/cpp/service_test.h"
384 "display_name": "Other Service", 413 #include "path/to/some_interface.mojom.h"
385 "interface_provider_specs": { 414
386 "service_manager:connector": { 415 class MyServiceTest : public service_manager::test::ServiceTest {
387 "provides": { 416 public:
388 "other_capability": [ "mojom.SomeInterface" ] 417 // Our tests run as service instances themselves. In this case each instance
389 } 418 // identifies as the service named "my_service_unittests".
390 } 419 MyServiceTest() : service_manager::test::ServiceTest("my_service_unittests") {
420 }
421
422 ~MyServiceTest() override {}
423 }
424
425 TEST_F(MyServiceTest, Basic) {
426 my_service::mojom::DatabsaePtr database;
427 connector()->BindInterface("my_service", &database);
428
429 base::RunLoop loop;
430
431 // This assumes DropTable expects a response with no arugments. When the
432 // response is received, the RunLoop is quit.
433 database->DropTable("foo", loop.QuitClosure());
434
435 loop.Run();
436 }
437 ```
438
439 If adding a new test binary for these tests, we can augment our `BUILD.gn` to
440 use the `service_test` GN template like so:
441
442 **`//services/my_service/BUILD.gn`**
443 ``` cpp
444 import("//services/catalog/public/tools/catalog.gni")
445 import("//services/service_manager/public/tools/test/service_test.gni")
446
447 service_test("my_service_unittests") {
448 sources = [
449 "my_service_unittest.cc",
450 ]
451 deps = [
452 "//services/my_service/public/interfaces",
453 ]
454 catalog = ":my_service_unittests_catalog"
455 }
456
457 service_manifest("my_service_unittests_manifest") {
458 name = "my_service_unittests"
459 manifest = "my_service_unittests_manifest.json"
460 }
461
462 catalog("my_service_unittests_catalog") {
463 testonly = true
464 embedded_services = [ ":my_service_unittests_manifest" ]
465 standalone_services = [ ":manifest" ]
466 }
467 ```
468
469 Alright, there's a lot going on here. First we also have to create a service
470 manifest for the test service itself, as the Service Manager needs to be able
471 to reason about the test's own required capabilities with respect to the
472 service-under-test.
473
474 We can do something like:
475
476 **`//services/my_service/my_service_unittests_manifest.json`**
477 ``` json
478 {
479 "name": "my_service_unittests",
480 "display_name": "my_service tests",
481 "interface_provider_spec": {
482 "service_manager:connector": {
483 "requires": {
484 "my_service": [ "database" ]
391 } 485 }
392 } 486 }
393 487 }
394 #### Required Capabilities 488 }
395 489 ```
396 The requires dictionary enumerates the capabilities required by the service. The 490
397 keys into this dictionary are the names of the services it intends to connect 491 You may also notice that we have suddenly introduced a **catalog** in the
398 to, and the values for each key are an array of capability names required of 492 `service_test` target incantation. Any runtime environment which hosts a
399 that service. A "*" key in the 'requires' dictionary allows the service to provi de 493 Service Manager must provide the Service Manager implementation with a catalog
400 a capability spec that must be adhered to by all services it connects to. 494 of service manifests. This catalog defines the complete set of services
401 495 recognized by the Service Manager instance and can be used in all kinds of
402 A consequence of this is that a service must statically declare every interface 496 interesting ways to control how various services are started in the system. See
403 it provides in at least one capability in its manifest. 497 [Service Manager Catalogs](#Service-Manager-Catalogs) for more information.
404 498
405 Armed with this knowledge, we can return to manifest.json from the first 499 For now let's just accept that we have to create a `catalog` rule for our test
406 example and fill out the interface_provider_specs: 500 suite and plug it into the `service_test` target.
407 501
408 { 502 In practice, we typically try to avoid introducing new unittest binaries for
409 "name": "service:my_service", 503 individual services. Instead we have an aggregate `service_unittests` target
410 "display_name": "My Service", 504 defined in [`//services/BUILD.gn`](https://cs.chromium.org/chromium/src/services /BUILD.gn).
411 "interface_provider_specs": { 505 There are several examples of other services adding their service tests to this
412 "service_manager:connector": { 506 suite.
413 "requires": { 507
414 "service:other_service": [], 508 ## Service Manager Catalogs
415 } 509
416 } 510 A **catalog** is an aggregation of service manifests which comprises a complete
417 } 511 runtime configuration of the Service Manager.
418 } 512
419 513 The GN `catalog` target template defined in
420 If we just run now, it still won't work, and we'll see this error: 514 [`//services/catalog/public/tools/catalog.gni`](https://cs.chromium.org/chromium /src/services/catalog/public/tools/catalog.gni).
421 515 provides a simple means of aggregating service manifests into a single build
422 InterfaceProviderSpec "service_manager:connector" prevented service: 516 artifact. See the comments on the template for detailed documentation.
423 service:my_service from binding interface mojom.SomeInterface exposed by: 517
424 service:other_service 518 This GNI also defines a `catalog_cpp_source` target which can generate a static
425 519 C++ representation of an aggregated catalog manifest so that it can be passed
426 The connection was allowed to complete, but the attempt to bind 520 the Service Manager at runtime.
427 `mojom.SomeInterface` was blocked. As it happens, this interface is provided as 521
428 part of the capability `other_capability` exported by `service:other_service`. 522 In general, service developers should never be concerned with creating new
429 We need to add that capability to the array in our manifest: 523 catalogs or instantiating the Service Manager, but it's important to be aware
430 524 of these concepts. When introducing a new service into any runtime environment
431 "requires": { 525 -- including Chrome, Content, or various unit test suites such as
432 "service:other_service": [ "other_capability" ], 526 `service_unittests` discussed in the previous section -- your service manifest
433 } 527 must be added to the catalog used in that environment.
434 528
435 Now everything should work. 529 TODO - expand on this
436 530
437 ### Testing 531 ## Packaging Services
438 532
439 Now that we've built a simple application and service, it's time to write a test 533 TODO
440 for them. The Service Manager client library provides a gtest base class 534
441 **service_manager::test::ServiceTest** that makes writing integration tests of 535 ## Chrome and Chrome OS Service Manager Integration
442 services straightforward. Let's look at a simple test of our service: 536
443 537 TODO
444 #include "base/bind.h"
445 #include "base/run_loop.h"
446 #include "services/service_manager/public/cpp/service_test.h"
447 #include "path/to/some_interface.mojom.h"
448
449 void QuitLoop(base::RunLoop* loop) {
450 loop->Quit();
451 }
452
453 class Test : public service_manager::test::ServiceTest {
454 public:
455 Test() : service_manager::test::ServiceTest("exe:service_unittest") {}
456 ~Test() override {}
457 }
458
459 TEST_F(Test, Basic) {
460 mojom::SomeInterface some_interface;
461 connector()->ConnectToInterface("service:other_service", &some_interface);
462 base::RunLoop loop;
463 some_interface->Foo(base::Bind(&QuitLoop, &loop));
464 loop.Run();
465 }
466
467 The BUILD.gn for this test file looks like any other using the test() template.
468 It must also depend on
469 //services/service_manager/public/cpp:service_test_support.
470
471 ServiceTest does a few things, but most importantly it register the test itself
472 as a Service, with the name you pass it via its constructor. In the example
473 above, we supplied the name 'exe:service_unittest'. This name is has no special
474 meaning other than that henceforth it will be used to identify the test service.
475
476 Behind the scenes, ServiceTest spins up the Service Manager on a background
477 thread, and asks it to create an instance for the test service on the main
478 thread, with the name supplied. ServiceTest blocks the main thread while the
479 Service Manager thread does this initialization. Once the Service Manager has
480 created the instance, it calls OnStart() (as for any other service), and the
481 main thread continues, running the test. At this point accessors defined in
482 service_test.h like connector() can be used to connect to other services.
483
484 You'll note in the example above I made Foo() take a callback, this is to give
485 the test something interesting to do. In the mojom for SomeInterface we'd have
486 the Foo() method return an empty response. In service:other_service, we'd have
487 Foo() take the callback as a parameter, and run it. In the test, we spin a
488 RunLoop until we get that response. In real world cases we can pass back state &
489 validate expectations. You can see real examples of this test framework in use
490 in the Service Manager's own suite of tests, under
491 //services/service_manager/tests.
492
493 ### Packaging
494
495 By default a .library statically links its dependencies, so having many of them
496 will yield an installed product many times larger than Chrome today. For this
497 reason it's desirable to package several Services together in a single binary.
498 The Service Manager provides an interface **service_manager.mojom.ServiceFactory **:
499
500 interface ServiceFactory {
501 CreateService(Service& service, string name);
502 };
503
504 When implemented by a service, the service becomes a 'package' of other
505 services, which are instantiated by this interface. Imagine we have two services
506 service:service1 and service:service2, and we wish to package them together in a
507 single package service:services. We write the Service implementations for
508 service:service1 and service:service2, and then a Service implementation for
509 service:services - the latter implements ServiceFactory and instantiates the
510 other two:
511
512 using service_manager::mojom::ServiceFactory;
513 using service_manager::mojom::ServiceRequest;
514
515 class Services : public service_manager::Service,
516 public service_manager::InterfaceFactory<ServiceFactory>,
517 public ServiceFactory {
518
519 // Expose ServiceFactory to inbound connections and implement
520 // InterfaceFactory to bind requests for it to this object.
521 void CreateService(ServiceRequest request,
522 const std::string& name) {
523 if (name == "service:service1")
524 new Service1(std::move(request));
525 else if (name == "service:service2")
526 new Service2(std::move(request));
527 }
528 }
529
530 This is only half the story though. While this does mean that service:service1
531 and service:service2 are now packaged (statically linked) with service:services,
532 as it stands to connect to either packaged service you'd have to connect to
533 service:services first, and call CreateService yourself. This is undesirable for
534 a couple of reasons, firstly in that it complicates the connect flow, secondly
535 in that it forces details of the packaging, which are a distribution-level
536 implementation detail on services wishing to use a service.
537
538 To solve this, the Service Manager actually automates resolving packaged service
539 names to the package service. The Service Manager considers the name of a
540 service provided by some other package service to be an 'alias' to that package
541 service. The Service Manager resolves these aliases based on information found,
542 you guessed it, in the manifests for the package service.
543
544 Let's imagine service:service1 and service:service2 have typical manifests of th e
545 form we covered earlier. Now imagine service:services, the package service that
546 combines the two. In the package install directory rather than the following
547 structure:
548
549 service1/service1.library,manifest.json
550 service2/service2.library,manifest.json
551
552 Instead we'll have:
553
554 package/services.library,manifest.json
555
556 The manifest for the package service describes not only itself, but includes the
557 manifests of all the services it provides. Fortunately there is some GN build
558 magic that automates generating this meta-manifest, so you don't need to write
559 it by hand. In the service_manifest() template instantiation for services, we
560 add the following lines:
561
562 deps = [ ":service1_manifest", ":service2_manifest" ]
563 packaged_services = [ "service1", "service2" ]
564
565 The deps line lists the service_manifest targets for the packaged services to be
566 consumed, and the packaged_services line provides the service names, without the
567 'service:' prefix. The presence of these two lines will cause the Manifest Colla tor
568 script to run, merging the dependent manifests into the package manifest. You
569 can study the resulting manifest to see what gets generated.
570
571 At startup, the Service Manager will scan the package directory and consume the
572 manifests it finds, so it can learn about how to resolve aliases that it might
573 encounter subsequently.
574
575 ### Executables
576
577 Thus far, the examples we've covered have packaged Services in .library files.
578 It's also possible to have a conventional executable provide a Service. There
579 are two different ways to use executables with the Service Manager, the first is
580 to have the Service Manager start the executable itself, the second is to have
581 some other executable start the process and then tell the Service Manager about
582 it. In both cases, the target executable has to perform a handshake with the
583 Service Manager early on so it can bind the Service request the Service Manager
584 sends it.
585
586 Assuming you have an executable that properly initializes the Mojo EDK, you add
587 the following lines at some point early in application startup to establish the
588 connection with the Service Manager:
589
590 #include "services/service_manager/public/cpp/service.h"
591 #include "services/service_manager/public/cpp/service_context.h"
592 #include "services/service_manager/runner/child/runner_connection.h"
593
594 class MyService : public service_manager::Service {
595 ..
596 };
597
598 service_manager::mojom::ServiceRequest request;
599 std::unique_ptr<service_manager::RunnerConnection> connection(
600 service_manager::RunnerConnection::ConnectToRunner(
601 &request, ScopedMessagePipeHandle()));
602 MyService service;
603 service_manager::ServiceContext context(&service, std::move(request));
604
605 What's happening here? The Service/ServiceContext usage should be familiar from
606 our earlier examples. The interesting part here happens in
607 `RunnerConnection::ConnectToRunner()`. Before we look at what ConnectToRunner
608 does, it's important to cover how this process is launched. In this example,
609 this process is launched by the Service Manager. This is achieved through the
610 use of the 'exe' Service Name type. The Service Names we've covered thus far
611 have looked like 'service:foo'. The 'mojo' prefix means that the Service Manager
612 should look for a .library file at 'foo/foo.library' alongside the Service Manag er
613 executable. If the code above was linked into an executable 'app.exe' alongside
614 the Service Manager executable in the output directory, it can be launched by
615 connecting to the name 'exe:app'. When the Service Manager launches an
616 executable, it passes a pipe to it on the command line, which the executable is
617 expected to bind to receive a ServiceRequest on. Now back to ConnectToRunner.
618 It spins up a background 'control' thread with the Service Manager, binds the
619 pipe from the command line parameter, and blocks the main thread until the
620 ServiceRequest arrives and can be bound.
621
622 Like services provided from .library files, we have to provide a manifest for
623 services provided from executables. The format is identical, but in the
624 service_manifest template we need to set the type property to 'exe' to cause the
625 generation step to put the manifest in the right place (it gets placed alongside
626 the executable, with the name <exe_name>_manifest.json.)
627
628 ### Service-Launched Processes
629
630 There are some scenarios where a service will need to launch its own process,
631 rather than relying on the Service Manager to do it. The Connector API provides
632 the ability to tell the Service Manager about a process that the service has or
633 will create. The executable that the service launches (henceforth referred to as
634 the 'target') should be written using RunnerConnection as discussed in the
635 previous section. The connect flow in the service that launches the target
636 (henceforth referred to as the driver) works like this:
637
638 base::FilePath target_path;
639 base::PathService::Get(base::DIR_EXE, &target_path);
640 target_path = target_path.Append(FILE_PATH_LITERAL("target.exe"));
641 base::CommandLine target_command_line(target_path);
642
643 mojo::edk::PlatformChannelPair pair;
644 mojo::edk::HandlePassingInformation info;
645 pair.PrepareToPassClientHandleToChildProcess(&target_command_line, &info);
646
647 mojo::edk::PendingProcessConnection connection;
648 std::string token;
649 mojo::ScopedMessagePipeHandle pipe = connection.CreateMessagePipe(&token);
650 target_command_line.AppendSwitchASCII(switches::kPrimordialPipeToken,
651 token);
652
653 service_manager::Identity target("exe:target",
654 service_manager::mojom::kInheritUserID);
655 service_manager::mojom::PIDReceiverPtr receiver;
656 connector->RegisterService(target, std::move(pipe), MakeRequest(&receiver));
657
658 base::LaunchOptions options;
659 options.handles_to_inherit = &info;
660 base::Process process = base::LaunchProcess(target_command_line, options);
661 connection.Connect(process.Handle(), pair.PassServerHandle());
662
663 That's a lot. But it boils down to these steps:
664 1. Creating the message pipe to connect the target process and the Service
665 Manager.
666 2. Putting the server end of the pipe onto the command line to the target
667 process.
668 3. Binding the client end to a ServiceFactoryPtr, constructing an Identity for
669 the target process and passing both through Connector::Connect().
670 4. Starting the process with the configured command line.
671
672 In this example the target executable could be the same as the previous example.
673
674 A word about process lifetimes. Processes created by the Service Manager are
675 also managed by the Service Manager. While a service-launched process may quit
676 itself at any point, when the Service Manager shuts down it will also shut down
677 any process it started. Processes created by services themselves are left to
678 those services to manage.
679
680 ### Other InterfaceProviderSpecs
681
682 We discussed InterfaceProviderSpecs in detail in the section above about
683 exchange of capabilities between services. That section focused on how
684 interfaces are exposed via Connect()/OnConnect(). Looking at the structure of
685 service manifests:
686
687 "interface_provider_specs": {
688 "service_manager:connector": {
689 "provides": {
690 ...
691 },
692 "requires": {
693 ...
694 }
695 }
696 }
697
698 It was discussed that the "service_manager:connector" dictionary described
699 capabilities of interest to the Service Manager. While our use cases thus far
700 have focused on this single InterfaceProviderSpec, it's possible (and desirable)
701 to use others, any time an InterfaceProvider is used. Why? Well
702 InterfaceProvider is a generic interface - it can theoretically be used to bind,
703 anything and as such it's useful to be able to statically assert what interfaces
704 are exposed to what contexts. In Chromium, manifest files get security review,
705 which provides an extra layer of care when we think about what capabilities are
706 being exposed between contexts at different trust levels. A concrete example
707 from Chrome - a pair of InterfaceProviders is used to expose frame-specific
708 interfaces between browser and renderer processes. To define another spec, we do
709 this:
710
711 "interface_provider_specs": {
712 "service_manager:connector": {
713 "provides": {
714 ...
715 },
716 "requires": {
717 ...
718 }
719 },
720 "my_spec_name": {
721 "provides": {
722 ...
723 },
724 "requires": {
725 ...
726 }
727 }
728 }
729
730 And here again we can define capabilities & consume them. To actually hook up
731 this new spec in code, we must do what `service_manager::ServiceContext` does
732 for us with the `service_manager:connector` spec, and configure a
733 `service_manager::InterfaceRegistry` appropriately:
734
735 void OnStart(const service_manager::ServiceInfo& info) override {
736 registry_ =
737 base::MakeUnique<service_manager::InterfaceRegistry>("my_spec_name");
738 registry_->AddInterface<mojom::Foo>(this);
739 registry_->AddInterface<mojom::Bar>(this);
740
741 // Store this so we can use it when we Bind() registry_.
742 local_info_ = info;
743 }
744
745 bool OnConnect(const service_manager::ServiceInfo& remote_info,
746 service_manager::InterfaceRegistry* remote) override {
747 remote_info_ = remote_info;
748 registry->AddInterface<mojom::MyInterface>(this);
749 return true;
750 }
751
752 ...
753
754 // mojom::MyInterface:
755 void GetInterfaceProvider(
756 service_manager::mojom::InterfaceProviderRequest request) override {
757 service_manager::InterfaceProviderSpec my_spec, remote_spec;
758 service_manager::GetInterfaceProviderSpec(
759 "my_spec_name", local_info_.interface_provider_specs, &my_spec);
760 service_manager::GetInterfaceProviderSpec(
761 "my_spec_name", remote_info_.interface_provider_specs, &remote_spec);
762 registry_->Bind(std::move(request), local_info_.identity, my_spec,
763 remote_info_.identity, remote_spec);
764 // |registry_| is now bound to the remote, and its GetInterface()
765 // implementation is now controlled via the rules set out in
766 // `my_spec_name` declared in this service's and the remote service's
767 // manifests.
768 }
769
770 ...
771
772 std::unique_ptr<service_manager::InterfaceRegistry> registry_;
773 service_manager::ServiceInfo local_info_;
774 service_manager::ServiceInfo remote_info_;
775
776 When we construct an `InterfaceRegistry` we pass the name of the spec that
777 controls it. When our service is started we're given (by the Service Manager)
778 our own spec. This allows us to know everything we provide. When we receive a
779 connection request from another service, the Service Manager provides us with
780 the remote service's spec. This is enough information that when we're asked to
781 bind the InterfaceRegistry to a pipe from the remote, the appropriate filtering
782 is performed.
783
784
785 ***
786
787 TBD:
788
789 Instances & Processes
790
791 Service lifetime strategies
792
793 Process lifetimes.
794
795 Under the Hood
796 Four major components: Service Manager API (Mojom), Service Manager, Catalog,
797 Service Manager Client Lib.
798 The connect flow, catalog, etc.
799 Capability brokering in the Service Manager
800 Userids
801
802 Finer points:
803
804 Service Names: mojo, exe
OLDNEW
« ipc/README.md ('K') | « services/README.md ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698