| Index: services/shell/service_manager.cc
|
| diff --git a/services/shell/service_manager.cc b/services/shell/service_manager.cc
|
| index 78c0059e8a1fd77bd3c022211534b16af84bc672..5e1de8467fe1d6f2d738fcf1758d13b7c543665f 100644
|
| --- a/services/shell/service_manager.cc
|
| +++ b/services/shell/service_manager.cc
|
| @@ -133,13 +133,6 @@ class ServiceManager::Instance
|
| }
|
|
|
| ~Instance() override {
|
| - if (parent_)
|
| - parent_->RemoveChild(this);
|
| - // |children_| will be modified during destruction.
|
| - std::set<Instance*> children = children_;
|
| - for (auto* child : children)
|
| - service_manager_->OnInstanceError(child, InstanceErrorType::DESTROY);
|
| -
|
| // Shutdown all bindings before we close the runner. This way the process
|
| // should see the pipes closed and exit, as well as waking up any potential
|
| // sync/WaitForIncomingResponse().
|
| @@ -148,6 +141,10 @@ class ServiceManager::Instance
|
| pid_receiver_binding_.Close();
|
| connectors_.CloseAllBindings();
|
| service_manager_bindings_.CloseAllBindings();
|
| +
|
| + // Notify the ServiceManager that this Instance is really going away.
|
| + service_manager_->OnInstanceStopped(identity_);
|
| +
|
| // Release |runner_| so that if we are called back to OnRunnerCompleted()
|
| // we know we're in the destructor.
|
| std::unique_ptr<NativeRunner> runner = std::move(runner_);
|
| @@ -156,16 +153,17 @@ class ServiceManager::Instance
|
|
|
| Instance* parent() { return parent_; }
|
|
|
| - void AddChild(Instance* child) {
|
| - children_.insert(child);
|
| + void AddChild(std::unique_ptr<Instance> child) {
|
| child->parent_ = this;
|
| + children_.insert(std::make_pair(child.get(), std::move(child)));
|
| }
|
|
|
| void RemoveChild(Instance* child) {
|
| auto it = children_.find(child);
|
| DCHECK(it != children_.end());
|
| +
|
| + // Deletes |child|.
|
| children_.erase(it);
|
| - child->parent_ = nullptr;
|
| }
|
|
|
| bool ConnectToService(std::unique_ptr<ConnectParams>* connect_params) {
|
| @@ -402,7 +400,7 @@ class ServiceManager::Instance
|
|
|
| void PIDAvailable(base::ProcessId pid) {
|
| if (pid == base::kNullProcessId) {
|
| - service_manager_->OnInstanceError(this, InstanceErrorType::DESTROY);
|
| + service_manager_->OnInstanceError(this);
|
| return;
|
| }
|
| pid_ = pid;
|
| @@ -418,10 +416,10 @@ class ServiceManager::Instance
|
| // Any time a Connector is lost or we lose the Service connection, it
|
| // may have been the last pipe using this Instance. If so, clean up.
|
| if (service_manager && !service_) {
|
| - InstanceErrorType instance_error_type =
|
| - connectors_.empty() ? InstanceErrorType::DESTROY
|
| - : InstanceErrorType::LOST_SERVICE;
|
| - service_manager->OnInstanceError(this, instance_error_type);
|
| + if (connectors_.empty())
|
| + service_manager->OnInstanceError(this);
|
| + else
|
| + service_manager->OnInstanceUnreachable(this);
|
| }
|
| }
|
|
|
| @@ -439,7 +437,7 @@ class ServiceManager::Instance
|
| if (!runner_.get())
|
| return; // We're in the destructor.
|
|
|
| - service_manager_->OnInstanceError(this, InstanceErrorType::DESTROY);
|
| + service_manager_->OnInstanceError(this);
|
| }
|
|
|
| shell::ServiceManager* const service_manager_;
|
| @@ -458,7 +456,7 @@ class ServiceManager::Instance
|
| mojo::BindingSet<mojom::ServiceManager> service_manager_bindings_;
|
| base::ProcessId pid_ = base::kNullProcessId;
|
| Instance* parent_ = nullptr;
|
| - std::set<Instance*> children_;
|
| + InstanceMap children_;
|
| base::WeakPtrFactory<Instance> weak_factory_;
|
|
|
| DISALLOW_COPY_AND_ASSIGN(Instance);
|
| @@ -500,16 +498,6 @@ ServiceManager::ServiceManager(
|
|
|
| ServiceManager::~ServiceManager() {
|
| TerminateServiceManagerConnections();
|
| - // Terminate any remaining instances.
|
| - while (!identity_to_instance_.empty()) {
|
| - OnInstanceError(identity_to_instance_.begin()->second,
|
| - InstanceErrorType::DESTROY);
|
| - }
|
| - while (!instances_without_service_.empty()) {
|
| - OnInstanceError(*instances_without_service_.begin(),
|
| - InstanceErrorType::DESTROY);
|
| - }
|
| - identity_to_resolver_.clear();
|
| }
|
|
|
| void ServiceManager::SetInstanceQuitCallback(
|
| @@ -588,32 +576,36 @@ mojom::Resolver* ServiceManager::GetResolver(const Identity& identity) {
|
| void ServiceManager::TerminateServiceManagerConnections() {
|
| Instance* instance = GetExistingInstance(CreateServiceManagerIdentity());
|
| if (instance)
|
| - OnInstanceError(instance, InstanceErrorType::DESTROY);
|
| + OnInstanceError(instance);
|
| }
|
|
|
| -void ServiceManager::OnInstanceError(Instance* instance,
|
| - InstanceErrorType error_type) {
|
| +void ServiceManager::OnInstanceError(Instance* instance) {
|
| const Identity identity = instance->identity();
|
| + identity_to_instance_.erase(identity);
|
|
|
| - const bool in_identity_to_instance =
|
| - identity_to_instance_.erase(identity) > 0;
|
| - const bool in_instances_without_services =
|
| - instances_without_service_.erase(instance) > 0;
|
| - DCHECK_NE(in_identity_to_instance, in_instances_without_services);
|
| -
|
| - if (error_type == InstanceErrorType::LOST_SERVICE) {
|
| - // |instance| has lost its service but still has connections to it, we need
|
| - // to keep it around. The instance is removed from |identity_to_instance_|
|
| - // so that if an attempt is made to connect to the same identity a new
|
| - // Instance is created.
|
| - instances_without_service_.insert(instance);
|
| - return;
|
| + if (instance->parent()) {
|
| + // Deletes |instance|.
|
| + instance->parent()->RemoveChild(instance);
|
| + } else {
|
| + auto it = root_instances_.find(instance);
|
| + DCHECK(it != root_instances_.end());
|
| +
|
| + // Deletes |instance|.
|
| + root_instances_.erase(it);
|
| }
|
| +}
|
| +
|
| +void ServiceManager::OnInstanceUnreachable(Instance* instance) {
|
| + // If an Instance becomes unreachable, new connection requests for this
|
| + // identity will elicit a new Instance instantiation. The unreachable instance
|
| + // remains alive.
|
| + identity_to_instance_.erase(instance->identity());
|
| +}
|
|
|
| +void ServiceManager::OnInstanceStopped(const Identity& identity) {
|
| listeners_.ForAllPtrs([identity](mojom::ServiceManagerListener* listener) {
|
| listener->OnServiceStopped(identity);
|
| });
|
| - delete instance;
|
| if (!instance_quit_callback_.is_null())
|
| instance_quit_callback_.Run(identity);
|
| }
|
| @@ -685,18 +677,29 @@ ServiceManager::Instance* ServiceManager::CreateInstance(
|
| const Identity& target,
|
| const CapabilitySpec& spec) {
|
| CHECK(target.user_id() != mojom::kInheritUserID);
|
| - Instance* instance = new Instance(this, target, spec);
|
| - DCHECK(identity_to_instance_.find(target) ==
|
| - identity_to_instance_.end());
|
| +
|
| + std::unique_ptr<Instance> instance(new Instance(this, target, spec));
|
| + Instance* raw_instance = instance.get();
|
| +
|
| Instance* source_instance = GetExistingInstance(source);
|
| if (source_instance)
|
| - source_instance->AddChild(instance);
|
| - identity_to_instance_[target] = instance;
|
| - mojom::ServiceInfoPtr info = instance->CreateServiceInfo();
|
| + source_instance->AddChild(std::move(instance));
|
| + else
|
| + root_instances_.insert(std::make_pair(raw_instance, std::move(instance)));
|
| +
|
| + // NOTE: |instance| has been passed elsewhere. Use |raw_instance| from this
|
| + // point forward. It's safe for the extent of this method.
|
| +
|
| + auto result =
|
| + identity_to_instance_.insert(std::make_pair(target, raw_instance));
|
| + DCHECK(result.second);
|
| +
|
| + mojom::ServiceInfoPtr info = raw_instance->CreateServiceInfo();
|
| listeners_.ForAllPtrs([&info](mojom::ServiceManagerListener* listener) {
|
| listener->OnServiceCreated(info.Clone());
|
| });
|
| - return instance;
|
| +
|
| + return raw_instance;
|
| }
|
|
|
| void ServiceManager::AddListener(mojom::ServiceManagerListenerPtr listener) {
|
|
|