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

Side by Side Diff: mojo/shell/shell.cc

Issue 1810713002: Cascade shutdown of instances (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@55all_users
Patch Set: . Created 4 years, 9 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 | « mojo/shell/shell.h ('k') | mojo/shell/tests/connect/BUILD.gn » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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());
164 if (source) { 161 if (source) {
165 spec = GenerateCapabilityRequestForConnection( 162 spec = GenerateCapabilityRequestForConnection(
166 source->capability_spec_, identity_, capability_spec_); 163 source->capability_spec_, identity_, capability_spec_);
167 source_id = source->id(); 164 source_id = source->id();
168 } 165 }
169 shell_client_->AcceptConnection( 166 shell_client_->AcceptConnection(
170 mojom::Identity::From(params->source()), source_id, 167 mojom::Identity::From(params->source()), source_id,
171 params->TakeRemoteInterfaces(), params->TakeLocalInterfaces(), 168 params->TakeRemoteInterfaces(), params->TakeLocalInterfaces(),
172 mojom::CapabilityRequest::From(spec), params->target().name()); 169 mojom::CapabilityRequest::From(spec), params->target().name());
173 } 170 }
174 171
175 void StartWithClient(mojom::ShellClientPtr client) { 172 void StartWithClient(mojom::ShellClientPtr client) {
176 CHECK(!shell_client_); 173 CHECK(!shell_client_);
177 shell_client_ = std::move(client); 174 shell_client_ = std::move(client);
178 shell_client_.set_connection_error_handler( 175 shell_client_.set_connection_error_handler(
179 base::Bind(&Instance::OnShellClientLost, base::Unretained(this))); 176 base::Bind(&Instance::OnShellClientLost, base::Unretained(this),
177 shell_->GetWeakPtr()));
180 shell_client_->Initialize(mojom::Identity::From(identity_), id_, 178 shell_client_->Initialize(mojom::Identity::From(identity_), id_,
181 base::Bind(&Instance::OnInitializeResponse, 179 base::Bind(&Instance::OnInitializeResponse,
182 base::Unretained(this))); 180 base::Unretained(this)));
183 } 181 }
184 182
185 void StartWithClientProcessConnection( 183 void StartWithClientProcessConnection(
186 mojom::ClientProcessConnectionPtr client_process_connection) { 184 mojom::ClientProcessConnectionPtr client_process_connection) {
187 mojom::ShellClientPtr client; 185 mojom::ShellClientPtr client;
188 client.Bind(mojom::ShellClientPtrInfo( 186 client.Bind(mojom::ShellClientPtrInfo(
189 std::move(client_process_connection->shell_client), 0)); 187 std::move(client_process_connection->shell_client), 0));
(...skipping 187 matching lines...) Expand 10 before | Expand all | Expand 10 after
377 ++id; 375 ++id;
378 CHECK_NE(mojom::kInvalidInstanceID, id); 376 CHECK_NE(mojom::kInvalidInstanceID, id);
379 return id; 377 return id;
380 } 378 }
381 379
382 void PIDAvailable(base::ProcessId pid) { 380 void PIDAvailable(base::ProcessId pid) {
383 pid_ = pid; 381 pid_ = pid;
384 shell_->NotifyPIDAvailable(id_, pid_); 382 shell_->NotifyPIDAvailable(id_, pid_);
385 } 383 }
386 384
385 void OnShellClientLost(base::WeakPtr<mojo::shell::Shell> shell) {
386 shell_client_.reset();
387 OnConnectionLost(shell);
388 }
389
390 void OnConnectionLost(base::WeakPtr<mojo::shell::Shell> shell) {
391 // Any time a Connector is lost or we lose the ShellClient connection, it
392 // may have been the last pipe using this Instance. If so, clean up.
393 if (shell && connectors_.empty() && !shell_client_) {
394 // Deletes |this|.
395 shell->OnInstanceError(this);
396 }
397 }
398
399 void OnInitializeResponse(mojom::ConnectorRequest connector_request) {
400 if (connector_request.is_pending()) {
401 connectors_.AddBinding(this, std::move(connector_request));
402 connectors_.set_connection_error_handler(
403 base::Bind(&Instance::OnConnectionLost, base::Unretained(this),
404 shell_->GetWeakPtr()));
405 }
406 }
407
387 mojo::shell::Shell* const shell_; 408 mojo::shell::Shell* const shell_;
388 409
389 // An id that identifies this instance. Distinct from pid, as a single process 410 // 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 411 // may vend multiple application instances, and this object may exist before a
391 // process is launched. 412 // process is launched.
392 const uint32_t id_; 413 const uint32_t id_;
393 const Identity identity_; 414 const Identity identity_;
394 const CapabilitySpec capability_spec_; 415 const CapabilitySpec capability_spec_;
395 const bool allow_any_application_; 416 const bool allow_any_application_;
396 mojom::ShellClientPtr shell_client_; 417 mojom::ShellClientPtr shell_client_;
397 Binding<mojom::PIDReceiver> pid_receiver_binding_; 418 Binding<mojom::PIDReceiver> pid_receiver_binding_;
398 BindingSet<mojom::Connector> connectors_; 419 BindingSet<mojom::Connector> connectors_;
399 BindingSet<mojom::Shell> shell_bindings_; 420 BindingSet<mojom::Shell> shell_bindings_;
400 NativeRunner* runner_ = nullptr; 421 NativeRunner* runner_ = nullptr;
401 base::ProcessId pid_ = base::kNullProcessId; 422 base::ProcessId pid_ = base::kNullProcessId;
423 Instance* parent_ = nullptr;
424 std::set<Instance*> children_;
402 base::WeakPtrFactory<Instance> weak_factory_; 425 base::WeakPtrFactory<Instance> weak_factory_;
403 426
404 DISALLOW_COPY_AND_ASSIGN(Instance); 427 DISALLOW_COPY_AND_ASSIGN(Instance);
405 }; 428 };
406 429
407 // static 430 // static
408 Shell::TestAPI::TestAPI(Shell* shell) : shell_(shell) {} 431 Shell::TestAPI::TestAPI(Shell* shell) : shell_(shell) {}
409 Shell::TestAPI::~TestAPI() {} 432 Shell::TestAPI::~TestAPI() {}
410 433
411 bool Shell::TestAPI::HasRunningInstanceForName(const std::string& name) const { 434 bool Shell::TestAPI::HasRunningInstanceForName(const std::string& name) const {
412 for (const auto& entry : shell_->identity_to_instance_) { 435 for (const auto& entry : shell_->identity_to_instance_) {
413 if (entry.first.name() == name) 436 if (entry.first.name() == name)
414 return true; 437 return true;
415 } 438 }
416 return false; 439 return false;
417 } 440 }
418 441
419 //////////////////////////////////////////////////////////////////////////////// 442 ////////////////////////////////////////////////////////////////////////////////
420 // Shell, public: 443 // Shell, public:
421 444
422 Shell::Shell(scoped_ptr<NativeRunnerFactory> native_runner_factory, 445 Shell::Shell(scoped_ptr<NativeRunnerFactory> native_runner_factory,
423 mojom::ShellClientPtr catalog) 446 mojom::ShellClientPtr catalog)
424 : native_runner_factory_(std::move(native_runner_factory)), 447 : native_runner_factory_(std::move(native_runner_factory)),
425 weak_ptr_factory_(this) { 448 weak_ptr_factory_(this) {
426 mojom::ShellClientPtr client; 449 mojom::ShellClientPtr client;
427 mojom::ShellClientRequest request = GetProxy(&client); 450 mojom::ShellClientRequest request = GetProxy(&client);
428 Instance* instance = CreateInstance(CreateShellIdentity(), 451 Instance* instance = CreateInstance(Identity(), CreateShellIdentity(),
429 GetPermissiveCapabilities()); 452 GetPermissiveCapabilities());
430 instance->StartWithClient(std::move(client)); 453 instance->StartWithClient(std::move(client));
454 singletons_.insert(kShellName);
431 shell_connection_.reset(new ShellConnection(this, std::move(request))); 455 shell_connection_.reset(new ShellConnection(this, std::move(request)));
432 456
433 if (catalog) 457 if (catalog)
434 InitCatalog(std::move(catalog)); 458 InitCatalog(std::move(catalog));
435 } 459 }
436 460
437 Shell::~Shell() { 461 Shell::~Shell() {
438 TerminateShellConnections(); 462 TerminateShellConnections();
439 STLDeleteValues(&name_to_loader_); 463 STLDeleteValues(&name_to_loader_);
440 for (auto& runner : native_runners_) 464 for (auto& runner : native_runners_)
(...skipping 19 matching lines...) Expand all
460 484
461 mojom::ShellClientPtr client; 485 mojom::ShellClientPtr client;
462 mojom::ShellClientRequest request = GetProxy(&client); 486 mojom::ShellClientRequest request = GetProxy(&client);
463 Connect(std::move(params), std::move(client)); 487 Connect(std::move(params), std::move(client));
464 488
465 return request; 489 return request;
466 } 490 }
467 491
468 void Shell::SetLoaderForName(scoped_ptr<Loader> loader, 492 void Shell::SetLoaderForName(scoped_ptr<Loader> loader,
469 const std::string& name) { 493 const std::string& name) {
470 NameToLoaderMap::iterator it = name_to_loader_.find(name); 494 auto it = name_to_loader_.find(name);
471 if (it != name_to_loader_.end()) 495 if (it != name_to_loader_.end())
472 delete it->second; 496 delete it->second;
473 name_to_loader_[name] = loader.release(); 497 name_to_loader_[name] = loader.release();
474 } 498 }
475 499
476 //////////////////////////////////////////////////////////////////////////////// 500 ////////////////////////////////////////////////////////////////////////////////
477 // Shell, ShellClient implementation: 501 // Shell, ShellClient implementation:
478 502
479 bool Shell::AcceptConnection(Connection* connection) { 503 bool Shell::AcceptConnection(Connection* connection) {
480 // The only interface we expose is mojom::Shell, and access to this interface 504 // 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 505 // 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 506 // instance. Here we look to see who's calling, and forward to the caller's
483 // instance to continue. 507 // instance to continue.
484 Instance* instance = nullptr; 508 Instance* instance = nullptr;
485 for (const auto& entry : identity_to_instance_) { 509 for (const auto& entry : identity_to_instance_) {
486 if (entry.second->id() == connection->GetRemoteInstanceID()) { 510 if (entry.second->id() == connection->GetRemoteInstanceID()) {
487 instance = entry.second; 511 instance = entry.second;
488 break; 512 break;
489 } 513 }
490 } 514 }
491 DCHECK(instance); 515 DCHECK(instance);
492 return instance->AcceptConnection(connection); 516 return instance->AcceptConnection(connection);
493 } 517 }
494 518
495 //////////////////////////////////////////////////////////////////////////////// 519 ////////////////////////////////////////////////////////////////////////////////
496 // Shell, private: 520 // Shell, private:
497 521
498 void Shell::InitCatalog(mojom::ShellClientPtr catalog) { 522 void Shell::InitCatalog(mojom::ShellClientPtr catalog) {
499 Instance* instance = 523 Instance* instance = CreateInstance(CreateShellIdentity(),
500 CreateInstance(CreateCatalogIdentity(), CapabilitySpec()); 524 CreateCatalogIdentity(),
525 CapabilitySpec());
526 singletons_.insert(kCatalogName);
501 instance->StartWithClient(std::move(catalog)); 527 instance->StartWithClient(std::move(catalog));
502 528
503 // TODO(beng): this doesn't work anymore. 529 // TODO(beng): this doesn't work anymore.
504 // Seed the catalog with manifest info for the shell & catalog. 530 // Seed the catalog with manifest info for the shell & catalog.
505 mojo::shell::mojom::ShellResolverPtr resolver; 531 mojo::shell::mojom::ShellResolverPtr resolver;
506 shell_connection_->connector()->ConnectToInterface(kCatalogName, &resolver); 532 shell_connection_->connector()->ConnectToInterface(kCatalogName, &resolver);
507 resolver->ResolveMojoName(kCatalogName, base::Bind(&EmptyResolverCallback)); 533 resolver->ResolveMojoName(kCatalogName, base::Bind(&EmptyResolverCallback));
508 resolver->ResolveMojoName(kShellName, base::Bind(&EmptyResolverCallback)); 534 resolver->ResolveMojoName(kShellName, base::Bind(&EmptyResolverCallback));
509 } 535 }
510 536
511 void Shell::TerminateShellConnections() { 537 void Shell::TerminateShellConnections() {
512 STLDeleteValues(&identity_to_instance_); 538 Instance* instance = GetExistingInstance(CreateShellIdentity());
539 DCHECK(instance);
540 OnInstanceError(instance);
513 } 541 }
514 542
515 void Shell::OnInstanceError(Instance* instance) { 543 void Shell::OnInstanceError(Instance* instance) {
516 const Identity identity = instance->identity(); 544 const Identity identity = instance->identity();
517 // Remove the shell. 545 // Remove the shell.
518 auto it = identity_to_instance_.find(identity); 546 auto it = identity_to_instance_.find(identity);
519 DCHECK(it != identity_to_instance_.end()); 547 DCHECK(it != identity_to_instance_.end());
520 int id = instance->id(); 548 int id = instance->id();
521 delete it->second; 549 delete it->second;
522 identity_to_instance_.erase(it); 550 identity_to_instance_.erase(it);
(...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after
581 }); 609 });
582 } 610 }
583 611
584 bool Shell::ConnectToExistingInstance(scoped_ptr<ConnectParams>* params) { 612 bool Shell::ConnectToExistingInstance(scoped_ptr<ConnectParams>* params) {
585 Instance* instance = GetExistingInstance((*params)->target()); 613 Instance* instance = GetExistingInstance((*params)->target());
586 if (instance) 614 if (instance)
587 instance->ConnectToClient(std::move(*params)); 615 instance->ConnectToClient(std::move(*params));
588 return !!instance; 616 return !!instance;
589 } 617 }
590 618
591 Shell::Instance* Shell::CreateInstance(const Identity& target, 619 Shell::Instance* Shell::CreateInstance(const Identity& source,
620 const Identity& target,
592 const CapabilitySpec& spec) { 621 const CapabilitySpec& spec) {
593 CHECK(target.user_id() != mojom::kInheritUserID); 622 CHECK(target.user_id() != mojom::kInheritUserID);
594 Instance* instance = new Instance(this, target, spec); 623 Instance* instance = new Instance(this, target, spec);
595 DCHECK(identity_to_instance_.find(target) == 624 DCHECK(identity_to_instance_.find(target) ==
596 identity_to_instance_.end()); 625 identity_to_instance_.end());
626 Instance* source_instance = GetExistingInstance(source);
627 if (source_instance)
628 source_instance->AddChild(instance);
597 identity_to_instance_[target] = instance; 629 identity_to_instance_[target] = instance;
598 mojom::InstanceInfoPtr info = instance->CreateInstanceInfo(); 630 mojom::InstanceInfoPtr info = instance->CreateInstanceInfo();
599 instance_listeners_.ForAllPtrs( 631 instance_listeners_.ForAllPtrs(
600 [this, &info](mojom::InstanceListener* listener) { 632 [this, &info](mojom::InstanceListener* listener) {
601 listener->InstanceCreated(info.Clone()); 633 listener->InstanceCreated(info.Clone());
602 }); 634 });
603 return instance; 635 return instance;
604 } 636 }
605 637
606 void Shell::AddInstanceListener(mojom::InstanceListenerPtr listener) { 638 void Shell::AddInstanceListener(mojom::InstanceListenerPtr listener) {
(...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after
671 return; 703 return;
672 704
673 Identity source = params->source(); 705 Identity source = params->source();
674 // |capabilities_ptr| can be null when there is no manifest, e.g. for URL 706 // |capabilities_ptr| can be null when there is no manifest, e.g. for URL
675 // types not resolvable by the resolver. 707 // types not resolvable by the resolver.
676 CapabilitySpec capabilities = GetPermissiveCapabilities(); 708 CapabilitySpec capabilities = GetPermissiveCapabilities();
677 if (!capabilities_ptr.is_null()) 709 if (!capabilities_ptr.is_null())
678 capabilities = capabilities_ptr.To<CapabilitySpec>(); 710 capabilities = capabilities_ptr.To<CapabilitySpec>();
679 711
680 // Clients that request "all_users" class from the shell are allowed to 712 // Clients that request "all_users" class from the shell are allowed to
681 // field connection requests from any user. 713 // field connection requests from any user. They also run with a synthetic
682 if (HasClass(capabilities, kCapabilityClass_AllUsers)) 714 // user id generated here. The user id provided via Connect() is ignored.
715 if (HasClass(capabilities, kCapabilityClass_AllUsers)) {
683 singletons_.insert(target.name()); 716 singletons_.insert(target.name());
717 target.set_user_id(base::GenerateGUID());
718 }
684 719
685 mojom::ClientProcessConnectionPtr client_process_connection = 720 mojom::ClientProcessConnectionPtr client_process_connection =
686 params->TakeClientProcessConnection(); 721 params->TakeClientProcessConnection();
687 Instance* instance = CreateInstance(target, capabilities); 722 Instance* instance = CreateInstance(params->source(), target, capabilities);
688 723
689 // Below are various paths through which a new Instance can be bound to a 724 // Below are various paths through which a new Instance can be bound to a
690 // ShellClient proxy. 725 // ShellClient proxy.
691 if (client.is_bound()) { 726 if (client.is_bound()) {
692 // If a ShellClientPtr was provided, there's no more work to do: someone 727 // If a ShellClientPtr was provided, there's no more work to do: someone
693 // is already holding a corresponding ShellClientRequest. 728 // is already holding a corresponding ShellClientRequest.
694 instance->StartWithClient(std::move(client)); 729 instance->StartWithClient(std::move(client));
695 } else if (!client_process_connection.is_null()) { 730 } else if (!client_process_connection.is_null()) {
696 // Likewise if a ClientProcessConnection was given via Connect(), it 731 // Likewise if a ClientProcessConnection was given via Connect(), it
697 // provides the ShellClient proxy to use. 732 // provides the ShellClient proxy to use.
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after
729 return true; 764 return true;
730 } 765 }
731 766
732 Loader* Shell::GetLoaderForName(const std::string& name) { 767 Loader* Shell::GetLoaderForName(const std::string& name) {
733 auto name_it = name_to_loader_.find(name); 768 auto name_it = name_to_loader_.find(name);
734 if (name_it != name_to_loader_.end()) 769 if (name_it != name_to_loader_.end())
735 return name_it->second; 770 return name_it->second;
736 return default_loader_.get(); 771 return default_loader_.get();
737 } 772 }
738 773
774 base::WeakPtr<Shell> Shell::GetWeakPtr() {
775 return weak_ptr_factory_.GetWeakPtr();
776 }
777
739 void Shell::CleanupRunner(NativeRunner* runner) { 778 void Shell::CleanupRunner(NativeRunner* runner) {
740 for (auto it = native_runners_.begin(); it != native_runners_.end(); ++it) { 779 for (auto it = native_runners_.begin(); it != native_runners_.end(); ++it) {
741 if (it->get() == runner) { 780 if (it->get() == runner) {
742 native_runners_.erase(it); 781 native_runners_.erase(it);
743 return; 782 return;
744 } 783 }
745 } 784 }
746 } 785 }
747 786
748 } // namespace shell 787 } // namespace shell
749 } // namespace mojo 788 } // namespace mojo
OLDNEW
« no previous file with comments | « mojo/shell/shell.h ('k') | mojo/shell/tests/connect/BUILD.gn » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698