OLD | NEW |
| (Empty) |
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 <stddef.h> | |
8 | |
9 #include "base/metrics/histogram.h" | |
10 #include "base/time/time.h" | |
11 #include "build/build_config.h" | |
12 #include "content/child/child_process.h" | |
13 #include "content/child/plugin_messages.h" | |
14 | |
15 #if defined(OS_POSIX) | |
16 #include "ipc/ipc_channel_posix.h" | |
17 #endif | |
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::SingleThreadTaskRunner* ipc_task_runner) { | |
64 PluginChannelHost* result = | |
65 static_cast<PluginChannelHost*>(NPChannelBase::GetChannel( | |
66 channel_handle, IPC::Channel::MODE_CLIENT, ClassFactory, | |
67 ipc_task_runner, true, ChildProcess::current()->GetShutDownEvent())); | |
68 return result; | |
69 } | |
70 | |
71 PluginChannelHost::PluginChannelHost() : expecting_shutdown_(false) { | |
72 } | |
73 | |
74 PluginChannelHost::~PluginChannelHost() { | |
75 } | |
76 | |
77 bool PluginChannelHost::Init(base::SingleThreadTaskRunner* ipc_task_runner, | |
78 bool create_pipe_now, | |
79 base::WaitableEvent* shutdown_event) { | |
80 return NPChannelBase::Init(ipc_task_runner, create_pipe_now, shutdown_event); | |
81 } | |
82 | |
83 int PluginChannelHost::GenerateRouteID() { | |
84 int route_id = MSG_ROUTING_NONE; | |
85 Send(new PluginMsg_GenerateRouteID(&route_id)); | |
86 | |
87 return route_id; | |
88 } | |
89 | |
90 void PluginChannelHost::AddRoute(int route_id, IPC::Listener* listener) { | |
91 NPChannelBase::AddRoute(route_id, listener); | |
92 proxies_[route_id] = listener; | |
93 } | |
94 | |
95 void PluginChannelHost::RemoveRoute(int route_id) { | |
96 #if defined(OS_MACOSX) | |
97 if (remove_tracking) { | |
98 base::debug::StackTrace trace; | |
99 size_t count = 0; | |
100 const void* const* addresses = trace.Addresses(&count); | |
101 base::debug::SetCrashKeyFromAddresses( | |
102 kRemoveRouteTraceKey, addresses, count); | |
103 } | |
104 #endif | |
105 | |
106 proxies_.erase(route_id); | |
107 NPChannelBase::RemoveRoute(route_id); | |
108 } | |
109 | |
110 bool PluginChannelHost::OnControlMessageReceived(const IPC::Message& message) { | |
111 bool handled = true; | |
112 IPC_BEGIN_MESSAGE_MAP(PluginChannelHost, message) | |
113 IPC_MESSAGE_HANDLER(PluginHostMsg_PluginShuttingDown, OnPluginShuttingDown) | |
114 IPC_MESSAGE_UNHANDLED(handled = false) | |
115 IPC_END_MESSAGE_MAP() | |
116 DCHECK(handled); | |
117 return handled; | |
118 } | |
119 | |
120 void PluginChannelHost::OnPluginShuttingDown() { | |
121 expecting_shutdown_ = true; | |
122 } | |
123 | |
124 bool PluginChannelHost::Send(IPC::Message* msg) { | |
125 if (msg->is_sync()) { | |
126 base::TimeTicks start_time(base::TimeTicks::Now()); | |
127 bool result = NPChannelBase::Send(msg); | |
128 UMA_HISTOGRAM_TIMES("Plugin.SyncMessageTime", | |
129 base::TimeTicks::Now() - start_time); | |
130 return result; | |
131 } | |
132 return NPChannelBase::Send(msg); | |
133 } | |
134 | |
135 void PluginChannelHost::OnChannelError() { | |
136 #if defined(OS_MACOSX) | |
137 if (remove_tracking) { | |
138 base::debug::StackTrace trace; | |
139 size_t count = 0; | |
140 const void* const* addresses = trace.Addresses(&count); | |
141 base::debug::SetCrashKeyFromAddresses( | |
142 kChannelErrorTraceKey, addresses, count); | |
143 } | |
144 #endif | |
145 | |
146 NPChannelBase::OnChannelError(); | |
147 | |
148 for (ProxyMap::iterator iter = proxies_.begin(); | |
149 iter != proxies_.end(); iter++) { | |
150 iter->second->OnChannelError(); | |
151 } | |
152 | |
153 proxies_.clear(); | |
154 } | |
155 | |
156 } // namespace content | |
OLD | NEW |