From a862471b184f63a6f39c854e3abe4c26fb1edd1c Mon Sep 17 00:00:00 2001 From: "pfeldman@chromium.org" Date: Fri, 17 Apr 2009 00:51:35 +0000 Subject: DevTools: Make all devtools messages dispatch through debugger interrupt. Review URL: http://codereview.chromium.org/73002 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@13910 0039d316-1c4b-4281-b951-d872f2087c98 --- chrome/renderer/devtools_agent.cc | 21 +++-- chrome/renderer/devtools_agent.h | 14 +++- chrome/renderer/devtools_agent_filter.cc | 128 ++++++++++++++++++++++++++++--- chrome/renderer/devtools_agent_filter.h | 25 +++--- chrome/renderer/render_thread.cc | 6 +- chrome/renderer/render_thread.h | 3 + chrome/renderer/render_view.cc | 13 ---- chrome/renderer/render_view.h | 4 - 8 files changed, 166 insertions(+), 48 deletions(-) (limited to 'chrome/renderer') diff --git a/chrome/renderer/devtools_agent.cc b/chrome/renderer/devtools_agent.cc index 046b755..918bb73 100644 --- a/chrome/renderer/devtools_agent.cc +++ b/chrome/renderer/devtools_agent.cc @@ -9,19 +9,23 @@ #include "chrome/renderer/render_view.h" #include "webkit/glue/webdevtoolsagent.h" +// static +std::map DevToolsAgent::agent_for_routing_id_; + DevToolsAgent::DevToolsAgent(int routing_id, RenderView* view) : routing_id_(routing_id), view_(view) { + agent_for_routing_id_[routing_id] = this; } DevToolsAgent::~DevToolsAgent() { + agent_for_routing_id_.erase(routing_id_); } // Called on the Renderer thread. bool DevToolsAgent::OnMessageReceived(const IPC::Message& message) { bool handled = true; IPC_BEGIN_MESSAGE_MAP(DevToolsAgent, message) - IPC_MESSAGE_HANDLER(DevToolsAgentMsg_Attach, OnAttach) IPC_MESSAGE_HANDLER(DevToolsAgentMsg_Detach, OnDetach) IPC_MESSAGE_HANDLER(DevToolsAgentMsg_RpcMessage, OnRpcMessage) IPC_MESSAGE_HANDLER(DevToolsAgentMsg_InspectElement, OnInspectElement) @@ -37,11 +41,18 @@ void DevToolsAgent::SendMessageToClient(const std::string& raw_msg) { view_->Send(m); } -void DevToolsAgent::OnAttach() { - WebDevToolsAgent* web_agent = GetWebAgent(); - if (web_agent) { - web_agent->Attach(); +int DevToolsAgent::GetHostId() { + return routing_id_; +} + +// static +DevToolsAgent* DevToolsAgent::FromHostId(int host_id) { + std::map::iterator it = + agent_for_routing_id_.find(host_id); + if (it != agent_for_routing_id_.end()) { + return it->second; } + return NULL; } void DevToolsAgent::OnDetach() { diff --git a/chrome/renderer/devtools_agent.h b/chrome/renderer/devtools_agent.h index 7d3c4a1..9f813a3 100644 --- a/chrome/renderer/devtools_agent.h +++ b/chrome/renderer/devtools_agent.h @@ -5,6 +5,7 @@ #ifndef CHROME_RENDERER_DEVTOOLS_AGENT_H_ #define CHROME_RENDERER_DEVTOOLS_AGENT_H_ +#include #include #include "webkit/glue/webdevtoolsagent_delegate.h" @@ -30,15 +31,24 @@ class DevToolsAgent : public WebDevToolsAgentDelegate { // WebDevToolsAgentDelegate implementation virtual void SendMessageToClient(const std::string& raw_msg); + virtual int GetHostId(); + + // Returns agent instance for its host id. + static DevToolsAgent* FromHostId(int host_id); + + RenderView* render_view() { return view_; } - private: WebDevToolsAgent* GetWebAgent(); - void OnAttach(); + private: + friend class DevToolsAgentFilter; + void OnDetach(); void OnRpcMessage(const std::string& raw_msg); void OnInspectElement(int x, int y); + static std::map agent_for_routing_id_; + int routing_id_; // View routing id that we can access from IO thread. RenderView* view_; diff --git a/chrome/renderer/devtools_agent_filter.cc b/chrome/renderer/devtools_agent_filter.cc index 9ecc2b4..ec7dd1c7 100644 --- a/chrome/renderer/devtools_agent_filter.cc +++ b/chrome/renderer/devtools_agent_filter.cc @@ -4,31 +4,135 @@ #include "chrome/renderer/devtools_agent_filter.h" +#include "base/command_line.h" +#include "chrome/common/chrome_switches.h" #include "chrome/common/devtools_messages.h" +#include "chrome/renderer/devtools_agent.h" +#include "chrome/renderer/plugin_channel_host.h" +#include "chrome/renderer/render_view.h" #include "webkit/glue/webdevtoolsagent.h" -DevToolsAgentFilter::DevToolsAgentFilter(WebDevToolsAgent* webdevtools_agent, - int routing_id) - : webdevtools_agent_(webdevtools_agent), - routing_id_(routing_id) { +namespace { + +class DebuggerMessage : public WebDevToolsAgent::Message { + public: + DebuggerMessage(int routing_id, const IPC::Message& message) + : routing_id_(routing_id), + message_(message) { + } + + virtual void Dispatch() { + DevToolsAgent* agent = DevToolsAgent::FromHostId(routing_id_); + if (agent) { + agent->OnMessageReceived(message_); + } + } + + private: + int routing_id_; + IPC::Message message_; + DISALLOW_COPY_AND_ASSIGN(DebuggerMessage); +}; + +} // namespace + +std::set DevToolsAgentFilter::attached_routing_ids_; + +DevToolsAgentFilter::DevToolsAgentFilter() + : current_routing_id_(0) { + const CommandLine& command_line = *CommandLine::ForCurrentProcess(); + devtools_enabled_ = command_line.HasSwitch( + switches::kEnableOutOfProcessDevTools); } DevToolsAgentFilter::~DevToolsAgentFilter() { } bool DevToolsAgentFilter::OnMessageReceived(const IPC::Message& message) { - if (routing_id_ != message.routing_id()) { + if (!devtools_enabled_) { + return false; + } + if (message.type() < DevToolsAgentStart || + message.type() >= DevToolsAgentEnd) { return false; } - bool handled = true; - IPC_BEGIN_MESSAGE_MAP(DevToolsAgentFilter, message) - IPC_MESSAGE_HANDLER(DevToolsAgentMsg_DebuggerCommand, OnDebuggerCommand) - IPC_MESSAGE_UNHANDLED(handled = false) - IPC_END_MESSAGE_MAP() - return handled; + int routing_id = message.routing_id(); + + MessageLoop* view_loop = RenderThread::current()->message_loop(); + if (attached_routing_ids_.find(routing_id) == attached_routing_ids_.end()) { + // Agent has not been scheduled for attachment yet. + // Schedule attach command, no matter which one is actually being + // dispatched. + view_loop->PostTask(FROM_HERE, NewRunnableMethod( + this, + &DevToolsAgentFilter::Attach, + message.routing_id())); + attached_routing_ids_.insert(routing_id); + +#if defined(OS_WIN) + // Disable plugin message routing. + PluginChannelHost::SetListening(false); +#endif + } + + // If this is attach request - we are done. + if (message.type() == DevToolsAgentMsg_Attach::ID) { + return true; + } + + if (message.type() == DevToolsAgentMsg_Detach::ID) { + // We are about to schedule detach. + attached_routing_ids_.erase(routing_id); + if (attached_routing_ids_.size() == 0) { +#if defined(OS_WIN) + // All the agents are scheduled for detach -> resume dispatching + // of plugin messages. + PluginChannelHost::SetListening(true); +#endif + } + } + + if (message.type() != DevToolsAgentMsg_DebuggerCommand::ID) { + // Dispatch everything except for command through the debugger interrupt. + DebuggerMessage* m = new DebuggerMessage(routing_id, message); + WebDevToolsAgent::ScheduleMessageDispatch(m); + view_loop->PostTask( + FROM_HERE, + NewRunnableMethod( + this, + &DevToolsAgentFilter::EvalNoop, + routing_id)); + return true; + } else { + // Dispatch command directly from IO. + bool handled = true; + current_routing_id_ = routing_id; + IPC_BEGIN_MESSAGE_MAP(DevToolsAgentFilter, message) + IPC_MESSAGE_HANDLER(DevToolsAgentMsg_DebuggerCommand, OnDebuggerCommand) + IPC_MESSAGE_UNHANDLED(handled = false) + IPC_END_MESSAGE_MAP() + return handled; + } +} + +void DevToolsAgentFilter::EvalNoop(int routing_id) { + DevToolsAgent* agent = DevToolsAgent::FromHostId(routing_id); + if (agent) { + agent->render_view()->EvaluateScript(L"", L"javascript:void(0)"); + } +} + +void DevToolsAgentFilter::Attach(int routing_id) { + DevToolsAgent* agent = DevToolsAgent::FromHostId(routing_id); + if (agent) { + WebDevToolsAgent* web_agent = agent->GetWebAgent(); + if (web_agent) { + web_agent->Attach(); + } + } } void DevToolsAgentFilter::OnDebuggerCommand(const std::string& command) { - WebDevToolsAgent::ExecuteDebuggerCommand(command, webdevtools_agent_); + WebDevToolsAgent::ExecuteDebuggerCommand(command, current_routing_id_); } diff --git a/chrome/renderer/devtools_agent_filter.h b/chrome/renderer/devtools_agent_filter.h index c784383..f97e4a3 100644 --- a/chrome/renderer/devtools_agent_filter.h +++ b/chrome/renderer/devtools_agent_filter.h @@ -5,6 +5,7 @@ #ifndef CHROME_RENDERER_DEVTOOLS_AGENT_FILTER_H_ #define CHROME_RENDERER_DEVTOOLS_AGENT_FILTER_H_ +#include #include #include "chrome/common/ipc_channel_proxy.h" @@ -19,15 +20,8 @@ class WebDevToolsAgent; // is being used from this communication agent on the IO thread. class DevToolsAgentFilter : public IPC::ChannelProxy::MessageFilter { public: - // DevToolsAgentFilter is a field of the RenderView. The view is supposed - // to remove this agent from the message filter list on IO thread before - // dying. - // - // Note that the pointer to WebDevToolsAgent should never be dereferenced on - // the IO thread because it is destroyed asynchronously on the render thread. - // However the filter needs it to pass along with debugger command request - // to WebDevToolsAgent::ExecuteDebuggerCommand static method. - DevToolsAgentFilter(WebDevToolsAgent* webdevtools_agent, int routing_id); + // There is a single instance of this class instantiated by the RenderThread. + DevToolsAgentFilter(); virtual ~DevToolsAgentFilter(); private: @@ -38,8 +32,17 @@ class DevToolsAgentFilter : public IPC::ChannelProxy::MessageFilter { // handle debug messages even when v8 is stopped. void OnDebuggerCommand(const std::string& command); - WebDevToolsAgent* webdevtools_agent_; - int routing_id_; // View routing id that we can access from IO thread. + // Evaluates noop to kick the debugger. + void EvalNoop(int routing_id); + + // Attaches agent. + void Attach(int routing_id); + + static std::set attached_routing_ids_; + + int current_routing_id_; + + bool devtools_enabled_; DISALLOW_COPY_AND_ASSIGN(DevToolsAgentFilter); }; diff --git a/chrome/renderer/render_thread.cc b/chrome/renderer/render_thread.cc index 5c084bb..6582be7 100644 --- a/chrome/renderer/render_thread.cc +++ b/chrome/renderer/render_thread.cc @@ -25,6 +25,7 @@ #include "chrome/plugin/plugin_channel_base.h" #include "webkit/glue/weburlrequest.h" #endif +#include "chrome/renderer/devtools_agent_filter.h" #include "chrome/renderer/extensions/event_bindings.h" #include "chrome/renderer/extensions/extension_process_bindings.h" #include "chrome/renderer/extensions/renderer_extension_bindings.h" @@ -118,11 +119,14 @@ void RenderThread::Init() { histogram_snapshots_.reset(new RendererHistogramSnapshots()); app_cache_dispatcher_.reset(new AppCacheDispatcher()); WebAppCacheContext::SetFactory(CreateAppCacheContextForRenderer); + devtools_agent_filter_ = new DevToolsAgentFilter(); + AddFilter(devtools_agent_filter_.get()); } void RenderThread::CleanUp() { // Shutdown in reverse of the initialization order. - + RemoveFilter(devtools_agent_filter_.get()); + devtools_agent_filter_ = NULL; WebAppCacheContext::SetFactory(NULL); app_cache_dispatcher_.reset(); histogram_snapshots_.reset(); diff --git a/chrome/renderer/render_thread.h b/chrome/renderer/render_thread.h index 637c4c5..d57026e 100644 --- a/chrome/renderer/render_thread.h +++ b/chrome/renderer/render_thread.h @@ -16,6 +16,7 @@ #include "chrome/renderer/renderer_histogram_snapshots.h" class AppCacheDispatcher; +class DevToolsAgentFilter; class FilePath; class NotificationService; class RenderDnsMaster; @@ -154,6 +155,8 @@ class RenderThread : public RenderThreadBase, scoped_ptr app_cache_dispatcher_; + scoped_refptr devtools_agent_filter_; + DISALLOW_COPY_AND_ASSIGN(RenderThread); }; diff --git a/chrome/renderer/render_view.cc b/chrome/renderer/render_view.cc index c0b13f2..64d20d2 100644 --- a/chrome/renderer/render_view.cc +++ b/chrome/renderer/render_view.cc @@ -31,7 +31,6 @@ #include "chrome/renderer/audio_message_filter.h" #include "chrome/renderer/debug_message_handler.h" #include "chrome/renderer/devtools_agent.h" -#include "chrome/renderer/devtools_agent_filter.h" #include "chrome/renderer/devtools_client.h" #include "chrome/renderer/extensions/extension_process_bindings.h" #include "chrome/renderer/localized_error.h" @@ -191,7 +190,6 @@ RenderView::RenderView(RenderThreadBase* render_thread) ALLOW_THIS_IN_INITIALIZER_LIST(method_factory_(this)), first_default_plugin_(NULL), devtools_agent_(NULL), - devtools_agent_filter_(NULL), devtools_client_(NULL), history_back_list_count_(0), history_forward_list_count_(0), @@ -218,8 +216,6 @@ RenderView::~RenderView() { } render_thread_->RemoveFilter(debug_message_handler_); - if (devtools_agent_filter_.get()) - render_thread_->RemoveFilter(devtools_agent_filter_); render_thread_->RemoveFilter(audio_message_filter_); #ifdef CHROME_PERSONALIZATION @@ -316,11 +312,6 @@ void RenderView::Init(gfx::NativeViewId parent_hwnd, webwidget_ = WebView::Create(this, webkit_prefs); - if (dev_tools_enabled) - devtools_agent_filter_ = new DevToolsAgentFilter( - webview()->GetWebDevToolsAgent(), - routing_id); - #if defined(OS_LINUX) // We have to enable ourselves as the editor delegate on linux so we can copy // text selections to the X clipboard. @@ -355,8 +346,6 @@ void RenderView::Init(gfx::NativeViewId parent_hwnd, debug_message_handler_ = new DebugMessageHandler(this); render_thread_->AddFilter(debug_message_handler_); - if (dev_tools_enabled) - render_thread_->AddFilter(devtools_agent_filter_); audio_message_filter_ = new AudioMessageFilter(routing_id_); render_thread_->AddFilter(audio_message_filter_); @@ -370,8 +359,6 @@ void RenderView::OnMessageReceived(const IPC::Message& message) { // If this is developer tools renderer intercept tools messages first. if (devtools_client_.get() && devtools_client_->OnMessageReceived(message)) return; - if (devtools_agent_.get() && devtools_agent_->OnMessageReceived(message)) - return; IPC_BEGIN_MESSAGE_MAP(RenderView, message) IPC_MESSAGE_HANDLER(ViewMsg_CaptureThumbnail, SendThumbnail) diff --git a/chrome/renderer/render_view.h b/chrome/renderer/render_view.h index f6bd01b..cbdf711 100644 --- a/chrome/renderer/render_view.h +++ b/chrome/renderer/render_view.h @@ -47,7 +47,6 @@ class AudioMessageFilter; class DictionaryValue; class DebugMessageHandler; class DevToolsAgent; -class DevToolsAgentFilter; class DevToolsClient; class FilePath; class GURL; @@ -743,9 +742,6 @@ class RenderView : public RenderWidget, // Provides access to this renderer from the remote Inspector UI. scoped_ptr devtools_agent_; - // Handles messages on the IO thread while Renderer is on breakpoint. - scoped_refptr devtools_agent_filter_; - // DevToolsClient for renderer hosting developer tools UI. It's NULL for other // render views. scoped_ptr devtools_client_; -- cgit v1.1