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

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: Address comments 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;
piman 2014/02/12 01:04:03 0 is actually valid.
jdduke (slow) 2014/02/12 02:12:39 Ugg, good catch.
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 NOTREACHED() << "Invalid message class: " << message_class;
piman 2014/02/12 01:04:03 Not NOTREACHED. This could be reached in 2 cases:
jdduke (slow) 2014/02/12 02:12:39 Ahh, I hadn't considered replies, I'll make a slig
80 return true; 122 return false;
81 }
82 } 123 }
83 return false; 124
125 return ApplyFilters(message_class_filters_[message_class],
126 message,
127 channel_id_);
84 } 128 }
85 129
86 // Called on the IPC::Channel thread 130 // Called on the IPC::Channel thread
87 bool ChannelProxy::Context::OnMessageReceived(const Message& message) { 131 bool ChannelProxy::Context::OnMessageReceived(const Message& message) {
88 // First give a chance to the filters to process this message. 132 // First give a chance to the filters to process this message.
89 if (!TryFilters(message)) 133 if (!TryFilters(message))
90 OnMessageReceivedNoFilter(message); 134 OnMessageReceivedNoFilter(message);
91 return true; 135 return true;
92 } 136 }
93 137
94 // Called on the IPC::Channel thread 138 // Called on the IPC::Channel thread
95 bool ChannelProxy::Context::OnMessageReceivedNoFilter(const Message& message) { 139 bool ChannelProxy::Context::OnMessageReceivedNoFilter(const Message& message) {
96 listener_task_runner_->PostTask( 140 listener_task_runner_->PostTask(
97 FROM_HERE, base::Bind(&Context::OnDispatchMessage, this, message)); 141 FROM_HERE, base::Bind(&Context::OnDispatchMessage, this, message));
98 return true; 142 return true;
99 } 143 }
100 144
101 // Called on the IPC::Channel thread 145 // Called on the IPC::Channel thread
102 void ChannelProxy::Context::OnChannelConnected(int32 peer_pid) { 146 void ChannelProxy::Context::OnChannelConnected(int32 peer_pid) {
103 // Add any pending filters. This avoids a race condition where someone 147 // Add any pending filters. This avoids a race condition where someone
104 // creates a ChannelProxy, calls AddFilter, and then right after starts the 148 // 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 149 // peer process. The IO thread could receive a message before the task to add
106 // the filter is run on the IO thread. 150 // the filter is run on the IO thread.
107 OnAddFilter(); 151 OnAddFilter();
108 152
109 // We cache off the peer_pid so it can be safely accessed from both threads. 153 // We cache off the peer_pid so it can be safely accessed from both threads.
110 peer_pid_ = channel_->peer_pid(); 154 peer_pid_ = channel_->peer_pid();
111 for (size_t i = 0; i < filters_.size(); ++i) 155 for (size_t i = 0; i < all_filters_.size(); ++i)
112 filters_[i]->OnChannelConnected(peer_pid); 156 all_filters_[i]->OnChannelConnected(peer_pid);
113 157
114 // See above comment about using listener_task_runner_ here. 158 // See above comment about using listener_task_runner_ here.
115 listener_task_runner_->PostTask( 159 listener_task_runner_->PostTask(
116 FROM_HERE, base::Bind(&Context::OnDispatchConnected, this)); 160 FROM_HERE, base::Bind(&Context::OnDispatchConnected, this));
117 } 161 }
118 162
119 // Called on the IPC::Channel thread 163 // Called on the IPC::Channel thread
120 void ChannelProxy::Context::OnChannelError() { 164 void ChannelProxy::Context::OnChannelError() {
121 for (size_t i = 0; i < filters_.size(); ++i) 165 for (size_t i = 0; i < all_filters_.size(); ++i)
122 filters_[i]->OnChannelError(); 166 all_filters_[i]->OnChannelError();
123 167
124 // See above comment about using listener_task_runner_ here. 168 // See above comment about using listener_task_runner_ here.
125 listener_task_runner_->PostTask( 169 listener_task_runner_->PostTask(
126 FROM_HERE, base::Bind(&Context::OnDispatchError, this)); 170 FROM_HERE, base::Bind(&Context::OnDispatchError, this));
127 } 171 }
128 172
129 // Called on the IPC::Channel thread 173 // Called on the IPC::Channel thread
130 void ChannelProxy::Context::OnChannelOpened() { 174 void ChannelProxy::Context::OnChannelOpened() {
131 DCHECK(channel_ != NULL); 175 DCHECK(channel_ != NULL);
132 176
133 // Assume a reference to ourselves on behalf of this thread. This reference 177 // Assume a reference to ourselves on behalf of this thread. This reference
134 // will be released when we are closed. 178 // will be released when we are closed.
135 AddRef(); 179 AddRef();
136 180
137 if (!channel_->Connect()) { 181 if (!channel_->Connect()) {
138 OnChannelError(); 182 OnChannelError();
139 return; 183 return;
140 } 184 }
141 185
142 for (size_t i = 0; i < filters_.size(); ++i) 186 for (size_t i = 0; i < all_filters_.size(); ++i)
143 filters_[i]->OnFilterAdded(channel_.get()); 187 all_filters_[i]->OnFilterAdded(channel_.get());
144 } 188 }
145 189
146 // Called on the IPC::Channel thread 190 // Called on the IPC::Channel thread
147 void ChannelProxy::Context::OnChannelClosed() { 191 void ChannelProxy::Context::OnChannelClosed() {
148 // It's okay for IPC::ChannelProxy::Close to be called more than once, which 192 // It's okay for IPC::ChannelProxy::Close to be called more than once, which
149 // would result in this branch being taken. 193 // would result in this branch being taken.
150 if (!channel_.get()) 194 if (!channel_.get())
151 return; 195 return;
152 196
153 for (size_t i = 0; i < filters_.size(); ++i) { 197 for (size_t i = 0; i < all_filters_.size(); ++i) {
154 filters_[i]->OnChannelClosing(); 198 all_filters_[i]->OnChannelClosing();
155 filters_[i]->OnFilterRemoved(); 199 all_filters_[i]->OnFilterRemoved();
156 } 200 }
157 201
158 // We don't need the filters anymore. 202 // We don't need the filters anymore.
159 filters_.clear(); 203 all_filters_.clear();
204 message_global_filters_.clear();
205 for (size_t i = 0; i < LastIPCMsgStart; ++i)
206 message_class_filters_[i].clear();
160 207
161 channel_.reset(); 208 channel_.reset();
162 209
163 // Balance with the reference taken during startup. This may result in 210 // Balance with the reference taken during startup. This may result in
164 // self-destruction. 211 // self-destruction.
165 Release(); 212 Release();
166 } 213 }
167 214
168 void ChannelProxy::Context::Clear() { 215 void ChannelProxy::Context::Clear() {
169 listener_ = NULL; 216 listener_ = NULL;
(...skipping 10 matching lines...) Expand all
180 } 227 }
181 228
182 // Called on the IPC::Channel thread 229 // Called on the IPC::Channel thread
183 void ChannelProxy::Context::OnAddFilter() { 230 void ChannelProxy::Context::OnAddFilter() {
184 std::vector<scoped_refptr<MessageFilter> > new_filters; 231 std::vector<scoped_refptr<MessageFilter> > new_filters;
185 { 232 {
186 base::AutoLock auto_lock(pending_filters_lock_); 233 base::AutoLock auto_lock(pending_filters_lock_);
187 new_filters.swap(pending_filters_); 234 new_filters.swap(pending_filters_);
188 } 235 }
189 236
237 std::vector<uint32> supported_message_classes;
190 for (size_t i = 0; i < new_filters.size(); ++i) { 238 for (size_t i = 0; i < new_filters.size(); ++i) {
191 filters_.push_back(new_filters[i]); 239 all_filters_.push_back(new_filters[i]);
240
241 // Determine if the filter should be applied to all messages, or only
242 // messages of a certain class.
243 MessageFilter* filter = new_filters[i].get();
244 if (filter->GetSupportedMessageClasses(&supported_message_classes)) {
245 DCHECK(!supported_message_classes.empty());
246 for (size_t i = 0; i < supported_message_classes.size(); ++i) {
247 DCHECK(ValidMessageClass(supported_message_classes[i]));
248 message_class_filters_[supported_message_classes[i]].push_back(filter);
249 }
250 } else {
251 message_global_filters_.push_back(filter);
252 }
253 supported_message_classes.clear();
192 254
193 // If the channel has already been created, then we need to send this 255 // If the channel has already been created, then we need to send this
194 // message so that the filter gets access to the Channel. 256 // message so that the filter gets access to the Channel.
195 if (channel_.get()) 257 if (channel_.get())
196 new_filters[i]->OnFilterAdded(channel_.get()); 258 filter->OnFilterAdded(channel_.get());
197 // Ditto for if the channel has been connected. 259 // Ditto for if the channel has been connected.
198 if (peer_pid_) 260 if (peer_pid_)
199 new_filters[i]->OnChannelConnected(peer_pid_); 261 filter->OnChannelConnected(peer_pid_);
200 } 262 }
201 } 263 }
202 264
203 // Called on the IPC::Channel thread 265 // Called on the IPC::Channel thread
204 void ChannelProxy::Context::OnRemoveFilter(MessageFilter* filter) { 266 void ChannelProxy::Context::OnRemoveFilter(MessageFilter* filter) {
205 if (!channel_.get()) 267 if (!channel_.get())
206 return; // The filters have already been deleted. 268 return; // The filters have already been deleted.
207 269
208 for (size_t i = 0; i < filters_.size(); ++i) { 270 bool filter_exists = false;
209 if (filters_[i].get() == filter) { 271 for (size_t i = 0; i < all_filters_.size(); ++i) {
272 if (all_filters_[i].get() == filter) {
210 filter->OnFilterRemoved(); 273 filter->OnFilterRemoved();
211 filters_.erase(filters_.begin() + i); 274 all_filters_.erase(all_filters_.begin() + i);
212 return; 275 filter_exists = true;
276 break;
213 } 277 }
214 } 278 }
215 279
216 NOTREACHED() << "filter to be removed not found"; 280 if (!filter_exists) {
281 NOTREACHED() << "filter to be removed not found";
282 return;
283 }
284
285 if (EraseFilter(filter, message_global_filters_))
286 return;
287
288 for (size_t i = 0; i < LastIPCMsgStart; ++i)
289 EraseFilter(filter, message_class_filters_[i]);
217 } 290 }
218 291
219 // Called on the listener's thread 292 // Called on the listener's thread
220 void ChannelProxy::Context::AddFilter(MessageFilter* filter) { 293 void ChannelProxy::Context::AddFilter(MessageFilter* filter) {
221 base::AutoLock auto_lock(pending_filters_lock_); 294 base::AutoLock auto_lock(pending_filters_lock_);
222 pending_filters_.push_back(make_scoped_refptr(filter)); 295 pending_filters_.push_back(make_scoped_refptr(filter));
223 ipc_task_runner_->PostTask( 296 ipc_task_runner_->PostTask(
224 FROM_HERE, base::Bind(&Context::OnAddFilter, this)); 297 FROM_HERE, base::Bind(&Context::OnAddFilter, this));
225 } 298 }
226 299
(...skipping 184 matching lines...) Expand 10 before | Expand all | Expand 10 after
411 Channel* channel = context_.get()->channel_.get(); 484 Channel* channel = context_.get()->channel_.get();
412 // Channel must have been created first. 485 // Channel must have been created first.
413 DCHECK(channel) << context_.get()->channel_id_; 486 DCHECK(channel) << context_.get()->channel_id_;
414 return channel->GetPeerEuid(peer_euid); 487 return channel->GetPeerEuid(peer_euid);
415 } 488 }
416 #endif 489 #endif
417 490
418 //----------------------------------------------------------------------------- 491 //-----------------------------------------------------------------------------
419 492
420 } // namespace IPC 493 } // 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