1 // Copyright 2012 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "ipc/ipc_channel_proxy.h"
6
7 #include <stddef.h>
8 #include <stdint.h>
9
10 #include <utility>
11
12 #include "base/compiler_specific.h"
13 #include "base/containers/contains.h"
14 #include "base/functional/bind.h"
15 #include "base/location.h"
16 #include "base/memory/ptr_util.h"
17 #include "base/memory/ref_counted.h"
18 #include "base/task/single_thread_task_runner.h"
19 #include "build/build_config.h"
20 #include "ipc/ipc_channel_factory.h"
21 #include "ipc/ipc_listener.h"
22 #include "ipc/ipc_logging.h"
23 #include "ipc/ipc_message_macros.h"
24 #include "ipc/message_filter.h"
25 #include "ipc/message_filter_router.h"
26 #include "mojo/public/cpp/bindings/pending_associated_receiver.h"
27
28 namespace IPC {
29
30 //------------------------------------------------------------------------------
31
Context(Listener * listener,const scoped_refptr<base::SingleThreadTaskRunner> & ipc_task_runner,const scoped_refptr<base::SingleThreadTaskRunner> & listener_task_runner)32 ChannelProxy::Context::Context(
33 Listener* listener,
34 const scoped_refptr<base::SingleThreadTaskRunner>& ipc_task_runner,
35 const scoped_refptr<base::SingleThreadTaskRunner>& listener_task_runner)
36 : default_listener_task_runner_(listener_task_runner),
37 listener_(listener),
38 ipc_task_runner_(ipc_task_runner),
39 channel_connected_called_(false),
40 message_filter_router_(new MessageFilterRouter()),
41 peer_pid_(base::kNullProcessId) {
42 DCHECK(ipc_task_runner_.get());
43 // The Listener thread where Messages are handled must be a separate thread
44 // to avoid oversubscribing the IO thread. If you trigger this error, you
45 // need to either:
46 // 1) Create the ChannelProxy on a different thread, or
47 // 2) Just use Channel
48 // We make an exception for NULL listeners.
49 DCHECK(!listener ||
50 (ipc_task_runner_.get() != default_listener_task_runner_.get()));
51 }
52
53 ChannelProxy::Context::~Context() = default;
54
ClearIPCTaskRunner()55 void ChannelProxy::Context::ClearIPCTaskRunner() {
56 ipc_task_runner_.reset();
57 }
58
CreateChannel(std::unique_ptr<ChannelFactory> factory)59 void ChannelProxy::Context::CreateChannel(
60 std::unique_ptr<ChannelFactory> factory) {
61 base::AutoLock channel_lock(channel_lifetime_lock_);
62 DCHECK(!channel_);
63 DCHECK_EQ(factory->GetIPCTaskRunner(), ipc_task_runner_);
64 channel_ = factory->BuildChannel(this);
65 channel_->SetUrgentMessageObserver(urgent_message_observer_);
66
67 Channel::AssociatedInterfaceSupport* support =
68 channel_->GetAssociatedInterfaceSupport();
69 if (support) {
70 thread_safe_channel_ = support->CreateThreadSafeChannel();
71
72 base::AutoLock filter_lock(pending_filters_lock_);
73 for (auto& entry : pending_io_thread_interfaces_)
74 support->AddGenericAssociatedInterface(entry.first, entry.second);
75 pending_io_thread_interfaces_.clear();
76 }
77 }
78
TryFilters(const Message & message)79 bool ChannelProxy::Context::TryFilters(const Message& message) {
80 DCHECK(message_filter_router_);
81 #if BUILDFLAG(IPC_MESSAGE_LOG_ENABLED)
82 Logging* logger = Logging::GetInstance();
83 if (logger->Enabled())
84 logger->OnPreDispatchMessage(message);
85 #endif
86
87 if (message_filter_router_->TryFilters(message)) {
88 if (message.dispatch_error()) {
89 GetTaskRunner(message.routing_id())
90 ->PostTask(FROM_HERE, base::BindOnce(&Context::OnDispatchBadMessage,
91 this, message));
92 }
93 #if BUILDFLAG(IPC_MESSAGE_LOG_ENABLED)
94 if (logger->Enabled())
95 logger->OnPostDispatchMessage(message);
96 #endif
97 return true;
98 }
99 return false;
100 }
101
102 // Called on the IPC::Channel thread
PauseChannel()103 void ChannelProxy::Context::PauseChannel() {
104 DCHECK(channel_);
105 channel_->Pause();
106 }
107
108 // Called on the IPC::Channel thread
UnpauseChannel(bool flush)109 void ChannelProxy::Context::UnpauseChannel(bool flush) {
110 DCHECK(channel_);
111 channel_->Unpause(flush);
112 }
113
114 // Called on the IPC::Channel thread
FlushChannel()115 void ChannelProxy::Context::FlushChannel() {
116 DCHECK(channel_);
117 channel_->Flush();
118 }
119
120 // Called on the IPC::Channel thread
OnMessageReceived(const Message & message)121 bool ChannelProxy::Context::OnMessageReceived(const Message& message) {
122 // First give a chance to the filters to process this message.
123 if (!TryFilters(message))
124 OnMessageReceivedNoFilter(message);
125 return true;
126 }
127
128 // Called on the IPC::Channel thread
OnMessageReceivedNoFilter(const Message & message)129 bool ChannelProxy::Context::OnMessageReceivedNoFilter(const Message& message) {
130 GetTaskRunner(message.routing_id())
131 ->PostTask(FROM_HERE,
132 base::BindOnce(&Context::OnDispatchMessage, this, message));
133 return true;
134 }
135
136 // Called on the IPC::Channel thread
OnChannelConnected(int32_t peer_pid)137 void ChannelProxy::Context::OnChannelConnected(int32_t peer_pid) {
138 // We cache off the peer_pid so it can be safely accessed from both threads.
139 {
140 base::AutoLock l(peer_pid_lock_);
141 peer_pid_ = peer_pid;
142 }
143
144 // Add any pending filters. This avoids a race condition where someone
145 // creates a ChannelProxy, calls AddFilter, and then right after starts the
146 // peer process. The IO thread could receive a message before the task to add
147 // the filter is run on the IO thread.
148 OnAddFilter();
149
150 // See above comment about using default_listener_task_runner_ here.
151 default_listener_task_runner_->PostTask(
152 FROM_HERE, base::BindOnce(&Context::OnDispatchConnected, this));
153 }
154
155 // Called on the IPC::Channel thread
OnChannelError()156 void ChannelProxy::Context::OnChannelError() {
157 for (size_t i = 0; i < filters_.size(); ++i)
158 filters_[i]->OnChannelError();
159
160 // See above comment about using default_listener_task_runner_ here.
161 default_listener_task_runner_->PostTask(
162 FROM_HERE, base::BindOnce(&Context::OnDispatchError, this));
163 }
164
165 // Called on the IPC::Channel thread
OnAssociatedInterfaceRequest(const std::string & interface_name,mojo::ScopedInterfaceEndpointHandle handle)166 void ChannelProxy::Context::OnAssociatedInterfaceRequest(
167 const std::string& interface_name,
168 mojo::ScopedInterfaceEndpointHandle handle) {
169 default_listener_task_runner_->PostTask(
170 FROM_HERE, base::BindOnce(&Context::OnDispatchAssociatedInterfaceRequest,
171 this, interface_name, std::move(handle)));
172 }
173
174 // Called on the IPC::Channel thread
OnChannelOpened()175 void ChannelProxy::Context::OnChannelOpened() {
176 DCHECK(channel_);
177
178 // Assume a reference to ourselves on behalf of this thread. This reference
179 // will be released when we are closed.
180 AddRef();
181
182 if (!channel_->Connect()) {
183 OnChannelError();
184 return;
185 }
186
187 for (size_t i = 0; i < filters_.size(); ++i)
188 filters_[i]->OnFilterAdded(channel_.get());
189 }
190
191 // Called on the IPC::Channel thread
OnChannelClosed()192 void ChannelProxy::Context::OnChannelClosed() {
193 // It's okay for IPC::ChannelProxy::Close to be called more than once, which
194 // would result in this branch being taken.
195 if (!channel_)
196 return;
197
198 for (auto& filter : pending_filters_) {
199 filter->OnChannelClosing();
200 filter->OnFilterRemoved();
201 }
202 for (auto& filter : filters_) {
203 filter->OnChannelClosing();
204 filter->OnFilterRemoved();
205 }
206
207 // We don't need the filters anymore.
208 message_filter_router_->Clear();
209 filters_.clear();
210 // We don't need the lock, because at this point, the listener thread can't
211 // access it any more.
212 pending_filters_.clear();
213
214 ClearChannel();
215
216 // Balance with the reference taken during startup. This may result in
217 // self-destruction.
218 Release();
219 }
220
Clear()221 void ChannelProxy::Context::Clear() {
222 listener_ = nullptr;
223 }
224
225 // Called on the IPC::Channel thread
OnSendMessage(std::unique_ptr<Message> message)226 void ChannelProxy::Context::OnSendMessage(std::unique_ptr<Message> message) {
227 if (!channel_) {
228 OnChannelClosed();
229 return;
230 }
231
232 if (!channel_->Send(message.release()))
233 OnChannelError();
234 }
235
236 // Called on the IPC::Channel thread
OnAddFilter()237 void ChannelProxy::Context::OnAddFilter() {
238 // Our OnChannelConnected method has not yet been called, so we can't be
239 // sure that channel_ is valid yet. When OnChannelConnected *is* called,
240 // it invokes OnAddFilter, so any pending filter(s) will be added at that
241 // time.
242 // No lock necessary for |peer_pid_| because it is only modified on this
243 // thread.
244 if (peer_pid_ == base::kNullProcessId)
245 return;
246
247 std::vector<scoped_refptr<MessageFilter> > new_filters;
248 {
249 base::AutoLock auto_lock(pending_filters_lock_);
250 new_filters.swap(pending_filters_);
251 }
252
253 for (size_t i = 0; i < new_filters.size(); ++i) {
254 filters_.push_back(new_filters[i]);
255
256 message_filter_router_->AddFilter(new_filters[i].get());
257
258 // The channel has already been created and connected, so we need to
259 // inform the filters right now.
260 new_filters[i]->OnFilterAdded(channel_.get());
261 new_filters[i]->OnChannelConnected(peer_pid_);
262 }
263 }
264
265 // Called on the IPC::Channel thread
OnRemoveFilter(MessageFilter * filter)266 void ChannelProxy::Context::OnRemoveFilter(MessageFilter* filter) {
267 // No lock necessary for |peer_pid_| because it is only modified on this
268 // thread.
269 if (peer_pid_ == base::kNullProcessId) {
270 // The channel is not yet connected, so any filters are still pending.
271 base::AutoLock auto_lock(pending_filters_lock_);
272 for (size_t i = 0; i < pending_filters_.size(); ++i) {
273 if (pending_filters_[i].get() == filter) {
274 filter->OnFilterRemoved();
275 pending_filters_.erase(pending_filters_.begin() + i);
276 return;
277 }
278 }
279 return;
280 }
281 if (!channel_)
282 return; // The filters have already been deleted.
283
284 message_filter_router_->RemoveFilter(filter);
285
286 for (size_t i = 0; i < filters_.size(); ++i) {
287 if (filters_[i].get() == filter) {
288 filter->OnFilterRemoved();
289 filters_.erase(filters_.begin() + i);
290 return;
291 }
292 }
293
294 NOTREACHED() << "filter to be removed not found";
295 }
296
297 // Called on the listener's thread
AddFilter(MessageFilter * filter)298 void ChannelProxy::Context::AddFilter(MessageFilter* filter) {
299 base::AutoLock auto_lock(pending_filters_lock_);
300 pending_filters_.push_back(base::WrapRefCounted(filter));
301 ipc_task_runner_->PostTask(FROM_HERE,
302 base::BindOnce(&Context::OnAddFilter, this));
303 }
304
305 // Called on the listener's thread
OnDispatchMessage(const Message & message)306 void ChannelProxy::Context::OnDispatchMessage(const Message& message) {
307 if (!listener_)
308 return;
309
310 OnDispatchConnected();
311
312 #if BUILDFLAG(IPC_MESSAGE_LOG_ENABLED)
313 Logging* logger = Logging::GetInstance();
314 if (message.type() == IPC_LOGGING_ID) {
315 logger->OnReceivedLoggingMessage(message);
316 return;
317 }
318
319 if (logger->Enabled())
320 logger->OnPreDispatchMessage(message);
321 #endif
322
323 listener_->OnMessageReceived(message);
324 if (message.dispatch_error())
325 listener_->OnBadMessageReceived(message);
326
327 #if BUILDFLAG(IPC_MESSAGE_LOG_ENABLED)
328 if (logger->Enabled())
329 logger->OnPostDispatchMessage(message);
330 #endif
331 }
332
333 // Called on the listener's thread.
AddListenerTaskRunner(int32_t routing_id,scoped_refptr<base::SingleThreadTaskRunner> task_runner)334 void ChannelProxy::Context::AddListenerTaskRunner(
335 int32_t routing_id,
336 scoped_refptr<base::SingleThreadTaskRunner> task_runner) {
337 DCHECK(default_listener_task_runner_->BelongsToCurrentThread());
338 DCHECK(task_runner);
339 base::AutoLock lock(listener_thread_task_runners_lock_);
340 if (!base::Contains(listener_thread_task_runners_, routing_id))
341 listener_thread_task_runners_.insert({routing_id, std::move(task_runner)});
342 }
343
344 // Called on the listener's thread.
RemoveListenerTaskRunner(int32_t routing_id)345 void ChannelProxy::Context::RemoveListenerTaskRunner(int32_t routing_id) {
346 DCHECK(default_listener_task_runner_->BelongsToCurrentThread());
347 base::AutoLock lock(listener_thread_task_runners_lock_);
348 listener_thread_task_runners_.erase(routing_id);
349 }
350
351 // Called on the IPC::Channel thread.
352 scoped_refptr<base::SingleThreadTaskRunner>
GetTaskRunner(int32_t routing_id)353 ChannelProxy::Context::GetTaskRunner(int32_t routing_id) {
354 DCHECK(ipc_task_runner_->BelongsToCurrentThread());
355 if (routing_id == MSG_ROUTING_NONE)
356 return default_listener_task_runner_;
357
358 base::AutoLock lock(listener_thread_task_runners_lock_);
359 auto task_runner = listener_thread_task_runners_.find(routing_id);
360 if (task_runner == listener_thread_task_runners_.end())
361 return default_listener_task_runner_;
362 DCHECK(task_runner->second);
363 return task_runner->second;
364 }
365
366 // Called on the listener's thread
OnDispatchConnected()367 void ChannelProxy::Context::OnDispatchConnected() {
368 if (channel_connected_called_)
369 return;
370
371 base::ProcessId peer_pid;
372 {
373 base::AutoLock l(peer_pid_lock_);
374 peer_pid = peer_pid_;
375 }
376 channel_connected_called_ = true;
377 if (listener_)
378 listener_->OnChannelConnected(peer_pid);
379 }
380
381 // Called on the listener's thread
OnDispatchError()382 void ChannelProxy::Context::OnDispatchError() {
383 if (listener_)
384 listener_->OnChannelError();
385 }
386
387 // Called on the listener's thread
OnDispatchBadMessage(const Message & message)388 void ChannelProxy::Context::OnDispatchBadMessage(const Message& message) {
389 if (listener_)
390 listener_->OnBadMessageReceived(message);
391 }
392
393 // Called on the listener's thread
OnDispatchAssociatedInterfaceRequest(const std::string & interface_name,mojo::ScopedInterfaceEndpointHandle handle)394 void ChannelProxy::Context::OnDispatchAssociatedInterfaceRequest(
395 const std::string& interface_name,
396 mojo::ScopedInterfaceEndpointHandle handle) {
397 if (listener_)
398 listener_->OnAssociatedInterfaceRequest(interface_name, std::move(handle));
399 }
400
ClearChannel()401 void ChannelProxy::Context::ClearChannel() {
402 base::AutoLock l(channel_lifetime_lock_);
403 channel_.reset();
404 }
405
AddGenericAssociatedInterfaceForIOThread(const std::string & name,const GenericAssociatedInterfaceFactory & factory)406 void ChannelProxy::Context::AddGenericAssociatedInterfaceForIOThread(
407 const std::string& name,
408 const GenericAssociatedInterfaceFactory& factory) {
409 base::AutoLock channel_lock(channel_lifetime_lock_);
410 if (!channel_) {
411 base::AutoLock filter_lock(pending_filters_lock_);
412 pending_io_thread_interfaces_.emplace_back(name, factory);
413 return;
414 }
415 Channel::AssociatedInterfaceSupport* support =
416 channel_->GetAssociatedInterfaceSupport();
417 if (support)
418 support->AddGenericAssociatedInterface(name, factory);
419 }
420
Send(Message * message)421 void ChannelProxy::Context::Send(Message* message) {
422 ipc_task_runner()->PostTask(
423 FROM_HERE, base::BindOnce(&ChannelProxy::Context::OnSendMessage, this,
424 base::WrapUnique(message)));
425 }
426
427 // Called on the listener's thread.
SetUrgentMessageObserver(UrgentMessageObserver * observer)428 void ChannelProxy::Context::SetUrgentMessageObserver(
429 UrgentMessageObserver* observer) {
430 urgent_message_observer_ = observer;
431 }
432
433 //-----------------------------------------------------------------------------
434
435 // static
Create(const IPC::ChannelHandle & channel_handle,Channel::Mode mode,Listener * listener,const scoped_refptr<base::SingleThreadTaskRunner> & ipc_task_runner,const scoped_refptr<base::SingleThreadTaskRunner> & listener_task_runner)436 std::unique_ptr<ChannelProxy> ChannelProxy::Create(
437 const IPC::ChannelHandle& channel_handle,
438 Channel::Mode mode,
439 Listener* listener,
440 const scoped_refptr<base::SingleThreadTaskRunner>& ipc_task_runner,
441 const scoped_refptr<base::SingleThreadTaskRunner>& listener_task_runner) {
442 std::unique_ptr<ChannelProxy> channel(
443 new ChannelProxy(listener, ipc_task_runner, listener_task_runner));
444 channel->Init(channel_handle, mode, true);
445 return channel;
446 }
447
448 // static
Create(std::unique_ptr<ChannelFactory> factory,Listener * listener,const scoped_refptr<base::SingleThreadTaskRunner> & ipc_task_runner,const scoped_refptr<base::SingleThreadTaskRunner> & listener_task_runner)449 std::unique_ptr<ChannelProxy> ChannelProxy::Create(
450 std::unique_ptr<ChannelFactory> factory,
451 Listener* listener,
452 const scoped_refptr<base::SingleThreadTaskRunner>& ipc_task_runner,
453 const scoped_refptr<base::SingleThreadTaskRunner>& listener_task_runner) {
454 std::unique_ptr<ChannelProxy> channel(
455 new ChannelProxy(listener, ipc_task_runner, listener_task_runner));
456 channel->Init(std::move(factory), true);
457 return channel;
458 }
459
ChannelProxy(Context * context)460 ChannelProxy::ChannelProxy(Context* context) : context_(context) {}
461
ChannelProxy(Listener * listener,const scoped_refptr<base::SingleThreadTaskRunner> & ipc_task_runner,const scoped_refptr<base::SingleThreadTaskRunner> & listener_task_runner)462 ChannelProxy::ChannelProxy(
463 Listener* listener,
464 const scoped_refptr<base::SingleThreadTaskRunner>& ipc_task_runner,
465 const scoped_refptr<base::SingleThreadTaskRunner>& listener_task_runner)
466 : context_(new Context(listener, ipc_task_runner, listener_task_runner)) {}
467
~ChannelProxy()468 ChannelProxy::~ChannelProxy() {
469 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
470
471 Close();
472 }
473
Init(const IPC::ChannelHandle & channel_handle,Channel::Mode mode,bool create_pipe_now)474 void ChannelProxy::Init(const IPC::ChannelHandle& channel_handle,
475 Channel::Mode mode,
476 bool create_pipe_now) {
477 #if BUILDFLAG(IS_POSIX) || BUILDFLAG(IS_FUCHSIA)
478 // When we are creating a server on POSIX, we need its file descriptor
479 // to be created immediately so that it can be accessed and passed
480 // to other processes. Forcing it to be created immediately avoids
481 // race conditions that may otherwise arise.
482 if (mode & Channel::MODE_SERVER_FLAG) {
483 create_pipe_now = true;
484 }
485 #endif // BUILDFLAG(IS_POSIX) || BUILDFLAG(IS_FUCHSIA)
486 Init(
487 ChannelFactory::Create(channel_handle, mode, context_->ipc_task_runner()),
488 create_pipe_now);
489 }
490
Init(std::unique_ptr<ChannelFactory> factory,bool create_pipe_now)491 void ChannelProxy::Init(std::unique_ptr<ChannelFactory> factory,
492 bool create_pipe_now) {
493 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
494 DCHECK(!did_init_);
495
496 if (create_pipe_now) {
497 // Create the channel immediately. This effectively sets up the
498 // low-level pipe so that the client can connect. Without creating
499 // the pipe immediately, it is possible for a listener to attempt
500 // to connect and get an error since the pipe doesn't exist yet.
501 context_->CreateChannel(std::move(factory));
502 } else {
503 context_->ipc_task_runner()->PostTask(
504 FROM_HERE,
505 base::BindOnce(&Context::CreateChannel, context_, std::move(factory)));
506 }
507
508 // complete initialization on the background thread
509 context_->ipc_task_runner()->PostTask(
510 FROM_HERE, base::BindOnce(&Context::OnChannelOpened, context_));
511
512 did_init_ = true;
513 OnChannelInit();
514 }
515
Pause()516 void ChannelProxy::Pause() {
517 context_->ipc_task_runner()->PostTask(
518 FROM_HERE, base::BindOnce(&Context::PauseChannel, context_));
519 }
520
Unpause(bool flush)521 void ChannelProxy::Unpause(bool flush) {
522 context_->ipc_task_runner()->PostTask(
523 FROM_HERE, base::BindOnce(&Context::UnpauseChannel, context_, flush));
524 }
525
Flush()526 void ChannelProxy::Flush() {
527 context_->ipc_task_runner()->PostTask(
528 FROM_HERE, base::BindOnce(&Context::FlushChannel, context_));
529 }
530
Close()531 void ChannelProxy::Close() {
532 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
533
534 // Clear the backpointer to the listener so that any pending calls to
535 // Context::OnDispatchMessage or OnDispatchError will be ignored. It is
536 // possible that the channel could be closed while it is receiving messages!
537 context_->Clear();
538
539 if (context_->ipc_task_runner()) {
540 context_->ipc_task_runner()->PostTask(
541 FROM_HERE, base::BindOnce(&Context::OnChannelClosed, context_));
542 }
543 }
544
Send(Message * message)545 bool ChannelProxy::Send(Message* message) {
546 DCHECK(!message->is_sync()) << "Need to use IPC::SyncChannel";
547 SendInternal(message);
548 return true;
549 }
550
SendInternal(Message * message)551 void ChannelProxy::SendInternal(Message* message) {
552 DCHECK(did_init_);
553
554 // TODO(alexeypa): add DCHECK(CalledOnValidThread()) here. Currently there are
555 // tests that call Send() from a wrong thread. See http://crbug.com/163523.
556
557 #ifdef ENABLE_IPC_FUZZER
558 // In IPC fuzzing builds, it is possible to define a filter to apply to
559 // outgoing messages. It will either rewrite the message and return a new
560 // one, freeing the original, or return the message unchanged.
561 if (outgoing_message_filter())
562 message = outgoing_message_filter()->Rewrite(message);
563 #endif
564
565 #if BUILDFLAG(IPC_MESSAGE_LOG_ENABLED)
566 Logging::GetInstance()->OnSendMessage(message);
567 #endif
568
569 context_->Send(message);
570 }
571
AddFilter(MessageFilter * filter)572 void ChannelProxy::AddFilter(MessageFilter* filter) {
573 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
574
575 context_->AddFilter(filter);
576 }
577
RemoveFilter(MessageFilter * filter)578 void ChannelProxy::RemoveFilter(MessageFilter* filter) {
579 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
580
581 context_->ipc_task_runner()->PostTask(
582 FROM_HERE, base::BindOnce(&Context::OnRemoveFilter, context_,
583 base::RetainedRef(filter)));
584 }
585
AddGenericAssociatedInterfaceForIOThread(const std::string & name,const GenericAssociatedInterfaceFactory & factory)586 void ChannelProxy::AddGenericAssociatedInterfaceForIOThread(
587 const std::string& name,
588 const GenericAssociatedInterfaceFactory& factory) {
589 context()->AddGenericAssociatedInterfaceForIOThread(name, factory);
590 }
591
GetRemoteAssociatedInterface(mojo::GenericPendingAssociatedReceiver receiver)592 void ChannelProxy::GetRemoteAssociatedInterface(
593 mojo::GenericPendingAssociatedReceiver receiver) {
594 DCHECK(did_init_);
595 context()->thread_safe_channel().GetAssociatedInterface(std::move(receiver));
596 }
597
ClearIPCTaskRunner()598 void ChannelProxy::ClearIPCTaskRunner() {
599 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
600 context()->ClearIPCTaskRunner();
601 }
602
OnChannelInit()603 void ChannelProxy::OnChannelInit() {
604 }
605
SetUrgentMessageObserver(UrgentMessageObserver * observer)606 void ChannelProxy::SetUrgentMessageObserver(UrgentMessageObserver* observer) {
607 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
608 DCHECK(!did_init_);
609 context_->SetUrgentMessageObserver(observer);
610 }
611
612 //-----------------------------------------------------------------------------
613
614 } // namespace IPC
615