LCOV - code coverage report
Current view: directory - ipc/chromium/src/chrome/common - ipc_channel_proxy.cc (source / functions) Found Hit Coverage
Test: app.info Lines: 133 0 0.0 %
Date: 2012-06-02 Functions: 23 0 0.0 %

       1                 : // Copyright (c) 2006-2008 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                 : 
       5                 : #include "base/message_loop.h"
       6                 : #include "base/thread.h"
       7                 : #include "chrome/common/ipc_channel_proxy.h"
       8                 : #include "chrome/common/ipc_logging.h"
       9                 : #include "chrome/common/ipc_message_utils.h"
      10                 : 
      11                 : namespace IPC {
      12                 : 
      13                 : //-----------------------------------------------------------------------------
      14                 : 
      15               0 : ChannelProxy::Context::Context(Channel::Listener* listener,
      16                 :                                MessageFilter* filter,
      17                 :                                MessageLoop* ipc_message_loop)
      18               0 :     : listener_message_loop_(MessageLoop::current()),
      19                 :       listener_(listener),
      20                 :       ipc_message_loop_(ipc_message_loop),
      21                 :       channel_(NULL),
      22                 :       peer_pid_(0),
      23               0 :       channel_connected_called_(false) {
      24               0 :   if (filter)
      25               0 :     filters_.push_back(filter);
      26               0 : }
      27                 : 
      28               0 : void ChannelProxy::Context::CreateChannel(const std::wstring& id,
      29                 :                                           const Channel::Mode& mode) {
      30               0 :   DCHECK(channel_ == NULL);
      31               0 :   channel_id_ = id;
      32               0 :   channel_ = new Channel(id, mode, this);
      33               0 : }
      34                 : 
      35               0 : bool ChannelProxy::Context::TryFilters(const Message& message) {
      36                 : #ifdef IPC_MESSAGE_LOG_ENABLED
      37               0 :   Logging* logger = Logging::current();
      38               0 :   if (logger->Enabled())
      39               0 :     logger->OnPreDispatchMessage(message);
      40                 : #endif
      41                 : 
      42               0 :   for (size_t i = 0; i < filters_.size(); ++i) {
      43               0 :     if (filters_[i]->OnMessageReceived(message)) {
      44                 : #ifdef IPC_MESSAGE_LOG_ENABLED
      45               0 :       if (logger->Enabled())
      46               0 :         logger->OnPostDispatchMessage(message, channel_id_);
      47                 : #endif
      48               0 :       return true;
      49                 :     }
      50                 :   }
      51               0 :   return false;
      52                 : }
      53                 : 
      54                 : // Called on the IPC::Channel thread
      55               0 : void ChannelProxy::Context::OnMessageReceived(const Message& message) {
      56                 :   // First give a chance to the filters to process this message.
      57               0 :   if (!TryFilters(message))
      58               0 :     OnMessageReceivedNoFilter(message);
      59               0 : }
      60                 : 
      61                 : // Called on the IPC::Channel thread
      62               0 : void ChannelProxy::Context::OnMessageReceivedNoFilter(const Message& message) {
      63                 :   // NOTE: This code relies on the listener's message loop not going away while
      64                 :   // this thread is active.  That should be a reasonable assumption, but it
      65                 :   // feels risky.  We may want to invent some more indirect way of referring to
      66                 :   // a MessageLoop if this becomes a problem.
      67                 :   listener_message_loop_->PostTask(FROM_HERE, NewRunnableMethod(
      68               0 :       this, &Context::OnDispatchMessage, message));
      69               0 : }
      70                 : 
      71                 : // Called on the IPC::Channel thread
      72               0 : void ChannelProxy::Context::OnChannelConnected(int32 peer_pid) {
      73               0 :   peer_pid_ = peer_pid;
      74               0 :   for (size_t i = 0; i < filters_.size(); ++i)
      75               0 :     filters_[i]->OnChannelConnected(peer_pid);
      76                 : 
      77                 :   // See above comment about using listener_message_loop_ here.
      78                 :   listener_message_loop_->PostTask(FROM_HERE, NewRunnableMethod(
      79               0 :       this, &Context::OnDispatchConnected));
      80               0 : }
      81                 : 
      82                 : // Called on the IPC::Channel thread
      83               0 : void ChannelProxy::Context::OnChannelError() {
      84               0 :   for (size_t i = 0; i < filters_.size(); ++i)
      85               0 :     filters_[i]->OnChannelError();
      86                 : 
      87                 :   // See above comment about using listener_message_loop_ here.
      88                 :   listener_message_loop_->PostTask(FROM_HERE, NewRunnableMethod(
      89               0 :       this, &Context::OnDispatchError));
      90               0 : }
      91                 : 
      92                 : // Called on the IPC::Channel thread
      93               0 : void ChannelProxy::Context::OnChannelOpened() {
      94               0 :   DCHECK(channel_ != NULL);
      95                 : 
      96                 :   // Assume a reference to ourselves on behalf of this thread.  This reference
      97                 :   // will be released when we are closed.
      98               0 :   AddRef();
      99                 : 
     100               0 :   if (!channel_->Connect()) {
     101               0 :     OnChannelError();
     102               0 :     return;
     103                 :   }
     104                 : 
     105               0 :   for (size_t i = 0; i < filters_.size(); ++i)
     106               0 :     filters_[i]->OnFilterAdded(channel_);
     107                 : }
     108                 : 
     109                 : // Called on the IPC::Channel thread
     110               0 : void ChannelProxy::Context::OnChannelClosed() {
     111                 :   // It's okay for IPC::ChannelProxy::Close to be called more than once, which
     112                 :   // would result in this branch being taken.
     113               0 :   if (!channel_)
     114               0 :     return;
     115                 : 
     116               0 :   for (size_t i = 0; i < filters_.size(); ++i) {
     117               0 :     filters_[i]->OnChannelClosing();
     118               0 :     filters_[i]->OnFilterRemoved();
     119                 :   }
     120                 : 
     121                 :   // We don't need the filters anymore.
     122               0 :   filters_.clear();
     123                 : 
     124               0 :   delete channel_;
     125               0 :   channel_ = NULL;
     126                 : 
     127                 :   // Balance with the reference taken during startup.  This may result in
     128                 :   // self-destruction.
     129               0 :   Release();
     130                 : }
     131                 : 
     132                 : // Called on the IPC::Channel thread
     133               0 : void ChannelProxy::Context::OnSendMessage(Message* message) {
     134               0 :   if (!channel_->Send(message))
     135               0 :     OnChannelError();
     136               0 : }
     137                 : 
     138                 : // Called on the IPC::Channel thread
     139               0 : void ChannelProxy::Context::OnAddFilter(MessageFilter* filter) {
     140               0 :   filters_.push_back(filter);
     141                 : 
     142                 :   // If the channel has already been created, then we need to send this message
     143                 :   // so that the filter gets access to the Channel.
     144               0 :   if (channel_)
     145               0 :     filter->OnFilterAdded(channel_);
     146                 : 
     147                 :   // Balances the AddRef in ChannelProxy::AddFilter.
     148               0 :   filter->Release();
     149               0 : }
     150                 : 
     151                 : // Called on the IPC::Channel thread
     152               0 : void ChannelProxy::Context::OnRemoveFilter(MessageFilter* filter) {
     153               0 :   for (size_t i = 0; i < filters_.size(); ++i) {
     154               0 :     if (filters_[i].get() == filter) {
     155               0 :       filter->OnFilterRemoved();
     156               0 :       filters_.erase(filters_.begin() + i);
     157               0 :       return;
     158                 :     }
     159                 :   }
     160                 : 
     161               0 :   NOTREACHED() << "filter to be removed not found";
     162                 : }
     163                 : 
     164                 : // Called on the listener's thread
     165               0 : void ChannelProxy::Context::OnDispatchMessage(const Message& message) {
     166               0 :   if (!listener_)
     167               0 :     return;
     168                 : 
     169               0 :   OnDispatchConnected();
     170                 : 
     171                 : #ifdef IPC_MESSAGE_LOG_ENABLED
     172               0 :   Logging* logger = Logging::current();
     173               0 :   if (message.type() == IPC_LOGGING_ID) {
     174               0 :     logger->OnReceivedLoggingMessage(message);
     175               0 :     return;
     176                 :   }
     177                 : 
     178               0 :   if (logger->Enabled())
     179               0 :     logger->OnPreDispatchMessage(message);
     180                 : #endif
     181                 : 
     182               0 :   listener_->OnMessageReceived(message);
     183                 : 
     184                 : #ifdef IPC_MESSAGE_LOG_ENABLED
     185               0 :   if (logger->Enabled())
     186               0 :     logger->OnPostDispatchMessage(message, channel_id_);
     187                 : #endif
     188                 : }
     189                 : 
     190                 : // Called on the listener's thread
     191               0 : void ChannelProxy::Context::OnDispatchConnected() {
     192               0 :   if (channel_connected_called_)
     193               0 :     return;
     194                 : 
     195               0 :   channel_connected_called_ = true;
     196               0 :   if (listener_)
     197               0 :     listener_->OnChannelConnected(peer_pid_);
     198                 : }
     199                 : 
     200                 : // Called on the listener's thread
     201               0 : void ChannelProxy::Context::OnDispatchError() {
     202               0 :   if (listener_)
     203               0 :     listener_->OnChannelError();
     204               0 : }
     205                 : 
     206                 : //-----------------------------------------------------------------------------
     207                 : 
     208               0 : ChannelProxy::ChannelProxy(const std::wstring& channel_id, Channel::Mode mode,
     209                 :                            Channel::Listener* listener, MessageFilter* filter,
     210                 :                            MessageLoop* ipc_thread)
     211               0 :     : context_(new Context(listener, filter, ipc_thread)) {
     212               0 :   Init(channel_id, mode, ipc_thread, true);
     213               0 : }
     214                 : 
     215               0 : ChannelProxy::ChannelProxy(const std::wstring& channel_id, Channel::Mode mode,
     216                 :                            MessageLoop* ipc_thread, Context* context,
     217                 :                            bool create_pipe_now)
     218               0 :     : context_(context) {
     219               0 :   Init(channel_id, mode, ipc_thread, create_pipe_now);
     220               0 : }
     221                 : 
     222               0 : void ChannelProxy::Init(const std::wstring& channel_id, Channel::Mode mode,
     223                 :                         MessageLoop* ipc_thread_loop, bool create_pipe_now) {
     224               0 :   if (create_pipe_now) {
     225                 :     // Create the channel immediately.  This effectively sets up the
     226                 :     // low-level pipe so that the client can connect.  Without creating
     227                 :     // the pipe immediately, it is possible for a listener to attempt
     228                 :     // to connect and get an error since the pipe doesn't exist yet.
     229               0 :     context_->CreateChannel(channel_id, mode);
     230                 :   } else {
     231                 : #if defined(OS_POSIX)
     232                 :     // TODO(playmobil): On POSIX, IPC::Channel uses a socketpair(), one side of
     233                 :     // which needs to be mapped into the child process' address space.
     234                 :     // To know the value of the client side FD we need to have already
     235                 :     // created a socketpair which currently occurs in IPC::Channel's
     236                 :     // constructor.
     237                 :     // If we lazilly construct the IPC::Channel then the caller has no way
     238                 :     // of knowing the FD #.
     239                 :     //
     240                 :     // We can solve this either by having the Channel's creation launch the
     241                 :     // subprocess itself or by creating the socketpair() externally.
     242               0 :     NOTIMPLEMENTED();
     243                 : #endif  // defined(OS_POSIX)
     244                 :     context_->ipc_message_loop()->PostTask(FROM_HERE, NewRunnableMethod(
     245               0 :         context_.get(), &Context::CreateChannel, channel_id, mode));
     246                 :   }
     247                 : 
     248                 :   // complete initialization on the background thread
     249                 :   context_->ipc_message_loop()->PostTask(FROM_HERE, NewRunnableMethod(
     250               0 :       context_.get(), &Context::OnChannelOpened));
     251               0 : }
     252                 : 
     253               0 : void ChannelProxy::Close() {
     254                 :   // Clear the backpointer to the listener so that any pending calls to
     255                 :   // Context::OnDispatchMessage or OnDispatchError will be ignored.  It is
     256                 :   // possible that the channel could be closed while it is receiving messages!
     257               0 :   context_->Clear();
     258                 : 
     259               0 :   if (context_->ipc_message_loop()) {
     260                 :     context_->ipc_message_loop()->PostTask(FROM_HERE, NewRunnableMethod(
     261               0 :         context_.get(), &Context::OnChannelClosed));
     262                 :   }
     263               0 : }
     264                 : 
     265               0 : bool ChannelProxy::Send(Message* message) {
     266                 : #ifdef IPC_MESSAGE_LOG_ENABLED
     267               0 :   Logging::current()->OnSendMessage(message, context_->channel_id());
     268                 : #endif
     269                 : 
     270                 :   context_->ipc_message_loop()->PostTask(FROM_HERE, NewRunnableMethod(
     271               0 :       context_.get(), &Context::OnSendMessage, message));
     272               0 :   return true;
     273                 : }
     274                 : 
     275               0 : void ChannelProxy::AddFilter(MessageFilter* filter) {
     276                 :   // We want to addref the filter to prevent it from
     277                 :   // being destroyed before the OnAddFilter call is invoked.
     278               0 :   filter->AddRef();
     279                 :   context_->ipc_message_loop()->PostTask(FROM_HERE, NewRunnableMethod(
     280               0 :       context_.get(), &Context::OnAddFilter, filter));
     281               0 : }
     282                 : 
     283               0 : void ChannelProxy::RemoveFilter(MessageFilter* filter) {
     284                 :   context_->ipc_message_loop()->PostTask(FROM_HERE, NewRunnableMethod(
     285               0 :       context_.get(), &Context::OnRemoveFilter, filter));
     286               0 : }
     287                 : 
     288                 : #if defined(OS_POSIX)
     289                 : // See the TODO regarding lazy initialization of the channel in
     290                 : // ChannelProxy::Init().
     291                 : // We assume that IPC::Channel::GetClientFileDescriptorMapping() is thread-safe.
     292               0 : void ChannelProxy::GetClientFileDescriptorMapping(int *src_fd,
     293                 :                                                   int *dest_fd) const {
     294               0 :   Channel *channel = context_.get()->channel_;
     295               0 :   DCHECK(channel); // Channel must have been created first.
     296               0 :   channel->GetClientFileDescriptorMapping(src_fd, dest_fd);
     297               0 : }
     298                 : #endif
     299                 : 
     300                 : //-----------------------------------------------------------------------------
     301                 : 
     302                 : }  // namespace IPC

Generated by: LCOV version 1.7