|
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_t 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 ~ChannelProxy() { |
|
95 Close(); |
|
96 } |
|
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 virtual ~Context() { } |
|
143 MessageLoop* ipc_message_loop() const { return ipc_message_loop_; } |
|
144 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_t 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 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 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__ |