blob: c276d33384b4a871fbb478704ee9c879a0db9921 [file] [log] [blame]
Torne (Richard Coles)58218062012-11-14 11:43:16 +00001// 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
Ben Murdochbb1529c2013-08-08 10:24:53 +01005#include "content/renderer/npapi/plugin_channel_host.h"
Torne (Richard Coles)58218062012-11-14 11:43:16 +00006
7#include "base/metrics/histogram.h"
Ben Murdocheb525c52013-07-10 11:40:50 +01008#include "base/time/time.h"
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +01009#include "content/child/child_process.h"
Ben Murdochca12bfa2013-07-23 11:17:05 +010010#include "content/child/npapi/npobject_base.h"
Torne (Richard Coles)868fa2f2013-06-11 10:57:03 +010011#include "content/child/plugin_messages.h"
Torne (Richard Coles)58218062012-11-14 11:43:16 +000012
13#if defined(OS_POSIX)
14#include "ipc/ipc_channel_posix.h"
15#endif
16
Torne (Richard Coles)7d4cd472013-06-19 11:58:07 +010017#include "third_party/WebKit/public/web/WebBindings.h"
Torne (Richard Coles)58218062012-11-14 11:43:16 +000018
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)
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +000030#include "base/debug/crash_logging.h"
Torne (Richard Coles)58218062012-11-14 11:43:16 +000031#include "base/debug/stack_trace.h"
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +010032#include "base/strings/sys_string_conversions.h"
Torne (Richard Coles)58218062012-11-14 11:43:16 +000033
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
Torne (Richard Coles)58218062012-11-14 11:43:16 +000053#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) {
Ben Murdochca12bfa2013-07-23 11:17:05 +010084 return NPChannelBase::Init(ipc_message_loop, create_pipe_now, shutdown_event);
Torne (Richard Coles)58218062012-11-14 11:43:16 +000085}
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);
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000109 base::debug::SetCrashKeyFromAddresses(
110 kRemoveRouteTraceKey, addresses, count);
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000111 }
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 WebKit::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);
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000154 base::debug::SetCrashKeyFromAddresses(
155 kChannelErrorTraceKey, addresses, count);
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000156 }
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