Commit 262a9e00 authored by rockot's avatar rockot Committed by Commit bot

ServiceManager: Simplify Instance lifetime management

Makes Instance ownership and lifetime management easier to
follow. Root instances are now explicitly owned by the
ServiceManager and non-root instances are explicitly owned by
their parent Instance.

OnInstanceError always destroys the Instance, either by
removing it from the root instance set or delegating to the parent
Instance. This avoids the need for children to re-enter their
parent on destruction.

Notification logic has been extracted from OnInstanceError and
moved to a new OnInstanceStopped, which is always called by
each Instance's destructor. This allows parents to delete their
own children without calling through to OnInstanceError, while
still allowing the ServiceManager to know about the destruction
and dispatch notifications accordingly.

InstanceErrorType is removed: if an Instance becomes
unreachable it's simply removed from the identity map
via a new OnInstanceUnreachable call.

BUG=640488

Review-Url: https://codereview.chromium.org/2341853002
Cr-Commit-Position: refs/heads/master@{#418643}
parent 01e7b50e
...@@ -133,13 +133,6 @@ class ServiceManager::Instance ...@@ -133,13 +133,6 @@ class ServiceManager::Instance
} }
~Instance() override { ~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 // 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 // should see the pipes closed and exit, as well as waking up any potential
// sync/WaitForIncomingResponse(). // sync/WaitForIncomingResponse().
...@@ -148,6 +141,10 @@ class ServiceManager::Instance ...@@ -148,6 +141,10 @@ class ServiceManager::Instance
pid_receiver_binding_.Close(); pid_receiver_binding_.Close();
connectors_.CloseAllBindings(); connectors_.CloseAllBindings();
service_manager_bindings_.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() // Release |runner_| so that if we are called back to OnRunnerCompleted()
// we know we're in the destructor. // we know we're in the destructor.
std::unique_ptr<NativeRunner> runner = std::move(runner_); std::unique_ptr<NativeRunner> runner = std::move(runner_);
...@@ -156,16 +153,17 @@ class ServiceManager::Instance ...@@ -156,16 +153,17 @@ class ServiceManager::Instance
Instance* parent() { return parent_; } Instance* parent() { return parent_; }
void AddChild(Instance* child) { void AddChild(std::unique_ptr<Instance> child) {
children_.insert(child);
child->parent_ = this; child->parent_ = this;
children_.insert(std::make_pair(child.get(), std::move(child)));
} }
void RemoveChild(Instance* child) { void RemoveChild(Instance* child) {
auto it = children_.find(child); auto it = children_.find(child);
DCHECK(it != children_.end()); DCHECK(it != children_.end());
// Deletes |child|.
children_.erase(it); children_.erase(it);
child->parent_ = nullptr;
} }
bool ConnectToService(std::unique_ptr<ConnectParams>* connect_params) { bool ConnectToService(std::unique_ptr<ConnectParams>* connect_params) {
...@@ -402,7 +400,7 @@ class ServiceManager::Instance ...@@ -402,7 +400,7 @@ class ServiceManager::Instance
void PIDAvailable(base::ProcessId pid) { void PIDAvailable(base::ProcessId pid) {
if (pid == base::kNullProcessId) { if (pid == base::kNullProcessId) {
service_manager_->OnInstanceError(this, InstanceErrorType::DESTROY); service_manager_->OnInstanceError(this);
return; return;
} }
pid_ = pid; pid_ = pid;
...@@ -418,10 +416,10 @@ class ServiceManager::Instance ...@@ -418,10 +416,10 @@ class ServiceManager::Instance
// Any time a Connector is lost or we lose the Service connection, it // 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. // may have been the last pipe using this Instance. If so, clean up.
if (service_manager && !service_) { if (service_manager && !service_) {
InstanceErrorType instance_error_type = if (connectors_.empty())
connectors_.empty() ? InstanceErrorType::DESTROY service_manager->OnInstanceError(this);
: InstanceErrorType::LOST_SERVICE; else
service_manager->OnInstanceError(this, instance_error_type); service_manager->OnInstanceUnreachable(this);
} }
} }
...@@ -439,7 +437,7 @@ class ServiceManager::Instance ...@@ -439,7 +437,7 @@ class ServiceManager::Instance
if (!runner_.get()) if (!runner_.get())
return; // We're in the destructor. return; // We're in the destructor.
service_manager_->OnInstanceError(this, InstanceErrorType::DESTROY); service_manager_->OnInstanceError(this);
} }
shell::ServiceManager* const service_manager_; shell::ServiceManager* const service_manager_;
...@@ -458,7 +456,7 @@ class ServiceManager::Instance ...@@ -458,7 +456,7 @@ class ServiceManager::Instance
mojo::BindingSet<mojom::ServiceManager> service_manager_bindings_; mojo::BindingSet<mojom::ServiceManager> service_manager_bindings_;
base::ProcessId pid_ = base::kNullProcessId; base::ProcessId pid_ = base::kNullProcessId;
Instance* parent_ = nullptr; Instance* parent_ = nullptr;
std::set<Instance*> children_; InstanceMap children_;
base::WeakPtrFactory<Instance> weak_factory_; base::WeakPtrFactory<Instance> weak_factory_;
DISALLOW_COPY_AND_ASSIGN(Instance); DISALLOW_COPY_AND_ASSIGN(Instance);
...@@ -500,16 +498,6 @@ ServiceManager::ServiceManager( ...@@ -500,16 +498,6 @@ ServiceManager::ServiceManager(
ServiceManager::~ServiceManager() { ServiceManager::~ServiceManager() {
TerminateServiceManagerConnections(); 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( void ServiceManager::SetInstanceQuitCallback(
...@@ -588,32 +576,36 @@ mojom::Resolver* ServiceManager::GetResolver(const Identity& identity) { ...@@ -588,32 +576,36 @@ mojom::Resolver* ServiceManager::GetResolver(const Identity& identity) {
void ServiceManager::TerminateServiceManagerConnections() { void ServiceManager::TerminateServiceManagerConnections() {
Instance* instance = GetExistingInstance(CreateServiceManagerIdentity()); Instance* instance = GetExistingInstance(CreateServiceManagerIdentity());
if (instance) if (instance)
OnInstanceError(instance, InstanceErrorType::DESTROY); OnInstanceError(instance);
} }
void ServiceManager::OnInstanceError(Instance* instance, void ServiceManager::OnInstanceError(Instance* instance) {
InstanceErrorType error_type) {
const Identity identity = instance->identity(); const Identity identity = instance->identity();
identity_to_instance_.erase(identity);
const bool in_identity_to_instance = if (instance->parent()) {
identity_to_instance_.erase(identity) > 0; // Deletes |instance|.
const bool in_instances_without_services = instance->parent()->RemoveChild(instance);
instances_without_service_.erase(instance) > 0; } else {
DCHECK_NE(in_identity_to_instance, in_instances_without_services); auto it = root_instances_.find(instance);
DCHECK(it != root_instances_.end());
if (error_type == InstanceErrorType::LOST_SERVICE) {
// |instance| has lost its service but still has connections to it, we need // Deletes |instance|.
// to keep it around. The instance is removed from |identity_to_instance_| root_instances_.erase(it);
// so that if an attempt is made to connect to the same identity a new
// Instance is created.
instances_without_service_.insert(instance);
return;
} }
}
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) { listeners_.ForAllPtrs([identity](mojom::ServiceManagerListener* listener) {
listener->OnServiceStopped(identity); listener->OnServiceStopped(identity);
}); });
delete instance;
if (!instance_quit_callback_.is_null()) if (!instance_quit_callback_.is_null())
instance_quit_callback_.Run(identity); instance_quit_callback_.Run(identity);
} }
...@@ -685,18 +677,29 @@ ServiceManager::Instance* ServiceManager::CreateInstance( ...@@ -685,18 +677,29 @@ ServiceManager::Instance* ServiceManager::CreateInstance(
const Identity& target, const Identity& target,
const CapabilitySpec& spec) { const CapabilitySpec& spec) {
CHECK(target.user_id() != mojom::kInheritUserID); CHECK(target.user_id() != mojom::kInheritUserID);
Instance* instance = new Instance(this, target, spec);
DCHECK(identity_to_instance_.find(target) == std::unique_ptr<Instance> instance(new Instance(this, target, spec));
identity_to_instance_.end()); Instance* raw_instance = instance.get();
Instance* source_instance = GetExistingInstance(source); Instance* source_instance = GetExistingInstance(source);
if (source_instance) if (source_instance)
source_instance->AddChild(instance); source_instance->AddChild(std::move(instance));
identity_to_instance_[target] = instance; else
mojom::ServiceInfoPtr info = instance->CreateServiceInfo(); 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) { listeners_.ForAllPtrs([&info](mojom::ServiceManagerListener* listener) {
listener->OnServiceCreated(info.Clone()); listener->OnServiceCreated(info.Clone());
}); });
return instance;
return raw_instance;
} }
void ServiceManager::AddListener(mojom::ServiceManagerListenerPtr listener) { void ServiceManager::AddListener(mojom::ServiceManagerListenerPtr listener) {
......
...@@ -74,15 +74,6 @@ class ServiceManager : public Service { ...@@ -74,15 +74,6 @@ class ServiceManager : public Service {
mojom::ServiceRequest StartEmbedderService(const std::string& name); mojom::ServiceRequest StartEmbedderService(const std::string& name);
private: private:
enum class InstanceErrorType {
// The Instance has lost it's Service pointer, but still has connections. It
// should not be immediately deleted.
LOST_SERVICE,
// The Instance should no longer be kept around.
DESTROY,
};
class Instance; class Instance;
// Service: // Service:
...@@ -102,10 +93,15 @@ class ServiceManager : public Service { ...@@ -102,10 +93,15 @@ class ServiceManager : public Service {
// have a chance to shut down. // have a chance to shut down.
void TerminateServiceManagerConnections(); void TerminateServiceManagerConnections();
// Called when |instance| encounters an error. If |error_type| is DESTROY // Called when |instance| encounters an error. Deletes |instance|.
// the instance is deleted immediately, otherwise it is moved to void OnInstanceError(Instance* instance);
// |instances_without_service_|.
void OnInstanceError(Instance* instance, InstanceErrorType error_type); // Called when |instance| becomes unreachable to new connections because it
// no longer has any pipes to the ServiceManager.
void OnInstanceUnreachable(Instance* instance);
// Called by an Instance as it's being destroyed.
void OnInstanceStopped(const Identity& identity);
// Completes a connection between a source and target application as defined // Completes a connection between a source and target application as defined
// by |params|, exchanging InterfaceProviders between them. If no existing // by |params|, exchanging InterfaceProviders between them. If no existing
...@@ -162,15 +158,19 @@ class ServiceManager : public Service { ...@@ -162,15 +158,19 @@ class ServiceManager : public Service {
base::WeakPtr<ServiceManager> GetWeakPtr(); base::WeakPtr<ServiceManager> GetWeakPtr();
// Ownership of all root Instances. Non-root Instances are owned by their
// parent Instance.
using InstanceMap = std::map<Instance*, std::unique_ptr<Instance>>;
InstanceMap root_instances_;
// Maps service identities to reachable instances. Note that the Instance*
// values here are NOT owned by this map.
std::map<Identity, Instance*> identity_to_instance_; std::map<Identity, Instance*> identity_to_instance_;
// Tracks the names of instances that are allowed to field connection requests // Tracks the names of instances that are allowed to field connection requests
// from all users. // from all users.
std::set<std::string> singletons_; std::set<std::string> singletons_;
// See OnInstanceError() for details.
std::set<Instance*> instances_without_service_;
std::map<Identity, mojom::ServiceFactoryPtr> service_factories_; std::map<Identity, mojom::ServiceFactoryPtr> service_factories_;
std::map<Identity, mojom::ResolverPtr> identity_to_resolver_; std::map<Identity, mojom::ResolverPtr> identity_to_resolver_;
mojo::InterfacePtrSet<mojom::ServiceManagerListener> listeners_; mojo::InterfacePtrSet<mojom::ServiceManagerListener> listeners_;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment