diff options
author | yurys@google.com <yurys@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-04-08 14:13:04 +0000 |
---|---|---|
committer | yurys@google.com <yurys@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-04-08 14:13:04 +0000 |
commit | 9b9d728c445b3c1c2ac0b3f66753a205dc2eafc3 (patch) | |
tree | d52354b9d35df88bff508b5936a7fd9b98f31d55 | |
parent | 51a5ea2a6ef9d361b62ef1e6f3590131ac395cea (diff) | |
download | chromium_src-9b9d728c445b3c1c2ac0b3f66753a205dc2eafc3.zip chromium_src-9b9d728c445b3c1c2ac0b3f66753a205dc2eafc3.tar.gz chromium_src-9b9d728c445b3c1c2ac0b3f66753a205dc2eafc3.tar.bz2 |
1. All debugger messages are dispatched in a static method on the IO thread. All responses from the v8 go to another static method where we should find out which devtool agent delegate should be used for sending the response. We use call_id to match request with the delegate its response should be sent to. We don't pass the delegate directly as it's designed to be accessed on the render thread only.
To match debug command response with its request the request sequence number is replaced with a number that is unique across the renderer(note that requests from different clients may have equal ids so we cannot rely on them). This happens before the command gets to the v8. When the command response is ready the original request_seq is restored. Before that the request_seq field is used to find out which devtools agent delegate should be used for sending the response.
2. For the debugger events we derive target agent from the current v8 execution context. If there is no agent attached to the RenderView owning that context 'continue' command is sent to the v8 automatically and the message is ignored.
Review URL: http://codereview.chromium.org/62106
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@13347 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r-- | chrome/renderer/devtools_agent_filter.cc | 14 | ||||
-rw-r--r-- | chrome/renderer/devtools_agent_filter.h | 10 | ||||
-rw-r--r-- | chrome/renderer/render_view.cc | 6 | ||||
-rw-r--r-- | webkit/glue/devtools/debugger_agent_impl.cc | 14 | ||||
-rw-r--r-- | webkit/glue/devtools/debugger_agent_impl.h | 13 | ||||
-rw-r--r-- | webkit/glue/devtools/debugger_agent_manager.cc | 165 | ||||
-rw-r--r-- | webkit/glue/devtools/debugger_agent_manager.h | 17 | ||||
-rw-r--r-- | webkit/glue/webdevtoolsagent.h | 4 | ||||
-rw-r--r-- | webkit/glue/webdevtoolsagent_impl.cc | 10 |
9 files changed, 229 insertions, 24 deletions
diff --git a/chrome/renderer/devtools_agent_filter.cc b/chrome/renderer/devtools_agent_filter.cc index 319746f..9ecc2b4 100644 --- a/chrome/renderer/devtools_agent_filter.cc +++ b/chrome/renderer/devtools_agent_filter.cc @@ -7,22 +7,28 @@ #include "chrome/common/devtools_messages.h" #include "webkit/glue/webdevtoolsagent.h" -DevToolsAgentFilter::DevToolsAgentFilter() { +DevToolsAgentFilter::DevToolsAgentFilter(WebDevToolsAgent* webdevtools_agent, + int routing_id) + : webdevtools_agent_(webdevtools_agent), + routing_id_(routing_id) { } DevToolsAgentFilter::~DevToolsAgentFilter() { } bool DevToolsAgentFilter::OnMessageReceived(const IPC::Message& message) { + if (routing_id_ != message.routing_id()) { + return false; + } + bool handled = true; IPC_BEGIN_MESSAGE_MAP(DevToolsAgentFilter, message) - IPC_MESSAGE_HANDLER(DevToolsAgentMsg_DebuggerCommand, - OnDebuggerCommand) + IPC_MESSAGE_HANDLER(DevToolsAgentMsg_DebuggerCommand, OnDebuggerCommand) IPC_MESSAGE_UNHANDLED(handled = false) IPC_END_MESSAGE_MAP() return handled; } void DevToolsAgentFilter::OnDebuggerCommand(const std::string& command) { - WebDevToolsAgent::ExecuteDebuggerCommand(command); + WebDevToolsAgent::ExecuteDebuggerCommand(command, webdevtools_agent_); } diff --git a/chrome/renderer/devtools_agent_filter.h b/chrome/renderer/devtools_agent_filter.h index edfe221..c784383 100644 --- a/chrome/renderer/devtools_agent_filter.h +++ b/chrome/renderer/devtools_agent_filter.h @@ -9,6 +9,8 @@ #include "chrome/common/ipc_channel_proxy.h" +class WebDevToolsAgent; + // DevToolsAgentFilter is registered as an IPC filter in order to be able to // dispatch messages while on the IO thread. The reason for that is that while // debugging, Render thread is being held by the v8 and hence no messages @@ -20,7 +22,12 @@ class DevToolsAgentFilter : public IPC::ChannelProxy::MessageFilter { // 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. - DevToolsAgentFilter(); + // + // 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); virtual ~DevToolsAgentFilter(); private: @@ -31,6 +38,7 @@ 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. DISALLOW_COPY_AND_ASSIGN(DevToolsAgentFilter); diff --git a/chrome/renderer/render_view.cc b/chrome/renderer/render_view.cc index 3ed10cf..e76d187 100644 --- a/chrome/renderer/render_view.cc +++ b/chrome/renderer/render_view.cc @@ -300,9 +300,13 @@ void RenderView::Init(gfx::NativeViewId parent_hwnd, } devtools_agent_.reset(new DevToolsAgent(routing_id, this)); - devtools_agent_filter_ = new DevToolsAgentFilter(); + webwidget_ = WebView::Create(this, webkit_prefs); + 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. diff --git a/webkit/glue/devtools/debugger_agent_impl.cc b/webkit/glue/devtools/debugger_agent_impl.cc index 6838d5b..dc475ab 100644 --- a/webkit/glue/devtools/debugger_agent_impl.cc +++ b/webkit/glue/devtools/debugger_agent_impl.cc @@ -16,6 +16,7 @@ #include "webkit/glue/devtools/debugger_agent_manager.h" #include "webkit/glue/glue_util.h" #include "webkit/glue/webkit_glue.h" +#include "webkit/glue/webview_impl.h" using WebCore::Document; using WebCore::Node; @@ -23,8 +24,13 @@ using WebCore::String; using WebCore::V8ClassIndex; using WebCore::V8Proxy; -DebuggerAgentImpl::DebuggerAgentImpl(DebuggerAgentDelegate* delegate) - : delegate_(delegate) { +DebuggerAgentImpl::DebuggerAgentImpl( + WebViewImpl* web_view_impl, + DebuggerAgentDelegate* delegate, + WebDevToolsAgent* webdevtools_agent) + : web_view_impl_(web_view_impl), + delegate_(delegate), + webdevtools_agent_(webdevtools_agent) { DebuggerAgentManager::DebugAttach(this); } @@ -86,3 +92,7 @@ String DebuggerAgentImpl::ExecuteUtilityFunction( v8::Handle<v8::String> res_json = v8::Handle<v8::String>::Cast(res_obj); return WebCore::toWebCoreString(res_json); } + +WebCore::Page* DebuggerAgentImpl::GetPage() { + return web_view_impl_->page(); +} diff --git a/webkit/glue/devtools/debugger_agent_impl.h b/webkit/glue/devtools/debugger_agent_impl.h index aa0db70..664d506 100644 --- a/webkit/glue/devtools/debugger_agent_impl.h +++ b/webkit/glue/devtools/debugger_agent_impl.h @@ -8,15 +8,21 @@ #include "v8.h" #include "webkit/glue/devtools/debugger_agent.h" +class WebDevToolsAgent; +class WebViewImpl; + namespace WebCore { class Document; class Node; +class Page; class String; } class DebuggerAgentImpl : public DebuggerAgent { public: - explicit DebuggerAgentImpl(DebuggerAgentDelegate* delegate); + DebuggerAgentImpl(WebViewImpl* web_view_impl, + DebuggerAgentDelegate* delegate, + WebDevToolsAgent* webdevtools_agent); virtual ~DebuggerAgentImpl(); // Initializes dom agent with the given document. @@ -35,9 +41,14 @@ class DebuggerAgentImpl : public DebuggerAgent { WebCore::Node* node, const WebCore::String& json_args); + WebCore::Page* GetPage(); + WebDevToolsAgent* webdevtools_agent() { return webdevtools_agent_; }; + private: v8::Persistent<v8::Context> context_; + WebViewImpl* web_view_impl_; DebuggerAgentDelegate* delegate_; + WebDevToolsAgent* webdevtools_agent_; DISALLOW_COPY_AND_ASSIGN(DebuggerAgentImpl); }; diff --git a/webkit/glue/devtools/debugger_agent_manager.cc b/webkit/glue/devtools/debugger_agent_manager.cc index d37c8d3..678c904 100644 --- a/webkit/glue/devtools/debugger_agent_manager.cc +++ b/webkit/glue/devtools/debugger_agent_manager.cc @@ -4,10 +4,15 @@ #include "config.h" +#include "Frame.h" +#include "v8_proxy.h" #include <wtf/HashSet.h> #undef LOG +#include "base/json_reader.h" +#include "base/json_writer.h" #include "base/string_util.h" +#include "base/values.h" #include "webkit/glue/devtools/debugger_agent_impl.h" #include "webkit/glue/devtools/debugger_agent_manager.h" @@ -15,6 +20,7 @@ #include "v8/include/v8-debug.h" #endif + // static void DebuggerAgentManager::V8DebugMessageHandler(const uint16_t* message, int length, @@ -71,29 +77,170 @@ void DebuggerAgentManager::DebugBreak(DebuggerAgentImpl* debugger_agent) { // static void DebuggerAgentManager::DebuggerOutput(const std::string& out) { - DebuggerAgentImpl* agent = GetAgentForCurrentV8Context(); + OwnPtr<Value> response(JSONReader::Read(out, + false /* allow_trailing_comma */)); + if (!response.get()) { + NOTREACHED(); + return; + } + if (!response->IsType(Value::TYPE_DICTIONARY)) { + NOTREACHED(); + return; + } + DictionaryValue* m = static_cast<DictionaryValue*>(response.get()); + + std::string type; + if (!m->GetString(L"type", &type)) { + NOTREACHED(); + return; + } + + // Agent that should be used for sending command response is determined based + // on the 'request_seq' field in the response body. + if (type == "response") { + SendCommandResponse(m); + return; + } + + // Agent that should be used for sending events is determined based + // on the active Frame. + DebuggerAgentImpl* agent = FindAgentForCurrentV8Context(); if (!agent) { + // Autocontinue execution on break and exception events if there is no + // handler. + std::wstring continue_cmd( + L"{\"seq\":1,\"type\":\"request\",\"command\":\"continue\"}"); + SendCommandToV8(continue_cmd); return; } agent->DebuggerOutput(out); } // static -void DebuggerAgentManager::ExecuteDebuggerCommand(const std::string& command) { +bool DebuggerAgentManager::SendCommandResponse(DictionaryValue* response) { + // TODO(yurys): there is a bug in v8 which converts original string seq into + // a json dictinary. + DictionaryValue* request_seq; + if (!response->GetDictionary(L"request_seq", &request_seq)) { + NOTREACHED(); + return false; + } + + int agent_ptr; + if (!request_seq->GetInteger(L"webdevtools_agent", &agent_ptr)) { + NOTREACHED(); + return false; + } + + Value* original_request_seq; + if (request_seq->Get(L"request_seq", &original_request_seq)) { + response->Set(L"request_seq", original_request_seq->DeepCopy()); + } else { + response->Remove(L"request_seq", NULL /* out_value */); + } + + DebuggerAgentImpl* debugger_agent = FindDebuggerAgentForToolsAgent( + reinterpret_cast<WebDevToolsAgent*>(agent_ptr)); + if (!debugger_agent) { + return false; + } + + std::string json; + JSONWriter::Write(response, false /* pretty_print */, &json); + debugger_agent->DebuggerOutput(json); + return true; +} + + +// static +void DebuggerAgentManager::ExecuteDebuggerCommand( + const std::string& command, + WebDevToolsAgent* webdevtools_agent) { + const std::string cmd = DebuggerAgentManager::ReplaceRequestSequenceId( + command, + webdevtools_agent); + + SendCommandToV8(UTF8ToWide(cmd)); +} + +// static +void DebuggerAgentManager::SendCommandToV8(const std::wstring& cmd) { #if USE(V8) - std::wstring cmd_wstring = UTF8ToWide(command); - v8::Debug::SendCommand(reinterpret_cast<const uint16_t*>(cmd_wstring.data()), - cmd_wstring.length()); + v8::Debug::SendCommand(reinterpret_cast<const uint16_t*>(cmd.data()), + cmd.length()); #endif } + // static -DebuggerAgentImpl* DebuggerAgentManager::GetAgentForCurrentV8Context() { +DebuggerAgentImpl* DebuggerAgentManager::FindAgentForCurrentV8Context() { if (!attached_agents_) { return NULL; } DCHECK(!attached_agents_->isEmpty()); - // TODO(yurys): find agent for current v8 global context. Now we return first - // agent in the set. - return *attached_agents_->begin(); + + WebCore::Frame* frame = WebCore::V8Proxy::retrieveActiveFrame(); + if (!frame) { + return NULL; + } + WebCore::Page* page = frame->page(); + for (AttachedAgentsSet::iterator it = attached_agents_->begin(); + it != attached_agents_->end(); ++it) { + if ((*it)->GetPage() == page) { + return *it; + } + } + return NULL; +} + +const std::string DebuggerAgentManager::ReplaceRequestSequenceId( + const std::string& request, + WebDevToolsAgent* webdevtools_agent) { + OwnPtr<Value> message(JSONReader::Read(request, + false /* allow_trailing_comma */)); + if (!message.get()) { + return request; + } + if (!message->IsType(Value::TYPE_DICTIONARY)) { + return request; + } + DictionaryValue* m = static_cast<DictionaryValue*>(message.get()); + + std::string type; + if (!(m->GetString(L"type", &type) && type == "request")) { + return request; + } + + DictionaryValue new_seq; + Value* request_seq; + if (m->Get(L"seq", &request_seq)) { + new_seq.Set(L"request_seq", request_seq->DeepCopy()); + } + + // TODO(yurys): get rid of this hack, handler pointer should be passed + // into v8::Debug::SendCommand along with the command. + int agent_ptr = reinterpret_cast<int>(webdevtools_agent); + new_seq.Set(L"webdevtools_agent", Value::CreateIntegerValue(agent_ptr)); + + // TODO(yurys): fix v8 parser so that it handle objects as ids correctly. + std::string new_seq_str; + JSONWriter::Write(&new_seq, false /* pretty_print */, &new_seq_str); + m->SetString(L"seq", new_seq_str); + + std::string json; + JSONWriter::Write(m, false /* pretty_print */, &json); + return json; +} + +// Note that we cannot safely dereference 'webdevtools_agent' bacause the +// referenced agent may already have been detached and destroyed. +DebuggerAgentImpl* DebuggerAgentManager::FindDebuggerAgentForToolsAgent( + WebDevToolsAgent* webdevtools_agent) { + for (AttachedAgentsSet::iterator it = attached_agents_->begin(); + it != attached_agents_->end(); ++it) { + if ((*it)->webdevtools_agent() == webdevtools_agent) { + return *it; + } + } + return NULL; } diff --git a/webkit/glue/devtools/debugger_agent_manager.h b/webkit/glue/devtools/debugger_agent_manager.h index ba48966..39469b8 100644 --- a/webkit/glue/devtools/debugger_agent_manager.h +++ b/webkit/glue/devtools/debugger_agent_manager.h @@ -5,12 +5,15 @@ #ifndef WEBKIT_GLUE_DEVTOOLS_DEBUGGER_AGENT_MANAGER_H_ #define WEBKIT_GLUE_DEVTOOLS_DEBUGGER_AGENT_MANAGER_H_ +#include <wtf/HashMap.h> #include <wtf/HashSet.h> #include "base/basictypes.h" #include "v8/include/v8-debug.h" class DebuggerAgentImpl; +class DictionaryValue; +class WebDevToolsAgent; // There is single v8 instance per render process. Also there may be several // RenderViews and consequently devtools agents in the process that want to talk @@ -34,7 +37,8 @@ class DebuggerAgentManager { static void DebugBreak(DebuggerAgentImpl* debugger_agent); static void DebugCommand(const std::string& command); - static void ExecuteDebuggerCommand(const std::string& command); + static void ExecuteDebuggerCommand(const std::string& command, + WebDevToolsAgent* webdevtools_agent); private: DebuggerAgentManager(); @@ -44,7 +48,16 @@ class DebuggerAgentManager { int length, void* data); static void DebuggerOutput(const std::string& out); - static DebuggerAgentImpl* GetAgentForCurrentV8Context(); + static void SendCommandToV8(const std::wstring& cmd); + static bool SendCommandResponse(DictionaryValue* response); + + static DebuggerAgentImpl* FindAgentForCurrentV8Context(); + static DebuggerAgentImpl* FindDebuggerAgentForToolsAgent( + WebDevToolsAgent* webdevtools_agent); + + static const std::string ReplaceRequestSequenceId( + const std::string& request, + WebDevToolsAgent* webdevtools_agent); typedef HashSet<DebuggerAgentImpl*> AttachedAgentsSet; static AttachedAgentsSet* attached_agents_; diff --git a/webkit/glue/webdevtoolsagent.h b/webkit/glue/webdevtoolsagent.h index e96cfc1..30b7b5d5 100644 --- a/webkit/glue/webdevtoolsagent.h +++ b/webkit/glue/webdevtoolsagent.h @@ -24,7 +24,9 @@ class WebDevToolsAgent { virtual void InspectElement(int x, int y) = 0; // Asynchronously executes debugger command in the render thread. - static void ExecuteDebuggerCommand(const std::string& command); + // |webdevtools_agent| will be used for sending response. + static void ExecuteDebuggerCommand(const std::string& command, + WebDevToolsAgent* webdevtools_agent); private: DISALLOW_COPY_AND_ASSIGN(WebDevToolsAgent); diff --git a/webkit/glue/webdevtoolsagent_impl.cc b/webkit/glue/webdevtoolsagent_impl.cc index 5a4c4b4..e5cf8ad 100644 --- a/webkit/glue/webdevtoolsagent_impl.cc +++ b/webkit/glue/webdevtoolsagent_impl.cc @@ -59,7 +59,9 @@ void WebDevToolsAgentImpl::Attach() { return; } debugger_agent_impl_.set( - new DebuggerAgentImpl(debugger_agent_delegate_stub_.get())); + new DebuggerAgentImpl(web_view_impl_, + debugger_agent_delegate_stub_.get(), + this)); dom_agent_impl_.set(new DomAgentImpl(dom_agent_delegate_stub_.get())); net_agent_impl_.set(new NetAgentImpl(net_agent_delegate_stub_.get())); @@ -236,6 +238,8 @@ void WebDevToolsAgentImpl::SendRpcMessage(const std::string& raw_msg) { } // static -void WebDevToolsAgent::ExecuteDebuggerCommand(const std::string& command) { - DebuggerAgentManager::ExecuteDebuggerCommand(command); +void WebDevToolsAgent::ExecuteDebuggerCommand( + const std::string& command, + WebDevToolsAgent* webdevtools_agent) { + DebuggerAgentManager::ExecuteDebuggerCommand(command, webdevtools_agent); } |