blob: 9755e13d7fb88a1208315be2f7f37273e46f5b93 [file] [log] [blame]
jschuh@chromium.orga5cd0762012-04-05 11:38:34 +09001// Copyright (c) 2012 The Chromium Authors. All rights reserved.
agl@chromium.org1c6dcf22009-07-23 08:57:21 +09002// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
jam@chromium.org06d18442011-05-03 03:00:49 +09005#ifndef IPC_IPC_CHANNEL_PROXY_H_
6#define IPC_IPC_CHANNEL_PROXY_H_
agl@chromium.org1c6dcf22009-07-23 08:57:21 +09007
8#include <vector>
9
levin@chromium.org5c528682011-03-28 10:54:15 +090010#include "base/memory/ref_counted.h"
11#include "base/memory/scoped_ptr.h"
brettw@chromium.orgabe477a2011-01-21 13:55:52 +090012#include "base/synchronization/lock.h"
agl@chromium.org1c6dcf22009-07-23 08:57:21 +090013#include "ipc/ipc_channel.h"
dmaclach@chromium.org058c4a72010-12-09 04:28:09 +090014#include "ipc/ipc_channel_handle.h"
brettw@chromium.orgf947ed02012-06-12 07:35:26 +090015#include "ipc/ipc_listener.h"
16#include "ipc/ipc_sender.h"
agl@chromium.org1c6dcf22009-07-23 08:57:21 +090017
sergeyu@chromium.org5b6d49c2012-07-03 06:15:52 +090018namespace base {
19class SingleThreadTaskRunner;
20}
21
agl@chromium.org1c6dcf22009-07-23 08:57:21 +090022namespace IPC {
23
jhawkins@chromium.orge34d0ad2011-11-29 11:24:28 +090024class SendCallbackHelper;
jcampan@chromium.org1c86b552009-07-29 07:09:45 +090025
agl@chromium.org1c6dcf22009-07-23 08:57:21 +090026//-----------------------------------------------------------------------------
27// IPC::ChannelProxy
28//
29// This class is a helper class that is useful when you wish to run an IPC
30// channel on a background thread. It provides you with the option of either
31// handling IPC messages on that background thread or having them dispatched to
32// your main thread (the thread on which the IPC::ChannelProxy is created).
33//
34// The API for an IPC::ChannelProxy is very similar to that of an IPC::Channel.
35// When you send a message to an IPC::ChannelProxy, the message is routed to
36// the background thread, where it is then passed to the IPC::Channel's Send
37// method. This means that you can send a message from your thread and your
38// message will be sent over the IPC channel when possible instead of being
39// delayed until your thread returns to its message loop. (Often IPC messages
40// will queue up on the IPC::Channel when there is a lot of traffic, and the
41// channel will not get cycles to flush its message queue until the thread, on
42// which it is running, returns to its message loop.)
43//
44// An IPC::ChannelProxy can have a MessageFilter associated with it, which will
45// be notified of incoming messages on the IPC::Channel's thread. This gives
46// the consumer of IPC::ChannelProxy the ability to respond to incoming
47// messages on this background thread instead of on their own thread, which may
48// be bogged down with other processing. The result can be greatly improved
49// latency for messages that can be handled on a background thread.
50//
51// The consumer of IPC::ChannelProxy is responsible for allocating the Thread
52// instance where the IPC::Channel will be created and operated.
53//
brettw@chromium.orgf947ed02012-06-12 07:35:26 +090054class IPC_EXPORT ChannelProxy : public Sender {
agl@chromium.org1c6dcf22009-07-23 08:57:21 +090055 public:
jam@chromium.orgb1f47b22009-11-06 06:53:08 +090056 struct MessageFilterTraits;
jam@chromium.org5863a192009-11-02 15:10:30 +090057
agl@chromium.org1c6dcf22009-07-23 08:57:21 +090058 // A class that receives messages on the thread where the IPC channel is
59 // running. It can choose to prevent the default action for an IPC message.
darin@chromium.org80e4c5e2011-08-16 05:41:46 +090060 class IPC_EXPORT MessageFilter
jam@chromium.org5863a192009-11-02 15:10:30 +090061 : public base::RefCountedThreadSafe<MessageFilter, MessageFilterTraits> {
agl@chromium.org1c6dcf22009-07-23 08:57:21 +090062 public:
erg@google.com20b66e32010-10-01 05:06:30 +090063 MessageFilter();
agl@chromium.org1c6dcf22009-07-23 08:57:21 +090064
65 // Called on the background thread to provide the filter with access to the
66 // channel. Called when the IPC channel is initialized or when AddFilter
67 // is called if the channel is already initialized.
erg@google.com2ec53b42010-09-24 07:43:53 +090068 virtual void OnFilterAdded(Channel* channel);
agl@chromium.org1c6dcf22009-07-23 08:57:21 +090069
70 // Called on the background thread when the filter has been removed from
71 // the ChannelProxy and when the Channel is closing. After a filter is
72 // removed, it will not be called again.
erg@google.com2ec53b42010-09-24 07:43:53 +090073 virtual void OnFilterRemoved();
agl@chromium.org1c6dcf22009-07-23 08:57:21 +090074
75 // Called to inform the filter that the IPC channel is connected and we
76 // have received the internal Hello message from the peer.
erg@google.com2ec53b42010-09-24 07:43:53 +090077 virtual void OnChannelConnected(int32 peer_pid);
agl@chromium.org1c6dcf22009-07-23 08:57:21 +090078
79 // Called when there is an error on the channel, typically that the channel
80 // has been closed.
erg@google.com2ec53b42010-09-24 07:43:53 +090081 virtual void OnChannelError();
agl@chromium.org1c6dcf22009-07-23 08:57:21 +090082
83 // Called to inform the filter that the IPC channel will be destroyed.
84 // OnFilterRemoved is called immediately after this.
erg@google.com2ec53b42010-09-24 07:43:53 +090085 virtual void OnChannelClosing();
agl@chromium.org1c6dcf22009-07-23 08:57:21 +090086
87 // Return true to indicate that the message was handled, or false to let
88 // the message be handled in the default way.
erg@google.com2ec53b42010-09-24 07:43:53 +090089 virtual bool OnMessageReceived(const Message& message);
jam@chromium.org5863a192009-11-02 15:10:30 +090090
91 // Called when the message filter is about to be deleted. This gives
92 // derived classes the option of controlling which thread they're deleted
93 // on etc.
mpcomplete@chromium.org78bc9752010-10-23 07:19:24 +090094 virtual void OnDestruct() const;
rsleevi@chromium.org997c1d42012-04-28 11:12:00 +090095
96 protected:
97 virtual ~MessageFilter();
98
99 private:
100 friend class base::RefCountedThreadSafe<MessageFilter,
101 MessageFilterTraits>;
agl@chromium.org1c6dcf22009-07-23 08:57:21 +0900102 };
103
jam@chromium.orgb1f47b22009-11-06 06:53:08 +0900104 struct MessageFilterTraits {
mpcomplete@chromium.org78bc9752010-10-23 07:19:24 +0900105 static void Destruct(const MessageFilter* filter) {
jam@chromium.orgb1f47b22009-11-06 06:53:08 +0900106 filter->OnDestruct();
107 }
108 };
109
rsleevi@chromium.org997c1d42012-04-28 11:12:00 +0900110
tsepez@chromium.orge68ddef2011-05-05 02:14:16 +0900111 // Interface for a filter to be imposed on outgoing messages which can
112 // re-write the message. Used mainly for testing.
113 class OutgoingMessageFilter {
114 public:
115 // Returns a re-written message, freeing the original, or simply the
116 // original unchanged if no rewrite indicated.
117 virtual Message *Rewrite(Message *message) = 0;
118 };
119
dmaclach@chromium.org058c4a72010-12-09 04:28:09 +0900120 // Initializes a channel proxy. The channel_handle and mode parameters are
agl@chromium.org1c6dcf22009-07-23 08:57:21 +0900121 // passed directly to the underlying IPC::Channel. The listener is called on
122 // the thread that creates the ChannelProxy. The filter's OnMessageReceived
123 // method is called on the thread where the IPC::Channel is running. The
124 // filter may be null if the consumer is not interested in handling messages
125 // on the background thread. Any message not handled by the filter will be
sergeyu@chromium.org5b6d49c2012-07-03 06:15:52 +0900126 // dispatched to the listener. The given task runner correspond to a thread
127 // on which IPC::Channel is created and used (e.g. IO thread).
dmaclach@chromium.org058c4a72010-12-09 04:28:09 +0900128 ChannelProxy(const IPC::ChannelHandle& channel_handle,
jam@chromium.orge57135c2010-12-03 04:16:07 +0900129 Channel::Mode mode,
brettw@chromium.orgf947ed02012-06-12 07:35:26 +0900130 Listener* listener,
sergeyu@chromium.org5b6d49c2012-07-03 06:15:52 +0900131 base::SingleThreadTaskRunner* ipc_task_runner);
agl@chromium.org1c6dcf22009-07-23 08:57:21 +0900132
erg@google.com2ec53b42010-09-24 07:43:53 +0900133 virtual ~ChannelProxy();
agl@chromium.org1c6dcf22009-07-23 08:57:21 +0900134
kkania@chromium.org9ccb4692011-11-16 10:06:46 +0900135 // Initializes the channel proxy. Only call this once to initialize a channel
136 // proxy that was not initialized in its constructor. If create_pipe_now is
137 // true, the pipe is created synchronously. Otherwise it's created on the IO
138 // thread.
139 void Init(const IPC::ChannelHandle& channel_handle, Channel::Mode mode,
140 bool create_pipe_now);
141
agl@chromium.org1c6dcf22009-07-23 08:57:21 +0900142 // Close the IPC::Channel. This operation completes asynchronously, once the
143 // background thread processes the command to close the channel. It is ok to
144 // call this method multiple times. Redundant calls are ignored.
145 //
146 // WARNING: The MessageFilter object held by the ChannelProxy is also
147 // released asynchronously, and it may in fact have its final reference
148 // released on the background thread. The caller should be careful to deal
149 // with / allow for this possibility.
150 void Close();
151
152 // Send a message asynchronously. The message is routed to the background
153 // thread where it is passed to the IPC::Channel's Send method.
avi@chromium.org362c8a82011-11-18 01:09:44 +0900154 virtual bool Send(Message* message) OVERRIDE;
agl@chromium.org1c6dcf22009-07-23 08:57:21 +0900155
156 // Used to intercept messages as they are received on the background thread.
157 //
158 // Ordinarily, messages sent to the ChannelProxy are routed to the matching
159 // listener on the worker thread. This API allows code to intercept messages
160 // before they are sent to the worker thread.
jam@chromium.orge57135c2010-12-03 04:16:07 +0900161 // If you call this before the target process is launched, then you're
162 // guaranteed to not miss any messages. But if you call this anytime after,
163 // then some messages might be missed since the filter is added internally on
164 // the IO thread.
agl@chromium.org1c6dcf22009-07-23 08:57:21 +0900165 void AddFilter(MessageFilter* filter);
166 void RemoveFilter(MessageFilter* filter);
167
tsepez@chromium.orge68ddef2011-05-05 02:14:16 +0900168 void set_outgoing_message_filter(OutgoingMessageFilter* filter) {
169 outgoing_message_filter_ = filter;
170 }
171
sergeyu@chromium.org5b6d49c2012-07-03 06:15:52 +0900172 // Called to clear the pointer to the IPC task runner when it's going away.
173 void ClearIPCTaskRunner();
nsylvain@chromium.orgc12dde32009-07-24 03:17:55 +0900174
jschuh@chromium.orga5cd0762012-04-05 11:38:34 +0900175 // Get the process ID for the connected peer.
176 // Returns base::kNullProcessId if the peer is not connected yet.
177 base::ProcessId peer_pid() const { return context_->peer_pid_; }
178
dmichael@chromium.orgb798bb42012-06-01 04:37:54 +0900179#if defined(OS_POSIX) && !defined(OS_NACL)
agl@chromium.org1c6dcf22009-07-23 08:57:21 +0900180 // Calls through to the underlying channel's methods.
phajdan.jr@chromium.orgaf9455b2011-09-20 02:08:12 +0900181 int GetClientFileDescriptor();
182 int TakeClientFileDescriptor();
wez@chromium.org7cce0912011-04-06 21:01:44 +0900183 bool GetClientEuid(uid_t* client_euid) const;
agl@chromium.org1c6dcf22009-07-23 08:57:21 +0900184#endif // defined(OS_POSIX)
185
186 protected:
187 class Context;
188 // A subclass uses this constructor if it needs to add more information
kkania@chromium.org9ccb4692011-11-16 10:06:46 +0900189 // to the internal state.
190 ChannelProxy(Context* context);
agl@chromium.org1c6dcf22009-07-23 08:57:21 +0900191
192 // Used internally to hold state that is referenced on the IPC thread.
193 class Context : public base::RefCountedThreadSafe<Context>,
brettw@chromium.orgf947ed02012-06-12 07:35:26 +0900194 public Listener {
agl@chromium.org1c6dcf22009-07-23 08:57:21 +0900195 public:
sergeyu@chromium.org5b6d49c2012-07-03 06:15:52 +0900196 Context(Listener* listener, base::SingleThreadTaskRunner* ipc_thread);
197 void ClearIPCTaskRunner();
198 base::SingleThreadTaskRunner* ipc_task_runner() const {
199 return ipc_task_runner_;
jam@chromium.org06d18442011-05-03 03:00:49 +0900200 }
agl@chromium.org1c6dcf22009-07-23 08:57:21 +0900201 const std::string& channel_id() const { return channel_id_; }
202
203 // Dispatches a message on the listener thread.
204 void OnDispatchMessage(const Message& message);
205
206 protected:
jam@chromium.orgb1f47b22009-11-06 06:53:08 +0900207 friend class base::RefCountedThreadSafe<Context>;
jam@chromium.org06d18442011-05-03 03:00:49 +0900208 virtual ~Context();
jam@chromium.orgb1f47b22009-11-06 06:53:08 +0900209
brettw@chromium.orgf947ed02012-06-12 07:35:26 +0900210 // IPC::Listener methods:
evan@chromium.orgecc3f072011-08-17 06:09:25 +0900211 virtual bool OnMessageReceived(const Message& message) OVERRIDE;
212 virtual void OnChannelConnected(int32 peer_pid) OVERRIDE;
213 virtual void OnChannelError() OVERRIDE;
agl@chromium.org1c6dcf22009-07-23 08:57:21 +0900214
215 // Like OnMessageReceived but doesn't try the filters.
jam@chromium.org8a2c7842010-12-24 15:19:28 +0900216 bool OnMessageReceivedNoFilter(const Message& message);
agl@chromium.org1c6dcf22009-07-23 08:57:21 +0900217
218 // Gives the filters a chance at processing |message|.
219 // Returns true if the message was processed, false otherwise.
220 bool TryFilters(const Message& message);
221
222 // Like Open and Close, but called on the IPC thread.
223 virtual void OnChannelOpened();
224 virtual void OnChannelClosed();
225
226 // Called on the consumers thread when the ChannelProxy is closed. At that
227 // point the consumer is telling us that they don't want to receive any
228 // more messages, so we honor that wish by forgetting them!
hans@chromium.orge62750c2012-08-10 05:39:12 +0900229 virtual void Clear();
agl@chromium.org1c6dcf22009-07-23 08:57:21 +0900230
231 private:
232 friend class ChannelProxy;
jhawkins@chromium.orge34d0ad2011-11-29 11:24:28 +0900233 friend class SendCallbackHelper;
jam@chromium.orgb1f47b22009-11-06 06:53:08 +0900234
agl@chromium.org1c6dcf22009-07-23 08:57:21 +0900235 // Create the Channel
dmaclach@chromium.org058c4a72010-12-09 04:28:09 +0900236 void CreateChannel(const IPC::ChannelHandle& channel_handle,
satorux@chromium.orgad12d3d2011-08-23 12:17:02 +0900237 const Channel::Mode& mode);
agl@chromium.org1c6dcf22009-07-23 08:57:21 +0900238
jam@chromium.orge57135c2010-12-03 04:16:07 +0900239 // Methods called on the IO thread.
rsleevi@chromium.org997c1d42012-04-28 11:12:00 +0900240 void OnSendMessage(scoped_ptr<Message> message_ptr);
jam@chromium.orge57135c2010-12-03 04:16:07 +0900241 void OnAddFilter();
agl@chromium.org1c6dcf22009-07-23 08:57:21 +0900242 void OnRemoveFilter(MessageFilter* filter);
jam@chromium.orge57135c2010-12-03 04:16:07 +0900243
244 // Methods called on the listener thread.
245 void AddFilter(MessageFilter* filter);
agl@chromium.org1c6dcf22009-07-23 08:57:21 +0900246 void OnDispatchConnected();
247 void OnDispatchError();
248
sergeyu@chromium.org5b6d49c2012-07-03 06:15:52 +0900249 scoped_refptr<base::SingleThreadTaskRunner> listener_task_runner_;
brettw@chromium.orgf947ed02012-06-12 07:35:26 +0900250 Listener* listener_;
agl@chromium.org1c6dcf22009-07-23 08:57:21 +0900251
252 // List of filters. This is only accessed on the IPC thread.
253 std::vector<scoped_refptr<MessageFilter> > filters_;
sergeyu@chromium.org5b6d49c2012-07-03 06:15:52 +0900254 scoped_refptr<base::SingleThreadTaskRunner> ipc_task_runner_;
dmaclach@chromium.org058c4a72010-12-09 04:28:09 +0900255 scoped_ptr<Channel> channel_;
agl@chromium.org1c6dcf22009-07-23 08:57:21 +0900256 std::string channel_id_;
agl@chromium.org1c6dcf22009-07-23 08:57:21 +0900257 bool channel_connected_called_;
jam@chromium.orge57135c2010-12-03 04:16:07 +0900258
259 // Holds filters between the AddFilter call on the listerner thread and the
260 // IPC thread when they're added to filters_.
261 std::vector<scoped_refptr<MessageFilter> > pending_filters_;
262 // Lock for pending_filters_.
brettw@chromium.orgabe477a2011-01-21 13:55:52 +0900263 base::Lock pending_filters_lock_;
jschuh@chromium.orga5cd0762012-04-05 11:38:34 +0900264
265 // Cached copy of the peer process ID. Set on IPC but read on both IPC and
266 // listener threads.
267 base::ProcessId peer_pid_;
agl@chromium.org1c6dcf22009-07-23 08:57:21 +0900268 };
269
270 Context* context() { return context_; }
271
tsepez@chromium.orge68ddef2011-05-05 02:14:16 +0900272 OutgoingMessageFilter* outgoing_message_filter() {
273 return outgoing_message_filter_;
274 }
275
agl@chromium.org1c6dcf22009-07-23 08:57:21 +0900276 private:
jhawkins@chromium.orge34d0ad2011-11-29 11:24:28 +0900277 friend class SendCallbackHelper;
jcampan@chromium.org1c86b552009-07-29 07:09:45 +0900278
agl@chromium.org1c6dcf22009-07-23 08:57:21 +0900279 // By maintaining this indirection (ref-counted) to our internal state, we
280 // can safely be destroyed while the background thread continues to do stuff
281 // that involves this data.
282 scoped_refptr<Context> context_;
tsepez@chromium.orge68ddef2011-05-05 02:14:16 +0900283
284 OutgoingMessageFilter* outgoing_message_filter_;
kkania@chromium.org9ccb4692011-11-16 10:06:46 +0900285
286 // Whether the channel has been initialized.
287 bool did_init_;
agl@chromium.org1c6dcf22009-07-23 08:57:21 +0900288};
289
290} // namespace IPC
291
jam@chromium.org06d18442011-05-03 03:00:49 +0900292#endif // IPC_IPC_CHANNEL_PROXY_H_