Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(256)

Side by Side Diff: ipc/ipc_channel_proxy.cc

Issue 142923005: Allow MessageFilters to restrict listening to specific message classes (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: DCHECK valid message class OR special message type Created 6 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « ipc/ipc_channel_proxy.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "base/bind.h" 5 #include "base/bind.h"
6 #include "base/compiler_specific.h" 6 #include "base/compiler_specific.h"
7 #include "base/debug/trace_event.h" 7 #include "base/debug/trace_event.h"
8 #include "base/location.h" 8 #include "base/location.h"
9 #include "base/memory/ref_counted.h" 9 #include "base/memory/ref_counted.h"
10 #include "base/memory/scoped_ptr.h" 10 #include "base/memory/scoped_ptr.h"
11 #include "base/single_thread_task_runner.h" 11 #include "base/single_thread_task_runner.h"
12 #include "base/thread_task_runner_handle.h" 12 #include "base/thread_task_runner_handle.h"
13 #include "ipc/ipc_channel_proxy.h" 13 #include "ipc/ipc_channel_proxy.h"
14 #include "ipc/ipc_listener.h" 14 #include "ipc/ipc_listener.h"
15 #include "ipc/ipc_logging.h" 15 #include "ipc/ipc_logging.h"
16 #include "ipc/ipc_message_macros.h" 16 #include "ipc/ipc_message_macros.h"
17 #include "ipc/ipc_message_utils.h" 17 #include "ipc/ipc_message_utils.h"
18 18
19 namespace IPC { 19 namespace IPC {
20 namespace {
21
22 bool ValidMessageClass(int message_class) {
23 return message_class >= 0 && message_class < LastIPCMsgStart;
24 }
25
26 bool EraseFilter(const ChannelProxy::MessageFilter* filter,
27 std::vector<ChannelProxy::MessageFilter*>& filters) {
28 std::vector<ChannelProxy::MessageFilter*>::iterator it =
29 std::find(filters.begin(), filters.end(), filter);
30 if (it == filters.end())
31 return false;
32
33 filters.erase(it);
34 return true;
35 }
36
37 bool ApplyFilters(std::vector<ChannelProxy::MessageFilter*>& filters,
38 const IPC::Message& message,
39 const std::string& channel_id) {
40 #ifdef IPC_MESSAGE_LOG_ENABLED
41 Logging* logger = Logging::GetInstance();
42 #endif
43
44 for (size_t i = 0; i < filters.size(); ++i) {
45 if (filters[i]->OnMessageReceived(message)) {
46 #ifdef IPC_MESSAGE_LOG_ENABLED
47 if (logger->Enabled())
48 logger->OnPostDispatchMessage(message, channel_id);
49 #endif
50 return true;
51 }
52 }
53 return false;
54 }
55
56 } // namespace
20 57
21 //------------------------------------------------------------------------------ 58 //------------------------------------------------------------------------------
22 59
23 ChannelProxy::MessageFilter::MessageFilter() {} 60 ChannelProxy::MessageFilter::MessageFilter() {}
24 61
25 void ChannelProxy::MessageFilter::OnFilterAdded(Channel* channel) {} 62 void ChannelProxy::MessageFilter::OnFilterAdded(Channel* channel) {}
26 63
27 void ChannelProxy::MessageFilter::OnFilterRemoved() {} 64 void ChannelProxy::MessageFilter::OnFilterRemoved() {}
28 65
29 void ChannelProxy::MessageFilter::OnChannelConnected(int32 peer_pid) {} 66 void ChannelProxy::MessageFilter::OnChannelConnected(int32 peer_pid) {}
30 67
31 void ChannelProxy::MessageFilter::OnChannelError() {} 68 void ChannelProxy::MessageFilter::OnChannelError() {}
32 69
33 void ChannelProxy::MessageFilter::OnChannelClosing() {} 70 void ChannelProxy::MessageFilter::OnChannelClosing() {}
34 71
35 bool ChannelProxy::MessageFilter::OnMessageReceived(const Message& message) { 72 bool ChannelProxy::MessageFilter::OnMessageReceived(const Message& message) {
36 return false; 73 return false;
37 } 74 }
38 75
76 bool ChannelProxy::MessageFilter::GetSupportedMessageClasses(
77 std::vector<uint32>* /*supported_message_classes*/) const {
78 return false;
79 }
80
39 ChannelProxy::MessageFilter::~MessageFilter() {} 81 ChannelProxy::MessageFilter::~MessageFilter() {}
40 82
41 //------------------------------------------------------------------------------ 83 //------------------------------------------------------------------------------
42 84
43 ChannelProxy::Context::Context(Listener* listener, 85 ChannelProxy::Context::Context(Listener* listener,
44 base::SingleThreadTaskRunner* ipc_task_runner) 86 base::SingleThreadTaskRunner* ipc_task_runner)
45 : listener_task_runner_(base::ThreadTaskRunnerHandle::Get()), 87 : listener_task_runner_(base::ThreadTaskRunnerHandle::Get()),
46 listener_(listener), 88 listener_(listener),
47 ipc_task_runner_(ipc_task_runner), 89 ipc_task_runner_(ipc_task_runner),
48 channel_connected_called_(false), 90 channel_connected_called_(false),
(...skipping 15 matching lines...) Expand all
64 channel_.reset(new Channel(handle, mode, this)); 106 channel_.reset(new Channel(handle, mode, this));
65 } 107 }
66 108
67 bool ChannelProxy::Context::TryFilters(const Message& message) { 109 bool ChannelProxy::Context::TryFilters(const Message& message) {
68 #ifdef IPC_MESSAGE_LOG_ENABLED 110 #ifdef IPC_MESSAGE_LOG_ENABLED
69 Logging* logger = Logging::GetInstance(); 111 Logging* logger = Logging::GetInstance();
70 if (logger->Enabled()) 112 if (logger->Enabled())
71 logger->OnPreDispatchMessage(message); 113 logger->OnPreDispatchMessage(message);
72 #endif 114 #endif
73 115
74 for (size_t i = 0; i < filters_.size(); ++i) { 116 if (ApplyFilters(message_global_filters_, message, channel_id_))
75 if (filters_[i]->OnMessageReceived(message)) { 117 return true;
76 #ifdef IPC_MESSAGE_LOG_ENABLED 118
77 if (logger->Enabled()) 119 const int message_class = IPC_MESSAGE_CLASS(message);
78 logger->OnPostDispatchMessage(message, channel_id_); 120 if (!ValidMessageClass(message_class)) {
79 #endif 121 DCHECK(message.type() == IPC_REPLY_ID || message.type() == IPC_LOGGING_ID)
80 return true; 122 << "Invalid message class: " << message_class;
piman 2014/02/12 02:37:29 You can DLOG_IF(ERROR), but don't DCHECK. The path
jdduke (slow) 2014/02/13 19:55:26 Right, makes perfect sense.
81 } 123 return false;
82 } 124 }
83 return false; 125
126 return ApplyFilters(message_class_filters_[message_class],
127 message,
128 channel_id_);
84 } 129 }
85 130
86 // Called on the IPC::Channel thread 131 // Called on the IPC::Channel thread
87 bool ChannelProxy::Context::OnMessageReceived(const Message& message) { 132 bool ChannelProxy::Context::OnMessageReceived(const Message& message) {
88 // First give a chance to the filters to process this message. 133 // First give a chance to the filters to process this message.
89 if (!TryFilters(message)) 134 if (!TryFilters(message))
90 OnMessageReceivedNoFilter(message); 135 OnMessageReceivedNoFilter(message);
91 return true; 136 return true;
92 } 137 }
93 138
94 // Called on the IPC::Channel thread 139 // Called on the IPC::Channel thread
95 bool ChannelProxy::Context::OnMessageReceivedNoFilter(const Message& message) { 140 bool ChannelProxy::Context::OnMessageReceivedNoFilter(const Message& message) {
96 listener_task_runner_->PostTask( 141 listener_task_runner_->PostTask(
97 FROM_HERE, base::Bind(&Context::OnDispatchMessage, this, message)); 142 FROM_HERE, base::Bind(&Context::OnDispatchMessage, this, message));
98 return true; 143 return true;
99 } 144 }
100 145
101 // Called on the IPC::Channel thread 146 // Called on the IPC::Channel thread
102 void ChannelProxy::Context::OnChannelConnected(int32 peer_pid) { 147 void ChannelProxy::Context::OnChannelConnected(int32 peer_pid) {
103 // Add any pending filters. This avoids a race condition where someone 148 // Add any pending filters. This avoids a race condition where someone
104 // creates a ChannelProxy, calls AddFilter, and then right after starts the 149 // creates a ChannelProxy, calls AddFilter, and then right after starts the
105 // peer process. The IO thread could receive a message before the task to add 150 // peer process. The IO thread could receive a message before the task to add
106 // the filter is run on the IO thread. 151 // the filter is run on the IO thread.
107 OnAddFilter(); 152 OnAddFilter();
108 153
109 // We cache off the peer_pid so it can be safely accessed from both threads. 154 // We cache off the peer_pid so it can be safely accessed from both threads.
110 peer_pid_ = channel_->peer_pid(); 155 peer_pid_ = channel_->peer_pid();
111 for (size_t i = 0; i < filters_.size(); ++i) 156 for (size_t i = 0; i < all_filters_.size(); ++i)
112 filters_[i]->OnChannelConnected(peer_pid); 157 all_filters_[i]->OnChannelConnected(peer_pid);
113 158
114 // See above comment about using listener_task_runner_ here. 159 // See above comment about using listener_task_runner_ here.
115 listener_task_runner_->PostTask( 160 listener_task_runner_->PostTask(
116 FROM_HERE, base::Bind(&Context::OnDispatchConnected, this)); 161 FROM_HERE, base::Bind(&Context::OnDispatchConnected, this));
117 } 162 }
118 163
119 // Called on the IPC::Channel thread 164 // Called on the IPC::Channel thread
120 void ChannelProxy::Context::OnChannelError() { 165 void ChannelProxy::Context::OnChannelError() {
121 for (size_t i = 0; i < filters_.size(); ++i) 166 for (size_t i = 0; i < all_filters_.size(); ++i)
122 filters_[i]->OnChannelError(); 167 all_filters_[i]->OnChannelError();
123 168
124 // See above comment about using listener_task_runner_ here. 169 // See above comment about using listener_task_runner_ here.
125 listener_task_runner_->PostTask( 170 listener_task_runner_->PostTask(
126 FROM_HERE, base::Bind(&Context::OnDispatchError, this)); 171 FROM_HERE, base::Bind(&Context::OnDispatchError, this));
127 } 172 }
128 173
129 // Called on the IPC::Channel thread 174 // Called on the IPC::Channel thread
130 void ChannelProxy::Context::OnChannelOpened() { 175 void ChannelProxy::Context::OnChannelOpened() {
131 DCHECK(channel_ != NULL); 176 DCHECK(channel_ != NULL);
132 177
133 // Assume a reference to ourselves on behalf of this thread. This reference 178 // Assume a reference to ourselves on behalf of this thread. This reference
134 // will be released when we are closed. 179 // will be released when we are closed.
135 AddRef(); 180 AddRef();
136 181
137 if (!channel_->Connect()) { 182 if (!channel_->Connect()) {
138 OnChannelError(); 183 OnChannelError();
139 return; 184 return;
140 } 185 }
141 186
142 for (size_t i = 0; i < filters_.size(); ++i) 187 for (size_t i = 0; i < all_filters_.size(); ++i)
143 filters_[i]->OnFilterAdded(channel_.get()); 188 all_filters_[i]->OnFilterAdded(channel_.get());
144 } 189 }
145 190
146 // Called on the IPC::Channel thread 191 // Called on the IPC::Channel thread
147 void ChannelProxy::Context::OnChannelClosed() { 192 void ChannelProxy::Context::OnChannelClosed() {
148 // It's okay for IPC::ChannelProxy::Close to be called more than once, which 193 // It's okay for IPC::ChannelProxy::Close to be called more than once, which
149 // would result in this branch being taken. 194 // would result in this branch being taken.
150 if (!channel_.get()) 195 if (!channel_.get())
151 return; 196 return;
152 197
153 for (size_t i = 0; i < filters_.size(); ++i) { 198 for (size_t i = 0; i < all_filters_.size(); ++i) {
154 filters_[i]->OnChannelClosing(); 199 all_filters_[i]->OnChannelClosing();
155 filters_[i]->OnFilterRemoved(); 200 all_filters_[i]->OnFilterRemoved();
156 } 201 }
157 202
158 // We don't need the filters anymore. 203 // We don't need the filters anymore.
159 filters_.clear(); 204 all_filters_.clear();
205 message_global_filters_.clear();
206 for (size_t i = 0; i < LastIPCMsgStart; ++i)
207 message_class_filters_[i].clear();
160 208
161 channel_.reset(); 209 channel_.reset();
162 210
163 // Balance with the reference taken during startup. This may result in 211 // Balance with the reference taken during startup. This may result in
164 // self-destruction. 212 // self-destruction.
165 Release(); 213 Release();
166 } 214 }
167 215
168 void ChannelProxy::Context::Clear() { 216 void ChannelProxy::Context::Clear() {
169 listener_ = NULL; 217 listener_ = NULL;
(...skipping 10 matching lines...) Expand all
180 } 228 }
181 229
182 // Called on the IPC::Channel thread 230 // Called on the IPC::Channel thread
183 void ChannelProxy::Context::OnAddFilter() { 231 void ChannelProxy::Context::OnAddFilter() {
184 std::vector<scoped_refptr<MessageFilter> > new_filters; 232 std::vector<scoped_refptr<MessageFilter> > new_filters;
185 { 233 {
186 base::AutoLock auto_lock(pending_filters_lock_); 234 base::AutoLock auto_lock(pending_filters_lock_);
187 new_filters.swap(pending_filters_); 235 new_filters.swap(pending_filters_);
188 } 236 }
189 237
238 std::vector<uint32> supported_message_classes;
190 for (size_t i = 0; i < new_filters.size(); ++i) { 239 for (size_t i = 0; i < new_filters.size(); ++i) {
191 filters_.push_back(new_filters[i]); 240 all_filters_.push_back(new_filters[i]);
241
242 // Determine if the filter should be applied to all messages, or only
243 // messages of a certain class.
244 MessageFilter* filter = new_filters[i].get();
245 if (filter->GetSupportedMessageClasses(&supported_message_classes)) {
246 DCHECK(!supported_message_classes.empty());
247 for (size_t i = 0; i < supported_message_classes.size(); ++i) {
248 DCHECK(ValidMessageClass(supported_message_classes[i]));
249 message_class_filters_[supported_message_classes[i]].push_back(filter);
250 }
251 } else {
252 message_global_filters_.push_back(filter);
253 }
254 supported_message_classes.clear();
192 255
193 // If the channel has already been created, then we need to send this 256 // If the channel has already been created, then we need to send this
194 // message so that the filter gets access to the Channel. 257 // message so that the filter gets access to the Channel.
195 if (channel_.get()) 258 if (channel_.get())
196 new_filters[i]->OnFilterAdded(channel_.get()); 259 filter->OnFilterAdded(channel_.get());
197 // Ditto for if the channel has been connected. 260 // Ditto for if the channel has been connected.
198 if (peer_pid_) 261 if (peer_pid_)
199 new_filters[i]->OnChannelConnected(peer_pid_); 262 filter->OnChannelConnected(peer_pid_);
200 } 263 }
201 } 264 }
202 265
203 // Called on the IPC::Channel thread 266 // Called on the IPC::Channel thread
204 void ChannelProxy::Context::OnRemoveFilter(MessageFilter* filter) { 267 void ChannelProxy::Context::OnRemoveFilter(MessageFilter* filter) {
205 if (!channel_.get()) 268 if (!channel_.get())
206 return; // The filters have already been deleted. 269 return; // The filters have already been deleted.
207 270
208 for (size_t i = 0; i < filters_.size(); ++i) { 271 bool filter_exists = false;
209 if (filters_[i].get() == filter) { 272 for (size_t i = 0; i < all_filters_.size(); ++i) {
273 if (all_filters_[i].get() == filter) {
210 filter->OnFilterRemoved(); 274 filter->OnFilterRemoved();
211 filters_.erase(filters_.begin() + i); 275 all_filters_.erase(all_filters_.begin() + i);
212 return; 276 filter_exists = true;
277 break;
213 } 278 }
214 } 279 }
215 280
216 NOTREACHED() << "filter to be removed not found"; 281 if (!filter_exists) {
282 NOTREACHED() << "filter to be removed not found";
283 return;
284 }
285
286 if (EraseFilter(filter, message_global_filters_))
287 return;
288
289 for (size_t i = 0; i < LastIPCMsgStart; ++i)
290 EraseFilter(filter, message_class_filters_[i]);
217 } 291 }
218 292
219 // Called on the listener's thread 293 // Called on the listener's thread
220 void ChannelProxy::Context::AddFilter(MessageFilter* filter) { 294 void ChannelProxy::Context::AddFilter(MessageFilter* filter) {
221 base::AutoLock auto_lock(pending_filters_lock_); 295 base::AutoLock auto_lock(pending_filters_lock_);
222 pending_filters_.push_back(make_scoped_refptr(filter)); 296 pending_filters_.push_back(make_scoped_refptr(filter));
223 ipc_task_runner_->PostTask( 297 ipc_task_runner_->PostTask(
224 FROM_HERE, base::Bind(&Context::OnAddFilter, this)); 298 FROM_HERE, base::Bind(&Context::OnAddFilter, this));
225 } 299 }
226 300
(...skipping 184 matching lines...) Expand 10 before | Expand all | Expand 10 after
411 Channel* channel = context_.get()->channel_.get(); 485 Channel* channel = context_.get()->channel_.get();
412 // Channel must have been created first. 486 // Channel must have been created first.
413 DCHECK(channel) << context_.get()->channel_id_; 487 DCHECK(channel) << context_.get()->channel_id_;
414 return channel->GetPeerEuid(peer_euid); 488 return channel->GetPeerEuid(peer_euid);
415 } 489 }
416 #endif 490 #endif
417 491
418 //----------------------------------------------------------------------------- 492 //-----------------------------------------------------------------------------
419 493
420 } // namespace IPC 494 } // namespace IPC
OLDNEW
« no previous file with comments | « ipc/ipc_channel_proxy.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698