Home | History | Annotate | Download | only in npapi
      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 
      5 #include "content/renderer/npapi/plugin_channel_host.h"
      6 
      7 #include "base/metrics/histogram.h"
      8 #include "base/time/time.h"
      9 #include "content/child/child_process.h"
     10 #include "content/child/npapi/npobject_base.h"
     11 #include "content/child/plugin_messages.h"
     12 
     13 #if defined(OS_POSIX)
     14 #include "ipc/ipc_channel_posix.h"
     15 #endif
     16 
     17 #include "third_party/WebKit/public/web/WebBindings.h"
     18 
     19 // TODO(shess): Debugging for http://crbug.com/97285
     20 //
     21 // The hypothesis at #55 requires that RemoveRoute() be called between
     22 // sending ViewHostMsg_OpenChannelToPlugin to the browser, and calling
     23 // GetPluginChannelHost() on the result.  This code detects that case
     24 // and stores the backtrace of the RemoveRoute() in a breakpad key.
     25 // The specific RemoveRoute() is not tracked (there could be multiple,
     26 // and which is the one can't be known until the open completes), but
     27 // the backtrace from any such nested call should be sufficient to
     28 // drive a repro.
     29 #if defined(OS_MACOSX)
     30 #include "base/debug/crash_logging.h"
     31 #include "base/debug/stack_trace.h"
     32 #include "base/strings/sys_string_conversions.h"
     33 
     34 namespace {
     35 
     36 // Breakpad key for the RemoveRoute() backtrace.
     37 const char* kRemoveRouteTraceKey = "remove_route_bt";
     38 
     39 // Breakpad key for the OnChannelError() backtrace.
     40 const char* kChannelErrorTraceKey = "channel_error_bt";
     41 
     42 // GetRemoveTrackingFlag() exposes this so that
     43 // WebPluginDelegateProxy::Initialize() can do scoped set/reset.  When
     44 // true, RemoveRoute() knows WBDP::Initialize() is on the stack, and
     45 // records the backtrace.
     46 bool remove_tracking = false;
     47 
     48 }  // namespace
     49 #endif
     50 
     51 namespace content {
     52 
     53 #if defined(OS_MACOSX)
     54 // static
     55 bool* PluginChannelHost::GetRemoveTrackingFlag() {
     56   return &remove_tracking;
     57 }
     58 #endif
     59 
     60 // static
     61 PluginChannelHost* PluginChannelHost::GetPluginChannelHost(
     62     const IPC::ChannelHandle& channel_handle,
     63     base::MessageLoopProxy* ipc_message_loop) {
     64   PluginChannelHost* result =
     65       static_cast<PluginChannelHost*>(NPChannelBase::GetChannel(
     66           channel_handle,
     67           IPC::Channel::MODE_CLIENT,
     68           ClassFactory,
     69           ipc_message_loop,
     70           true,
     71           ChildProcess::current()->GetShutDownEvent()));
     72   return result;
     73 }
     74 
     75 PluginChannelHost::PluginChannelHost() : expecting_shutdown_(false) {
     76 }
     77 
     78 PluginChannelHost::~PluginChannelHost() {
     79 }
     80 
     81 bool PluginChannelHost::Init(base::MessageLoopProxy* ipc_message_loop,
     82                              bool create_pipe_now,
     83                              base::WaitableEvent* shutdown_event) {
     84   return NPChannelBase::Init(ipc_message_loop, create_pipe_now, shutdown_event);
     85 }
     86 
     87 int PluginChannelHost::GenerateRouteID() {
     88   int route_id = MSG_ROUTING_NONE;
     89   Send(new PluginMsg_GenerateRouteID(&route_id));
     90 
     91   return route_id;
     92 }
     93 
     94 void PluginChannelHost::AddRoute(int route_id,
     95                                  IPC::Listener* listener,
     96                                  NPObjectBase* npobject) {
     97   NPChannelBase::AddRoute(route_id, listener, npobject);
     98 
     99   if (!npobject)
    100     proxies_[route_id] = listener;
    101 }
    102 
    103 void PluginChannelHost::RemoveRoute(int route_id) {
    104 #if defined(OS_MACOSX)
    105   if (remove_tracking) {
    106     base::debug::StackTrace trace;
    107     size_t count = 0;
    108     const void* const* addresses = trace.Addresses(&count);
    109     base::debug::SetCrashKeyFromAddresses(
    110         kRemoveRouteTraceKey, addresses, count);
    111   }
    112 #endif
    113 
    114   proxies_.erase(route_id);
    115   NPChannelBase::RemoveRoute(route_id);
    116 }
    117 
    118 bool PluginChannelHost::OnControlMessageReceived(const IPC::Message& message) {
    119   bool handled = true;
    120   IPC_BEGIN_MESSAGE_MAP(PluginChannelHost, message)
    121     IPC_MESSAGE_HANDLER(PluginHostMsg_SetException, OnSetException)
    122     IPC_MESSAGE_HANDLER(PluginHostMsg_PluginShuttingDown, OnPluginShuttingDown)
    123     IPC_MESSAGE_UNHANDLED(handled = false)
    124   IPC_END_MESSAGE_MAP()
    125   DCHECK(handled);
    126   return handled;
    127 }
    128 
    129 void PluginChannelHost::OnSetException(const std::string& message) {
    130   blink::WebBindings::setException(NULL, message.c_str());
    131 }
    132 
    133 void PluginChannelHost::OnPluginShuttingDown() {
    134   expecting_shutdown_ = true;
    135 }
    136 
    137 bool PluginChannelHost::Send(IPC::Message* msg) {
    138   if (msg->is_sync()) {
    139     base::TimeTicks start_time(base::TimeTicks::Now());
    140     bool result = NPChannelBase::Send(msg);
    141     UMA_HISTOGRAM_TIMES("Plugin.SyncMessageTime",
    142                         base::TimeTicks::Now() - start_time);
    143     return result;
    144   }
    145   return NPChannelBase::Send(msg);
    146 }
    147 
    148 void PluginChannelHost::OnChannelError() {
    149 #if defined(OS_MACOSX)
    150   if (remove_tracking) {
    151     base::debug::StackTrace trace;
    152     size_t count = 0;
    153     const void* const* addresses = trace.Addresses(&count);
    154     base::debug::SetCrashKeyFromAddresses(
    155         kChannelErrorTraceKey, addresses, count);
    156   }
    157 #endif
    158 
    159   NPChannelBase::OnChannelError();
    160 
    161   for (ProxyMap::iterator iter = proxies_.begin();
    162        iter != proxies_.end(); iter++) {
    163     iter->second->OnChannelError();
    164   }
    165 
    166   proxies_.clear();
    167 }
    168 
    169 }  // namespace content
    170