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.
4 :
5 : #ifndef CHROME_COMMON_IPC_CHANNEL_PROXY_H__
6 : #define CHROME_COMMON_IPC_CHANNEL_PROXY_H__
7 :
8 : #include <vector>
9 : #include "base/lock.h"
10 : #include "base/ref_counted.h"
11 : #include "chrome/common/ipc_channel.h"
12 :
13 : class MessageLoop;
14 :
15 : namespace IPC {
16 :
17 : //-----------------------------------------------------------------------------
18 : // IPC::ChannelProxy
19 : //
20 : // This class is a helper class that is useful when you wish to run an IPC
21 : // channel on a background thread. It provides you with the option of either
22 : // handling IPC messages on that background thread or having them dispatched to
23 : // your main thread (the thread on which the IPC::ChannelProxy is created).
24 : //
25 : // The API for an IPC::ChannelProxy is very similar to that of an IPC::Channel.
26 : // When you send a message to an IPC::ChannelProxy, the message is routed to
27 : // the background thread, where it is then passed to the IPC::Channel's Send
28 : // method. This means that you can send a message from your thread and your
29 : // message will be sent over the IPC channel when possible instead of being
30 : // delayed until your thread returns to its message loop. (Often IPC messages
31 : // will queue up on the IPC::Channel when there is a lot of traffic, and the
32 : // channel will not get cycles to flush its message queue until the thread, on
33 : // which it is running, returns to its message loop.)
34 : //
35 : // An IPC::ChannelProxy can have a MessageFilter associated with it, which will
36 : // be notified of incoming messages on the IPC::Channel's thread. This gives
37 : // the consumer of IPC::ChannelProxy the ability to respond to incoming
38 : // messages on this background thread instead of on their own thread, which may
39 : // be bogged down with other processing. The result can be greatly improved
40 : // latency for messages that can be handled on a background thread.
41 : //
42 : // The consumer of IPC::ChannelProxy is responsible for allocating the Thread
43 : // instance where the IPC::Channel will be created and operated.
44 : //
45 : class ChannelProxy : public Message::Sender {
46 : public:
47 : // A class that receives messages on the thread where the IPC channel is
48 : // running. It can choose to prevent the default action for an IPC message.
49 : class MessageFilter : public base::RefCountedThreadSafe<MessageFilter> {
50 : public:
51 : virtual ~MessageFilter() {}
52 :
53 : // Called on the background thread to provide the filter with access to the
54 : // channel. Called when the IPC channel is initialized or when AddFilter
55 : // is called if the channel is already initialized.
56 : virtual void OnFilterAdded(Channel* channel) {}
57 :
58 : // Called on the background thread when the filter has been removed from
59 : // the ChannelProxy and when the Channel is closing. After a filter is
60 : // removed, it will not be called again.
61 : virtual void OnFilterRemoved() {}
62 :
63 : // Called to inform the filter that the IPC channel is connected and we
64 : // have received the internal Hello message from the peer.
65 : virtual void OnChannelConnected(int32 peer_pid) {}
66 :
67 : // Called when there is an error on the channel, typically that the channel
68 : // has been closed.
69 : virtual void OnChannelError() {}
70 :
71 : // Called to inform the filter that the IPC channel will be destroyed.
72 : // OnFilterRemoved is called immediately after this.
73 : virtual void OnChannelClosing() {}
74 :
75 : // Return true to indicate that the message was handled, or false to let
76 : // the message be handled in the default way.
77 : virtual bool OnMessageReceived(const Message& message) {
78 : return false;
79 : }
80 : };
81 :
82 : // Initializes a channel proxy. The channel_id and mode parameters are
83 : // passed directly to the underlying IPC::Channel. The listener is called on
84 : // the thread that creates the ChannelProxy. The filter's OnMessageReceived
85 : // method is called on the thread where the IPC::Channel is running. The
86 : // filter may be null if the consumer is not interested in handling messages
87 : // on the background thread. Any message not handled by the filter will be
88 : // dispatched to the listener. The given message loop indicates where the
89 : // IPC::Channel should be created.
90 : ChannelProxy(const std::wstring& channel_id, Channel::Mode mode,
91 : Channel::Listener* listener, MessageFilter* filter,
92 : MessageLoop* ipc_thread_loop);
93 :
94 0 : ~ChannelProxy() {
95 0 : Close();
96 0 : }
97 :
98 : // Close the IPC::Channel. This operation completes asynchronously, once the
99 : // background thread processes the command to close the channel. It is ok to
100 : // call this method multiple times. Redundant calls are ignored.
101 : //
102 : // WARNING: The MessageFilter object held by the ChannelProxy is also
103 : // released asynchronously, and it may in fact have its final reference
104 : // released on the background thread. The caller should be careful to deal
105 : // with / allow for this possibility.
106 : void Close();
107 :
108 : // Send a message asynchronously. The message is routed to the background
109 : // thread where it is passed to the IPC::Channel's Send method.
110 : virtual bool Send(Message* message);
111 :
112 : // Used to intercept messages as they are received on the background thread.
113 : //
114 : // Ordinarily, messages sent to the ChannelProxy are routed to the matching
115 : // listener on the worker thread. This API allows code to intercept messages
116 : // before they are sent to the worker thread.
117 : void AddFilter(MessageFilter* filter);
118 : void RemoveFilter(MessageFilter* filter);
119 :
120 : #if defined(OS_POSIX)
121 : // Calls through to the underlying channel's methods.
122 : // TODO(playmobil): For now this is only implemented in the case of
123 : // create_pipe_now = true, we need to figure this out for the latter case.
124 : void GetClientFileDescriptorMapping(int *src_fd, int *dest_fd) const;
125 : #endif // defined(OS_POSIX)
126 :
127 : protected:
128 : class Context;
129 : // A subclass uses this constructor if it needs to add more information
130 : // to the internal state. If create_pipe_now is true, the pipe is created
131 : // immediately. Otherwise it's created on the IO thread.
132 : ChannelProxy(const std::wstring& channel_id, Channel::Mode mode,
133 : MessageLoop* ipc_thread_loop, Context* context,
134 : bool create_pipe_now);
135 :
136 : // Used internally to hold state that is referenced on the IPC thread.
137 : class Context : public base::RefCountedThreadSafe<Context>,
138 : public Channel::Listener {
139 : public:
140 : Context(Channel::Listener* listener, MessageFilter* filter,
141 : MessageLoop* ipc_thread);
142 0 : virtual ~Context() { }
143 0 : MessageLoop* ipc_message_loop() const { return ipc_message_loop_; }
144 0 : const std::wstring& channel_id() const { return channel_id_; }
145 :
146 : // Dispatches a message on the listener thread.
147 : void OnDispatchMessage(const Message& message);
148 :
149 : protected:
150 : // IPC::Channel::Listener methods:
151 : virtual void OnMessageReceived(const Message& message);
152 : virtual void OnChannelConnected(int32 peer_pid);
153 : virtual void OnChannelError();
154 :
155 : // Like OnMessageReceived but doesn't try the filters.
156 : void OnMessageReceivedNoFilter(const Message& message);
157 :
158 : // Gives the filters a chance at processing |message|.
159 : // Returns true if the message was processed, false otherwise.
160 : bool TryFilters(const Message& message);
161 :
162 : // Like Open and Close, but called on the IPC thread.
163 : virtual void OnChannelOpened();
164 : virtual void OnChannelClosed();
165 :
166 : // Called on the consumers thread when the ChannelProxy is closed. At that
167 : // point the consumer is telling us that they don't want to receive any
168 : // more messages, so we honor that wish by forgetting them!
169 0 : virtual void Clear() { listener_ = NULL; }
170 :
171 : private:
172 : friend class ChannelProxy;
173 : // Create the Channel
174 : void CreateChannel(const std::wstring& id, const Channel::Mode& mode);
175 :
176 : // Methods called via InvokeLater:
177 : void OnSendMessage(Message* message_ptr);
178 : void OnAddFilter(MessageFilter* filter);
179 : void OnRemoveFilter(MessageFilter* filter);
180 : void OnDispatchConnected();
181 : void OnDispatchError();
182 :
183 : MessageLoop* listener_message_loop_;
184 : Channel::Listener* listener_;
185 :
186 : // List of filters. This is only accessed on the IPC thread.
187 : std::vector<scoped_refptr<MessageFilter> > filters_;
188 : MessageLoop* ipc_message_loop_;
189 : Channel* channel_;
190 : std::wstring channel_id_;
191 : int peer_pid_;
192 : bool channel_connected_called_;
193 : };
194 :
195 0 : Context* context() { return context_; }
196 :
197 : private:
198 : void Init(const std::wstring& channel_id, Channel::Mode mode,
199 : MessageLoop* ipc_thread_loop, bool create_pipe_now);
200 :
201 : // By maintaining this indirection (ref-counted) to our internal state, we
202 : // can safely be destroyed while the background thread continues to do stuff
203 : // that involves this data.
204 : scoped_refptr<Context> context_;
205 : };
206 :
207 : } // namespace IPC
208 :
209 : #endif // CHROME_COMMON_IPC_CHANNEL_PROXY_H__
|