blob: e76e56f6ee7da20996ebeabe31ee3745d6355be7 [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"
alexeypa@chromium.org0192ff02012-12-05 10:00:36 +090013#include "base/threading/non_thread_safe.h"
agl@chromium.org1c6dcf22009-07-23 08:57:21 +090014#include "ipc/ipc_channel.h"
dmaclach@chromium.org058c4a72010-12-09 04:28:09 +090015#include "ipc/ipc_channel_handle.h"
brettw@chromium.orgf947ed02012-06-12 07:35:26 +090016#include "ipc/ipc_listener.h"
17#include "ipc/ipc_sender.h"
agl@chromium.org1c6dcf22009-07-23 08:57:21 +090018
sergeyu@chromium.org5b6d49c2012-07-03 06:15:52 +090019namespace base {
20class SingleThreadTaskRunner;
21}
22
agl@chromium.org1c6dcf22009-07-23 08:57:21 +090023namespace IPC {
24
morrita@chromium.org15996aa2014-08-05 08:44:17 +090025class ChannelFactory;
dmichael@chromium.orgc0c370e2014-04-25 09:07:30 +090026class MessageFilter;
27class MessageFilterRouter;
jhawkins@chromium.orge34d0ad2011-11-29 11:24:28 +090028class SendCallbackHelper;
jcampan@chromium.org1c86b552009-07-29 07:09:45 +090029
agl@chromium.org1c6dcf22009-07-23 08:57:21 +090030//-----------------------------------------------------------------------------
31// IPC::ChannelProxy
32//
33// This class is a helper class that is useful when you wish to run an IPC
34// channel on a background thread. It provides you with the option of either
35// handling IPC messages on that background thread or having them dispatched to
36// your main thread (the thread on which the IPC::ChannelProxy is created).
37//
38// The API for an IPC::ChannelProxy is very similar to that of an IPC::Channel.
39// When you send a message to an IPC::ChannelProxy, the message is routed to
40// the background thread, where it is then passed to the IPC::Channel's Send
41// method. This means that you can send a message from your thread and your
42// message will be sent over the IPC channel when possible instead of being
43// delayed until your thread returns to its message loop. (Often IPC messages
44// will queue up on the IPC::Channel when there is a lot of traffic, and the
45// channel will not get cycles to flush its message queue until the thread, on
46// which it is running, returns to its message loop.)
47//
48// An IPC::ChannelProxy can have a MessageFilter associated with it, which will
49// be notified of incoming messages on the IPC::Channel's thread. This gives
50// the consumer of IPC::ChannelProxy the ability to respond to incoming
51// messages on this background thread instead of on their own thread, which may
52// be bogged down with other processing. The result can be greatly improved
53// latency for messages that can be handled on a background thread.
54//
55// The consumer of IPC::ChannelProxy is responsible for allocating the Thread
56// instance where the IPC::Channel will be created and operated.
57//
alexeypa@chromium.org0192ff02012-12-05 10:00:36 +090058class IPC_EXPORT ChannelProxy : public Sender, public base::NonThreadSafe {
agl@chromium.org1c6dcf22009-07-23 08:57:21 +090059 public:
dmaclach@chromium.org058c4a72010-12-09 04:28:09 +090060 // Initializes a channel proxy. The channel_handle and mode parameters are
agl@chromium.org1c6dcf22009-07-23 08:57:21 +090061 // passed directly to the underlying IPC::Channel. The listener is called on
62 // the thread that creates the ChannelProxy. The filter's OnMessageReceived
63 // method is called on the thread where the IPC::Channel is running. The
64 // filter may be null if the consumer is not interested in handling messages
65 // on the background thread. Any message not handled by the filter will be
sergeyu@chromium.org5b6d49c2012-07-03 06:15:52 +090066 // dispatched to the listener. The given task runner correspond to a thread
67 // on which IPC::Channel is created and used (e.g. IO thread).
morrita@chromium.org15b48602014-06-06 01:15:38 +090068 static scoped_ptr<ChannelProxy> Create(
69 const IPC::ChannelHandle& channel_handle,
70 Channel::Mode mode,
71 Listener* listener,
72 base::SingleThreadTaskRunner* ipc_task_runner);
agl@chromium.org1c6dcf22009-07-23 08:57:21 +090073
morrita@chromium.org15996aa2014-08-05 08:44:17 +090074 static scoped_ptr<ChannelProxy> Create(
75 scoped_ptr<ChannelFactory> factory,
76 Listener* listener,
77 base::SingleThreadTaskRunner* ipc_task_runner);
78
erg@google.com2ec53b42010-09-24 07:43:53 +090079 virtual ~ChannelProxy();
agl@chromium.org1c6dcf22009-07-23 08:57:21 +090080
kkania@chromium.org9ccb4692011-11-16 10:06:46 +090081 // Initializes the channel proxy. Only call this once to initialize a channel
82 // proxy that was not initialized in its constructor. If create_pipe_now is
83 // true, the pipe is created synchronously. Otherwise it's created on the IO
84 // thread.
lambroslambrou@chromium.org773476a2014-06-03 05:29:30 +090085 void Init(const IPC::ChannelHandle& channel_handle, Channel::Mode mode,
86 bool create_pipe_now);
morrita@chromium.org15996aa2014-08-05 08:44:17 +090087 void Init(scoped_ptr<ChannelFactory> factory, bool create_pipe_now);
kkania@chromium.org9ccb4692011-11-16 10:06:46 +090088
agl@chromium.org1c6dcf22009-07-23 08:57:21 +090089 // Close the IPC::Channel. This operation completes asynchronously, once the
90 // background thread processes the command to close the channel. It is ok to
91 // call this method multiple times. Redundant calls are ignored.
92 //
dmichael@chromium.orgc0c370e2014-04-25 09:07:30 +090093 // WARNING: MessageFilter objects held by the ChannelProxy is also
agl@chromium.org1c6dcf22009-07-23 08:57:21 +090094 // released asynchronously, and it may in fact have its final reference
95 // released on the background thread. The caller should be careful to deal
96 // with / allow for this possibility.
97 void Close();
98
99 // Send a message asynchronously. The message is routed to the background
100 // thread where it is passed to the IPC::Channel's Send method.
avi@chromium.org362c8a82011-11-18 01:09:44 +0900101 virtual bool Send(Message* message) OVERRIDE;
agl@chromium.org1c6dcf22009-07-23 08:57:21 +0900102
103 // Used to intercept messages as they are received on the background thread.
104 //
105 // Ordinarily, messages sent to the ChannelProxy are routed to the matching
106 // listener on the worker thread. This API allows code to intercept messages
107 // before they are sent to the worker thread.
jam@chromium.orge57135c2010-12-03 04:16:07 +0900108 // If you call this before the target process is launched, then you're
109 // guaranteed to not miss any messages. But if you call this anytime after,
110 // then some messages might be missed since the filter is added internally on
111 // the IO thread.
agl@chromium.org1c6dcf22009-07-23 08:57:21 +0900112 void AddFilter(MessageFilter* filter);
113 void RemoveFilter(MessageFilter* filter);
114
sergeyu@chromium.org5b6d49c2012-07-03 06:15:52 +0900115 // Called to clear the pointer to the IPC task runner when it's going away.
116 void ClearIPCTaskRunner();
nsylvain@chromium.orgc12dde32009-07-24 03:17:55 +0900117
jschuh@chromium.orga5cd0762012-04-05 11:38:34 +0900118 // Get the process ID for the connected peer.
119 // Returns base::kNullProcessId if the peer is not connected yet.
morrita@chromium.orgfde2b6b2014-06-07 05:13:51 +0900120 base::ProcessId GetPeerPID() const { return context_->peer_pid_; }
jschuh@chromium.orga5cd0762012-04-05 11:38:34 +0900121
dmichael@chromium.orgb798bb42012-06-01 04:37:54 +0900122#if defined(OS_POSIX) && !defined(OS_NACL)
agl@chromium.org1c6dcf22009-07-23 08:57:21 +0900123 // Calls through to the underlying channel's methods.
phajdan.jr@chromium.orgaf9455b2011-09-20 02:08:12 +0900124 int GetClientFileDescriptor();
125 int TakeClientFileDescriptor();
agl@chromium.org1c6dcf22009-07-23 08:57:21 +0900126#endif // defined(OS_POSIX)
127
128 protected:
129 class Context;
130 // A subclass uses this constructor if it needs to add more information
kkania@chromium.org9ccb4692011-11-16 10:06:46 +0900131 // to the internal state.
132 ChannelProxy(Context* context);
agl@chromium.org1c6dcf22009-07-23 08:57:21 +0900133
morrita@chromium.org15b48602014-06-06 01:15:38 +0900134 ChannelProxy(Listener* listener,
135 base::SingleThreadTaskRunner* ipc_task_runner);
136
agl@chromium.org1c6dcf22009-07-23 08:57:21 +0900137 // Used internally to hold state that is referenced on the IPC thread.
138 class Context : public base::RefCountedThreadSafe<Context>,
brettw@chromium.orgf947ed02012-06-12 07:35:26 +0900139 public Listener {
agl@chromium.org1c6dcf22009-07-23 08:57:21 +0900140 public:
sergeyu@chromium.org5b6d49c2012-07-03 06:15:52 +0900141 Context(Listener* listener, base::SingleThreadTaskRunner* ipc_thread);
142 void ClearIPCTaskRunner();
143 base::SingleThreadTaskRunner* ipc_task_runner() const {
rsleevi@chromium.org23b66232013-06-01 13:11:27 +0900144 return ipc_task_runner_.get();
jam@chromium.org06d18442011-05-03 03:00:49 +0900145 }
agl@chromium.org1c6dcf22009-07-23 08:57:21 +0900146 const std::string& channel_id() const { return channel_id_; }
147
148 // Dispatches a message on the listener thread.
149 void OnDispatchMessage(const Message& message);
150
151 protected:
jam@chromium.orgb1f47b22009-11-06 06:53:08 +0900152 friend class base::RefCountedThreadSafe<Context>;
jam@chromium.org06d18442011-05-03 03:00:49 +0900153 virtual ~Context();
jam@chromium.orgb1f47b22009-11-06 06:53:08 +0900154
brettw@chromium.orgf947ed02012-06-12 07:35:26 +0900155 // IPC::Listener methods:
evan@chromium.orgecc3f072011-08-17 06:09:25 +0900156 virtual bool OnMessageReceived(const Message& message) OVERRIDE;
157 virtual void OnChannelConnected(int32 peer_pid) OVERRIDE;
158 virtual void OnChannelError() OVERRIDE;
agl@chromium.org1c6dcf22009-07-23 08:57:21 +0900159
160 // Like OnMessageReceived but doesn't try the filters.
jam@chromium.org8a2c7842010-12-24 15:19:28 +0900161 bool OnMessageReceivedNoFilter(const Message& message);
agl@chromium.org1c6dcf22009-07-23 08:57:21 +0900162
163 // Gives the filters a chance at processing |message|.
164 // Returns true if the message was processed, false otherwise.
165 bool TryFilters(const Message& message);
166
167 // Like Open and Close, but called on the IPC thread.
168 virtual void OnChannelOpened();
169 virtual void OnChannelClosed();
170
171 // Called on the consumers thread when the ChannelProxy is closed. At that
172 // point the consumer is telling us that they don't want to receive any
173 // more messages, so we honor that wish by forgetting them!
hans@chromium.orge62750c2012-08-10 05:39:12 +0900174 virtual void Clear();
agl@chromium.org1c6dcf22009-07-23 08:57:21 +0900175
176 private:
177 friend class ChannelProxy;
jhawkins@chromium.orge34d0ad2011-11-29 11:24:28 +0900178 friend class SendCallbackHelper;
jam@chromium.orgb1f47b22009-11-06 06:53:08 +0900179
agl@chromium.org1c6dcf22009-07-23 08:57:21 +0900180 // Create the Channel
morrita@chromium.org15996aa2014-08-05 08:44:17 +0900181 void CreateChannel(scoped_ptr<ChannelFactory> factory);
agl@chromium.org1c6dcf22009-07-23 08:57:21 +0900182
jam@chromium.orge57135c2010-12-03 04:16:07 +0900183 // Methods called on the IO thread.
rsleevi@chromium.org997c1d42012-04-28 11:12:00 +0900184 void OnSendMessage(scoped_ptr<Message> message_ptr);
jam@chromium.orge57135c2010-12-03 04:16:07 +0900185 void OnAddFilter();
agl@chromium.org1c6dcf22009-07-23 08:57:21 +0900186 void OnRemoveFilter(MessageFilter* filter);
jam@chromium.orge57135c2010-12-03 04:16:07 +0900187
188 // Methods called on the listener thread.
189 void AddFilter(MessageFilter* filter);
agl@chromium.org1c6dcf22009-07-23 08:57:21 +0900190 void OnDispatchConnected();
191 void OnDispatchError();
jam@chromium.org822f1fb2014-05-16 08:06:07 +0900192 void OnDispatchBadMessage(const Message& message);
agl@chromium.org1c6dcf22009-07-23 08:57:21 +0900193
sergeyu@chromium.org5b6d49c2012-07-03 06:15:52 +0900194 scoped_refptr<base::SingleThreadTaskRunner> listener_task_runner_;
brettw@chromium.orgf947ed02012-06-12 07:35:26 +0900195 Listener* listener_;
agl@chromium.org1c6dcf22009-07-23 08:57:21 +0900196
197 // List of filters. This is only accessed on the IPC thread.
198 std::vector<scoped_refptr<MessageFilter> > filters_;
sergeyu@chromium.org5b6d49c2012-07-03 06:15:52 +0900199 scoped_refptr<base::SingleThreadTaskRunner> ipc_task_runner_;
dmichael@chromium.org31a16812014-03-21 06:00:50 +0900200
201 // Note, channel_ may be set on the Listener thread or the IPC thread.
202 // But once it has been set, it must only be read or cleared on the IPC
203 // thread.
dmaclach@chromium.org058c4a72010-12-09 04:28:09 +0900204 scoped_ptr<Channel> channel_;
agl@chromium.org1c6dcf22009-07-23 08:57:21 +0900205 std::string channel_id_;
agl@chromium.org1c6dcf22009-07-23 08:57:21 +0900206 bool channel_connected_called_;
jam@chromium.orge57135c2010-12-03 04:16:07 +0900207
jdduke@chromium.org03f232f2014-02-26 14:18:04 +0900208 // Routes a given message to a proper subset of |filters_|, depending
209 // on which message classes a filter might support.
jdduke@chromium.org03f232f2014-02-26 14:18:04 +0900210 scoped_ptr<MessageFilterRouter> message_filter_router_;
211
jam@chromium.orge57135c2010-12-03 04:16:07 +0900212 // Holds filters between the AddFilter call on the listerner thread and the
213 // IPC thread when they're added to filters_.
214 std::vector<scoped_refptr<MessageFilter> > pending_filters_;
215 // Lock for pending_filters_.
brettw@chromium.orgabe477a2011-01-21 13:55:52 +0900216 base::Lock pending_filters_lock_;
jschuh@chromium.orga5cd0762012-04-05 11:38:34 +0900217
218 // Cached copy of the peer process ID. Set on IPC but read on both IPC and
219 // listener threads.
220 base::ProcessId peer_pid_;
agl@chromium.org1c6dcf22009-07-23 08:57:21 +0900221 };
222
rsleevi@chromium.org23b66232013-06-01 13:11:27 +0900223 Context* context() { return context_.get(); }
agl@chromium.org1c6dcf22009-07-23 08:57:21 +0900224
225 private:
jhawkins@chromium.orge34d0ad2011-11-29 11:24:28 +0900226 friend class SendCallbackHelper;
jcampan@chromium.org1c86b552009-07-29 07:09:45 +0900227
agl@chromium.org1c6dcf22009-07-23 08:57:21 +0900228 // By maintaining this indirection (ref-counted) to our internal state, we
229 // can safely be destroyed while the background thread continues to do stuff
230 // that involves this data.
231 scoped_refptr<Context> context_;
tsepez@chromium.orge68ddef2011-05-05 02:14:16 +0900232
kkania@chromium.org9ccb4692011-11-16 10:06:46 +0900233 // Whether the channel has been initialized.
234 bool did_init_;
agl@chromium.org1c6dcf22009-07-23 08:57:21 +0900235};
236
237} // namespace IPC
238
jam@chromium.org06d18442011-05-03 03:00:49 +0900239#endif // IPC_IPC_CHANNEL_PROXY_H_