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

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
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());
(...skipping 213 matching lines...) Expand 10 before | Expand all | Expand 10 after
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
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
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
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
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
OLDNEW
« mash/init/init.h ('K') | « 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