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()); |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 |
OLD | NEW |