| Index: ipc/ipc_channel_proxy.cc
|
| diff --git a/ipc/ipc_channel_proxy.cc b/ipc/ipc_channel_proxy.cc
|
| index 50431d575604c43045d174fa0800613bba17d463..ca09146294d6a9fcf85e834a57c90f30707dc753 100644
|
| --- a/ipc/ipc_channel_proxy.cc
|
| +++ b/ipc/ipc_channel_proxy.cc
|
| @@ -156,7 +156,7 @@ void ChannelProxy::Context::ClearIPCTaskRunner() {
|
|
|
| void ChannelProxy::Context::CreateChannel(const IPC::ChannelHandle& handle,
|
| const Channel::Mode& mode) {
|
| - DCHECK(channel_.get() == NULL);
|
| + DCHECK(!channel_);
|
| channel_id_ = handle.name;
|
| channel_.reset(new Channel(handle, mode, this));
|
| }
|
| @@ -196,17 +196,15 @@ bool ChannelProxy::Context::OnMessageReceivedNoFilter(const Message& message) {
|
|
|
| // Called on the IPC::Channel thread
|
| void ChannelProxy::Context::OnChannelConnected(int32 peer_pid) {
|
| + // We cache off the peer_pid so it can be safely accessed from both threads.
|
| + peer_pid_ = channel_->peer_pid();
|
| +
|
| // Add any pending filters. This avoids a race condition where someone
|
| // creates a ChannelProxy, calls AddFilter, and then right after starts the
|
| // peer process. The IO thread could receive a message before the task to add
|
| // the filter is run on the IO thread.
|
| OnAddFilter();
|
|
|
| - // We cache off the peer_pid so it can be safely accessed from both threads.
|
| - peer_pid_ = channel_->peer_pid();
|
| - for (size_t i = 0; i < filters_.size(); ++i)
|
| - filters_[i]->OnChannelConnected(peer_pid);
|
| -
|
| // See above comment about using listener_task_runner_ here.
|
| listener_task_runner_->PostTask(
|
| FROM_HERE, base::Bind(&Context::OnDispatchConnected, this));
|
| @@ -243,7 +241,7 @@ void ChannelProxy::Context::OnChannelOpened() {
|
| void ChannelProxy::Context::OnChannelClosed() {
|
| // It's okay for IPC::ChannelProxy::Close to be called more than once, which
|
| // would result in this branch being taken.
|
| - if (!channel_.get())
|
| + if (!channel_)
|
| return;
|
|
|
| for (size_t i = 0; i < filters_.size(); ++i) {
|
| @@ -254,6 +252,9 @@ void ChannelProxy::Context::OnChannelClosed() {
|
| // We don't need the filters anymore.
|
| message_filter_router_->Clear();
|
| filters_.clear();
|
| + // We don't need the lock, because at this point, the listener thread can't
|
| + // access it any more.
|
| + pending_filters_.clear();
|
|
|
| channel_.reset();
|
|
|
| @@ -268,16 +269,24 @@ void ChannelProxy::Context::Clear() {
|
|
|
| // Called on the IPC::Channel thread
|
| void ChannelProxy::Context::OnSendMessage(scoped_ptr<Message> message) {
|
| - if (!channel_.get()) {
|
| + if (!channel_) {
|
| OnChannelClosed();
|
| return;
|
| }
|
| +
|
| if (!channel_->Send(message.release()))
|
| OnChannelError();
|
| }
|
|
|
| // Called on the IPC::Channel thread
|
| void ChannelProxy::Context::OnAddFilter() {
|
| + // Our OnChannelConnected method has not yet been called, so we can't be
|
| + // sure that channel_ is valid yet. When OnChannelConnected *is* called,
|
| + // it invokes OnAddFilter, so any pending filter(s) will be added at that
|
| + // time.
|
| + if (peer_pid_ == base::kNullProcessId)
|
| + return;
|
| +
|
| std::vector<scoped_refptr<MessageFilter> > new_filters;
|
| {
|
| base::AutoLock auto_lock(pending_filters_lock_);
|
| @@ -289,19 +298,28 @@ void ChannelProxy::Context::OnAddFilter() {
|
|
|
| message_filter_router_->AddFilter(new_filters[i].get());
|
|
|
| - // If the channel has already been created, then we need to send this
|
| - // message so that the filter gets access to the Channel.
|
| - if (channel_.get())
|
| - new_filters[i]->OnFilterAdded(channel_.get());
|
| - // Ditto for if the channel has been connected.
|
| - if (peer_pid_)
|
| - new_filters[i]->OnChannelConnected(peer_pid_);
|
| + // The channel has already been created and connected, so we need to
|
| + // inform the filters right now.
|
| + new_filters[i]->OnFilterAdded(channel_.get());
|
| + new_filters[i]->OnChannelConnected(peer_pid_);
|
| }
|
| }
|
|
|
| // Called on the IPC::Channel thread
|
| void ChannelProxy::Context::OnRemoveFilter(MessageFilter* filter) {
|
| - if (!channel_.get())
|
| + if (peer_pid_ == base::kNullProcessId) {
|
| + // The channel is not yet connected, so any filters are still pending.
|
| + base::AutoLock auto_lock(pending_filters_lock_);
|
| + for (size_t i = 0; i < pending_filters_.size(); ++i) {
|
| + if (pending_filters_[i].get() == filter) {
|
| + filter->OnFilterRemoved();
|
| + pending_filters_.erase(pending_filters_.begin() + i);
|
| + return;
|
| + }
|
| + }
|
| + return;
|
| + }
|
| + if (!channel_)
|
| return; // The filters have already been deleted.
|
|
|
| message_filter_router_->RemoveFilter(filter);
|
|
|