| 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 |