OLD | NEW |
1 // Copyright 2014 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "mojo/shell/shell.h" | 5 #include "mojo/shell/shell.h" |
6 | 6 |
7 #include <stdint.h> | 7 #include <stdint.h> |
8 | 8 |
9 #include <utility> | 9 #include <utility> |
10 | 10 |
(...skipping 111 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
122 allow_any_application_(capability_spec.required.count("*") == 1), | 122 allow_any_application_(capability_spec.required.count("*") == 1), |
123 pid_receiver_binding_(this), | 123 pid_receiver_binding_(this), |
124 weak_factory_(this) { | 124 weak_factory_(this) { |
125 if (identity_.name() == kShellName || | 125 if (identity_.name() == kShellName || |
126 shell_->GetLoaderForName(identity_.name())) { | 126 shell_->GetLoaderForName(identity_.name())) { |
127 pid_ = base::Process::Current().Pid(); | 127 pid_ = base::Process::Current().Pid(); |
128 } | 128 } |
129 DCHECK_NE(mojom::kInvalidInstanceID, id_); | 129 DCHECK_NE(mojom::kInvalidInstanceID, id_); |
130 } | 130 } |
131 | 131 |
132 ~Instance() override {} | 132 ~Instance() override { |
133 | 133 if (parent_) |
134 void OnShellClientLost() { | 134 parent_->RemoveChild(this); |
135 shell_client_.reset(); | 135 // |children_| will be modified during destruction. |
136 OnConnectionLost(); | 136 std::set<Instance*> children = children_; |
| 137 for (auto child : children) |
| 138 shell_->OnInstanceError(child); |
137 } | 139 } |
138 | 140 |
139 void OnConnectionLost() { | 141 Instance* parent() { return parent_; } |
140 // Any time a Connector is lost or we lose the ShellClient connection, it | 142 void AddChild(Instance* child) { |
141 // may have been the last pipe using this Instance. If so, clean up. | 143 children_.insert(child); |
142 if (connectors_.empty() && !shell_client_) { | 144 child->parent_ = this; |
143 // Deletes |this|. | |
144 shell_->OnInstanceError(this); | |
145 } | |
146 } | 145 } |
147 | 146 void RemoveChild(Instance* child) { |
148 void OnInitializeResponse(mojom::ConnectorRequest connector_request) { | 147 auto it = children_.find(child); |
149 if (connector_request.is_pending()) { | 148 DCHECK(it != children_.end()); |
150 connectors_.AddBinding(this, std::move(connector_request)); | 149 children_.erase(it); |
151 connectors_.set_connection_error_handler( | 150 child->parent_ = nullptr; |
152 base::Bind(&Instance::OnConnectionLost, base::Unretained(this))); | |
153 } | |
154 } | 151 } |
155 | 152 |
156 void ConnectToClient(scoped_ptr<ConnectParams> params) { | 153 void ConnectToClient(scoped_ptr<ConnectParams> params) { |
157 CHECK(shell_client_.is_bound()); | 154 CHECK(shell_client_.is_bound()); |
158 params->connect_callback().Run(mojom::ConnectResult::SUCCEEDED, | 155 params->connect_callback().Run(mojom::ConnectResult::SUCCEEDED, |
159 identity_.user_id(), id_); | 156 identity_.user_id(), id_); |
160 uint32_t source_id = mojom::kInvalidInstanceID; | 157 uint32_t source_id = mojom::kInvalidInstanceID; |
161 CapabilityRequest spec; | 158 CapabilityRequest spec; |
162 spec.interfaces.insert("*"); | 159 spec.interfaces.insert("*"); |
163 Instance* source = shell_->GetExistingInstance(params->source()); | 160 Instance* source = shell_->GetExistingInstance(params->source()); |
(...skipping 213 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
377 ++id; | 374 ++id; |
378 CHECK_NE(mojom::kInvalidInstanceID, id); | 375 CHECK_NE(mojom::kInvalidInstanceID, id); |
379 return id; | 376 return id; |
380 } | 377 } |
381 | 378 |
382 void PIDAvailable(base::ProcessId pid) { | 379 void PIDAvailable(base::ProcessId pid) { |
383 pid_ = pid; | 380 pid_ = pid; |
384 shell_->NotifyPIDAvailable(id_, pid_); | 381 shell_->NotifyPIDAvailable(id_, pid_); |
385 } | 382 } |
386 | 383 |
| 384 void OnShellClientLost() { |
| 385 shell_client_.reset(); |
| 386 OnConnectionLost(); |
| 387 } |
| 388 |
| 389 void OnConnectionLost() { |
| 390 // Any time a Connector is lost or we lose the ShellClient connection, it |
| 391 // may have been the last pipe using this Instance. If so, clean up. |
| 392 if (connectors_.empty() && !shell_client_) { |
| 393 // Deletes |this|. |
| 394 shell_->OnInstanceError(this); |
| 395 } |
| 396 } |
| 397 |
| 398 void OnInitializeResponse(mojom::ConnectorRequest connector_request) { |
| 399 if (connector_request.is_pending()) { |
| 400 connectors_.AddBinding(this, std::move(connector_request)); |
| 401 connectors_.set_connection_error_handler( |
| 402 base::Bind(&Instance::OnConnectionLost, base::Unretained(this))); |
| 403 } |
| 404 } |
| 405 |
387 mojo::shell::Shell* const shell_; | 406 mojo::shell::Shell* const shell_; |
388 | 407 |
389 // An id that identifies this instance. Distinct from pid, as a single process | 408 // An id that identifies this instance. Distinct from pid, as a single process |
390 // may vend multiple application instances, and this object may exist before a | 409 // may vend multiple application instances, and this object may exist before a |
391 // process is launched. | 410 // process is launched. |
392 const uint32_t id_; | 411 const uint32_t id_; |
393 const Identity identity_; | 412 const Identity identity_; |
394 const CapabilitySpec capability_spec_; | 413 const CapabilitySpec capability_spec_; |
395 const bool allow_any_application_; | 414 const bool allow_any_application_; |
396 mojom::ShellClientPtr shell_client_; | 415 mojom::ShellClientPtr shell_client_; |
397 Binding<mojom::PIDReceiver> pid_receiver_binding_; | 416 Binding<mojom::PIDReceiver> pid_receiver_binding_; |
398 BindingSet<mojom::Connector> connectors_; | 417 BindingSet<mojom::Connector> connectors_; |
399 BindingSet<mojom::Shell> shell_bindings_; | 418 BindingSet<mojom::Shell> shell_bindings_; |
400 NativeRunner* runner_ = nullptr; | 419 NativeRunner* runner_ = nullptr; |
401 base::ProcessId pid_ = base::kNullProcessId; | 420 base::ProcessId pid_ = base::kNullProcessId; |
| 421 Instance* parent_ = nullptr; |
| 422 std::set<Instance*> children_; |
402 base::WeakPtrFactory<Instance> weak_factory_; | 423 base::WeakPtrFactory<Instance> weak_factory_; |
403 | 424 |
404 DISALLOW_COPY_AND_ASSIGN(Instance); | 425 DISALLOW_COPY_AND_ASSIGN(Instance); |
405 }; | 426 }; |
406 | 427 |
407 // static | 428 // static |
408 Shell::TestAPI::TestAPI(Shell* shell) : shell_(shell) {} | 429 Shell::TestAPI::TestAPI(Shell* shell) : shell_(shell) {} |
409 Shell::TestAPI::~TestAPI() {} | 430 Shell::TestAPI::~TestAPI() {} |
410 | 431 |
411 bool Shell::TestAPI::HasRunningInstanceForName(const std::string& name) const { | 432 bool Shell::TestAPI::HasRunningInstanceForName(const std::string& name) const { |
412 for (const auto& entry : shell_->identity_to_instance_) { | 433 for (const auto& entry : shell_->identity_to_instance_) { |
413 if (entry.first.name() == name) | 434 if (entry.first.name() == name) |
414 return true; | 435 return true; |
415 } | 436 } |
416 return false; | 437 return false; |
417 } | 438 } |
418 | 439 |
419 //////////////////////////////////////////////////////////////////////////////// | 440 //////////////////////////////////////////////////////////////////////////////// |
420 // Shell, public: | 441 // Shell, public: |
421 | 442 |
422 Shell::Shell(scoped_ptr<NativeRunnerFactory> native_runner_factory, | 443 Shell::Shell(scoped_ptr<NativeRunnerFactory> native_runner_factory, |
423 mojom::ShellClientPtr catalog) | 444 mojom::ShellClientPtr catalog) |
424 : native_runner_factory_(std::move(native_runner_factory)), | 445 : native_runner_factory_(std::move(native_runner_factory)), |
425 weak_ptr_factory_(this) { | 446 weak_ptr_factory_(this) { |
426 mojom::ShellClientPtr client; | 447 mojom::ShellClientPtr client; |
427 mojom::ShellClientRequest request = GetProxy(&client); | 448 mojom::ShellClientRequest request = GetProxy(&client); |
428 Instance* instance = CreateInstance(CreateShellIdentity(), | 449 Instance* instance = CreateInstance(Identity(), CreateShellIdentity(), |
429 GetPermissiveCapabilities()); | 450 GetPermissiveCapabilities()); |
430 instance->StartWithClient(std::move(client)); | 451 instance->StartWithClient(std::move(client)); |
431 shell_connection_.reset(new ShellConnection(this, std::move(request))); | 452 shell_connection_.reset(new ShellConnection(this, std::move(request))); |
432 | 453 |
433 if (catalog) | 454 if (catalog) |
434 InitCatalog(std::move(catalog)); | 455 InitCatalog(std::move(catalog)); |
435 } | 456 } |
436 | 457 |
437 Shell::~Shell() { | 458 Shell::~Shell() { |
438 TerminateShellConnections(); | 459 TerminateShellConnections(); |
(...skipping 21 matching lines...) Expand all Loading... |
460 | 481 |
461 mojom::ShellClientPtr client; | 482 mojom::ShellClientPtr client; |
462 mojom::ShellClientRequest request = GetProxy(&client); | 483 mojom::ShellClientRequest request = GetProxy(&client); |
463 Connect(std::move(params), std::move(client)); | 484 Connect(std::move(params), std::move(client)); |
464 | 485 |
465 return request; | 486 return request; |
466 } | 487 } |
467 | 488 |
468 void Shell::SetLoaderForName(scoped_ptr<Loader> loader, | 489 void Shell::SetLoaderForName(scoped_ptr<Loader> loader, |
469 const std::string& name) { | 490 const std::string& name) { |
470 NameToLoaderMap::iterator it = name_to_loader_.find(name); | 491 auto it = name_to_loader_.find(name); |
471 if (it != name_to_loader_.end()) | 492 if (it != name_to_loader_.end()) |
472 delete it->second; | 493 delete it->second; |
473 name_to_loader_[name] = loader.release(); | 494 name_to_loader_[name] = loader.release(); |
474 } | 495 } |
475 | 496 |
476 //////////////////////////////////////////////////////////////////////////////// | 497 //////////////////////////////////////////////////////////////////////////////// |
477 // Shell, ShellClient implementation: | 498 // Shell, ShellClient implementation: |
478 | 499 |
479 bool Shell::AcceptConnection(Connection* connection) { | 500 bool Shell::AcceptConnection(Connection* connection) { |
480 // The only interface we expose is mojom::Shell, and access to this interface | 501 // The only interface we expose is mojom::Shell, and access to this interface |
481 // is brokered by a policy specific to each caller, managed by the caller's | 502 // is brokered by a policy specific to each caller, managed by the caller's |
482 // instance. Here we look to see who's calling, and forward to the caller's | 503 // instance. Here we look to see who's calling, and forward to the caller's |
483 // instance to continue. | 504 // instance to continue. |
484 Instance* instance = nullptr; | 505 Instance* instance = nullptr; |
485 for (const auto& entry : identity_to_instance_) { | 506 for (const auto& entry : identity_to_instance_) { |
486 if (entry.second->id() == connection->GetRemoteInstanceID()) { | 507 if (entry.second->id() == connection->GetRemoteInstanceID()) { |
487 instance = entry.second; | 508 instance = entry.second; |
488 break; | 509 break; |
489 } | 510 } |
490 } | 511 } |
491 DCHECK(instance); | 512 DCHECK(instance); |
492 return instance->AcceptConnection(connection); | 513 return instance->AcceptConnection(connection); |
493 } | 514 } |
494 | 515 |
495 //////////////////////////////////////////////////////////////////////////////// | 516 //////////////////////////////////////////////////////////////////////////////// |
496 // Shell, private: | 517 // Shell, private: |
497 | 518 |
498 void Shell::InitCatalog(mojom::ShellClientPtr catalog) { | 519 void Shell::InitCatalog(mojom::ShellClientPtr catalog) { |
499 Instance* instance = | 520 Instance* instance = CreateInstance(CreateShellIdentity(), |
500 CreateInstance(CreateCatalogIdentity(), CapabilitySpec()); | 521 CreateCatalogIdentity(), |
| 522 CapabilitySpec()); |
501 instance->StartWithClient(std::move(catalog)); | 523 instance->StartWithClient(std::move(catalog)); |
502 | 524 |
503 // TODO(beng): this doesn't work anymore. | 525 // TODO(beng): this doesn't work anymore. |
504 // Seed the catalog with manifest info for the shell & catalog. | 526 // Seed the catalog with manifest info for the shell & catalog. |
505 mojo::shell::mojom::ShellResolverPtr resolver; | 527 mojo::shell::mojom::ShellResolverPtr resolver; |
506 shell_connection_->connector()->ConnectToInterface(kCatalogName, &resolver); | 528 shell_connection_->connector()->ConnectToInterface(kCatalogName, &resolver); |
507 resolver->ResolveMojoName(kCatalogName, base::Bind(&EmptyResolverCallback)); | 529 resolver->ResolveMojoName(kCatalogName, base::Bind(&EmptyResolverCallback)); |
508 resolver->ResolveMojoName(kShellName, base::Bind(&EmptyResolverCallback)); | 530 resolver->ResolveMojoName(kShellName, base::Bind(&EmptyResolverCallback)); |
509 } | 531 } |
510 | 532 |
511 void Shell::TerminateShellConnections() { | 533 void Shell::TerminateShellConnections() { |
512 STLDeleteValues(&identity_to_instance_); | 534 Instance* instance = GetExistingInstance(CreateShellIdentity()); |
| 535 DCHECK(instance); |
| 536 OnInstanceError(instance); |
513 } | 537 } |
514 | 538 |
515 void Shell::OnInstanceError(Instance* instance) { | 539 void Shell::OnInstanceError(Instance* instance) { |
516 const Identity identity = instance->identity(); | 540 const Identity identity = instance->identity(); |
517 // Remove the shell. | 541 // Remove the shell. |
518 auto it = identity_to_instance_.find(identity); | 542 auto it = identity_to_instance_.find(identity); |
519 DCHECK(it != identity_to_instance_.end()); | 543 DCHECK(it != identity_to_instance_.end()); |
520 int id = instance->id(); | 544 int id = instance->id(); |
521 delete it->second; | 545 delete it->second; |
522 identity_to_instance_.erase(it); | 546 identity_to_instance_.erase(it); |
(...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
581 }); | 605 }); |
582 } | 606 } |
583 | 607 |
584 bool Shell::ConnectToExistingInstance(scoped_ptr<ConnectParams>* params) { | 608 bool Shell::ConnectToExistingInstance(scoped_ptr<ConnectParams>* params) { |
585 Instance* instance = GetExistingInstance((*params)->target()); | 609 Instance* instance = GetExistingInstance((*params)->target()); |
586 if (instance) | 610 if (instance) |
587 instance->ConnectToClient(std::move(*params)); | 611 instance->ConnectToClient(std::move(*params)); |
588 return !!instance; | 612 return !!instance; |
589 } | 613 } |
590 | 614 |
591 Shell::Instance* Shell::CreateInstance(const Identity& target, | 615 Shell::Instance* Shell::CreateInstance(const Identity& source, |
| 616 const Identity& target, |
592 const CapabilitySpec& spec) { | 617 const CapabilitySpec& spec) { |
593 CHECK(target.user_id() != mojom::kInheritUserID); | 618 CHECK(target.user_id() != mojom::kInheritUserID); |
594 Instance* instance = new Instance(this, target, spec); | 619 Instance* instance = new Instance(this, target, spec); |
595 DCHECK(identity_to_instance_.find(target) == | 620 DCHECK(identity_to_instance_.find(target) == |
596 identity_to_instance_.end()); | 621 identity_to_instance_.end()); |
| 622 Instance* source_instance = GetExistingInstance(source); |
| 623 if (source_instance) |
| 624 source_instance->AddChild(instance); |
597 identity_to_instance_[target] = instance; | 625 identity_to_instance_[target] = instance; |
598 mojom::InstanceInfoPtr info = instance->CreateInstanceInfo(); | 626 mojom::InstanceInfoPtr info = instance->CreateInstanceInfo(); |
599 instance_listeners_.ForAllPtrs( | 627 instance_listeners_.ForAllPtrs( |
600 [this, &info](mojom::InstanceListener* listener) { | 628 [this, &info](mojom::InstanceListener* listener) { |
601 listener->InstanceCreated(info.Clone()); | 629 listener->InstanceCreated(info.Clone()); |
602 }); | 630 }); |
603 return instance; | 631 return instance; |
604 } | 632 } |
605 | 633 |
606 void Shell::AddInstanceListener(mojom::InstanceListenerPtr listener) { | 634 void Shell::AddInstanceListener(mojom::InstanceListenerPtr listener) { |
(...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
671 return; | 699 return; |
672 | 700 |
673 Identity source = params->source(); | 701 Identity source = params->source(); |
674 // |capabilities_ptr| can be null when there is no manifest, e.g. for URL | 702 // |capabilities_ptr| can be null when there is no manifest, e.g. for URL |
675 // types not resolvable by the resolver. | 703 // types not resolvable by the resolver. |
676 CapabilitySpec capabilities = GetPermissiveCapabilities(); | 704 CapabilitySpec capabilities = GetPermissiveCapabilities(); |
677 if (!capabilities_ptr.is_null()) | 705 if (!capabilities_ptr.is_null()) |
678 capabilities = capabilities_ptr.To<CapabilitySpec>(); | 706 capabilities = capabilities_ptr.To<CapabilitySpec>(); |
679 | 707 |
680 // Clients that request "all_users" class from the shell are allowed to | 708 // Clients that request "all_users" class from the shell are allowed to |
681 // field connection requests from any user. | 709 // field connection requests from any user. They also run with a synthetic |
682 if (HasClass(capabilities, kCapabilityClass_AllUsers)) | 710 // user id generated here. The user id provided via Connect() is ignored. |
| 711 if (HasClass(capabilities, kCapabilityClass_AllUsers)) { |
683 singletons_.insert(target.name()); | 712 singletons_.insert(target.name()); |
| 713 target.set_user_id(base::GenerateGUID()); |
| 714 } |
684 | 715 |
685 mojom::ClientProcessConnectionPtr client_process_connection = | 716 mojom::ClientProcessConnectionPtr client_process_connection = |
686 params->TakeClientProcessConnection(); | 717 params->TakeClientProcessConnection(); |
687 Instance* instance = CreateInstance(target, capabilities); | 718 Instance* instance = CreateInstance(params->source(), target, capabilities); |
688 | 719 |
689 // Below are various paths through which a new Instance can be bound to a | 720 // Below are various paths through which a new Instance can be bound to a |
690 // ShellClient proxy. | 721 // ShellClient proxy. |
691 if (client.is_bound()) { | 722 if (client.is_bound()) { |
692 // If a ShellClientPtr was provided, there's no more work to do: someone | 723 // If a ShellClientPtr was provided, there's no more work to do: someone |
693 // is already holding a corresponding ShellClientRequest. | 724 // is already holding a corresponding ShellClientRequest. |
694 instance->StartWithClient(std::move(client)); | 725 instance->StartWithClient(std::move(client)); |
695 } else if (!client_process_connection.is_null()) { | 726 } else if (!client_process_connection.is_null()) { |
696 // Likewise if a ClientProcessConnection was given via Connect(), it | 727 // Likewise if a ClientProcessConnection was given via Connect(), it |
697 // provides the ShellClient proxy to use. | 728 // provides the ShellClient proxy to use. |
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
740 for (auto it = native_runners_.begin(); it != native_runners_.end(); ++it) { | 771 for (auto it = native_runners_.begin(); it != native_runners_.end(); ++it) { |
741 if (it->get() == runner) { | 772 if (it->get() == runner) { |
742 native_runners_.erase(it); | 773 native_runners_.erase(it); |
743 return; | 774 return; |
744 } | 775 } |
745 } | 776 } |
746 } | 777 } |
747 | 778 |
748 } // namespace shell | 779 } // namespace shell |
749 } // namespace mojo | 780 } // namespace mojo |
OLD | NEW |