1 // Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "base/message_loop.h"
6 #include "base/thread.h"
7 #include "ipc/ipc_channel_proxy.h"
8 #include "ipc/ipc_logging.h"
9 #include "ipc/ipc_message_utils.h"
13 //------------------------------------------------------------------------------
15 // This task ensures the message is deleted if the task is deleted without
17 class SendTask
: public Task
{
19 SendTask(ChannelProxy::Context
* context
, Message
* message
)
25 context_
->OnSendMessage(message_
.release());
29 scoped_refptr
<ChannelProxy::Context
> context_
;
30 scoped_ptr
<Message
> message_
;
32 DISALLOW_COPY_AND_ASSIGN(SendTask
);
35 //------------------------------------------------------------------------------
37 ChannelProxy::Context::Context(Channel::Listener
* listener
,
38 MessageFilter
* filter
,
39 MessageLoop
* ipc_message_loop
)
40 : listener_message_loop_(MessageLoop::current()),
42 ipc_message_loop_(ipc_message_loop
),
45 channel_connected_called_(false) {
47 filters_
.push_back(filter
);
50 void ChannelProxy::Context::CreateChannel(const std::string
& id
,
51 const Channel::Mode
& mode
) {
52 DCHECK(channel_
== NULL
);
54 channel_
= new Channel(id
, mode
, this);
57 bool ChannelProxy::Context::TryFilters(const Message
& message
) {
58 #ifdef IPC_MESSAGE_LOG_ENABLED
59 Logging
* logger
= Logging::current();
60 if (logger
->Enabled())
61 logger
->OnPreDispatchMessage(message
);
64 for (size_t i
= 0; i
< filters_
.size(); ++i
) {
65 if (filters_
[i
]->OnMessageReceived(message
)) {
66 #ifdef IPC_MESSAGE_LOG_ENABLED
67 if (logger
->Enabled())
68 logger
->OnPostDispatchMessage(message
, channel_id_
);
76 // Called on the IPC::Channel thread
77 void ChannelProxy::Context::OnMessageReceived(const Message
& message
) {
78 // First give a chance to the filters to process this message.
79 if (!TryFilters(message
))
80 OnMessageReceivedNoFilter(message
);
83 // Called on the IPC::Channel thread
84 void ChannelProxy::Context::OnMessageReceivedNoFilter(const Message
& message
) {
85 // NOTE: This code relies on the listener's message loop not going away while
86 // this thread is active. That should be a reasonable assumption, but it
87 // feels risky. We may want to invent some more indirect way of referring to
88 // a MessageLoop if this becomes a problem.
89 listener_message_loop_
->PostTask(FROM_HERE
, NewRunnableMethod(
90 this, &Context::OnDispatchMessage
, message
));
93 // Called on the IPC::Channel thread
94 void ChannelProxy::Context::OnChannelConnected(int32 peer_pid
) {
96 for (size_t i
= 0; i
< filters_
.size(); ++i
)
97 filters_
[i
]->OnChannelConnected(peer_pid
);
99 // See above comment about using listener_message_loop_ here.
100 listener_message_loop_
->PostTask(FROM_HERE
, NewRunnableMethod(
101 this, &Context::OnDispatchConnected
));
104 // Called on the IPC::Channel thread
105 void ChannelProxy::Context::OnChannelError() {
106 for (size_t i
= 0; i
< filters_
.size(); ++i
)
107 filters_
[i
]->OnChannelError();
109 // See above comment about using listener_message_loop_ here.
110 listener_message_loop_
->PostTask(FROM_HERE
, NewRunnableMethod(
111 this, &Context::OnDispatchError
));
114 // Called on the IPC::Channel thread
115 void ChannelProxy::Context::OnChannelOpened() {
116 DCHECK(channel_
!= NULL
);
118 // Assume a reference to ourselves on behalf of this thread. This reference
119 // will be released when we are closed.
122 if (!channel_
->Connect()) {
127 for (size_t i
= 0; i
< filters_
.size(); ++i
)
128 filters_
[i
]->OnFilterAdded(channel_
);
131 // Called on the IPC::Channel thread
132 void ChannelProxy::Context::OnChannelClosed() {
133 // It's okay for IPC::ChannelProxy::Close to be called more than once, which
134 // would result in this branch being taken.
138 for (size_t i
= 0; i
< filters_
.size(); ++i
) {
139 filters_
[i
]->OnChannelClosing();
140 filters_
[i
]->OnFilterRemoved();
143 // We don't need the filters anymore.
149 // Balance with the reference taken during startup. This may result in
154 // Called on the IPC::Channel thread
155 void ChannelProxy::Context::OnSendMessage(Message
* message
) {
156 if (!channel_
->Send(message
))
160 // Called on the IPC::Channel thread
161 void ChannelProxy::Context::OnAddFilter(MessageFilter
* filter
) {
162 filters_
.push_back(filter
);
164 // If the channel has already been created, then we need to send this message
165 // so that the filter gets access to the Channel.
167 filter
->OnFilterAdded(channel_
);
169 // Balances the AddRef in ChannelProxy::AddFilter.
173 // Called on the IPC::Channel thread
174 void ChannelProxy::Context::OnRemoveFilter(MessageFilter
* filter
) {
175 for (size_t i
= 0; i
< filters_
.size(); ++i
) {
176 if (filters_
[i
].get() == filter
) {
177 filter
->OnFilterRemoved();
178 filters_
.erase(filters_
.begin() + i
);
183 NOTREACHED() << "filter to be removed not found";
186 // Called on the listener's thread
187 void ChannelProxy::Context::OnDispatchMessage(const Message
& message
) {
191 OnDispatchConnected();
193 #ifdef IPC_MESSAGE_LOG_ENABLED
194 Logging
* logger
= Logging::current();
195 if (message
.type() == IPC_LOGGING_ID
) {
196 logger
->OnReceivedLoggingMessage(message
);
200 if (logger
->Enabled())
201 logger
->OnPreDispatchMessage(message
);
204 listener_
->OnMessageReceived(message
);
206 #ifdef IPC_MESSAGE_LOG_ENABLED
207 if (logger
->Enabled())
208 logger
->OnPostDispatchMessage(message
, channel_id_
);
212 // Called on the listener's thread
213 void ChannelProxy::Context::OnDispatchConnected() {
214 if (channel_connected_called_
)
217 channel_connected_called_
= true;
219 listener_
->OnChannelConnected(peer_pid_
);
222 // Called on the listener's thread
223 void ChannelProxy::Context::OnDispatchError() {
225 listener_
->OnChannelError();
228 //-----------------------------------------------------------------------------
230 ChannelProxy::ChannelProxy(const std::string
& channel_id
, Channel::Mode mode
,
231 Channel::Listener
* listener
, MessageFilter
* filter
,
232 MessageLoop
* ipc_thread
)
233 : context_(new Context(listener
, filter
, ipc_thread
)) {
234 Init(channel_id
, mode
, ipc_thread
, true);
237 ChannelProxy::ChannelProxy(const std::string
& channel_id
, Channel::Mode mode
,
238 MessageLoop
* ipc_thread
, Context
* context
,
239 bool create_pipe_now
)
240 : context_(context
) {
241 Init(channel_id
, mode
, ipc_thread
, create_pipe_now
);
244 void ChannelProxy::Init(const std::string
& channel_id
, Channel::Mode mode
,
245 MessageLoop
* ipc_thread_loop
, bool create_pipe_now
) {
246 if (create_pipe_now
) {
247 // Create the channel immediately. This effectively sets up the
248 // low-level pipe so that the client can connect. Without creating
249 // the pipe immediately, it is possible for a listener to attempt
250 // to connect and get an error since the pipe doesn't exist yet.
251 context_
->CreateChannel(channel_id
, mode
);
253 context_
->ipc_message_loop()->PostTask(FROM_HERE
, NewRunnableMethod(
254 context_
.get(), &Context::CreateChannel
, channel_id
, mode
));
257 // complete initialization on the background thread
258 context_
->ipc_message_loop()->PostTask(FROM_HERE
, NewRunnableMethod(
259 context_
.get(), &Context::OnChannelOpened
));
262 void ChannelProxy::Close() {
263 // Clear the backpointer to the listener so that any pending calls to
264 // Context::OnDispatchMessage or OnDispatchError will be ignored. It is
265 // possible that the channel could be closed while it is receiving messages!
268 if (context_
->ipc_message_loop()) {
269 context_
->ipc_message_loop()->PostTask(FROM_HERE
, NewRunnableMethod(
270 context_
.get(), &Context::OnChannelClosed
));
274 bool ChannelProxy::Send(Message
* message
) {
275 #ifdef IPC_MESSAGE_LOG_ENABLED
276 Logging::current()->OnSendMessage(message
, context_
->channel_id());
279 context_
->ipc_message_loop()->PostTask(FROM_HERE
,
280 new SendTask(context_
.get(), message
));
284 void ChannelProxy::AddFilter(MessageFilter
* filter
) {
285 // We want to addref the filter to prevent it from
286 // being destroyed before the OnAddFilter call is invoked.
288 context_
->ipc_message_loop()->PostTask(FROM_HERE
, NewRunnableMethod(
289 context_
.get(), &Context::OnAddFilter
, filter
));
292 void ChannelProxy::RemoveFilter(MessageFilter
* filter
) {
293 context_
->ipc_message_loop()->PostTask(FROM_HERE
, NewRunnableMethod(
294 context_
.get(), &Context::OnRemoveFilter
, filter
));
297 void ChannelProxy::ClearIPCMessageLoop() {
298 context()->ClearIPCMessageLoop();
301 #if defined(OS_POSIX)
302 // See the TODO regarding lazy initialization of the channel in
303 // ChannelProxy::Init().
304 // We assume that IPC::Channel::GetClientFileDescriptorMapping() is thread-safe.
305 int ChannelProxy::GetClientFileDescriptor() const {
306 Channel
*channel
= context_
.get()->channel_
;
307 DCHECK(channel
); // Channel must have been created first.
308 return channel
->GetClientFileDescriptor();
312 //-----------------------------------------------------------------------------