ipc_channel_proxy.cc 19 KB

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