This source file includes following definitions.
- MessageFilter
- GetModalDialogEvent
- ReleaseModalDialogEvent
- Send
- OnFilterAdded
- OnMessageReceived
- MessageFilter
- OnInit
- OnSignalModalDialogEvent
- OnResetModalDialogEvent
- GetPluginChannel
- NotifyRenderersOfPendingShutdown
- Send
- OnMessageReceived
- OnChannelError
- GenerateRouteID
- GetModalDialogEvent
- CleanUp
- Init
- npp_
- OnControlMessageReceived
- OnCreateInstance
- OnDestroyInstance
- OnGenerateRouteID
- OnClearSiteData
- OnDidAbortLoading
#include "content/plugin/plugin_channel.h"
#include "base/bind.h"
#include "base/command_line.h"
#include "base/process/process_handle.h"
#include "base/strings/string_util.h"
#include "base/synchronization/lock.h"
#include "base/synchronization/waitable_event.h"
#include "build/build_config.h"
#include "content/child/child_process.h"
#include "content/child/npapi/plugin_instance.h"
#include "content/child/npapi/webplugin_delegate_impl.h"
#include "content/child/plugin_messages.h"
#include "content/common/plugin_process_messages.h"
#include "content/plugin/plugin_thread.h"
#include "content/plugin/webplugin_delegate_stub.h"
#include "content/plugin/webplugin_proxy.h"
#include "content/public/common/content_switches.h"
#include "third_party/WebKit/public/web/WebBindings.h"
#if defined(OS_POSIX)
#include "ipc/ipc_channel_posix.h"
#endif
using blink::WebBindings;
namespace content {
namespace {
const int kPluginReleaseTimeMinutes = 5;
}  
class PluginChannel::MessageFilter : public IPC::ChannelProxy::MessageFilter {
 public:
  MessageFilter() : channel_(NULL) { }
  base::WaitableEvent* GetModalDialogEvent(int render_view_id) {
    base::AutoLock auto_lock(modal_dialog_event_map_lock_);
    if (!modal_dialog_event_map_.count(render_view_id)) {
      NOTREACHED();
      return NULL;
    }
    return modal_dialog_event_map_[render_view_id].event;
  }
  
  
  void ReleaseModalDialogEvent(int render_view_id) {
    base::AutoLock auto_lock(modal_dialog_event_map_lock_);
    if (!modal_dialog_event_map_.count(render_view_id)) {
      NOTREACHED();
      return;
    }
    if (--(modal_dialog_event_map_[render_view_id].refcount))
      return;
    
    base::MessageLoop::current()->DeleteSoon(
        FROM_HERE, modal_dialog_event_map_[render_view_id].event);
    modal_dialog_event_map_.erase(render_view_id);
  }
  bool Send(IPC::Message* message) {
    
    return channel_->Send(message);
  }
  
