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

Side by Side Diff: services/shell/service_manager.cc

Issue 2419723002: Move services/shell to services/service_manager (Closed)
Patch Set: rebase Created 4 years, 2 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
« no previous file with comments | « services/shell/service_manager.h ('k') | services/shell/service_overrides.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "services/shell/service_manager.h"
6
7 #include <stdint.h>
8
9 #include <utility>
10
11 #include "base/bind.h"
12 #include "base/command_line.h"
13 #include "base/debug/alias.h"
14 #include "base/guid.h"
15 #include "base/logging.h"
16 #include "base/macros.h"
17 #include "base/process/process.h"
18 #include "base/process/process_handle.h"
19 #include "base/stl_util.h"
20 #include "base/strings/string_util.h"
21 #include "base/trace_event/trace_event.h"
22 #include "mojo/public/cpp/bindings/binding.h"
23 #include "mojo/public/cpp/bindings/binding_set.h"
24 #include "services/shell/connect_util.h"
25 #include "services/shell/public/cpp/connector.h"
26 #include "services/shell/public/cpp/names.h"
27 #include "services/shell/public/cpp/service_context.h"
28 #include "services/shell/public/interfaces/connector.mojom.h"
29 #include "services/shell/public/interfaces/service.mojom.h"
30 #include "services/shell/public/interfaces/service_manager.mojom.h"
31
32 namespace shell {
33
34 namespace {
35
36 const char kCatalogName[] = "service:catalog";
37 const char kServiceManagerName[] = "service:shell";
38 const char kCapabilityClass_UserID[] = "shell:user_id";
39 const char kCapabilityClass_ClientProcess[] = "shell:client_process";
40 const char kCapabilityClass_InstanceName[] = "shell:instance_name";
41 const char kCapabilityClass_AllUsers[] = "shell:all_users";
42 const char kCapabilityClass_ExplicitClass[] = "shell:explicit_class";
43 const char kCapabilityClass_ServiceManager[] = "shell:service_manager";
44
45 } // namespace
46
47 Identity CreateServiceManagerIdentity() {
48 return Identity(kServiceManagerName, mojom::kRootUserID);
49 }
50
51 Identity CreateCatalogIdentity() {
52 return Identity(kCatalogName, mojom::kRootUserID);
53 }
54
55 CapabilitySpec GetPermissiveCapabilities() {
56 CapabilitySpec capabilities;
57 Interfaces interfaces;
58 interfaces.insert("*");
59 capabilities.required["*"] = interfaces;
60 return capabilities;
61 }
62
63 Classes GetRequestedClasses(const CapabilitySpec& source_spec,
64 const Identity& target) {
65 Classes classes;
66
67 // Start by looking for specs specific to the supplied identity.
68 auto it = source_spec.required.find(target.name());
69 if (it != source_spec.required.end()) {
70 std::copy(it->second.begin(), it->second.end(),
71 std::inserter(classes, classes.begin()));
72 }
73
74 // Apply wild card rules too.
75 it = source_spec.required.find("*");
76 if (it != source_spec.required.end()) {
77 std::copy(it->second.begin(), it->second.end(),
78 std::inserter(classes, classes.begin()));
79 }
80 return classes;
81 }
82
83 void GetClassesAndInterfacesForConnection(
84 const CapabilitySpec& source_spec,
85 const Identity& target,
86 const CapabilitySpec& target_spec,
87 Classes* classes,
88 Interfaces* interfaces) {
89 DCHECK(classes && interfaces);
90 *classes = GetRequestedClasses(source_spec, target);
91 // Flatten all interfaces from classes requested by the source into the
92 // allowed interface set in the request.
93 for (const auto& class_name : *classes) {
94 auto it = target_spec.provided.find(class_name);
95 if (it != target_spec.provided.end()) {
96 for (const auto& interface_name : it->second)
97 interfaces->insert(interface_name);
98 }
99 }
100 }
101
102 bool HasClass(const CapabilitySpec& spec, const std::string& class_name) {
103 auto it = spec.required.find(kServiceManagerName);
104 if (it == spec.required.end())
105 return false;
106 return it->second.find(class_name) != it->second.end();
107 }
108
109 // Encapsulates a connection to an instance of a service, tracked by the
110 // Service Manager.
111 class ServiceManager::Instance
112 : public mojom::Connector,
113 public mojom::PIDReceiver,
114 public Service,
115 public InterfaceFactory<mojom::ServiceManager>,
116 public mojom::ServiceManager {
117 public:
118 Instance(shell::ServiceManager* service_manager,
119 const Identity& identity,
120 const CapabilitySpec& capability_spec)
121 : service_manager_(service_manager),
122 id_(GenerateUniqueID()),
123 identity_(identity),
124 capability_spec_(capability_spec),
125 allow_any_application_(capability_spec.required.count("*") == 1),
126 pid_receiver_binding_(this),
127 weak_factory_(this) {
128 if (identity_.name() == kServiceManagerName ||
129 identity_.name() == kCatalogName) {
130 pid_ = base::Process::Current().Pid();
131 }
132 DCHECK_NE(mojom::kInvalidInstanceID, id_);
133 }
134
135 ~Instance() override {
136 // Shutdown all bindings before we close the runner. This way the process
137 // should see the pipes closed and exit, as well as waking up any potential
138 // sync/WaitForIncomingResponse().
139 service_.reset();
140 if (pid_receiver_binding_.is_bound())
141 pid_receiver_binding_.Close();
142 connectors_.CloseAllBindings();
143 service_manager_bindings_.CloseAllBindings();
144
145 // Notify the ServiceManager that this Instance is really going away.
146 service_manager_->OnInstanceStopped(identity_);
147
148 // Release |runner_| so that if we are called back to OnRunnerCompleted()
149 // we know we're in the destructor.
150 std::unique_ptr<NativeRunner> runner = std::move(runner_);
151 runner.reset();
152 }
153
154 Instance* parent() { return parent_; }
155
156 void AddChild(std::unique_ptr<Instance> child) {
157 child->parent_ = this;
158 children_.insert(std::make_pair(child.get(), std::move(child)));
159 }
160
161 void RemoveChild(Instance* child) {
162 auto it = children_.find(child);
163 DCHECK(it != children_.end());
164
165 // Deletes |child|.
166 children_.erase(it);
167 }
168
169 bool ConnectToService(std::unique_ptr<ConnectParams>* connect_params) {
170 if (!service_.is_bound())
171 return false;
172
173 std::unique_ptr<ConnectParams> params(std::move(*connect_params));
174 if (!params->connect_callback().is_null()) {
175 params->connect_callback().Run(mojom::ConnectResult::SUCCEEDED,
176 identity_.user_id());
177 }
178
179 Classes classes;
180 Interfaces interfaces;
181 Instance* source = service_manager_->GetExistingInstance(params->source());
182 if (source) {
183 GetClassesAndInterfacesForConnection(source->capability_spec_,
184 identity_, capability_spec_,
185 &classes, &interfaces);
186 } else {
187 interfaces.insert("*");
188 }
189
190 // The target has specified that sources must request one of its provided
191 // classes instead of specifying a wild-card for interfaces.
192 if (HasClass(capability_spec_, kCapabilityClass_ExplicitClass) &&
193 (interfaces.count("*") != 0)) {
194 interfaces.erase("*");
195 }
196
197 service_->OnConnect(params->source(), params->TakeRemoteInterfaces(),
198 interfaces, classes);
199 return true;
200 }
201
202 void StartWithService(mojom::ServicePtr service) {
203 CHECK(!service_);
204 service_ = std::move(service);
205 service_.set_connection_error_handler(
206 base::Bind(&Instance::OnServiceLost, base::Unretained(this),
207 service_manager_->GetWeakPtr()));
208 service_->OnStart(identity_,
209 base::Bind(&Instance::OnInitializeResponse,
210 base::Unretained(this)));
211 }
212
213 void StartWithClientProcessConnection(
214 mojom::ClientProcessConnectionPtr client_process_connection) {
215 mojom::ServicePtr service;
216 service.Bind(mojom::ServicePtrInfo(
217 std::move(client_process_connection->service), 0));
218 pid_receiver_binding_.Bind(
219 std::move(client_process_connection->pid_receiver_request));
220 StartWithService(std::move(service));
221 }
222
223 void StartWithFilePath(const base::FilePath& path) {
224 CHECK(!service_);
225 runner_ = service_manager_->native_runner_factory_->Create(path);
226 bool start_sandboxed = false;
227 mojom::ServicePtr service = runner_->Start(
228 path, identity_, start_sandboxed,
229 base::Bind(&Instance::PIDAvailable, weak_factory_.GetWeakPtr()),
230 base::Bind(&Instance::OnRunnerCompleted, weak_factory_.GetWeakPtr()));
231 StartWithService(std::move(service));
232 }
233
234 mojom::ServiceInfoPtr CreateServiceInfo() const {
235 mojom::ServiceInfoPtr info(mojom::ServiceInfo::New());
236 info->id = id_;
237 info->identity = identity_;
238 info->pid = pid_;
239 return info;
240 }
241
242 const CapabilitySpec& capability_spec() const {
243 return capability_spec_;
244 }
245 const Identity& identity() const { return identity_; }
246 uint32_t id() const { return id_; }
247
248 // Service:
249 bool OnConnect(const Identity& remote_identity,
250 InterfaceRegistry* registry) override {
251 Instance* source = service_manager_->GetExistingInstance(remote_identity);
252 DCHECK(source);
253 if (HasClass(source->capability_spec_, kCapabilityClass_ServiceManager)) {
254 registry->AddInterface<mojom::ServiceManager>(this);
255 return true;
256 }
257 return false;
258 }
259
260 private:
261 // mojom::Connector implementation:
262 void Connect(const shell::Identity& in_target,
263 mojom::InterfaceProviderRequest remote_interfaces,
264 mojom::ClientProcessConnectionPtr client_process_connection,
265 const ConnectCallback& callback) override {
266 Identity target = in_target;
267 if (target.user_id() == mojom::kInheritUserID)
268 target.set_user_id(identity_.user_id());
269
270 if (!ValidateIdentity(target, callback))
271 return;
272 if (!ValidateClientProcessConnection(&client_process_connection, target,
273 callback)) {
274 return;
275 }
276 if (!ValidateCapabilities(target, callback))
277 return;
278
279 std::unique_ptr<ConnectParams> params(new ConnectParams);
280 params->set_source(identity_);
281 params->set_target(target);
282 params->set_remote_interfaces(std::move(remote_interfaces));
283 params->set_client_process_connection(std::move(client_process_connection));
284 params->set_connect_callback(callback);
285 service_manager_->Connect(
286 std::move(params), nullptr, weak_factory_.GetWeakPtr());
287 }
288
289 void Clone(mojom::ConnectorRequest request) override {
290 connectors_.AddBinding(this, std::move(request));
291 }
292
293 // mojom::PIDReceiver:
294 void SetPID(uint32_t pid) override {
295 PIDAvailable(pid);
296 }
297
298 // InterfaceFactory<mojom::ServiceManager>:
299 void Create(const Identity& remote_identity,
300 mojom::ServiceManagerRequest request) override {
301 service_manager_bindings_.AddBinding(this, std::move(request));
302 }
303
304 // mojom::ServiceManager implementation:
305 void AddListener(mojom::ServiceManagerListenerPtr listener) override {
306 // TODO(beng): this should only track the instances matching this user, and
307 // root.
308 service_manager_->AddListener(std::move(listener));
309 }
310
311 bool ValidateIdentity(const Identity& identity,
312 const ConnectCallback& callback) {
313 if (!IsValidName(identity.name())) {
314 LOG(ERROR) << "Error: invalid Name: " << identity.name();
315 callback.Run(mojom::ConnectResult::INVALID_ARGUMENT,
316 mojom::kInheritUserID);
317 return false;
318 }
319 if (!base::IsValidGUID(identity.user_id())) {
320 LOG(ERROR) << "Error: invalid user_id: " << identity.user_id();
321 callback.Run(mojom::ConnectResult::INVALID_ARGUMENT,
322 mojom::kInheritUserID);
323 return false;
324 }
325 return true;
326 }
327
328 bool ValidateClientProcessConnection(
329 mojom::ClientProcessConnectionPtr* client_process_connection,
330 const Identity& target,
331 const ConnectCallback& callback) {
332 if (!client_process_connection->is_null()) {
333 if (!HasClass(capability_spec_, kCapabilityClass_ClientProcess)) {
334 LOG(ERROR) << "Instance: " << identity_.name() << " attempting "
335 << "to register an instance for a process it created for "
336 << "target: " << target.name() << " without the "
337 << "service:shell{client_process} capability class.";
338 callback.Run(mojom::ConnectResult::ACCESS_DENIED,
339 mojom::kInheritUserID);
340 return false;
341 }
342
343 if (!(*client_process_connection)->service.is_valid() ||
344 !(*client_process_connection)->pid_receiver_request.is_valid()) {
345 LOG(ERROR) << "Must supply both service AND "
346 << "pid_receiver_request when sending "
347 << "client_process_connection.";
348 callback.Run(mojom::ConnectResult::INVALID_ARGUMENT,
349 mojom::kInheritUserID);
350 return false;
351 }
352 if (service_manager_->GetExistingInstance(target)) {
353 LOG(ERROR) << "Cannot client process matching existing identity:"
354 << "Name: " << target.name() << " User: "
355 << target.user_id() << " Instance: " << target.instance();
356 callback.Run(mojom::ConnectResult::INVALID_ARGUMENT,
357 mojom::kInheritUserID);
358 return false;
359 }
360 }
361 return true;
362 }
363
364 bool ValidateCapabilities(const Identity& target,
365 const ConnectCallback& callback) {
366 // TODO(beng): Need to do the following additional policy validation of
367 // whether this instance is allowed to connect using:
368 // - a non-null client_process_connection.
369 if (target.user_id() != identity_.user_id() &&
370 target.user_id() != mojom::kRootUserID &&
371 !HasClass(capability_spec_, kCapabilityClass_UserID)) {
372 LOG(ERROR) << "Instance: " << identity_.name() << " running as: "
373 << identity_.user_id() << " attempting to connect to: "
374 << target.name() << " as: " << target.user_id() << " without "
375 << " the service:shell{user_id} capability class.";
376 callback.Run(mojom::ConnectResult::ACCESS_DENIED,
377 mojom::kInheritUserID);
378 return false;
379 }
380 if (!target.instance().empty() &&
381 target.instance() != GetNamePath(target.name()) &&
382 !HasClass(capability_spec_, kCapabilityClass_InstanceName)) {
383 LOG(ERROR) << "Instance: " << identity_.name() << " attempting to "
384 << "connect to " << target.name() << " using Instance name: "
385 << target.instance() << " without the "
386 << "service:shell{instance_name} capability class.";
387 callback.Run(mojom::ConnectResult::ACCESS_DENIED, mojom::kInheritUserID);
388 return false;
389
390 }
391
392 if (allow_any_application_ ||
393 capability_spec_.required.find(target.name()) !=
394 capability_spec_.required.end()) {
395 return true;
396 }
397 LOG(ERROR) << "Capabilities prevented connection from: " <<
398 identity_.name() << " to: " << target.name();
399 callback.Run(mojom::ConnectResult::ACCESS_DENIED, mojom::kInheritUserID);
400 return false;
401 }
402
403 uint32_t GenerateUniqueID() const {
404 static uint32_t id = mojom::kInvalidInstanceID;
405 ++id;
406 CHECK_NE(mojom::kInvalidInstanceID, id);
407 return id;
408 }
409
410 void PIDAvailable(base::ProcessId pid) {
411 if (pid == base::kNullProcessId) {
412 service_manager_->OnInstanceError(this);
413 return;
414 }
415 pid_ = pid;
416 service_manager_->NotifyPIDAvailable(identity_, pid_);
417 }
418
419 void OnServiceLost(base::WeakPtr<shell::ServiceManager> service_manager) {
420 service_.reset();
421 OnConnectionLost(service_manager);
422 }
423
424 void OnConnectionLost(base::WeakPtr<shell::ServiceManager> service_manager) {
425 // Any time a Connector is lost or we lose the Service connection, it
426 // may have been the last pipe using this Instance. If so, clean up.
427 if (service_manager && !service_) {
428 if (connectors_.empty())
429 service_manager->OnInstanceError(this);
430 else
431 service_manager->OnInstanceUnreachable(this);
432 }
433 }
434
435 void OnInitializeResponse(mojom::ConnectorRequest connector_request) {
436 if (connector_request.is_pending()) {
437 connectors_.AddBinding(this, std::move(connector_request));
438 connectors_.set_connection_error_handler(
439 base::Bind(&Instance::OnConnectionLost, base::Unretained(this),
440 service_manager_->GetWeakPtr()));
441 }
442 }
443
444 // Callback when NativeRunner completes.
445 void OnRunnerCompleted() {
446 if (!runner_.get())
447 return; // We're in the destructor.
448
449 service_manager_->OnInstanceError(this);
450 }
451
452 shell::ServiceManager* const service_manager_;
453
454 // An id that identifies this instance. Distinct from pid, as a single process
455 // may vend multiple application instances, and this object may exist before a
456 // process is launched.
457 const uint32_t id_;
458 const Identity identity_;
459 const CapabilitySpec capability_spec_;
460 const bool allow_any_application_;
461 std::unique_ptr<NativeRunner> runner_;
462 mojom::ServicePtr service_;
463 mojo::Binding<mojom::PIDReceiver> pid_receiver_binding_;
464 mojo::BindingSet<mojom::Connector> connectors_;
465 mojo::BindingSet<mojom::ServiceManager> service_manager_bindings_;
466 base::ProcessId pid_ = base::kNullProcessId;
467 Instance* parent_ = nullptr;
468 InstanceMap children_;
469 base::WeakPtrFactory<Instance> weak_factory_;
470
471 DISALLOW_COPY_AND_ASSIGN(Instance);
472 };
473
474 // static
475 ServiceManager::TestAPI::TestAPI(ServiceManager* service_manager)
476 : service_manager_(service_manager) {}
477 ServiceManager::TestAPI::~TestAPI() {}
478
479 bool ServiceManager::TestAPI::HasRunningInstanceForName(
480 const std::string& name) const {
481 for (const auto& entry : service_manager_->identity_to_instance_) {
482 if (entry.first.name() == name)
483 return true;
484 }
485 return false;
486 }
487
488 ////////////////////////////////////////////////////////////////////////////////
489 // ServiceManager, public:
490
491 ServiceManager::ServiceManager(
492 std::unique_ptr<NativeRunnerFactory> native_runner_factory,
493 mojom::ServicePtr catalog)
494 : native_runner_factory_(std::move(native_runner_factory)),
495 weak_ptr_factory_(this) {
496 mojom::ServicePtr service;
497 mojom::ServiceRequest request = mojo::GetProxy(&service);
498
499 CapabilitySpec spec;
500 spec.provided[kCapabilityClass_ServiceManager].insert(
501 "shell::mojom::ServiceManager");
502 spec.required["*"].insert("shell:service_factory");
503 spec.required["service:catalog"].insert("shell:resolver");
504
505 service_manager_instance_ =
506 CreateInstance(Identity(), CreateServiceManagerIdentity(), spec);
507 service_manager_instance_->StartWithService(std::move(service));
508 singletons_.insert(kServiceManagerName);
509 service_context_.reset(new ServiceContext(this, std::move(request)));
510
511 if (catalog)
512 InitCatalog(std::move(catalog));
513 }
514
515 ServiceManager::~ServiceManager() {
516 // Ensure we tear down the ServiceManager instance last. This is to avoid
517 // hitting bindings DCHECKs, since the ServiceManager or Catalog may at any
518 // given time own in-flight responders for Instances' Connector requests.
519 std::unique_ptr<Instance> service_manager_instance;
520 auto iter = root_instances_.find(service_manager_instance_);
521 DCHECK(iter != root_instances_.end());
522 service_manager_instance = std::move(iter->second);
523
524 root_instances_.clear();
525 }
526
527 void ServiceManager::SetServiceOverrides(
528 std::unique_ptr<ServiceOverrides> overrides) {
529 service_overrides_ = std::move(overrides);
530 }
531
532 void ServiceManager::SetInstanceQuitCallback(
533 base::Callback<void(const Identity&)> callback) {
534 instance_quit_callback_ = callback;
535 }
536
537 void ServiceManager::Connect(std::unique_ptr<ConnectParams> params) {
538 Connect(std::move(params), nullptr, nullptr);
539 }
540
541 mojom::ServiceRequest ServiceManager::StartEmbedderService(
542 const std::string& name) {
543 std::unique_ptr<ConnectParams> params(new ConnectParams);
544
545 Identity embedder_identity(name, mojom::kRootUserID);
546 params->set_source(embedder_identity);
547 params->set_target(embedder_identity);
548
549 mojom::ServicePtr service;
550 mojom::ServiceRequest request = mojo::GetProxy(&service);
551 Connect(std::move(params), std::move(service), nullptr);
552
553 return request;
554 }
555
556 ////////////////////////////////////////////////////////////////////////////////
557 // ServiceManager, Service implementation:
558
559 bool ServiceManager::OnConnect(const Identity& remote_identity,
560 InterfaceRegistry* registry) {
561 // The only interface we expose is mojom::ServiceManager, and access to this
562 // interface is brokered by a policy specific to each caller, managed by the
563 // caller's instance. Here we look to see who's calling, and forward to the
564 // caller's instance to continue.
565 Instance* instance = nullptr;
566 for (const auto& entry : identity_to_instance_) {
567 if (entry.first == remote_identity) {
568 instance = entry.second;
569 break;
570 }
571 }
572 DCHECK(instance);
573 return instance->OnConnect(remote_identity, registry);
574 }
575
576 ////////////////////////////////////////////////////////////////////////////////
577 // ServiceManager, private:
578
579 void ServiceManager::InitCatalog(mojom::ServicePtr catalog) {
580 // TODO(beng): It'd be great to build this from the manifest, however there's
581 // a bit of a chicken-and-egg problem.
582 CapabilitySpec spec;
583 spec.provided["app"].insert("filesystem::mojom::Directory");
584 spec.provided["catalog:catalog"].insert("catalog::mojom::Catalog");
585 spec.provided["shell:resolver"].insert("shell::mojom::Resolver");
586 spec.provided["control"].insert("catalog::mojom::CatalogControl");
587 Instance* instance = CreateInstance(
588 CreateServiceManagerIdentity(), CreateCatalogIdentity(), spec);
589 singletons_.insert(kCatalogName);
590 instance->StartWithService(std::move(catalog));
591 }
592
593 mojom::Resolver* ServiceManager::GetResolver(const Identity& identity) {
594 auto iter = identity_to_resolver_.find(identity);
595 if (iter != identity_to_resolver_.end())
596 return iter->second.get();
597
598 mojom::ResolverPtr resolver_ptr;
599 ConnectToInterface(this, identity, CreateCatalogIdentity(), &resolver_ptr);
600 mojom::Resolver* resolver = resolver_ptr.get();
601 identity_to_resolver_[identity] = std::move(resolver_ptr);
602 return resolver;
603 }
604
605 void ServiceManager::OnInstanceError(Instance* instance) {
606 // We never clean up the ServiceManager's own instance.
607 if (instance == service_manager_instance_)
608 return;
609
610 const Identity identity = instance->identity();
611 identity_to_instance_.erase(identity);
612
613 if (instance->parent()) {
614 // Deletes |instance|.
615 instance->parent()->RemoveChild(instance);
616 } else {
617 auto it = root_instances_.find(instance);
618 DCHECK(it != root_instances_.end());
619
620 // Deletes |instance|.
621 root_instances_.erase(it);
622 }
623 }
624
625 void ServiceManager::OnInstanceUnreachable(Instance* instance) {
626 // If an Instance becomes unreachable, new connection requests for this
627 // identity will elicit a new Instance instantiation. The unreachable instance
628 // remains alive.
629 identity_to_instance_.erase(instance->identity());
630 }
631
632 void ServiceManager::OnInstanceStopped(const Identity& identity) {
633 listeners_.ForAllPtrs([identity](mojom::ServiceManagerListener* listener) {
634 listener->OnServiceStopped(identity);
635 });
636 if (!instance_quit_callback_.is_null())
637 instance_quit_callback_.Run(identity);
638 }
639
640 void ServiceManager::Connect(std::unique_ptr<ConnectParams> params,
641 mojom::ServicePtr service,
642 base::WeakPtr<Instance> source_instance) {
643 TRACE_EVENT_INSTANT1("mojo_shell", "ServiceManager::Connect",
644 TRACE_EVENT_SCOPE_THREAD, "original_name",
645 params->target().name());
646 DCHECK(IsValidName(params->target().name()));
647 DCHECK(base::IsValidGUID(params->target().user_id()));
648 DCHECK_NE(mojom::kInheritUserID, params->target().user_id());
649 DCHECK(!service.is_bound() || !identity_to_instance_.count(params->target()));
650
651 // Connect to an existing matching instance, if possible.
652 if (!service.is_bound() && ConnectToExistingInstance(&params))
653 return;
654
655 // The catalog needs to see the source identity as that of the originating
656 // app so it loads the correct store. Since the catalog is itself run as root
657 // when this re-enters Connect() it'll be handled by
658 // ConnectToExistingInstance().
659 mojom::Resolver* resolver =
660 GetResolver(Identity(kServiceManagerName, params->target().user_id()));
661
662 std::string name = params->target().name();
663 resolver->ResolveMojoName(
664 name, base::Bind(&shell::ServiceManager::OnGotResolvedName,
665 weak_ptr_factory_.GetWeakPtr(), base::Passed(&params),
666 base::Passed(&service), !!source_instance,
667 source_instance));
668 }
669
670 ServiceManager::Instance* ServiceManager::GetExistingInstance(
671 const Identity& identity) const {
672 const auto& it = identity_to_instance_.find(identity);
673 Instance* instance = it != identity_to_instance_.end() ? it->second : nullptr;
674 if (instance)
675 return instance;
676
677 if (singletons_.find(identity.name()) != singletons_.end()) {
678 for (auto entry : identity_to_instance_) {
679 if (entry.first.name() == identity.name() &&
680 entry.first.instance() == identity.instance()) {
681 return entry.second;
682 }
683 }
684 }
685 return nullptr;
686 }
687
688 void ServiceManager::NotifyPIDAvailable(const Identity& identity,
689 base::ProcessId pid) {
690 listeners_.ForAllPtrs(
691 [identity, pid](mojom::ServiceManagerListener* listener) {
692 listener->OnServiceStarted(identity, pid);
693 });
694 }
695
696 bool ServiceManager::ConnectToExistingInstance(
697 std::unique_ptr<ConnectParams>* params) {
698 Instance* instance = GetExistingInstance((*params)->target());
699 return instance && instance->ConnectToService(params);
700 }
701
702 ServiceManager::Instance* ServiceManager::CreateInstance(
703 const Identity& source,
704 const Identity& target,
705 const CapabilitySpec& spec) {
706 CHECK(target.user_id() != mojom::kInheritUserID);
707
708 std::unique_ptr<Instance> instance(new Instance(this, target, spec));
709 Instance* raw_instance = instance.get();
710
711 Instance* source_instance = GetExistingInstance(source);
712 if (source_instance)
713 source_instance->AddChild(std::move(instance));
714 else
715 root_instances_.insert(std::make_pair(raw_instance, std::move(instance)));
716
717 // NOTE: |instance| has been passed elsewhere. Use |raw_instance| from this
718 // point forward. It's safe for the extent of this method.
719
720 auto result =
721 identity_to_instance_.insert(std::make_pair(target, raw_instance));
722 DCHECK(result.second);
723
724 mojom::ServiceInfoPtr info = raw_instance->CreateServiceInfo();
725 listeners_.ForAllPtrs([&info](mojom::ServiceManagerListener* listener) {
726 listener->OnServiceCreated(info.Clone());
727 });
728
729 return raw_instance;
730 }
731
732 void ServiceManager::AddListener(mojom::ServiceManagerListenerPtr listener) {
733 // TODO(beng): filter instances provided by those visible to this service.
734 std::vector<mojom::ServiceInfoPtr> instances;
735 instances.reserve(identity_to_instance_.size());
736 for (auto& instance : identity_to_instance_)
737 instances.push_back(instance.second->CreateServiceInfo());
738 listener->OnInit(std::move(instances));
739
740 listeners_.AddPtr(std::move(listener));
741 }
742
743 void ServiceManager::CreateServiceWithFactory(const Identity& service_factory,
744 const std::string& name,
745 mojom::ServiceRequest request) {
746 mojom::ServiceFactory* factory = GetServiceFactory(service_factory);
747 factory->CreateService(std::move(request), name);
748 }
749
750 mojom::ServiceFactory* ServiceManager::GetServiceFactory(
751 const Identity& service_factory_identity) {
752 auto it = service_factories_.find(service_factory_identity);
753 if (it != service_factories_.end())
754 return it->second.get();
755
756 Identity source_identity(kServiceManagerName, mojom::kInheritUserID);
757 mojom::ServiceFactoryPtr factory;
758 ConnectToInterface(this, source_identity, service_factory_identity,
759 &factory);
760 mojom::ServiceFactory* factory_interface = factory.get();
761 factory.set_connection_error_handler(base::Bind(
762 &shell::ServiceManager::OnServiceFactoryLost,
763 weak_ptr_factory_.GetWeakPtr(), service_factory_identity));
764 service_factories_[service_factory_identity] = std::move(factory);
765 return factory_interface;
766 }
767
768 void ServiceManager::OnServiceFactoryLost(const Identity& which) {
769 // Remove the mapping.
770 auto it = service_factories_.find(which);
771 DCHECK(it != service_factories_.end());
772 service_factories_.erase(it);
773 }
774
775 void ServiceManager::OnGotResolvedName(std::unique_ptr<ConnectParams> params,
776 mojom::ServicePtr service,
777 bool has_source_instance,
778 base::WeakPtr<Instance> source_instance,
779 mojom::ResolveResultPtr result) {
780 // If this request was originated by a specific Instance and that Instance is
781 // no longer around, we ignore this response.
782 if (has_source_instance && !source_instance)
783 return;
784
785 std::string instance_name = params->target().instance();
786 if (instance_name == GetNamePath(params->target().name()) &&
787 result->qualifier != GetNamePath(result->resolved_name)) {
788 instance_name = result->qualifier;
789 }
790 // |result->capabilities| can be null when there is no manifest, e.g. for URL
791 // types not resolvable by the resolver.
792 CapabilitySpec capabilities = GetPermissiveCapabilities();
793 if (result->capabilities.has_value())
794 capabilities = result->capabilities.value();
795
796 const std::string user_id = HasClass(capabilities, kCapabilityClass_AllUsers)
797 ? base::GenerateGUID()
798 : params->target().user_id();
799 const Identity target(params->target().name(), user_id, instance_name);
800 params->set_target(target);
801
802 // It's possible that when this manifest request was issued, another one was
803 // already in-progress and completed by the time this one did, and so the
804 // requested application may already be running.
805 if (ConnectToExistingInstance(&params))
806 return;
807
808 Identity source = params->source();
809
810 // Services that request "all_users" class from the Service Manager are
811 // allowed to field connection requests from any user. They also run with a
812 // synthetic user id generated here. The user id provided via Connect() is
813 // ignored. Additionally services with the "all_users" class are not tied to
814 // the lifetime of the service that started them, instead they are owned by
815 // the Service Manager.
816 Identity source_identity_for_creation;
817 if (HasClass(capabilities, kCapabilityClass_AllUsers)) {
818 singletons_.insert(target.name());
819 source_identity_for_creation = CreateServiceManagerIdentity();
820 } else {
821 source_identity_for_creation = params->source();
822 }
823
824 mojom::ClientProcessConnectionPtr client_process_connection =
825 params->TakeClientProcessConnection();
826 Instance* instance = CreateInstance(source_identity_for_creation,
827 target, capabilities);
828
829 // Below are various paths through which a new Instance can be bound to a
830 // Service proxy.
831 if (service.is_bound()) {
832 // If a ServicePtr was provided, there's no more work to do: someone
833 // is already holding a corresponding ServiceRequest.
834 instance->StartWithService(std::move(service));
835 } else if (!client_process_connection.is_null()) {
836 // Likewise if a ClientProcessConnection was given via Connect(), it
837 // provides the Service proxy to use.
838 instance->StartWithClientProcessConnection(
839 std::move(client_process_connection));
840 } else {
841 // Otherwise we create a new Service pipe.
842 mojom::ServiceRequest request = GetProxy(&service);
843 CHECK(!result->package_path.empty() && result->capabilities.has_value());
844
845 if (target.name() != result->resolved_name) {
846 instance->StartWithService(std::move(service));
847 Identity factory(result->resolved_name, target.user_id(),
848 instance_name);
849 CreateServiceWithFactory(factory, target.name(), std::move(request));
850 } else {
851 base::FilePath package_path;
852 if (!service_overrides_ || !service_overrides_->GetExecutablePathOverride(
853 target.name(), &package_path)) {
854 package_path = result->package_path;
855 }
856
857 Identity source_instance_identity;
858 base::debug::Alias(&has_source_instance);
859 base::debug::Alias(&package_path);
860 base::debug::Alias(&source);
861 base::debug::Alias(&target);
862 if (source_instance)
863 source_instance_identity = source_instance->identity();
864 base::debug::Alias(&source_instance_identity);
865 #if defined(GOOGLE_CHROME_BUILD)
866 // We do not currently want to hit this code path in production, but it's
867 // happening somehow. https://crbug.com/649673.
868 CHECK(false);
869 #endif
870 instance->StartWithFilePath(package_path);
871 }
872 }
873
874 // Now that the instance has a Service, we can connect to it.
875 bool connected = instance->ConnectToService(&params);
876 DCHECK(connected);
877 }
878
879 base::WeakPtr<ServiceManager> ServiceManager::GetWeakPtr() {
880 return weak_ptr_factory_.GetWeakPtr();
881 }
882
883 } // namespace shell
OLDNEW
« no previous file with comments | « services/shell/service_manager.h ('k') | services/shell/service_overrides.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698