| 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 |