  virtual void OnFilterAdded(IPC::Channel* channel) OVERRIDE {
    channel_ = channel;
  }
  virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE {
    IPC_BEGIN_MESSAGE_MAP(PluginChannel::MessageFilter, message)
      IPC_MESSAGE_HANDLER_DELAY_REPLY(PluginMsg_Init, OnInit)
      IPC_MESSAGE_HANDLER(PluginMsg_SignalModalDialogEvent,
                          OnSignalModalDialogEvent)
      IPC_MESSAGE_HANDLER(PluginMsg_ResetModalDialogEvent,
                          OnResetModalDialogEvent)
    IPC_END_MESSAGE_MAP()
    return message.type() == PluginMsg_SignalModalDialogEvent::ID ||
           message.type() == PluginMsg_ResetModalDialogEvent::ID;
  }
 protected:
  virtual ~MessageFilter() {
    
    for (ModalDialogEventMap::iterator i = modal_dialog_event_map_.begin();
        i != modal_dialog_event_map_.end(); ++i) {
      delete i->second.event;
    }
  }
 private:
  void OnInit(const PluginMsg_Init_Params& params, IPC::Message* reply_msg) {
    base::AutoLock auto_lock(modal_dialog_event_map_lock_);
    if (modal_dialog_event_map_.count(params.host_render_view_routing_id)) {
      modal_dialog_event_map_[params.host_render_view_routing_id].refcount++;
      return;
    }
    WaitableEventWrapper wrapper;
    wrapper.event = new base::WaitableEvent(true, false);
    wrapper.refcount = 1;
    modal_dialog_event_map_[params.host_render_view_routing_id] = wrapper;
  }
  void OnSignalModalDialogEvent(int render_view_id) {
    base::AutoLock auto_lock(modal_dialog_event_map_lock_);
    if (modal_dialog_event_map_.count(render_view_id))
      modal_dialog_event_map_[render_view_id].event->Signal();
  }
  void OnResetModalDialogEvent(int render_view_id) {
    base::AutoLock auto_lock(modal_dialog_event_map_lock_);
    if (modal_dialog_event_map_.count(render_view_id))
      modal_dialog_event_map_[render_view_id].event->Reset();
  }
  struct WaitableEventWrapper {
    base::WaitableEvent* event;
    int refcount;  
  };
  typedef std::map<int, WaitableEventWrapper> ModalDialogEventMap;
  ModalDialogEventMap modal_dialog_event_map_;
  base::Lock modal_dialog_event_map_lock_;
  IPC::Channel* channel_;
};
PluginChannel* PluginChannel::GetPluginChannel(
    int renderer_id, base::MessageLoopProxy* ipc_message_loop) {
  
  std::string channel_key = base::StringPrintf(
      "%d.r%d", base::GetCurrentProcId(), renderer_id);
  PluginChannel* channel =
      static_cast<PluginChannel*>(NPChannelBase::GetChannel(
          channel_key,
          IPC::Channel::MODE_SERVER,
          ClassFactory,
          ipc_message_loop,
          false,
          ChildProcess::current()->GetShutDownEvent()));
  if (channel)
    channel->renderer_id_ = renderer_id;
  return channel;
}
void PluginChannel::NotifyRenderersOfPendingShutdown() {
  Broadcast(new PluginHostMsg_PluginShuttingDown());
}
bool PluginChannel::Send(IPC::Message* msg) {
  in_send_++;
  if (log_messages_) {
    VLOG(1) << "sending message @" << msg << " on channel @" << this
            << " with type " << msg->type();
  }
  bool result = NPChannelBase::Send(msg);
  in_send_--;
  return result;
}
bool PluginChannel::OnMessageReceived(const IPC::Message& msg) {
  if (log_messages_) {
    VLOG(1) << "received message @" << &msg << " on channel @" << this
            << " with type " << msg.type();
  }
  return NPChannelBase::OnMessageReceived(msg);
}
void PluginChannel::OnChannelError() {
  NPChannelBase::OnChannelError();
  CleanUp();
}
int PluginChannel::GenerateRouteID() {
  static int last_id = 0;
  return ++last_id;
}
base::WaitableEvent* PluginChannel::GetModalDialogEvent(int render_view_id) {
  return filter_->GetModalDialogEvent(render_view_id);
}
PluginChannel::~PluginChannel() {
  PluginThread::current()->Send(new PluginProcessHostMsg_ChannelDestroyed(
      renderer_id_));
  process_ref_.ReleaseWithDelay(
      base::TimeDelta::FromMinutes(kPluginReleaseTimeMinutes));
}
void PluginChannel::CleanUp() {
  
  
  
  for (size_t i = 0; i < plugin_stubs_.size(); ++i)
    RemoveRoute(plugin_stubs_[i]->instance_id());
  
  
  
  
  scoped_refptr<PluginChannel> me(this);
  while (!plugin_stubs_.empty()) {
    
    
    scoped_refptr<WebPluginDelegateStub> stub = plugin_stubs_[0];
    plugin_stubs_.erase(plugin_stubs_.begin());
  }
}
bool PluginChannel::Init(base::MessageLoopProxy* ipc_message_loop,
                         bool create_pipe_now,
                         base::WaitableEvent* shutdown_event) {
  if (!NPChannelBase::Init(ipc_message_loop, create_pipe_now, shutdown_event))
    return false;
  channel_->AddFilter(filter_.get());
  return true;
}
PluginChannel::PluginChannel()
    : renderer_id_(-1),
      in_send_(0),
      incognito_(false),
      filter_(new MessageFilter()),
      npp_(new struct _NPP) {
  set_send_unblocking_only_during_unblock_dispatch();
  const CommandLine* command_line = CommandLine::ForCurrentProcess();
  log_messages_ = command_line->HasSwitch(switches::kLogPluginMessages);
  
  
  SetDefaultNPObjectOwner(npp_.get());
  WebBindings::registerObjectOwner(npp_.get());
}
bool PluginChannel::OnControlMessageReceived(const IPC::Message& msg) {
  bool handled = true;
  IPC_BEGIN_MESSAGE_MAP(PluginChannel, msg)
    IPC_MESSAGE_HANDLER(PluginMsg_CreateInstance, OnCreateInstance)
    IPC_MESSAGE_HANDLER_DELAY_REPLY(PluginMsg_DestroyInstance,
                                    OnDestroyInstance)
    IPC_MESSAGE_HANDLER(PluginMsg_GenerateRouteID, OnGenerateRouteID)
    IPC_MESSAGE_HANDLER(PluginProcessMsg_ClearSiteData, OnClearSiteData)
    IPC_MESSAGE_HANDLER(PluginHostMsg_DidAbortLoading, OnDidAbortLoading)
    IPC_MESSAGE_UNHANDLED(handled = false)
  IPC_END_MESSAGE_MAP()
  DCHECK(handled);
  return handled;
}
void PluginChannel::OnCreateInstance(const std::string& mime_type,
                                     int* instance_id) {
  *instance_id = GenerateRouteID();
  scoped_refptr<WebPluginDelegateStub> stub(new WebPluginDelegateStub(
      mime_type, *instance_id, this));
  AddRoute(*instance_id, stub.get(), NULL);
  plugin_stubs_.push_back(stub);
}
void PluginChannel::OnDestroyInstance(int instance_id,
                                      IPC::Message* reply_msg) {
  for (size_t i = 0; i < plugin_stubs_.size(); ++i) {
    if (plugin_stubs_[i]->instance_id() == instance_id) {
      scoped_refptr<MessageFilter> filter(filter_);
      int render_view_id =
          plugin_stubs_[i]->webplugin()->host_render_view_routing_id();
      
      
      scoped_refptr<WebPluginDelegateStub> stub = plugin_stubs_[i];
      plugin_stubs_.erase(plugin_stubs_.begin() + i);
      stub = NULL;
      Send(reply_msg);
      RemoveRoute(instance_id);
      
      
      
      
      base::MessageLoop::current()->PostNonNestableTask(
          FROM_HERE,
          base::Bind(&MessageFilter::ReleaseModalDialogEvent,
                     filter.get(),
                     render_view_id));
      return;
    }
  }
  NOTREACHED() << "Couldn't find WebPluginDelegateStub to destroy";
}
void PluginChannel::OnGenerateRouteID(int* route_id) {
  *route_id = GenerateRouteID();
}
void PluginChannel::OnClearSiteData(const std::string& site,
                                    uint64 flags,
                                    uint64 max_age) {
  bool success = false;
  CommandLine* command_line = CommandLine::ForCurrentProcess();
  base::FilePath path = command_line->GetSwitchValuePath(switches::kPluginPath);
  scoped_refptr<PluginLib> plugin_lib(PluginLib::CreatePluginLib(path));
  if (plugin_lib.get()) {
    NPError err = plugin_lib->NP_Initialize();
    if (err == NPERR_NO_ERROR) {
      const char* site_str = site.empty() ? NULL : site.c_str();
      err = plugin_lib->NP_ClearSiteData(site_str, flags, max_age);
      std::string site_name =
          site.empty() ? "NULL"
                       : base::StringPrintf("\"%s\"", site_str);
      VLOG(1) << "NPP_ClearSiteData(" << site_name << ", " << flags << ", "
              << max_age << ") returned " << err;
      success = (err == NPERR_NO_ERROR);
    }
  }
  Send(new PluginProcessHostMsg_ClearSiteDataResult(success));
}
void PluginChannel::OnDidAbortLoading(int render_view_id) {
  for (size_t i = 0; i < plugin_stubs_.size(); ++i) {
    if (plugin_stubs_[i]->webplugin()->host_render_view_routing_id() ==
            render_view_id) {
      plugin_stubs_[i]->delegate()->instance()->CloseStreams();
    }
  }
}
}