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