plugin_channel_host.cc revision f2477e01787aa58f445919b809d89e252beef54f
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
34namespace {
35
36// Breakpad key for the RemoveRoute() backtrace.
37const char* kRemoveRouteTraceKey = "remove_route_bt";
38
39// Breakpad key for the OnChannelError() backtrace.
40const 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.
46bool remove_tracking = false;
47
48}  // namespace
49#endif
50
51namespace content {
52
53#if defined(OS_MACOSX)
54// static
55bool* PluginChannelHost::GetRemoveTrackingFlag() {
56  return &remove_tracking;
57}
58#endif
59
60// static
61PluginChannelHost* 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
75PluginChannelHost::PluginChannelHost() : expecting_shutdown_(false) {
76}
77
78PluginChannelHost::~PluginChannelHost() {
79}
80
81bool 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
87int PluginChannelHost::GenerateRouteID() {
88  int route_id = MSG_ROUTING_NONE;
89  Send(new PluginMsg_GenerateRouteID(&route_id));
90
91  return route_id;
92}
93
94void 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
103void 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
118bool 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
129void PluginChannelHost::OnSetException(const std::string& message) {
130  blink::WebBindings::setException(NULL, message.c_str());
131}
132
133void PluginChannelHost::OnPluginShuttingDown() {
134  expecting_shutdown_ = true;
135}
136
137bool 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
148void 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