Index: content/common/mojo/mojo_shell_connection_impl.cc |
diff --git a/content/common/mojo/mojo_shell_connection_impl.cc b/content/common/mojo/mojo_shell_connection_impl.cc |
index a4a23f4bc2cdc41183f171caa5e803eda732b050..7528df61914d60213c96b637e043f7595d9ed956 100644 |
--- a/content/common/mojo/mojo_shell_connection_impl.cc |
+++ b/content/common/mojo/mojo_shell_connection_impl.cc |
@@ -90,7 +90,12 @@ class MojoShellConnectionImpl::IOThreadContext |
// i.e. can be called when starting the process but not afterwards. |
int AddConnectionFilter(std::unique_ptr<ConnectionFilter> filter) { |
base::AutoLock lock(lock_); |
+ |
int id = ++next_filter_id_; |
+ |
+ // We should never hit this in practice, but let's crash just in case. |
+ CHECK_NE(id, kInvalidConnectionFilterId); |
+ |
connection_filters_[id] = std::move(filter); |
return id; |
} |
@@ -114,25 +119,40 @@ class MojoShellConnectionImpl::IOThreadContext |
private: |
friend class base::RefCountedThreadSafe<IOThreadContext>; |
- class Obs : public base::MessageLoop::DestructionObserver { |
+ class MessageLoopObserver : public base::MessageLoop::DestructionObserver { |
public: |
- explicit Obs(base::WeakPtr<IOThreadContext> context) : context_(context) { |
+ explicit MessageLoopObserver(base::WeakPtr<IOThreadContext> context) |
+ : context_(context) { |
base::MessageLoop::current()->AddDestructionObserver(this); |
} |
- ~Obs() override { |
+ |
+ ~MessageLoopObserver() override { |
base::MessageLoop::current()->RemoveDestructionObserver(this); |
} |
- private: |
- void WillDestroyCurrentMessageLoop() override { |
+ void ShutDown() { |
+ if (!is_active_) |
+ return; |
+ |
+ // The call into |context_| below may reenter ShutDown(), hence we set |
+ // |is_active_| to false here. |
+ is_active_ = false; |
if (context_) |
context_->ShutDownOnIOThread(); |
+ |
delete this; |
} |
+ private: |
+ void WillDestroyCurrentMessageLoop() override { |
+ DCHECK(is_active_); |
+ ShutDown(); |
+ } |
+ |
+ bool is_active_ = true; |
base::WeakPtr<IOThreadContext> context_; |
- DISALLOW_COPY_AND_ASSIGN(Obs); |
+ DISALLOW_COPY_AND_ASSIGN(MessageLoopObserver); |
}; |
~IOThreadContext() override {} |
@@ -144,18 +164,37 @@ class MojoShellConnectionImpl::IOThreadContext |
this, std::move(pending_service_request_), |
std::move(io_thread_connector_), |
std::move(pending_connector_request_))); |
- new Obs(weak_factory_.GetWeakPtr()); |
+ |
+ // MessageLoopObserver owns itself. |
+ message_loop_observer_ = |
+ new MessageLoopObserver(weak_factory_.GetWeakPtr()); |
} |
void ShutDownOnIOThread() { |
DCHECK(io_thread_checker_.CalledOnValidThread()); |
+ |
weak_factory_.InvalidateWeakPtrs(); |
+ |
+ // Note that this method may be invoked by MessageLoopObserver observing |
+ // MessageLoop destruction. In that case, this call to ShutDown is |
+ // effectively a no-op. In any case it's safe. |
+ message_loop_observer_->ShutDown(); |
+ message_loop_observer_ = nullptr; |
+ |
+ // Resetting the ServiceContext below may otherwise release the last |
+ // reference to this IOThreadContext. We keep it alive until the stack |
+ // unwinds. |
+ scoped_refptr<IOThreadContext> keepalive(this); |
+ |
factory_bindings_.CloseAllBindings(); |
- connection_filters_.clear(); |
service_context_.reset(); |
+ |
+ base::AutoLock lock(lock_); |
+ connection_filters_.clear(); |
} |
void RemoveConnectionFilterOnIOThread(int filter_id) { |
+ base::AutoLock lock(lock_); |
auto it = connection_filters_.find(filter_id); |
DCHECK(it != connection_filters_.end()); |
connection_filters_.erase(it); |
@@ -189,9 +228,12 @@ class MojoShellConnectionImpl::IOThreadContext |
} |
bool accept = false; |
- for (auto& entry : connection_filters_) { |
- accept |= entry.second->OnConnect(remote_identity, registry, |
- service_context_->connector()); |
+ { |
+ base::AutoLock lock(lock_); |
+ for (auto& entry : connection_filters_) { |
+ accept |= entry.second->OnConnect(remote_identity, registry, |
+ service_context_->connector()); |
+ } |
} |
if (remote_identity.name() == "exe:content_browser" && |
@@ -279,10 +321,14 @@ class MojoShellConnectionImpl::IOThreadContext |
std::unique_ptr<shell::ServiceContext> service_context_; |
mojo::BindingSet<shell::mojom::ServiceFactory> factory_bindings_; |
- std::map<int, std::unique_ptr<ConnectionFilter>> connection_filters_; |
int next_filter_id_ = kInvalidConnectionFilterId; |
+ // Not owned. |
+ MessageLoopObserver* message_loop_observer_ = nullptr; |
+ |
+ // Guards |connection_filters_|. |
base::Lock lock_; |
+ std::map<int, std::unique_ptr<ConnectionFilter>> connection_filters_; |
base::WeakPtrFactory<IOThreadContext> weak_factory_; |