Chromium Code Reviews| Index: ipc/ipc_channel_proxy.cc |
| diff --git a/ipc/ipc_channel_proxy.cc b/ipc/ipc_channel_proxy.cc |
| index 50431d575604c43045d174fa0800613bba17d463..b8bbe90aec34e6d822f15056715321df18c722da 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) { |
| @@ -268,40 +266,57 @@ void ChannelProxy::Context::Clear() { |
| // Called on the IPC::Channel thread |
| void ChannelProxy::Context::OnSendMessage(scoped_ptr<Message> message) { |
| - if (!channel_.get()) { |
| - OnChannelClosed(); |
| + if (!channel_) |
| return; |
|
dmichael (off chromium)
2014/02/28 23:25:47
There's no need to call OnChannelClosed; it's alre
|
| - } |
| + |
| 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_); |
| new_filters.swap(pending_filters_); |
| } |
| + if (!channel_) |
| + return; // The channel has been closed, so don't really add the filters. |
|
jam
2014/03/03 16:27:03
can this condition really get hit since we're only
dmichael (off chromium)
2014/03/03 16:37:02
Good point, looks like it can't happen now.
I'll
|
| for (size_t i = 0; i < new_filters.size(); ++i) { |
| filters_.push_back(new_filters[i]); |
| 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); |