diff options
author | Jocelyn Turcotte <jocelyn.turcotte@digia.com> | 2014-08-08 14:30:41 +0200 |
---|---|---|
committer | Jocelyn Turcotte <jocelyn.turcotte@digia.com> | 2014-08-12 13:49:54 +0200 |
commit | ab0a50979b9eb4dfa3320eff7e187e41efedf7a9 (patch) | |
tree | 498dfb8a97ff3361a9f7486863a52bb4e26bb898 /chromium/content/browser/devtools | |
parent | 4ce69f7403811819800e7c5ae1318b2647e778d1 (diff) |
Update Chromium to beta version 37.0.2062.68
Change-Id: I188e3b5aff1bec75566014291b654eb19f5bc8ca
Reviewed-by: Andras Becsi <andras.becsi@digia.com>
Diffstat (limited to 'chromium/content/browser/devtools')
42 files changed, 1761 insertions, 1079 deletions
diff --git a/chromium/content/browser/devtools/BUILD.gn b/chromium/content/browser/devtools/BUILD.gn new file mode 100644 index 00000000000..4aab2bab11e --- /dev/null +++ b/chromium/content/browser/devtools/BUILD.gn @@ -0,0 +1,71 @@ +# Copyright 2014 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +import("//tools/grit/grit_rule.gni") + +# In GYP: devtools_resources target. +group("resources") { + deps = [ + ":devtools_resources", + ":devtools_protocol_constants", + ] +} + +# In GYP: devtools_resources action in the devtools_resources target. +action("devtools_resources") { + visibility = ":resources" + + # This can't use grit_rule.gni because the grd file is generated at build + # time, so the trick of using grit_info to get the real inputs/outputs at GYP + # time isn't possible. + script = "//tools/grit/grit.py" + + grdfile = "$root_gen_dir/devtools/devtools_resources.grd" + + source_prereqs = [ grdfile ] + + rebase_path(exec_script("//tools/grit/grit_info.py", [ "--inputs" ], + "list lines"), + ".", "//") + + out_dir = "$root_gen_dir/webkit" + outputs = [ + "$out_dir/grit/devtools_resources.h", + "$out_dir/devtools_resources.pak", + "$out_dir/grit/devtools_resources_map.cc", + "$out_dir/grit/devtools_resources_map.h", + ] + + args = [ + "-i", rebase_path(grdfile, root_build_dir), "build", + "-f", rebase_path("//tools/gritsettings/resource_ids", root_build_dir), + "-o", rebase_path(out_dir, root_build_dir), + "-D", "SHARED_INTERMEDIATE_DIR=" + + rebase_path(root_gen_dir, root_build_dir), + ] + grit_defines + + deps = [ + # This is the action that generates out .grd input file. + "//third_party/WebKit/public:blink_generate_devtools_grd", + ] +} + +action("devtools_protocol_constants") { + visibility = ":resources" + + script = "//content/public/browser/devtools_protocol_constants_generator.py" + + blink_protocol = "//third_party/WebKit/Source/devtools/protocol.json" + browser_protocol = "browser_protocol.json" + source_prereqs = [ blink_protocol, browser_protocol ] + + outputs = [ + "$target_gen_dir/devtools_protocol_constants.cc", + "$target_gen_dir/devtools_protocol_constants.h", + ] + + args = [ "content" ] + rebase_path(outputs, root_build_dir) + [ + rebase_path(blink_protocol, root_build_dir), + rebase_path(browser_protocol, root_build_dir), + ] +} diff --git a/chromium/content/browser/devtools/browser_protocol.json b/chromium/content/browser/devtools/browser_protocol.json index 59e73c0c590..dfb462febf2 100644 --- a/chromium/content/browser/devtools/browser_protocol.json +++ b/chromium/content/browser/devtools/browser_protocol.json @@ -22,7 +22,8 @@ "properties": [ { "name": "devices", "type": "array", "items": { "$ref": "GPUDevice" }, "description": "The graphics devices on the system. Element 0 is the primary GPU." }, { "name": "auxAttributes", "type": "object", "optional": "true", "description": "An optional dictionary of additional GPU related attributes." }, - { "name": "featureStatus", "type": "object", "optional": "true", "description": "An optional dictionary of graphics features and their status." } + { "name": "featureStatus", "type": "object", "optional": "true", "description": "An optional dictionary of graphics features and their status." }, + { "name": "driverBugWorkarounds", "type": "array", "items": { "type": "string" }, "description": "An optional array of GPU driver bug workarounds." } ], "description": "Provides information about the GPU(s) on the system." }, diff --git a/chromium/content/browser/devtools/devtools_agent_host_impl.cc b/chromium/content/browser/devtools/devtools_agent_host_impl.cc index 087004296d5..bcb60b55b78 100644 --- a/chromium/content/browser/devtools/devtools_agent_host_impl.cc +++ b/chromium/content/browser/devtools/devtools_agent_host_impl.cc @@ -10,6 +10,7 @@ #include "base/guid.h" #include "base/lazy_instance.h" #include "content/browser/devtools/devtools_manager_impl.h" +#include "content/browser/devtools/forwarding_agent_host.h" #include "content/public/browser/browser_thread.h" namespace content { @@ -31,6 +32,7 @@ DevToolsAgentHostImpl::~DevToolsAgentHostImpl() { g_instances.Get().erase(g_instances.Get().find(id_)); } +//static scoped_refptr<DevToolsAgentHost> DevToolsAgentHost::GetForId( const std::string& id) { if (g_instances == NULL) @@ -41,6 +43,12 @@ scoped_refptr<DevToolsAgentHost> DevToolsAgentHost::GetForId( return it->second; } +//static +scoped_refptr<DevToolsAgentHost> DevToolsAgentHost::Create( + DevToolsExternalAgentProxyDelegate* delegate) { + return new ForwardingAgentHost(delegate); +} + bool DevToolsAgentHostImpl::IsAttached() { return !!DevToolsManagerImpl::GetInstance()->GetDevToolsClientHostFor(this); } @@ -60,6 +68,10 @@ void DevToolsAgentHostImpl::DisconnectRenderViewHost() {} void DevToolsAgentHostImpl::ConnectRenderViewHost(RenderViewHost* rvh) {} +bool DevToolsAgentHostImpl::IsWorker() const { + return false; +} + void DevToolsAgentHostImpl::NotifyCloseListener() { if (close_listener_) { scoped_refptr<DevToolsAgentHostImpl> protect(this); diff --git a/chromium/content/browser/devtools/devtools_agent_host_impl.h b/chromium/content/browser/devtools/devtools_agent_host_impl.h index 9bd800dc398..d0fad668b49 100644 --- a/chromium/content/browser/devtools/devtools_agent_host_impl.h +++ b/chromium/content/browser/devtools/devtools_agent_host_impl.h @@ -53,6 +53,8 @@ class CONTENT_EXPORT DevToolsAgentHostImpl : public DevToolsAgentHost { virtual void ConnectRenderViewHost(RenderViewHost* rvh) OVERRIDE; + virtual bool IsWorker() const OVERRIDE; + protected: DevToolsAgentHostImpl(); virtual ~DevToolsAgentHostImpl(); diff --git a/chromium/content/browser/devtools/devtools_browser_target.cc b/chromium/content/browser/devtools/devtools_browser_target.cc index a782462ba4c..b050152d2e4 100644 --- a/chromium/content/browser/devtools/devtools_browser_target.cc +++ b/chromium/content/browser/devtools/devtools_browser_target.cc @@ -5,9 +5,12 @@ #include "content/browser/devtools/devtools_browser_target.h" #include "base/bind.h" +#include "base/lazy_instance.h" #include "base/location.h" #include "base/logging.h" #include "base/message_loop/message_loop_proxy.h" +#include "base/stl_util.h" +#include "base/strings/stringprintf.h" #include "base/values.h" #include "content/public/browser/browser_thread.h" #include "net/server/http_server.h" @@ -15,13 +18,11 @@ namespace content { DevToolsBrowserTarget::DevToolsBrowserTarget( - base::MessageLoopProxy* message_loop_proxy, net::HttpServer* http_server, int connection_id) - : message_loop_proxy_(message_loop_proxy), + : message_loop_proxy_(base::MessageLoopProxy::current()), http_server_(http_server), connection_id_(connection_id), - handlers_deleter_(&handlers_), weak_factory_(this) { } @@ -29,6 +30,8 @@ void DevToolsBrowserTarget::RegisterDomainHandler( const std::string& domain, DevToolsProtocol::Handler* handler, bool handle_on_ui_thread) { + DCHECK_EQ(message_loop_proxy_, base::MessageLoopProxy::current()); + DCHECK(handlers_.find(domain) == handlers_.end()); handlers_[domain] = handler; if (handle_on_ui_thread) { @@ -41,7 +44,11 @@ void DevToolsBrowserTarget::RegisterDomainHandler( } } +typedef std::map<std::string, DevToolsBrowserTarget*> DomainMap; +base::LazyInstance<DomainMap>::Leaky g_used_domains = LAZY_INSTANCE_INITIALIZER; + void DevToolsBrowserTarget::HandleMessage(const std::string& data) { + DCHECK_EQ(message_loop_proxy_, base::MessageLoopProxy::current()); std::string error_response; scoped_refptr<DevToolsProtocol::Command> command = DevToolsProtocol::ParseCommand(data, &error_response); @@ -55,9 +62,21 @@ void DevToolsBrowserTarget::HandleMessage(const std::string& data) { Respond(command->NoSuchMethodErrorResponse()->Serialize()); return; } + DomainMap& used_domains(g_used_domains.Get()); + std::string domain = command->domain(); + DomainMap::iterator jt = used_domains.find(domain); + if (jt == used_domains.end()) { + used_domains[domain] = this; + } else if (jt->second != this) { + std::string message = + base::StringPrintf("'%s' is held by another connection", + domain.c_str()); + Respond(command->ServerErrorResponse(message)->Serialize()); + return; + } DevToolsProtocol::Handler* handler = it->second; - bool handle_directly = handle_on_ui_thread_.find(command->domain()) == + bool handle_directly = handle_on_ui_thread_.find(domain) == handle_on_ui_thread_.end(); if (handle_directly) { scoped_refptr<DevToolsProtocol::Response> response = @@ -81,9 +100,23 @@ void DevToolsBrowserTarget::HandleMessage(const std::string& data) { } void DevToolsBrowserTarget::Detach() { - message_loop_proxy_ = NULL; + DCHECK_EQ(message_loop_proxy_, base::MessageLoopProxy::current()); + DCHECK(http_server_); + http_server_ = NULL; + DomainMap& used_domains(g_used_domains.Get()); + for (DomainMap::iterator it = used_domains.begin(); + it != used_domains.end();) { + if (it->second == this) { + DomainMap::iterator to_erase = it; + ++it; + used_domains.erase(to_erase); + } else { + ++it; + } + } + std::vector<DevToolsProtocol::Handler*> ui_handlers; for (std::set<std::string>::iterator domain_it = handle_on_ui_thread_.begin(); domain_it != handle_on_ui_thread_.end(); @@ -94,6 +127,8 @@ void DevToolsBrowserTarget::Detach() { handlers_.erase(handler_it); } + STLDeleteValues(&handlers_); + BrowserThread::PostTask( BrowserThread::UI, FROM_HERE, @@ -103,11 +138,14 @@ void DevToolsBrowserTarget::Detach() { } DevToolsBrowserTarget::~DevToolsBrowserTarget() { + // DCHECK that Detach has been called or no handler has ever been registered. + DCHECK(handlers_.empty()); } void DevToolsBrowserTarget::HandleCommandOnUIThread( DevToolsProtocol::Handler* handler, scoped_refptr<DevToolsProtocol::Command> command) { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); scoped_refptr<DevToolsProtocol::Response> response = handler->HandleCommand(command); if (response && response->is_async_promise()) @@ -121,18 +159,19 @@ void DevToolsBrowserTarget::HandleCommandOnUIThread( void DevToolsBrowserTarget::DeleteHandlersOnUIThread( std::vector<DevToolsProtocol::Handler*> handlers) { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); STLDeleteElements(&handlers); } void DevToolsBrowserTarget::Respond(const std::string& message) { + DCHECK_EQ(message_loop_proxy_, base::MessageLoopProxy::current()); if (!http_server_) return; http_server_->SendOverWebSocket(connection_id_, message); } void DevToolsBrowserTarget::RespondFromUIThread(const std::string& message) { - if (!message_loop_proxy_) - return; + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); message_loop_proxy_->PostTask( FROM_HERE, base::Bind(&DevToolsBrowserTarget::Respond, this, message)); diff --git a/chromium/content/browser/devtools/devtools_browser_target.h b/chromium/content/browser/devtools/devtools_browser_target.h index 46ed291cfd7..0dda59b2ad4 100644 --- a/chromium/content/browser/devtools/devtools_browser_target.h +++ b/chromium/content/browser/devtools/devtools_browser_target.h @@ -13,7 +13,6 @@ #include "base/compiler_specific.h" #include "base/memory/ref_counted.h" #include "base/memory/weak_ptr.h" -#include "base/stl_util.h" #include "content/browser/devtools/devtools_protocol.h" namespace base { @@ -32,9 +31,7 @@ namespace content { class DevToolsBrowserTarget : public base::RefCountedThreadSafe<DevToolsBrowserTarget> { public: - DevToolsBrowserTarget(base::MessageLoopProxy* message_loop_proxy, - net::HttpServer* server, - int connection_id); + DevToolsBrowserTarget(net::HttpServer* server, int connection_id); int connection_id() const { return connection_id_; } @@ -61,13 +58,12 @@ class DevToolsBrowserTarget void Respond(const std::string& message); void RespondFromUIThread(const std::string& message); - base::MessageLoopProxy* message_loop_proxy_; + scoped_refptr<base::MessageLoopProxy> message_loop_proxy_; net::HttpServer* http_server_; const int connection_id_; typedef std::map<std::string, DevToolsProtocol::Handler*> DomainHandlerMap; DomainHandlerMap handlers_; - STLValueDeleter<DomainHandlerMap> handlers_deleter_; std::set<std::string> handle_on_ui_thread_; base::WeakPtrFactory<DevToolsBrowserTarget> weak_factory_; diff --git a/chromium/content/browser/devtools/devtools_external_agent_proxy_impl.cc b/chromium/content/browser/devtools/devtools_external_agent_proxy_impl.cc deleted file mode 100644 index 0513dc238b1..00000000000 --- a/chromium/content/browser/devtools/devtools_external_agent_proxy_impl.cc +++ /dev/null @@ -1,73 +0,0 @@ -// Copyright (c) 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "content/browser/devtools/devtools_external_agent_proxy_impl.h" - -#include "content/browser/devtools/devtools_agent_host_impl.h" -#include "content/browser/devtools/devtools_manager_impl.h" -#include "content/public/browser/devtools_external_agent_proxy_delegate.h" - -namespace content { - -class DevToolsExternalAgentProxyImpl::ForwardingAgentHost - : public DevToolsAgentHostImpl { - public: - ForwardingAgentHost(DevToolsExternalAgentProxyDelegate* delegate) - : delegate_(delegate) { - } - - void ConnectionClosed() { - NotifyCloseListener(); - } - - private: - virtual ~ForwardingAgentHost() { - } - - // DevToolsAgentHostImpl implementation. - virtual void Attach() OVERRIDE { - delegate_->Attach(); - }; - - virtual void Detach() OVERRIDE { - delegate_->Detach(); - }; - - virtual void DispatchOnInspectorBackend(const std::string& message) OVERRIDE { - delegate_->SendMessageToBackend(message); - } - - DevToolsExternalAgentProxyDelegate* delegate_; -}; - -//static -DevToolsExternalAgentProxy* DevToolsExternalAgentProxy::Create( - DevToolsExternalAgentProxyDelegate* delegate) { - return new DevToolsExternalAgentProxyImpl(delegate); -} - -DevToolsExternalAgentProxyImpl::DevToolsExternalAgentProxyImpl( - DevToolsExternalAgentProxyDelegate* delegate) - : agent_host_(new ForwardingAgentHost(delegate)) { -} - -DevToolsExternalAgentProxyImpl::~DevToolsExternalAgentProxyImpl() { -} - -scoped_refptr<DevToolsAgentHost> DevToolsExternalAgentProxyImpl:: - GetAgentHost() { - return agent_host_; -} - -void DevToolsExternalAgentProxyImpl::DispatchOnClientHost( - const std::string& message) { - DevToolsManagerImpl::GetInstance()->DispatchOnInspectorFrontend( - agent_host_.get(), message); -} - -void DevToolsExternalAgentProxyImpl::ConnectionClosed() { - agent_host_->ConnectionClosed(); -} - -} // content diff --git a/chromium/content/browser/devtools/devtools_external_agent_proxy_impl.h b/chromium/content/browser/devtools/devtools_external_agent_proxy_impl.h deleted file mode 100644 index cf025ec7b4f..00000000000 --- a/chromium/content/browser/devtools/devtools_external_agent_proxy_impl.h +++ /dev/null @@ -1,35 +0,0 @@ -// Copyright (c) 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef CONTENT_BROWSER_DEVTOOLS_DEVTOOLS_EXTERNAL_AGENT_PROXY_IMPL_H -#define CONTENT_BROWSER_DEVTOOLS_DEVTOOLS_EXTERNAL_AGENT_PROXY_IMPL_H - -#include "base/memory/ref_counted.h" -#include "content/public/browser/devtools_external_agent_proxy.h" - -namespace content { - -class DevToolsExternalAgentProxyImpl - : public DevToolsExternalAgentProxy { - public: - explicit DevToolsExternalAgentProxyImpl( - DevToolsExternalAgentProxyDelegate* delegate); - virtual ~DevToolsExternalAgentProxyImpl(); - - // DevToolsExternalAgentProxy implementation. - virtual scoped_refptr<DevToolsAgentHost> GetAgentHost() OVERRIDE; - virtual void DispatchOnClientHost(const std::string& message) OVERRIDE; - virtual void ConnectionClosed() OVERRIDE; - - private: - class ForwardingAgentHost; - - scoped_refptr<ForwardingAgentHost> agent_host_; - - DISALLOW_COPY_AND_ASSIGN(DevToolsExternalAgentProxyImpl); -}; - -} // namespace content - -#endif // CONTENT_BROWSER_DEVTOOLS_DEVTOOLS_EXTERNAL_AGENT_PROXY_IMPL_H diff --git a/chromium/content/browser/devtools/devtools_http_handler_impl.cc b/chromium/content/browser/devtools/devtools_http_handler_impl.cc index 1d0fca1e282..d1b5b1e6724 100644 --- a/chromium/content/browser/devtools/devtools_http_handler_impl.cc +++ b/chromium/content/browser/devtools/devtools_http_handler_impl.cc @@ -14,6 +14,7 @@ #include "base/logging.h" #include "base/message_loop/message_loop_proxy.h" #include "base/stl_util.h" +#include "base/strings/string_number_conversions.h" #include "base/threading/thread.h" #include "base/values.h" #include "content/browser/devtools/devtools_browser_target.h" @@ -31,14 +32,15 @@ #include "content/public/browser/devtools_target.h" #include "content/public/common/content_client.h" #include "content/public/common/url_constants.h" +#include "content/public/common/user_agent.h" +#include "content/public/common/user_agent.h" #include "grit/devtools_resources_map.h" #include "net/base/escape.h" #include "net/base/io_buffer.h" #include "net/base/ip_endpoint.h" +#include "net/base/net_errors.h" #include "net/server/http_server_request_info.h" #include "net/server/http_server_response_info.h" -#include "webkit/common/user_agent/user_agent.h" -#include "webkit/common/user_agent/user_agent_util.h" #if defined(OS_ANDROID) #include "base/android/build_info.h" @@ -48,7 +50,8 @@ namespace content { namespace { -const char kProtocolVersion[] = "1.0"; +const base::FilePath::CharType kDevToolsActivePortFileName[] = + FILE_PATH_LITERAL("DevToolsActivePort"); const char kDevToolsHandlerThreadName[] = "Chrome_DevToolsHandlerThread"; @@ -56,6 +59,7 @@ const char kThumbUrlPrefix[] = "/thumb/"; const char kPageUrlPrefix[] = "/devtools/page/"; const char kTargetIdField[] = "id"; +const char kTargetParentIdField[] = "parentId"; const char kTargetTypeField[] = "type"; const char kTargetTitleField[] = "title"; const char kTargetDescriptionField[] = "description"; @@ -135,7 +139,7 @@ static bool TimeComparator(const DevToolsTarget* target1, // static bool DevToolsHttpHandler::IsSupportedProtocolVersion( const std::string& version) { - return version == kProtocolVersion; + return devtools::IsSupportedProtocolVersion(version); } // static @@ -151,11 +155,13 @@ int DevToolsHttpHandler::GetFrontendResourceId(const std::string& name) { DevToolsHttpHandler* DevToolsHttpHandler::Start( const net::StreamListenSocketFactory* socket_factory, const std::string& frontend_url, - DevToolsHttpHandlerDelegate* delegate) { + DevToolsHttpHandlerDelegate* delegate, + const base::FilePath& active_port_output_directory) { DevToolsHttpHandlerImpl* http_handler = new DevToolsHttpHandlerImpl(socket_factory, frontend_url, - delegate); + delegate, + active_port_output_directory); http_handler->Start(); return http_handler; } @@ -215,8 +221,7 @@ GURL DevToolsHttpHandlerImpl::GetFrontendURL() { net::IPEndPoint ip_address; if (server_->GetLocalAddress(&ip_address)) return GURL(); - return GURL(std::string("http://") + ip_address.ToString() + - overridden_frontend_url_); + return GURL(std::string("http://") + ip_address.ToString() + frontend_url_); } static std::string PathWithoutParams(const std::string& path) { @@ -237,7 +242,12 @@ static std::string GetMimeType(const std::string& filename) { return "image/png"; } else if (EndsWith(filename, ".gif", false)) { return "image/gif"; + } else if (EndsWith(filename, ".json", false)) { + return "application/json"; } + LOG(ERROR) << "GetMimeType doesn't know mime type for: " + << filename + << " text/plain will be returned"; NOTREACHED(); return "text/plain"; } @@ -262,7 +272,7 @@ void DevToolsHttpHandlerImpl::OnHttpRequest( DevToolsTarget* target = GetTarget(target_id); GURL page_url; if (target) - page_url = target->GetUrl(); + page_url = target->GetURL(); BrowserThread::PostTask( BrowserThread::UI, FROM_HERE, @@ -318,24 +328,21 @@ void DevToolsHttpHandlerImpl::OnWebSocketRequest( std::string browser_prefix = "/devtools/browser"; size_t browser_pos = request.path.find(browser_prefix); if (browser_pos == 0) { - if (browser_target_) { - server_->Send500(connection_id, "Another client already attached"); - return; - } - browser_target_ = new DevToolsBrowserTarget( - thread_->message_loop_proxy().get(), server_.get(), connection_id); - browser_target_->RegisterDomainHandler( + scoped_refptr<DevToolsBrowserTarget> browser_target = + new DevToolsBrowserTarget(server_.get(), connection_id); + browser_target->RegisterDomainHandler( devtools::Tracing::kName, - new DevToolsTracingHandler(), + new DevToolsTracingHandler(DevToolsTracingHandler::Browser), true /* handle on UI thread */); - browser_target_->RegisterDomainHandler( + browser_target->RegisterDomainHandler( TetheringHandler::kDomain, new TetheringHandler(delegate_.get()), false /* handle on this thread */); - browser_target_->RegisterDomainHandler( + browser_target->RegisterDomainHandler( devtools::SystemInfo::kName, new DevToolsSystemInfoHandler(), true /* handle on UI thread */); + browser_targets_[connection_id] = browser_target; server_->AcceptWebSocket(connection_id, request); return; @@ -354,8 +361,9 @@ void DevToolsHttpHandlerImpl::OnWebSocketRequest( void DevToolsHttpHandlerImpl::OnWebSocketMessage( int connection_id, const std::string& data) { - if (browser_target_ && connection_id == browser_target_->connection_id()) { - browser_target_->HandleMessage(data); + BrowserTargets::iterator it = browser_targets_.find(connection_id); + if (it != browser_targets_.end()) { + it->second->HandleMessage(data); return; } @@ -370,9 +378,10 @@ void DevToolsHttpHandlerImpl::OnWebSocketMessage( } void DevToolsHttpHandlerImpl::OnClose(int connection_id) { - if (browser_target_ && browser_target_->connection_id() == connection_id) { - browser_target_->Detach(); - browser_target_ = NULL; + BrowserTargets::iterator it = browser_targets_.find(connection_id); + if (it != browser_targets_.end()) { + it->second->Detach(); + browser_targets_.erase(it); return; } @@ -390,8 +399,8 @@ std::string DevToolsHttpHandlerImpl::GetFrontendURLInternal( const std::string& host) { return base::StringPrintf( "%s%sws=%s%s%s", - overridden_frontend_url_.c_str(), - overridden_frontend_url_.find("?") == std::string::npos ? "?" : "&", + frontend_url_.c_str(), + frontend_url_.find("?") == std::string::npos ? "?" : "&", host.c_str(), kPageUrlPrefix, id.c_str()); @@ -452,11 +461,10 @@ void DevToolsHttpHandlerImpl::OnJsonRequestUI( if (command == "version") { base::DictionaryValue version; - version.SetString("Protocol-Version", kProtocolVersion); - version.SetString("WebKit-Version", webkit_glue::GetWebKitVersion()); - version.SetString("Browser", content::GetContentClient()->GetProduct()); - version.SetString("User-Agent", - webkit_glue::GetUserAgent(GURL(kAboutBlankURL))); + version.SetString("Protocol-Version", devtools::kProtocolVersion); + version.SetString("WebKit-Version", GetWebKitVersion()); + version.SetString("Browser", GetContentClient()->GetProduct()); + version.SetString("User-Agent", GetContentClient()->GetUserAgent()); #if defined(OS_ANDROID) version.SetString("Android-Package", base::android::BuildInfo::GetInstance()->package_name()); @@ -478,7 +486,7 @@ void DevToolsHttpHandlerImpl::OnJsonRequestUI( GURL url(net::UnescapeURLComponent( query, net::UnescapeRule::URL_SPECIAL_CHARS)); if (!url.is_valid()) - url = GURL(kAboutBlankURL); + url = GURL(url::kAboutBlankURL); scoped_ptr<DevToolsTarget> target(delegate_->CreateNewTarget(url)); if (!target) { SendJson(connection_id, @@ -641,12 +649,14 @@ void DevToolsHttpHandlerImpl::OnCloseUI(int connection_id) { DevToolsHttpHandlerImpl::DevToolsHttpHandlerImpl( const net::StreamListenSocketFactory* socket_factory, const std::string& frontend_url, - DevToolsHttpHandlerDelegate* delegate) - : overridden_frontend_url_(frontend_url), + DevToolsHttpHandlerDelegate* delegate, + const base::FilePath& active_port_output_directory) + : frontend_url_(frontend_url), socket_factory_(socket_factory), - delegate_(delegate) { - if (overridden_frontend_url_.empty()) - overridden_frontend_url_ = "/devtools/devtools.html"; + delegate_(delegate), + active_port_output_directory_(active_port_output_directory) { + if (frontend_url_.empty()) + frontend_url_ = "/devtools/devtools.html"; // Balanced in ResetHandlerThreadAndRelease(). AddRef(); @@ -655,6 +665,8 @@ DevToolsHttpHandlerImpl::DevToolsHttpHandlerImpl( // Runs on the handler thread void DevToolsHttpHandlerImpl::Init() { server_ = new net::HttpServer(*socket_factory_.get(), this); + if (!active_port_output_directory_.empty()) + WriteActivePortToUserProfile(); } // Runs on the handler thread @@ -674,6 +686,25 @@ void DevToolsHttpHandlerImpl::StopHandlerThread() { thread_->Stop(); } +void DevToolsHttpHandlerImpl::WriteActivePortToUserProfile() { + DCHECK(!active_port_output_directory_.empty()); + net::IPEndPoint endpoint; + int err; + if ((err = server_->GetLocalAddress(&endpoint)) != net::OK) { + LOG(ERROR) << "Error " << err << " getting local address"; + return; + } + + // Write this port to a well-known file in the profile directory + // so Telemetry can pick it up. + base::FilePath path = active_port_output_directory_.Append( + kDevToolsActivePortFileName); + std::string port_string = base::IntToString(endpoint.port()); + if (base::WriteFile(path, port_string.c_str(), port_string.length()) < 0) { + LOG(ERROR) << "Error writing DevTools active port to file"; + } +} + void DevToolsHttpHandlerImpl::SendJson(int connection_id, net::HttpStatusCode status_code, base::Value* value, @@ -753,15 +784,18 @@ base::DictionaryValue* DevToolsHttpHandlerImpl::SerializeTarget( std::string id = target.GetId(); dictionary->SetString(kTargetIdField, id); + std::string parent_id = target.GetParentId(); + if (!parent_id.empty()) + dictionary->SetString(kTargetParentIdField, parent_id); dictionary->SetString(kTargetTypeField, target.GetType()); dictionary->SetString(kTargetTitleField, net::EscapeForHTML(target.GetTitle())); dictionary->SetString(kTargetDescriptionField, target.GetDescription()); - GURL url = target.GetUrl(); + GURL url = target.GetURL(); dictionary->SetString(kTargetUrlField, url.spec()); - GURL favicon_url = target.GetFaviconUrl(); + GURL favicon_url = target.GetFaviconURL(); if (favicon_url.is_valid()) dictionary->SetString(kTargetFaviconUrlField, favicon_url.spec()); diff --git a/chromium/content/browser/devtools/devtools_http_handler_impl.h b/chromium/content/browser/devtools/devtools_http_handler_impl.h index 4e40db07f11..0d08d9897aa 100644 --- a/chromium/content/browser/devtools/devtools_http_handler_impl.h +++ b/chromium/content/browser/devtools/devtools_http_handler_impl.h @@ -46,7 +46,8 @@ class DevToolsHttpHandlerImpl // Takes ownership over |socket_factory|. DevToolsHttpHandlerImpl(const net::StreamListenSocketFactory* socket_factory, const std::string& frontend_url, - DevToolsHttpHandlerDelegate* delegate); + DevToolsHttpHandlerDelegate* delegate, + const base::FilePath& active_port_output_directory); virtual ~DevToolsHttpHandlerImpl(); void Start(); @@ -90,6 +91,8 @@ class DevToolsHttpHandlerImpl void StartHandlerThread(); void StopHandlerThread(); + void WriteActivePortToUserProfile(); + void SendJson(int connection_id, net::HttpStatusCode status_code, base::Value* value, @@ -113,15 +116,17 @@ class DevToolsHttpHandlerImpl // The thread used by the devtools handler to run server socket. scoped_ptr<base::Thread> thread_; - std::string overridden_frontend_url_; + std::string frontend_url_; scoped_ptr<const net::StreamListenSocketFactory> socket_factory_; scoped_refptr<net::HttpServer> server_; typedef std::map<int, DevToolsClientHost*> ConnectionToClientHostMap; ConnectionToClientHostMap connection_to_client_host_ui_; scoped_ptr<DevToolsHttpHandlerDelegate> delegate_; + base::FilePath active_port_output_directory_; typedef std::map<std::string, DevToolsTarget*> TargetMap; TargetMap target_map_; - scoped_refptr<DevToolsBrowserTarget> browser_target_; + typedef std::map<int, scoped_refptr<DevToolsBrowserTarget> > BrowserTargets; + BrowserTargets browser_targets_; DISALLOW_COPY_AND_ASSIGN(DevToolsHttpHandlerImpl); }; diff --git a/chromium/content/browser/devtools/devtools_http_handler_unittest.cc b/chromium/content/browser/devtools/devtools_http_handler_unittest.cc index f3179f0f140..88710924c2a 100644 --- a/chromium/content/browser/devtools/devtools_http_handler_unittest.cc +++ b/chromium/content/browser/devtools/devtools_http_handler_unittest.cc @@ -2,25 +2,34 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include "base/file_util.h" +#include "base/files/scoped_temp_dir.h" #include "base/message_loop/message_loop.h" #include "base/run_loop.h" +#include "base/strings/string_number_conversions.h" #include "content/browser/browser_thread_impl.h" #include "content/public/browser/devtools_http_handler.h" #include "content/public/browser/devtools_http_handler_delegate.h" #include "content/public/browser/devtools_target.h" +#include "net/base/ip_endpoint.h" +#include "net/base/net_errors.h" #include "net/socket/stream_listen_socket.h" #include "testing/gtest/include/gtest/gtest.h" namespace content { namespace { +const int kDummyPort = 4321; +const base::FilePath::CharType kDevToolsActivePortFileName[] = + FILE_PATH_LITERAL("DevToolsActivePort"); + using net::StreamListenSocket; class DummyListenSocket : public StreamListenSocket, public StreamListenSocket::Delegate { public: DummyListenSocket() - : StreamListenSocket(0, this) {} + : StreamListenSocket(net::kInvalidSocket, this) {} // StreamListenSocket::Delegate "implementation" virtual void DidAccept(StreamListenSocket* server, @@ -32,6 +41,12 @@ class DummyListenSocket : public StreamListenSocket, protected: virtual ~DummyListenSocket() {} virtual void Accept() OVERRIDE {} + virtual int GetLocalAddress(net::IPEndPoint* address) OVERRIDE { + net::IPAddressNumber number; + EXPECT_TRUE(net::ParseIPLiteralToNumber("127.0.0.1", &number)); + *address = net::IPEndPoint(number, kDummyPort); + return net::OK; + } }; class DummyListenSocketFactory : public net::StreamListenSocketFactory { @@ -106,7 +121,8 @@ TEST_F(DevToolsHttpHandlerTest, TestStartStop) { new DummyListenSocketFactory(run_loop.QuitClosure(), run_loop_2.QuitClosure()), std::string(), - new DummyDelegate()); + new DummyDelegate(), + base::FilePath()); // Our dummy socket factory will post a quit message once the server will // become ready. run_loop.Run(); @@ -115,4 +131,34 @@ TEST_F(DevToolsHttpHandlerTest, TestStartStop) { run_loop_2.Run(); } +TEST_F(DevToolsHttpHandlerTest, TestDevToolsActivePort) { + base::RunLoop run_loop, run_loop_2; + base::ScopedTempDir temp_dir; + EXPECT_TRUE(temp_dir.CreateUniqueTempDir()); + content::DevToolsHttpHandler* devtools_http_handler_ = + content::DevToolsHttpHandler::Start( + new DummyListenSocketFactory(run_loop.QuitClosure(), + run_loop_2.QuitClosure()), + std::string(), + new DummyDelegate(), + temp_dir.path()); + // Our dummy socket factory will post a quit message once the server will + // become ready. + run_loop.Run(); + devtools_http_handler_->Stop(); + // Make sure the handler actually stops. + run_loop_2.Run(); + + // Now make sure the DevToolsActivePort was written into the + // temporary directory and its contents are as expected. + base::FilePath active_port_file = temp_dir.path().Append( + kDevToolsActivePortFileName); + EXPECT_TRUE(base::PathExists(active_port_file)); + std::string file_contents; + EXPECT_TRUE(base::ReadFileToString(active_port_file, &file_contents)); + int port = 0; + EXPECT_TRUE(base::StringToInt(file_contents, &port)); + EXPECT_EQ(kDummyPort, port); +} + } // namespace content diff --git a/chromium/content/browser/devtools/devtools_manager_impl.cc b/chromium/content/browser/devtools/devtools_manager_impl.cc index 56b2dd7d2f4..3aafd1c2e2e 100644 --- a/chromium/content/browser/devtools/devtools_manager_impl.cc +++ b/chromium/content/browser/devtools/devtools_manager_impl.cc @@ -13,7 +13,9 @@ #include "content/browser/renderer_host/render_view_host_impl.h" #include "content/browser/web_contents/web_contents_impl.h" #include "content/public/browser/browser_thread.h" +#include "content/public/browser/content_browser_client.h" #include "content/public/browser/devtools_client_host.h" +#include "content/public/browser/devtools_manager_delegate.h" namespace content { @@ -27,7 +29,8 @@ DevToolsManagerImpl* DevToolsManagerImpl::GetInstance() { return Singleton<DevToolsManagerImpl>::get(); } -DevToolsManagerImpl::DevToolsManagerImpl() { +DevToolsManagerImpl::DevToolsManagerImpl() + : delegate_(GetContentClient()->browser()->GetDevToolsManagerDelegate()) { } DevToolsManagerImpl::~DevToolsManagerImpl() { @@ -35,6 +38,12 @@ DevToolsManagerImpl::~DevToolsManagerImpl() { DCHECK(client_to_agent_host_.empty()); } +void DevToolsManagerImpl::Inspect(BrowserContext* browser_context, + DevToolsAgentHost* agent_host) { + if (delegate_) + delegate_->Inspect(browser_context, agent_host); +} + DevToolsClientHost* DevToolsManagerImpl::GetDevToolsClientHostFor( DevToolsAgentHostImpl* agent_host_impl) { AgentToClientHostMap::iterator it = @@ -184,6 +193,8 @@ void DevToolsManagerImpl::RemoveAgentStateCallback(const Callback& callback) { void DevToolsManagerImpl::NotifyObservers(DevToolsAgentHost* agent_host, bool attached) { CallbackContainer copy(callbacks_); + if (delegate_) + delegate_->DevToolsAgentStateChanged(agent_host, attached); for (CallbackContainer::iterator it = copy.begin(); it != copy.end(); ++it) (*it)->Run(agent_host, attached); } diff --git a/chromium/content/browser/devtools/devtools_manager_impl.h b/chromium/content/browser/devtools/devtools_manager_impl.h index a14b2f1ca11..19b6918518b 100644 --- a/chromium/content/browser/devtools/devtools_manager_impl.h +++ b/chromium/content/browser/devtools/devtools_manager_impl.h @@ -24,6 +24,8 @@ class Message; namespace content { +class BrowserContext; +class DevToolsManagerDelegate; class RenderViewHost; // This class is a singleton that manages DevToolsClientHost instances and @@ -43,9 +45,14 @@ class CONTENT_EXPORT DevToolsManagerImpl DevToolsManagerImpl(); virtual ~DevToolsManagerImpl(); + // Opens the inspector for |agent_host|. + void Inspect(BrowserContext* browser_context, DevToolsAgentHost* agent_host); + void DispatchOnInspectorFrontend(DevToolsAgentHost* agent_host, const std::string& message); + DevToolsManagerDelegate* delegate() const { return delegate_.get(); } + // DevToolsManager implementation virtual bool DispatchOnInspectorBackend(DevToolsClientHost* from, const std::string& message) OVERRIDE; @@ -96,6 +103,8 @@ class CONTENT_EXPORT DevToolsManagerImpl typedef std::vector<const Callback*> CallbackContainer; CallbackContainer callbacks_; + scoped_ptr<DevToolsManagerDelegate> delegate_; + DISALLOW_COPY_AND_ASSIGN(DevToolsManagerImpl); }; diff --git a/chromium/content/browser/devtools/devtools_manager_unittest.cc b/chromium/content/browser/devtools/devtools_manager_unittest.cc index aac9b6cbb92..75c527388b4 100644 --- a/chromium/content/browser/devtools/devtools_manager_unittest.cc +++ b/chromium/content/browser/devtools/devtools_manager_unittest.cc @@ -216,7 +216,7 @@ class TestExternalAgentDelegate: public DevToolsExternalAgentProxyDelegate { EXPECT_EQ(count, event_counter_[name]); } - virtual void Attach() OVERRIDE { + virtual void Attach(DevToolsExternalAgentProxy* proxy) OVERRIDE { recordEvent("Attach"); }; @@ -239,12 +239,10 @@ class TestExternalAgentDelegate: public DevToolsExternalAgentProxyDelegate { }; TEST_F(DevToolsManagerTest, TestExternalProxy) { - TestExternalAgentDelegate delegate; + TestExternalAgentDelegate* delegate = new TestExternalAgentDelegate(); - scoped_ptr<DevToolsExternalAgentProxy> proxy( - DevToolsExternalAgentProxy::Create(&delegate)); - - scoped_refptr<DevToolsAgentHost> agent_host = proxy->GetAgentHost(); + scoped_refptr<DevToolsAgentHost> agent_host = + DevToolsAgentHost::Create(delegate); EXPECT_EQ(agent_host, DevToolsAgentHost::GetForId(agent_host->GetId())); DevToolsManager* manager = DevToolsManager::GetInstance(); diff --git a/chromium/content/browser/devtools/devtools_netlog_observer.cc b/chromium/content/browser/devtools/devtools_netlog_observer.cc index 21a835b9e99..27ce58ae49b 100644 --- a/chromium/content/browser/devtools/devtools_netlog_observer.cc +++ b/chromium/content/browser/devtools/devtools_netlog_observer.cc @@ -42,10 +42,6 @@ void DevToolsNetLogObserver::OnAddEntry(const net::NetLog::Entry& entry) { if (entry.source().type == net::NetLog::SOURCE_URL_REQUEST) OnAddURLRequestEntry(entry); - else if (entry.source().type == net::NetLog::SOURCE_HTTP_STREAM_JOB) - OnAddHTTPStreamJobEntry(entry); - else if (entry.source().type == net::NetLog::SOURCE_SOCKET) - OnAddSocketEntry(entry); } void DevToolsNetLogObserver::OnAddURLRequestEntry( @@ -74,22 +70,12 @@ void DevToolsNetLogObserver::OnAddURLRequestEntry( } request_to_info_[entry.source().id] = new ResourceInfo(); - - if (request_to_encoded_data_length_.size() > kMaxNumEntries) { - LOG(WARNING) << "The encoded data length observer url request count " - "has grown larger than expected, resetting"; - request_to_encoded_data_length_.clear(); - } - - request_to_encoded_data_length_[entry.source().id] = 0; } return; } else if (entry.type() == net::NetLog::TYPE_REQUEST_ALIVE) { // Cleanup records based on the TYPE_REQUEST_ALIVE entry. - if (is_end) { + if (is_end) request_to_info_.erase(entry.source().id); - request_to_encoded_data_length_.erase(entry.source().id); - } return; } @@ -162,35 +148,15 @@ void DevToolsNetLogObserver::OnAddURLRequestEntry( response_headers->EnumerateHeaderLines(&it, &name, &value); ) { info->response_headers.push_back(std::make_pair(name, value)); } - info->response_headers_text = - net::HttpUtil::ConvertHeadersBackToHTTPResponse( - response_headers->raw_headers()); - break; - } - case net::NetLog::TYPE_HTTP_STREAM_REQUEST_BOUND_TO_JOB: { - scoped_ptr<base::Value> event_params(entry.ParametersToValue()); - net::NetLog::Source http_stream_job_source; - if (!net::NetLog::Source::FromEventParameters(event_params.get(), - &http_stream_job_source)) { - NOTREACHED(); - break; - } - uint32 http_stream_job_id = http_stream_job_source.id; - HTTPStreamJobToSocketMap::iterator it = - http_stream_job_to_socket_.find(http_stream_job_id); - if (it == http_stream_job_to_socket_.end()) - return; - uint32 socket_id = it->second; - - if (socket_to_request_.size() > kMaxNumEntries) { - LOG(WARNING) << "The url request observer socket count has grown " - "larger than expected, resetting"; - socket_to_request_.clear(); + if (!info->request_headers_text.empty()) { + info->response_headers_text = + net::HttpUtil::ConvertHeadersBackToHTTPResponse( + response_headers->raw_headers()); + } else { + // SPDY request. + info->response_headers_text = ""; } - - socket_to_request_[socket_id] = entry.source().id; - http_stream_job_to_socket_.erase(http_stream_job_id); break; } default: @@ -198,68 +164,6 @@ void DevToolsNetLogObserver::OnAddURLRequestEntry( } } -void DevToolsNetLogObserver::OnAddHTTPStreamJobEntry( - const net::NetLog::Entry& entry) { - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); - - if (entry.type() == net::NetLog::TYPE_SOCKET_POOL_BOUND_TO_SOCKET) { - scoped_ptr<base::Value> event_params(entry.ParametersToValue()); - net::NetLog::Source socket_source; - if (!net::NetLog::Source::FromEventParameters(event_params.get(), - &socket_source)) { - NOTREACHED(); - return; - } - - // Prevents us from passively growing the memory unbounded in - // case something went wrong. Should not happen. - if (http_stream_job_to_socket_.size() > kMaxNumEntries) { - LOG(WARNING) << "The load timing observer http stream job count " - "has grown larger than expected, resetting"; - http_stream_job_to_socket_.clear(); - } - http_stream_job_to_socket_[entry.source().id] = socket_source.id; - } -} - -void DevToolsNetLogObserver::OnAddSocketEntry( - const net::NetLog::Entry& entry) { - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); - - bool is_end = entry.phase() == net::NetLog::PHASE_END; - - SocketToRequestMap::iterator it = - socket_to_request_.find(entry.source().id); - if (it == socket_to_request_.end()) - return; - uint32 request_id = it->second; - - if (entry.type() == net::NetLog::TYPE_SOCKET_IN_USE) { - if (is_end) - socket_to_request_.erase(entry.source().id); - return; - } - - RequestToEncodedDataLengthMap::iterator encoded_data_length_it = - request_to_encoded_data_length_.find(request_id); - if (encoded_data_length_it == request_to_encoded_data_length_.end()) - return; - - if (net::NetLog::TYPE_SOCKET_BYTES_RECEIVED == entry.type()) { - int byte_count = 0; - scoped_ptr<base::Value> value(entry.ParametersToValue()); - if (!value->IsType(base::Value::TYPE_DICTIONARY)) - return; - - base::DictionaryValue* dValue = - static_cast<base::DictionaryValue*>(value.get()); - if (!dValue->GetInteger("byte_count", &byte_count)) - return; - - encoded_data_length_it->second += byte_count; - } -} - void DevToolsNetLogObserver::Attach() { DCHECK(!instance_); net::NetLog* net_log = GetContentClient()->browser()->GetNetLog(); @@ -303,26 +207,4 @@ void DevToolsNetLogObserver::PopulateResponseInfo( dev_tools_net_log_observer->GetResourceInfo(source_id); } -// static -int DevToolsNetLogObserver::GetAndResetEncodedDataLength( - net::URLRequest* request) { - if (!(request->load_flags() & net::LOAD_REPORT_RAW_HEADERS)) - return -1; - - uint32 source_id = request->net_log().source().id; - DevToolsNetLogObserver* dev_tools_net_log_observer = - DevToolsNetLogObserver::GetInstance(); - if (dev_tools_net_log_observer == NULL) - return -1; - - RequestToEncodedDataLengthMap::iterator it = - dev_tools_net_log_observer->request_to_encoded_data_length_.find( - source_id); - if (it == dev_tools_net_log_observer->request_to_encoded_data_length_.end()) - return -1; - int encoded_data_length = it->second; - it->second = 0; - return encoded_data_length; -} - } // namespace content diff --git a/chromium/content/browser/devtools/devtools_netlog_observer.h b/chromium/content/browser/devtools/devtools_netlog_observer.h index d1d478c3791..f063a3d432c 100644 --- a/chromium/content/browser/devtools/devtools_netlog_observer.h +++ b/chromium/content/browser/devtools/devtools_netlog_observer.h @@ -7,8 +7,8 @@ #include "base/containers/hash_tables.h" #include "base/memory/ref_counted.h" +#include "content/public/common/resource_devtools_info.h" #include "net/base/net_log.h" -#include "webkit/common/resource_devtools_info.h" namespace net { class URLRequest; @@ -25,15 +25,13 @@ struct ResourceResponse; // IO Thread, it must also reside on the IO Thread. Only OnAddEntry can be // called from other threads. class DevToolsNetLogObserver : public net::NetLog::ThreadSafeObserver { - typedef webkit_glue::ResourceDevToolsInfo ResourceInfo; + typedef ResourceDevToolsInfo ResourceInfo; public: // net::NetLog::ThreadSafeObserver implementation: virtual void OnAddEntry(const net::NetLog::Entry& entry) OVERRIDE; void OnAddURLRequestEntry(const net::NetLog::Entry& entry); - void OnAddHTTPStreamJobEntry(const net::NetLog::Entry& entry); - void OnAddSocketEntry(const net::NetLog::Entry& entry); static void Attach(); static void Detach(); @@ -43,7 +41,6 @@ class DevToolsNetLogObserver : public net::NetLog::ThreadSafeObserver { static DevToolsNetLogObserver* GetInstance(); static void PopulateResponseInfo(net::URLRequest*, ResourceResponse*); - static int GetAndResetEncodedDataLength(net::URLRequest* request); private: static DevToolsNetLogObserver* instance_; @@ -54,13 +51,7 @@ class DevToolsNetLogObserver : public net::NetLog::ThreadSafeObserver { ResourceInfo* GetResourceInfo(uint32 id); typedef base::hash_map<uint32, scoped_refptr<ResourceInfo> > RequestToInfoMap; - typedef base::hash_map<uint32, int> RequestToEncodedDataLengthMap; - typedef base::hash_map<uint32, uint32> HTTPStreamJobToSocketMap; - typedef base::hash_map<uint32, uint32> SocketToRequestMap; RequestToInfoMap request_to_info_; - RequestToEncodedDataLengthMap request_to_encoded_data_length_; - HTTPStreamJobToSocketMap http_stream_job_to_socket_; - SocketToRequestMap socket_to_request_; DISALLOW_COPY_AND_ASSIGN(DevToolsNetLogObserver); }; diff --git a/chromium/content/browser/devtools/devtools_power_handler.cc b/chromium/content/browser/devtools/devtools_power_handler.cc new file mode 100644 index 00000000000..43772b47607 --- /dev/null +++ b/chromium/content/browser/devtools/devtools_power_handler.cc @@ -0,0 +1,83 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "content/browser/devtools/devtools_power_handler.h" + +#include "base/bind.h" +#include "base/values.h" +#include "content/browser/devtools/devtools_protocol_constants.h" +#include "content/browser/power_profiler/power_profiler_service.h" + +namespace content { + +DevToolsPowerHandler::DevToolsPowerHandler() { + RegisterCommandHandler(devtools::Power::start::kName, + base::Bind(&DevToolsPowerHandler::OnStart, + base::Unretained(this))); + RegisterCommandHandler(devtools::Power::end::kName, + base::Bind(&DevToolsPowerHandler::OnEnd, + base::Unretained(this))); + RegisterCommandHandler(devtools::Power::canProfilePower::kName, + base::Bind(&DevToolsPowerHandler::OnCanProfilePower, + base::Unretained(this))); +} + +DevToolsPowerHandler::~DevToolsPowerHandler() { + PowerProfilerService::GetInstance()->RemoveObserver(this); +} + +void DevToolsPowerHandler::OnPowerEvent(const PowerEventVector& events) { + base::DictionaryValue* params = new base::DictionaryValue(); + base::ListValue* event_list = new base::ListValue(); + + std::vector<PowerEvent>::const_iterator iter; + for (iter = events.begin(); iter != events.end(); ++iter) { + base::DictionaryValue* event_body = new base::DictionaryValue(); + + DCHECK(iter->type < PowerEvent::ID_COUNT); + event_body->SetString("type", kPowerTypeNames[iter->type]); + // Use internal value to be consistent with Blink's + // monotonicallyIncreasingTime. + event_body->SetDouble("timestamp", iter->time.ToInternalValue() / + static_cast<double>(base::Time::kMicrosecondsPerMillisecond)); + event_body->SetDouble("value", iter->value); + event_list->Append(event_body); + } + + params->Set(devtools::Power::dataAvailable::kParamValue, event_list); + SendNotification(devtools::Power::dataAvailable::kName, params); +} + +scoped_refptr<DevToolsProtocol::Response> +DevToolsPowerHandler::OnStart( + scoped_refptr<DevToolsProtocol::Command> command) { + if (PowerProfilerService::GetInstance()->IsAvailable()) { + PowerProfilerService::GetInstance()->AddObserver(this); + return command->SuccessResponse(NULL); + } + + return command->InternalErrorResponse("Power profiler service unavailable"); +} + +scoped_refptr<DevToolsProtocol::Response> +DevToolsPowerHandler::OnEnd(scoped_refptr<DevToolsProtocol::Command> command) { + if (PowerProfilerService::GetInstance()->IsAvailable()) { + PowerProfilerService::GetInstance()->RemoveObserver(this); + return command->SuccessResponse(NULL); + } + + return command->InternalErrorResponse("Power profiler service unavailable"); +} + +scoped_refptr<DevToolsProtocol::Response> +DevToolsPowerHandler::OnCanProfilePower( + scoped_refptr<DevToolsProtocol::Command> command) { + base::DictionaryValue* result = new base::DictionaryValue(); + result->SetBoolean(devtools::kResult, + PowerProfilerService::GetInstance()->IsAvailable()); + + return command->SuccessResponse(result); +} + +} // namespace content diff --git a/chromium/content/browser/devtools/devtools_power_handler.h b/chromium/content/browser/devtools/devtools_power_handler.h new file mode 100644 index 00000000000..f645392a199 --- /dev/null +++ b/chromium/content/browser/devtools/devtools_power_handler.h @@ -0,0 +1,38 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CONTENT_BROWSER_DEVTOOLS_DEVTOOLS_POWER_HANDLER_H_ +#define CONTENT_BROWSER_DEVTOOLS_DEVTOOLS_POWER_HANDLER_H_ + +#include "base/time/time.h" +#include "content/browser/devtools/devtools_protocol.h" +#include "content/browser/power_profiler/power_profiler_observer.h" + +namespace content { + +// This class provides power information to DevTools. +class DevToolsPowerHandler + : public DevToolsProtocol::Handler, + public PowerProfilerObserver { + public: + DevToolsPowerHandler(); + virtual ~DevToolsPowerHandler(); + + // PowerProfilerObserver override. + virtual void OnPowerEvent(const PowerEventVector&) OVERRIDE; + + private: + scoped_refptr<DevToolsProtocol::Response> OnStart( + scoped_refptr<DevToolsProtocol::Command> command); + scoped_refptr<DevToolsProtocol::Response> OnEnd( + scoped_refptr<DevToolsProtocol::Command> command); + scoped_refptr<DevToolsProtocol::Response> OnCanProfilePower( + scoped_refptr<DevToolsProtocol::Command> command); + + DISALLOW_COPY_AND_ASSIGN(DevToolsPowerHandler); +}; + +} // namespace content + +#endif // CONTENT_BROWSER_DEVTOOLS_DEVTOOLS_POWER_HANDLER_H_ diff --git a/chromium/content/browser/devtools/devtools_protocol.cc b/chromium/content/browser/devtools/devtools_protocol.cc index e0e544e54c4..5e127f1dcba 100644 --- a/chromium/content/browser/devtools/devtools_protocol.cc +++ b/chromium/content/browser/devtools/devtools_protocol.cc @@ -27,7 +27,8 @@ enum Error { kErrorInvalidRequest = -32600, kErrorNoSuchMethod = -32601, kErrorInvalidParams = -32602, - kErrorInternalError = -32603 + kErrorInternalError = -32603, + kErrorServerError = -32000 }; } // namespace @@ -84,6 +85,11 @@ DevToolsProtocol::Command::NoSuchMethodErrorResponse() { } scoped_refptr<DevToolsProtocol::Response> +DevToolsProtocol::Command::ServerErrorResponse(const std::string& message) { + return new Response(id_, kErrorServerError, message); +} + +scoped_refptr<DevToolsProtocol::Response> DevToolsProtocol::Command::AsyncResponsePromise() { scoped_refptr<DevToolsProtocol::Response> promise = new DevToolsProtocol::Response(0, NULL); @@ -216,13 +222,20 @@ scoped_refptr<DevToolsProtocol::Command> DevToolsProtocol::ParseCommand( std::string* error_response) { scoped_ptr<base::DictionaryValue> command_dict( ParseMessage(json, error_response)); + return ParseCommand(command_dict.get(), error_response); +} + +// static +scoped_refptr<DevToolsProtocol::Command> DevToolsProtocol::ParseCommand( + base::DictionaryValue* command_dict, + std::string* error_response) { if (!command_dict) return NULL; int id; std::string method; bool ok = command_dict->GetInteger(kIdParam, &id) && id >= 0; - ok = ok && ParseMethod(command_dict.get(), &method); + ok = ok && ParseMethod(command_dict, &method); if (!ok) { scoped_refptr<Response> response = new Response(kNoId, kErrorInvalidRequest, "No such method"); @@ -244,6 +257,28 @@ DevToolsProtocol::CreateCommand( return new Command(id, method, params); } +//static +scoped_refptr<DevToolsProtocol::Response> +DevToolsProtocol::ParseResponse( + base::DictionaryValue* response_dict) { + int id; + if (!response_dict->GetInteger(kIdParam, &id)) + id = kNoId; + + const base::DictionaryValue* error_dict; + if (response_dict->GetDictionary(kErrorParam, &error_dict)) { + int error_code = kErrorInternalError; + response_dict->GetInteger(kErrorCodeParam, &error_code); + std::string error_message; + response_dict->GetString(kErrorMessageParam, &error_message); + return new Response(id, error_code, error_message); + } + + const base::DictionaryValue* result = NULL; + response_dict->GetDictionary(kResultParam, &result); + return new Response(id, result ? result->DeepCopy() : NULL); +} + // static scoped_refptr<DevToolsProtocol::Notification> DevToolsProtocol::ParseNotification(const std::string& json) { @@ -275,11 +310,11 @@ base::DictionaryValue* DevToolsProtocol::ParseMessage( std::string* error_response) { int parse_error_code; std::string error_message; - scoped_ptr<Value> message( + scoped_ptr<base::Value> message( base::JSONReader::ReadAndReturnError( json, 0, &parse_error_code, &error_message)); - if (!message || !message->IsType(Value::TYPE_DICTIONARY)) { + if (!message || !message->IsType(base::Value::TYPE_DICTIONARY)) { scoped_refptr<Response> response = new Response(0, kErrorParseError, error_message); if (error_response) diff --git a/chromium/content/browser/devtools/devtools_protocol.h b/chromium/content/browser/devtools/devtools_protocol.h index 15b0a8087be..cbc075b3715 100644 --- a/chromium/content/browser/devtools/devtools_protocol.h +++ b/chromium/content/browser/devtools/devtools_protocol.h @@ -64,6 +64,9 @@ class DevToolsProtocol { // Creates error response. scoped_refptr<Response> NoSuchMethodErrorResponse(); + // Creates error response. + scoped_refptr<Response> ServerErrorResponse(const std::string& message); + // Creates async response promise. scoped_refptr<Response> AsyncResponsePromise(); @@ -157,25 +160,32 @@ class DevToolsProtocol { DISALLOW_COPY_AND_ASSIGN(Handler); }; + CONTENT_EXPORT static base::DictionaryValue* ParseMessage( + const std::string& json, + std::string* error_response); + CONTENT_EXPORT static scoped_refptr<Command> ParseCommand( const std::string& json, std::string* error_response); + CONTENT_EXPORT static scoped_refptr<Command> ParseCommand( + base::DictionaryValue* command_dict, + std::string* error_response); + CONTENT_EXPORT static scoped_refptr<Command> CreateCommand( int id, const std::string& method, base::DictionaryValue* params); + CONTENT_EXPORT static scoped_refptr<Response> ParseResponse( + base::DictionaryValue* response_dict); + static scoped_refptr<Notification> ParseNotification( const std::string& json); static scoped_refptr<Notification> CreateNotification( const std::string& method, base::DictionaryValue* params); - private: - static base::DictionaryValue* ParseMessage(const std::string& json, - std::string* error_response); - DevToolsProtocol() {} ~DevToolsProtocol() {} }; diff --git a/chromium/content/browser/devtools/devtools_protocol_constants.cc b/chromium/content/browser/devtools/devtools_protocol_constants.cc deleted file mode 100644 index af5ecd1f580..00000000000 --- a/chromium/content/browser/devtools/devtools_protocol_constants.cc +++ /dev/null @@ -1,293 +0,0 @@ -// Copyright (c) 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -// THIS FILE IS AUTOGENERATED. -// If you need change something in this file, please see -// protocol.json and browser_protocol.json - -#include "content/browser/devtools/devtools_protocol_constants.h" - -namespace content { -namespace devtools { - -const char kResult[] = "result"; - -namespace DOM { - const char kName[] = "DOM"; - - namespace Rect { - const char kParamHeight[] = "height"; - const char kParamWidth[] = "width"; - const char kParamX[] = "x"; - const char kParamY[] = "y"; - } // Rect - - namespace setFileInputFiles { - const char kName[] = "DOM.setFileInputFiles"; - const char kParamFiles[] = "files"; - const char kParamNodeId[] = "nodeId"; - } // setFileInputFiles -} // DOM - -namespace Input { - const char kName[] = "Input"; - - namespace dispatchGestureEvent { - const char kName[] = "Input.dispatchGestureEvent"; - const char kParamDeltaX[] = "deltaX"; - const char kParamDeltaY[] = "deltaY"; - const char kParamPinchScale[] = "pinchScale"; - const char kParamTimestamp[] = "timestamp"; - const char kParamType[] = "type"; - const char kParamX[] = "x"; - const char kParamY[] = "y"; - - namespace Type { - const char kEnumPinchBegin[] = "pinchBegin"; - const char kEnumPinchEnd[] = "pinchEnd"; - const char kEnumPinchUpdate[] = "pinchUpdate"; - const char kEnumScrollBegin[] = "scrollBegin"; - const char kEnumScrollEnd[] = "scrollEnd"; - const char kEnumScrollUpdate[] = "scrollUpdate"; - const char kEnumTap[] = "tap"; - const char kEnumTapDown[] = "tapDown"; - } // Type - } // dispatchGestureEvent - - namespace dispatchMouseEvent { - const char kName[] = "Input.dispatchMouseEvent"; - const char kParamButton[] = "button"; - const char kParamClickCount[] = "clickCount"; - const char kParamDeviceSpace[] = "deviceSpace"; - const char kParamModifiers[] = "modifiers"; - const char kParamTimestamp[] = "timestamp"; - const char kParamType[] = "type"; - const char kParamX[] = "x"; - const char kParamY[] = "y"; - - namespace Button { - const char kEnumLeft[] = "left"; - const char kEnumMiddle[] = "middle"; - const char kEnumNone[] = "none"; - const char kEnumRight[] = "right"; - } // Button - - namespace Type { - const char kEnumMouseMoved[] = "mouseMoved"; - const char kEnumMousePressed[] = "mousePressed"; - const char kEnumMouseReleased[] = "mouseReleased"; - } // Type - } // dispatchMouseEvent -} // Input - -namespace Inspector { - const char kName[] = "Inspector"; - - namespace detached { - const char kName[] = "Inspector.detached"; - const char kParamReason[] = "reason"; - } // detached - - namespace targetCrashed { - const char kName[] = "Inspector.targetCrashed"; - } // targetCrashed -} // Inspector - -namespace Page { - const char kName[] = "Page"; - - namespace NavigationEntry { - const char kParamId[] = "id"; - const char kParamTitle[] = "title"; - const char kParamUrl[] = "url"; - } // NavigationEntry - - namespace Quota { - const char kParamPersistent[] = "persistent"; - const char kParamTemporary[] = "temporary"; - } // Quota - - namespace ScreencastFrameMetadata { - const char kParamDeviceScaleFactor[] = "deviceScaleFactor"; - const char kParamOffsetBottom[] = "offsetBottom"; - const char kParamOffsetTop[] = "offsetTop"; - const char kParamPageScaleFactor[] = "pageScaleFactor"; - const char kParamPageScaleFactorMax[] = "pageScaleFactorMax"; - const char kParamPageScaleFactorMin[] = "pageScaleFactorMin"; - const char kParamViewport[] = "viewport"; - } // ScreencastFrameMetadata - - namespace Usage { - const char kParamPersistent[] = "persistent"; - const char kParamSyncable[] = "syncable"; - const char kParamTemporary[] = "temporary"; - } // Usage - - namespace UsageItem { - const char kParamId[] = "id"; - const char kParamValue[] = "value"; - - namespace Id { - const char kEnumAppcache[] = "appcache"; - const char kEnumDatabase[] = "database"; - const char kEnumFilesystem[] = "filesystem"; - const char kEnumIndexeddatabase[] = "indexeddatabase"; - } // Id - } // UsageItem - - namespace canScreencast { - const char kName[] = "Page.canScreencast"; - const char kResponseResult[] = "result"; - } // canScreencast - - namespace captureScreenshot { - const char kName[] = "Page.captureScreenshot"; - const char kParamFormat[] = "format"; - const char kParamMaxHeight[] = "maxHeight"; - const char kParamMaxWidth[] = "maxWidth"; - const char kParamQuality[] = "quality"; - const char kResponseData[] = "data"; - const char kResponseMetadata[] = "metadata"; - - namespace Format { - const char kEnumJpeg[] = "jpeg"; - const char kEnumPng[] = "png"; - } // Format - } // captureScreenshot - - namespace disable { - const char kName[] = "Page.disable"; - } // disable - - namespace getNavigationHistory { - const char kName[] = "Page.getNavigationHistory"; - const char kResponseCurrentIndex[] = "currentIndex"; - const char kResponseEntries[] = "entries"; - } // getNavigationHistory - - namespace handleJavaScriptDialog { - const char kName[] = "Page.handleJavaScriptDialog"; - const char kParamAccept[] = "accept"; - const char kParamPromptText[] = "promptText"; - } // handleJavaScriptDialog - - namespace navigate { - const char kName[] = "Page.navigate"; - const char kParamUrl[] = "url"; - } // navigate - - namespace navigateToHistoryEntry { - const char kName[] = "Page.navigateToHistoryEntry"; - const char kParamEntryId[] = "entryId"; - } // navigateToHistoryEntry - - namespace queryUsageAndQuota { - const char kName[] = "Page.queryUsageAndQuota"; - const char kParamSecurityOrigin[] = "securityOrigin"; - const char kResponseQuota[] = "quota"; - const char kResponseUsage[] = "usage"; - } // queryUsageAndQuota - - namespace reload { - const char kName[] = "Page.reload"; - const char kParamIgnoreCache[] = "ignoreCache"; - const char kParamScriptPreprocessor[] = "scriptPreprocessor"; - const char kParamScriptToEvaluateOnLoad[] = "scriptToEvaluateOnLoad"; - } // reload - - namespace screencastFrame { - const char kName[] = "Page.screencastFrame"; - const char kParamData[] = "data"; - const char kParamMetadata[] = "metadata"; - } // screencastFrame - - namespace screencastVisibilityChanged { - const char kName[] = "Page.screencastVisibilityChanged"; - const char kParamVisible[] = "visible"; - } // screencastVisibilityChanged - - namespace startScreencast { - const char kName[] = "Page.startScreencast"; - const char kParamFormat[] = "format"; - const char kParamMaxHeight[] = "maxHeight"; - const char kParamMaxWidth[] = "maxWidth"; - const char kParamQuality[] = "quality"; - - namespace Format { - const char kEnumJpeg[] = "jpeg"; - const char kEnumPng[] = "png"; - } // Format - } // startScreencast - - namespace stopScreencast { - const char kName[] = "Page.stopScreencast"; - } // stopScreencast -} // Page - -namespace SystemInfo { - const char kName[] = "SystemInfo"; - - namespace GPUDevice { - const char kParamDeviceId[] = "deviceId"; - const char kParamDeviceString[] = "deviceString"; - const char kParamVendorId[] = "vendorId"; - const char kParamVendorString[] = "vendorString"; - } // GPUDevice - - namespace GPUInfo { - const char kParamAuxAttributes[] = "auxAttributes"; - const char kParamDevices[] = "devices"; - const char kParamFeatureStatus[] = "featureStatus"; - } // GPUInfo - - namespace SystemInfo { - const char kParamGpu[] = "gpu"; - const char kParamModelName[] = "modelName"; - } // SystemInfo - - namespace getInfo { - const char kName[] = "SystemInfo.getInfo"; - const char kResponseInfo[] = "info"; - } // getInfo -} // SystemInfo - -namespace Tracing { - const char kName[] = "Tracing"; - - namespace dataCollected { - const char kName[] = "Tracing.dataCollected"; - const char kParamValue[] = "value"; - } // dataCollected - - namespace end { - const char kName[] = "Tracing.end"; - } // end - - namespace start { - const char kName[] = "Tracing.start"; - const char kParamCategories[] = "categories"; - const char kParamOptions[] = "options"; - } // start - - namespace tracingComplete { - const char kName[] = "Tracing.tracingComplete"; - } // tracingComplete -} // Tracing - -namespace Worker { - const char kName[] = "Worker"; - - namespace disconnectFromWorker { - const char kName[] = "Worker.disconnectFromWorker"; - const char kParamWorkerId[] = "workerId"; - } // disconnectFromWorker - - namespace disconnectedFromWorker { - const char kName[] = "Worker.disconnectedFromWorker"; - } // disconnectedFromWorker -} // Worker - - -} // devtools -} // content diff --git a/chromium/content/browser/devtools/devtools_protocol_constants.h b/chromium/content/browser/devtools/devtools_protocol_constants.h deleted file mode 100644 index 8ed159bc0df..00000000000 --- a/chromium/content/browser/devtools/devtools_protocol_constants.h +++ /dev/null @@ -1,296 +0,0 @@ -// Copyright (c) 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef CONTENT_BROWSER_DEVTOOLS_DEVTOOLS_PROTOCOL_CONSTANTSH_ -#define CONTENT_BROWSER_DEVTOOLS_DEVTOOLS_PROTOCOL_CONSTANTSH_ - -// THIS FILE IS AUTOGENERATED. -// If you need change something in this file, please see -// protocol.json and browser_protocol.json - -namespace content { -namespace devtools { - -extern const char kResult[]; - -namespace DOM { - extern const char kName[]; - - namespace Rect { - extern const char kParamHeight[]; - extern const char kParamWidth[]; - extern const char kParamX[]; - extern const char kParamY[]; - } // Rect - - namespace setFileInputFiles { - extern const char kName[]; - extern const char kParamFiles[]; - extern const char kParamNodeId[]; - } // setFileInputFiles -} // DOM - -namespace Input { - extern const char kName[]; - - namespace dispatchGestureEvent { - extern const char kName[]; - extern const char kParamDeltaX[]; - extern const char kParamDeltaY[]; - extern const char kParamPinchScale[]; - extern const char kParamTimestamp[]; - extern const char kParamType[]; - extern const char kParamX[]; - extern const char kParamY[]; - - namespace Type { - extern const char kEnumPinchBegin[]; - extern const char kEnumPinchEnd[]; - extern const char kEnumPinchUpdate[]; - extern const char kEnumScrollBegin[]; - extern const char kEnumScrollEnd[]; - extern const char kEnumScrollUpdate[]; - extern const char kEnumTap[]; - extern const char kEnumTapDown[]; - } // Type - } // dispatchGestureEvent - - namespace dispatchMouseEvent { - extern const char kName[]; - extern const char kParamButton[]; - extern const char kParamClickCount[]; - extern const char kParamDeviceSpace[]; - extern const char kParamModifiers[]; - extern const char kParamTimestamp[]; - extern const char kParamType[]; - extern const char kParamX[]; - extern const char kParamY[]; - - namespace Button { - extern const char kEnumLeft[]; - extern const char kEnumMiddle[]; - extern const char kEnumNone[]; - extern const char kEnumRight[]; - } // Button - - namespace Type { - extern const char kEnumMouseMoved[]; - extern const char kEnumMousePressed[]; - extern const char kEnumMouseReleased[]; - } // Type - } // dispatchMouseEvent -} // Input - -namespace Inspector { - extern const char kName[]; - - namespace detached { - extern const char kName[]; - extern const char kParamReason[]; - } // detached - - namespace targetCrashed { - extern const char kName[]; - } // targetCrashed -} // Inspector - -namespace Page { - extern const char kName[]; - - namespace NavigationEntry { - extern const char kParamId[]; - extern const char kParamTitle[]; - extern const char kParamUrl[]; - } // NavigationEntry - - namespace Quota { - extern const char kParamPersistent[]; - extern const char kParamTemporary[]; - } // Quota - - namespace ScreencastFrameMetadata { - extern const char kParamDeviceScaleFactor[]; - extern const char kParamOffsetBottom[]; - extern const char kParamOffsetTop[]; - extern const char kParamPageScaleFactor[]; - extern const char kParamPageScaleFactorMax[]; - extern const char kParamPageScaleFactorMin[]; - extern const char kParamViewport[]; - } // ScreencastFrameMetadata - - namespace Usage { - extern const char kParamPersistent[]; - extern const char kParamSyncable[]; - extern const char kParamTemporary[]; - } // Usage - - namespace UsageItem { - extern const char kParamId[]; - extern const char kParamValue[]; - - namespace Id { - extern const char kEnumAppcache[]; - extern const char kEnumDatabase[]; - extern const char kEnumFilesystem[]; - extern const char kEnumIndexeddatabase[]; - } // Id - } // UsageItem - - namespace canScreencast { - extern const char kName[]; - extern const char kResponseResult[]; - } // canScreencast - - namespace captureScreenshot { - extern const char kName[]; - extern const char kParamFormat[]; - extern const char kParamMaxHeight[]; - extern const char kParamMaxWidth[]; - extern const char kParamQuality[]; - extern const char kResponseData[]; - extern const char kResponseMetadata[]; - - namespace Format { - extern const char kEnumJpeg[]; - extern const char kEnumPng[]; - } // Format - } // captureScreenshot - - namespace disable { - extern const char kName[]; - } // disable - - namespace getNavigationHistory { - extern const char kName[]; - extern const char kResponseCurrentIndex[]; - extern const char kResponseEntries[]; - } // getNavigationHistory - - namespace handleJavaScriptDialog { - extern const char kName[]; - extern const char kParamAccept[]; - extern const char kParamPromptText[]; - } // handleJavaScriptDialog - - namespace navigate { - extern const char kName[]; - extern const char kParamUrl[]; - } // navigate - - namespace navigateToHistoryEntry { - extern const char kName[]; - extern const char kParamEntryId[]; - } // navigateToHistoryEntry - - namespace queryUsageAndQuota { - extern const char kName[]; - extern const char kParamSecurityOrigin[]; - extern const char kResponseQuota[]; - extern const char kResponseUsage[]; - } // queryUsageAndQuota - - namespace reload { - extern const char kName[]; - extern const char kParamIgnoreCache[]; - extern const char kParamScriptPreprocessor[]; - extern const char kParamScriptToEvaluateOnLoad[]; - } // reload - - namespace screencastFrame { - extern const char kName[]; - extern const char kParamData[]; - extern const char kParamMetadata[]; - } // screencastFrame - - namespace screencastVisibilityChanged { - extern const char kName[]; - extern const char kParamVisible[]; - } // screencastVisibilityChanged - - namespace startScreencast { - extern const char kName[]; - extern const char kParamFormat[]; - extern const char kParamMaxHeight[]; - extern const char kParamMaxWidth[]; - extern const char kParamQuality[]; - - namespace Format { - extern const char kEnumJpeg[]; - extern const char kEnumPng[]; - } // Format - } // startScreencast - - namespace stopScreencast { - extern const char kName[]; - } // stopScreencast -} // Page - -namespace SystemInfo { - extern const char kName[]; - - namespace GPUDevice { - extern const char kParamDeviceId[]; - extern const char kParamDeviceString[]; - extern const char kParamVendorId[]; - extern const char kParamVendorString[]; - } // GPUDevice - - namespace GPUInfo { - extern const char kParamAuxAttributes[]; - extern const char kParamDevices[]; - extern const char kParamFeatureStatus[]; - } // GPUInfo - - namespace SystemInfo { - extern const char kParamGpu[]; - extern const char kParamModelName[]; - } // SystemInfo - - namespace getInfo { - extern const char kName[]; - extern const char kResponseInfo[]; - } // getInfo -} // SystemInfo - -namespace Tracing { - extern const char kName[]; - - namespace dataCollected { - extern const char kName[]; - extern const char kParamValue[]; - } // dataCollected - - namespace end { - extern const char kName[]; - } // end - - namespace start { - extern const char kName[]; - extern const char kParamCategories[]; - extern const char kParamOptions[]; - } // start - - namespace tracingComplete { - extern const char kName[]; - } // tracingComplete -} // Tracing - -namespace Worker { - extern const char kName[]; - - namespace disconnectFromWorker { - extern const char kName[]; - extern const char kParamWorkerId[]; - } // disconnectFromWorker - - namespace disconnectedFromWorker { - extern const char kName[]; - } // disconnectedFromWorker -} // Worker - - -} // devtools -} // content - -#endif // CONTENT_BROWSER_DEVTOOLS_DEVTOOLS_PROTOCOL_CONSTANTSH_ diff --git a/chromium/content/browser/devtools/devtools_resources.gyp b/chromium/content/browser/devtools/devtools_resources.gyp index 30b42209453..72ae7060549 100644 --- a/chromium/content/browser/devtools/devtools_resources.gyp +++ b/chromium/content/browser/devtools/devtools_resources.gyp @@ -22,6 +22,7 @@ 'variables': { 'grit_cmd': ['python', '../../../tools/grit/grit.py'], 'grit_grd_file': '<(SHARED_INTERMEDIATE_DIR)/devtools/devtools_resources.grd', + 'grit_rc_header_format%': '', }, 'inputs': [ '<(grit_grd_file)', @@ -35,14 +36,47 @@ ], 'action': ['<@(grit_cmd)', '-i', '<(grit_grd_file)', 'build', - '-f', 'GRIT_DIR/../gritsettings/resource_ids', + '-f', '<(DEPTH)/tools/gritsettings/resource_ids', '-o', '<(grit_out_dir)', '-D', 'SHARED_INTERMEDIATE_DIR=<(SHARED_INTERMEDIATE_DIR)', - '<@(grit_defines)' ], + '<@(grit_defines)', + '<@(grit_rc_header_format)'], 'message': 'Generating resources from <(grit_grd_file)', - 'msvs_cygwin_shell': 1, + }, + { + 'action_name': 'devtools_protocol_constants', + 'variables': { + 'blink_protocol': '../../../third_party/WebKit/Source/devtools/protocol.json', + 'browser_protocol': 'browser_protocol.json', + 'generator': '../../public/browser/devtools_protocol_constants_generator.py', + 'package': 'content' + }, + 'inputs': [ + '<(blink_protocol)', + '<(browser_protocol)', + '<(generator)', + ], + 'outputs': [ + '<(SHARED_INTERMEDIATE_DIR)/<(package)/browser/devtools/devtools_protocol_constants.cc', + '<(SHARED_INTERMEDIATE_DIR)/<(package)/browser/devtools/devtools_protocol_constants.h' + ], + 'action':[ + 'python', + '<(generator)', + '<(package)', + '<(SHARED_INTERMEDIATE_DIR)/<(package)/browser/devtools/devtools_protocol_constants.cc', + '<(SHARED_INTERMEDIATE_DIR)/<(package)/browser/devtools/devtools_protocol_constants.h', + '<(blink_protocol)', + '<(browser_protocol)', + ], + 'message': 'Generating DevTools protocol constants from <(blink_protocol)' } ], + 'direct_dependent_settings': { + 'include_dirs': [ + '<(SHARED_INTERMEDIATE_DIR)', + ] + }, 'includes': [ '../../../build/grit_target.gypi' ], }, ], diff --git a/chromium/content/browser/devtools/devtools_system_info_handler.cc b/chromium/content/browser/devtools/devtools_system_info_handler.cc index 4ade158c2bc..6e0336d2c08 100644 --- a/chromium/content/browser/devtools/devtools_system_info_handler.cc +++ b/chromium/content/browser/devtools/devtools_system_info_handler.cc @@ -20,9 +20,11 @@ const char kAuxAttributes[] = "auxAttributes"; const char kDeviceId[] = "deviceId"; const char kDeviceString[] = "deviceString"; const char kDevices[] = "devices"; +const char kDriverBugWorkarounds[] = "driverBugWorkarounds"; const char kFeatureStatus[] = "featureStatus"; const char kGPU[] = "gpu"; const char kModelName[] = "modelName"; +const char kModelVersion[] = "modelVersion"; const char kVendorId[] = "vendorId"; const char kVendorString[] = "vendorString"; @@ -118,8 +120,11 @@ DevToolsSystemInfoHandler::OnGetInfo( gpu_dict->Set(kFeatureStatus, GetFeatureStatus()); + gpu_dict->Set(kDriverBugWorkarounds, GetDriverBugWorkarounds()); + base::DictionaryValue* system_dict = new base::DictionaryValue; - system_dict->SetString(kModelName, gpu_info.machine_model); + system_dict->SetString(kModelName, gpu_info.machine_model_name); + system_dict->SetString(kModelVersion, gpu_info.machine_model_version); system_dict->Set(kGPU, gpu_dict); return command->SuccessResponse(system_dict); } diff --git a/chromium/content/browser/devtools/devtools_tracing_handler.cc b/chromium/content/browser/devtools/devtools_tracing_handler.cc index e9f6cf10b29..7d308642212 100644 --- a/chromium/content/browser/devtools/devtools_tracing_handler.cc +++ b/chromium/content/browser/devtools/devtools_tracing_handler.cc @@ -4,6 +4,8 @@ #include "content/browser/devtools/devtools_tracing_handler.h" +#include <cmath> + #include "base/bind.h" #include "base/callback.h" #include "base/file_util.h" @@ -13,6 +15,8 @@ #include "base/memory/ref_counted_memory.h" #include "base/strings/string_split.h" #include "base/strings/stringprintf.h" +#include "base/time/time.h" +#include "base/timer/timer.h" #include "base/values.h" #include "content/browser/devtools/devtools_http_handler_impl.h" #include "content/browser/devtools/devtools_protocol_constants.h" @@ -42,14 +46,18 @@ void ReadFile( } // namespace -DevToolsTracingHandler::DevToolsTracingHandler() - : weak_factory_(this) { +DevToolsTracingHandler::DevToolsTracingHandler( + DevToolsTracingHandler::Target target) + : weak_factory_(this), target_(target) { RegisterCommandHandler(devtools::Tracing::start::kName, base::Bind(&DevToolsTracingHandler::OnStart, base::Unretained(this))); RegisterCommandHandler(devtools::Tracing::end::kName, base::Bind(&DevToolsTracingHandler::OnEnd, base::Unretained(this))); + RegisterCommandHandler(devtools::Tracing::getCategories::kName, + base::Bind(&DevToolsTracingHandler::OnGetCategories, + base::Unretained(this))); } DevToolsTracingHandler::~DevToolsTracingHandler() { @@ -69,10 +77,10 @@ void DevToolsTracingHandler::ReadRecordingResult( if (trace_data->data().size()) { scoped_ptr<base::Value> trace_value(base::JSONReader::Read( trace_data->data())); - DictionaryValue* dictionary = NULL; + base::DictionaryValue* dictionary = NULL; bool ok = trace_value->GetAsDictionary(&dictionary); DCHECK(ok); - ListValue* list = NULL; + base::ListValue* list = NULL; ok = dictionary->GetList("traceEvents", &list); DCHECK(ok); std::string buffer; @@ -142,20 +150,99 @@ DevToolsTracingHandler::OnStart( options = TraceOptionsFromString(options_param); } + if (params && params->HasKey( + devtools::Tracing::start::kParamBufferUsageReportingInterval)) { + double usage_reporting_interval = 0.0; + params->GetDouble( + devtools::Tracing::start::kParamBufferUsageReportingInterval, + &usage_reporting_interval); + if (usage_reporting_interval > 0) { + base::TimeDelta interval = base::TimeDelta::FromMilliseconds( + std::ceil(usage_reporting_interval)); + buffer_usage_poll_timer_.reset(new base::Timer( + FROM_HERE, + interval, + base::Bind( + base::IgnoreResult(&TracingController::GetTraceBufferPercentFull), + base::Unretained(TracingController::GetInstance()), + base::Bind(&DevToolsTracingHandler::OnBufferUsage, + weak_factory_.GetWeakPtr())), + true)); + buffer_usage_poll_timer_->Reset(); + } + } + + // If inspected target is a render process Tracing.start will be handled by + // tracing agent in the renderer. + if (target_ == Renderer) { + TracingController::GetInstance()->EnableRecording( + categories, options, TracingController::EnableRecordingDoneCallback()); + return NULL; + } + TracingController::GetInstance()->EnableRecording( categories, options, - TracingController::EnableRecordingDoneCallback()); - return command->SuccessResponse(NULL); + base::Bind(&DevToolsTracingHandler::OnTracingStarted, + weak_factory_.GetWeakPtr(), + command)); + + return command->AsyncResponsePromise(); +} + +void DevToolsTracingHandler::OnTracingStarted( + scoped_refptr<DevToolsProtocol::Command> command) { + SendAsyncResponse(command->SuccessResponse(NULL)); +} + +void DevToolsTracingHandler::OnBufferUsage(float usage) { + base::DictionaryValue* params = new base::DictionaryValue(); + params->SetDouble(devtools::Tracing::bufferUsage::kParamValue, usage); + SendNotification(devtools::Tracing::bufferUsage::kName, params); } scoped_refptr<DevToolsProtocol::Response> DevToolsTracingHandler::OnEnd( scoped_refptr<DevToolsProtocol::Command> command) { - TracingController::GetInstance()->DisableRecording( - base::FilePath(), + DisableRecording( base::Bind(&DevToolsTracingHandler::BeginReadingRecordingResult, weak_factory_.GetWeakPtr())); return command->SuccessResponse(NULL); } +void DevToolsTracingHandler::DisableRecording( + const TracingController::TracingFileResultCallback& callback) { + buffer_usage_poll_timer_.reset(); + TracingController::GetInstance()->DisableRecording(base::FilePath(), + callback); +} + +void DevToolsTracingHandler::OnClientDetached() { + DisableRecording(); +} + +scoped_refptr<DevToolsProtocol::Response> +DevToolsTracingHandler::OnGetCategories( + scoped_refptr<DevToolsProtocol::Command> command) { + TracingController::GetInstance()->GetCategories( + base::Bind(&DevToolsTracingHandler::OnCategoriesReceived, + weak_factory_.GetWeakPtr(), + command)); + return command->AsyncResponsePromise(); +} + +void DevToolsTracingHandler::OnCategoriesReceived( + scoped_refptr<DevToolsProtocol::Command> command, + const std::set<std::string>& category_set) { + base::DictionaryValue* response = new base::DictionaryValue; + base::ListValue* category_list = new base::ListValue; + for (std::set<std::string>::const_iterator it = category_set.begin(); + it != category_set.end(); ++it) { + category_list->AppendString(*it); + } + + response->Set(devtools::Tracing::getCategories::kResponseCategories, + category_list); + SendAsyncResponse(command->SuccessResponse(response)); +} + } // namespace content diff --git a/chromium/content/browser/devtools/devtools_tracing_handler.h b/chromium/content/browser/devtools/devtools_tracing_handler.h index b551e7579e2..7c3b8e645e4 100644 --- a/chromium/content/browser/devtools/devtools_tracing_handler.h +++ b/chromium/content/browser/devtools/devtools_tracing_handler.h @@ -5,12 +5,16 @@ #ifndef CONTENT_BROWSER_DEVTOOLS_DEVTOOLS_TRACING_HANDLER_H_ #define CONTENT_BROWSER_DEVTOOLS_DEVTOOLS_TRACING_HANDLER_H_ +#include <set> +#include <string> + #include "base/memory/weak_ptr.h" #include "content/browser/devtools/devtools_protocol.h" #include "content/public/browser/tracing_controller.h" namespace base { class RefCountedString; +class Timer; } namespace content { @@ -19,23 +23,38 @@ namespace content { // infrastructure. class DevToolsTracingHandler : public DevToolsProtocol::Handler { public: - DevToolsTracingHandler(); + enum Target { Browser, Renderer }; + explicit DevToolsTracingHandler(Target target); virtual ~DevToolsTracingHandler(); + void OnClientDetached(); + private: void BeginReadingRecordingResult(const base::FilePath& path); void ReadRecordingResult(const scoped_refptr<base::RefCountedString>& result); void OnTraceDataCollected(const std::string& trace_fragment); + void OnTracingStarted(scoped_refptr<DevToolsProtocol::Command> command); + void OnBufferUsage(float usage); scoped_refptr<DevToolsProtocol::Response> OnStart( scoped_refptr<DevToolsProtocol::Command> command); scoped_refptr<DevToolsProtocol::Response> OnEnd( scoped_refptr<DevToolsProtocol::Command> command); + scoped_refptr<DevToolsProtocol::Response> OnGetCategories( + scoped_refptr<DevToolsProtocol::Command> command); + void OnCategoriesReceived(scoped_refptr<DevToolsProtocol::Command> command, + const std::set<std::string>& category_set); + TracingController::Options TraceOptionsFromString(const std::string& options); - base::WeakPtrFactory<DevToolsTracingHandler> weak_factory_; + void DisableRecording( + const TracingController::TracingFileResultCallback& callback = + TracingController::TracingFileResultCallback()); + base::WeakPtrFactory<DevToolsTracingHandler> weak_factory_; + scoped_ptr<base::Timer> buffer_usage_poll_timer_; + Target target_; DISALLOW_COPY_AND_ASSIGN(DevToolsTracingHandler); }; diff --git a/chromium/content/browser/devtools/embedded_worker_devtools_manager.cc b/chromium/content/browser/devtools/embedded_worker_devtools_manager.cc new file mode 100644 index 00000000000..3ba61aafeea --- /dev/null +++ b/chromium/content/browser/devtools/embedded_worker_devtools_manager.cc @@ -0,0 +1,379 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "content/browser/devtools/embedded_worker_devtools_manager.h" + +#include "content/browser/devtools/devtools_manager_impl.h" +#include "content/browser/devtools/devtools_protocol.h" +#include "content/browser/devtools/devtools_protocol_constants.h" +#include "content/browser/devtools/ipc_devtools_agent_host.h" +#include "content/browser/shared_worker/shared_worker_instance.h" +#include "content/common/devtools_messages.h" +#include "content/public/browser/browser_thread.h" +#include "content/public/browser/render_process_host.h" +#include "content/public/browser/worker_service.h" +#include "ipc/ipc_listener.h" + +namespace content { + +namespace { + +bool SendMessageToWorker( + const EmbeddedWorkerDevToolsManager::WorkerId& worker_id, + IPC::Message* message) { + RenderProcessHost* host = RenderProcessHost::FromID(worker_id.first); + if (!host) { + delete message; + return false; + } + message->set_routing_id(worker_id.second); + host->Send(message); + return true; +} + +} // namespace + +EmbeddedWorkerDevToolsManager::ServiceWorkerIdentifier::ServiceWorkerIdentifier( + const ServiceWorkerContextCore* const service_worker_context, + int64 service_worker_version_id) + : service_worker_context_(service_worker_context), + service_worker_version_id_(service_worker_version_id) { +} + +EmbeddedWorkerDevToolsManager::ServiceWorkerIdentifier::ServiceWorkerIdentifier( + const ServiceWorkerIdentifier& other) + : service_worker_context_(other.service_worker_context_), + service_worker_version_id_(other.service_worker_version_id_) { +} + +bool EmbeddedWorkerDevToolsManager::ServiceWorkerIdentifier::Matches( + const ServiceWorkerIdentifier& other) const { + return service_worker_context_ == other.service_worker_context_ && + service_worker_version_id_ == other.service_worker_version_id_; +} + +EmbeddedWorkerDevToolsManager::WorkerInfo::WorkerInfo( + const SharedWorkerInstance& instance) + : shared_worker_instance_(new SharedWorkerInstance(instance)), + state_(WORKER_UNINSPECTED), + agent_host_(NULL) { +} + +EmbeddedWorkerDevToolsManager::WorkerInfo::WorkerInfo( + const ServiceWorkerIdentifier& service_worker_id) + : service_worker_id_(new ServiceWorkerIdentifier(service_worker_id)), + state_(WORKER_UNINSPECTED), + agent_host_(NULL) { +} + +bool EmbeddedWorkerDevToolsManager::WorkerInfo::Matches( + const SharedWorkerInstance& other) { + if (!shared_worker_instance_) + return false; + return shared_worker_instance_->Matches(other); +} + +bool EmbeddedWorkerDevToolsManager::WorkerInfo::Matches( + const ServiceWorkerIdentifier& other) { + if (!service_worker_id_) + return false; + return service_worker_id_->Matches(other); +} + +EmbeddedWorkerDevToolsManager::WorkerInfo::~WorkerInfo() { +} + +class EmbeddedWorkerDevToolsManager::EmbeddedWorkerDevToolsAgentHost + : public IPCDevToolsAgentHost, + public IPC::Listener { + public: + explicit EmbeddedWorkerDevToolsAgentHost(WorkerId worker_id) + : worker_id_(worker_id), worker_attached_(false) { + AttachToWorker(); + } + + // DevToolsAgentHost override. + virtual bool IsWorker() const OVERRIDE { return true; } + + // IPCDevToolsAgentHost implementation. + virtual void SendMessageToAgent(IPC::Message* message) OVERRIDE { + if (worker_attached_) + SendMessageToWorker(worker_id_, message); + else + delete message; + } + virtual void Attach() OVERRIDE { + AttachToWorker(); + IPCDevToolsAgentHost::Attach(); + } + virtual void OnClientAttached() OVERRIDE {} + virtual void OnClientDetached() OVERRIDE { DetachFromWorker(); } + + // IPC::Listener implementation. + virtual bool OnMessageReceived(const IPC::Message& msg) OVERRIDE { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); + bool handled = true; + IPC_BEGIN_MESSAGE_MAP(EmbeddedWorkerDevToolsAgentHost, msg) + IPC_MESSAGE_HANDLER(DevToolsClientMsg_DispatchOnInspectorFrontend, + OnDispatchOnInspectorFrontend) + IPC_MESSAGE_HANDLER(DevToolsHostMsg_SaveAgentRuntimeState, + OnSaveAgentRuntimeState) + IPC_MESSAGE_UNHANDLED(handled = false) + IPC_END_MESSAGE_MAP() + return handled; + } + + void ReattachToWorker(WorkerId worker_id) { + CHECK(!worker_attached_); + worker_id_ = worker_id; + if (!IsAttached()) + return; + AttachToWorker(); + Reattach(state_); + } + + void DetachFromWorker() { + if (!worker_attached_) + return; + worker_attached_ = false; + if (RenderProcessHost* host = RenderProcessHost::FromID(worker_id_.first)) + host->RemoveRoute(worker_id_.second); + Release(); + } + + WorkerId worker_id() const { return worker_id_; } + + private: + virtual ~EmbeddedWorkerDevToolsAgentHost() { + CHECK(!worker_attached_); + EmbeddedWorkerDevToolsManager::GetInstance()->RemoveInspectedWorkerData( + this); + } + + void OnDispatchOnInspectorFrontend(const std::string& message) { + DevToolsManagerImpl::GetInstance()->DispatchOnInspectorFrontend(this, + message); + } + + void OnSaveAgentRuntimeState(const std::string& state) { state_ = state; } + + void AttachToWorker() { + if (worker_attached_) + return; + worker_attached_ = true; + AddRef(); + if (RenderProcessHost* host = RenderProcessHost::FromID(worker_id_.first)) + host->AddRoute(worker_id_.second, this); + } + + WorkerId worker_id_; + bool worker_attached_; + std::string state_; + DISALLOW_COPY_AND_ASSIGN(EmbeddedWorkerDevToolsAgentHost); +}; + +// static +EmbeddedWorkerDevToolsManager* EmbeddedWorkerDevToolsManager::GetInstance() { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); + return Singleton<EmbeddedWorkerDevToolsManager>::get(); +} + +DevToolsAgentHost* EmbeddedWorkerDevToolsManager::GetDevToolsAgentHostForWorker( + int worker_process_id, + int worker_route_id) { + WorkerId id(worker_process_id, worker_route_id); + + WorkerInfoMap::iterator it = workers_.find(id); + if (it == workers_.end()) + return NULL; + + WorkerInfo* info = it->second; + if (info->state() != WORKER_UNINSPECTED && + info->state() != WORKER_PAUSED_FOR_DEBUG_ON_START) { + return info->agent_host(); + } + + EmbeddedWorkerDevToolsAgentHost* agent_host = + new EmbeddedWorkerDevToolsAgentHost(id); + info->set_agent_host(agent_host); + info->set_state(WORKER_INSPECTED); + return agent_host; +} + +DevToolsAgentHost* +EmbeddedWorkerDevToolsManager::GetDevToolsAgentHostForServiceWorker( + const ServiceWorkerIdentifier& service_worker_id) { + WorkerInfoMap::iterator it = FindExistingServiceWorkerInfo(service_worker_id); + if (it == workers_.end()) + return NULL; + return GetDevToolsAgentHostForWorker(it->first.first, it->first.second); +} + +EmbeddedWorkerDevToolsManager::EmbeddedWorkerDevToolsManager() + : debug_service_worker_on_start_(false) { +} + +EmbeddedWorkerDevToolsManager::~EmbeddedWorkerDevToolsManager() { +} + +bool EmbeddedWorkerDevToolsManager::SharedWorkerCreated( + int worker_process_id, + int worker_route_id, + const SharedWorkerInstance& instance) { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); + const WorkerId id(worker_process_id, worker_route_id); + WorkerInfoMap::iterator it = FindExistingSharedWorkerInfo(instance); + if (it == workers_.end()) { + scoped_ptr<WorkerInfo> info(new WorkerInfo(instance)); + workers_.set(id, info.Pass()); + return false; + } + MoveToPausedState(id, it); + return true; +} + +bool EmbeddedWorkerDevToolsManager::ServiceWorkerCreated( + int worker_process_id, + int worker_route_id, + const ServiceWorkerIdentifier& service_worker_id) { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); + const WorkerId id(worker_process_id, worker_route_id); + WorkerInfoMap::iterator it = FindExistingServiceWorkerInfo(service_worker_id); + if (it == workers_.end()) { + scoped_ptr<WorkerInfo> info(new WorkerInfo(service_worker_id)); + if (debug_service_worker_on_start_) + info->set_state(WORKER_PAUSED_FOR_DEBUG_ON_START); + workers_.set(id, info.Pass()); + return debug_service_worker_on_start_; + } + MoveToPausedState(id, it); + return true; +} + +void EmbeddedWorkerDevToolsManager::WorkerDestroyed(int worker_process_id, + int worker_route_id) { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); + const WorkerId id(worker_process_id, worker_route_id); + WorkerInfoMap::iterator it = workers_.find(id); + DCHECK(it != workers_.end()); + WorkerInfo* info = it->second; + switch (info->state()) { + case WORKER_UNINSPECTED: + case WORKER_PAUSED_FOR_DEBUG_ON_START: + workers_.erase(it); + break; + case WORKER_INSPECTED: { + EmbeddedWorkerDevToolsAgentHost* agent_host = info->agent_host(); + info->set_state(WORKER_TERMINATED); + if (!agent_host->IsAttached()) { + agent_host->DetachFromWorker(); + return; + } + // Client host is debugging this worker agent host. + std::string notification = + DevToolsProtocol::CreateNotification( + devtools::Worker::disconnectedFromWorker::kName, NULL) + ->Serialize(); + DevToolsManagerImpl::GetInstance()->DispatchOnInspectorFrontend( + agent_host, notification); + agent_host->DetachFromWorker(); + break; + } + case WORKER_TERMINATED: + NOTREACHED(); + break; + case WORKER_PAUSED_FOR_REATTACH: { + scoped_ptr<WorkerInfo> worker_info = workers_.take_and_erase(it); + worker_info->set_state(WORKER_TERMINATED); + const WorkerId old_id = worker_info->agent_host()->worker_id(); + workers_.set(old_id, worker_info.Pass()); + break; + } + } +} + +void EmbeddedWorkerDevToolsManager::WorkerContextStarted(int worker_process_id, + int worker_route_id) { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); + const WorkerId id(worker_process_id, worker_route_id); + WorkerInfoMap::iterator it = workers_.find(id); + DCHECK(it != workers_.end()); + WorkerInfo* info = it->second; + if (info->state() == WORKER_PAUSED_FOR_DEBUG_ON_START) { + RenderProcessHost* rph = RenderProcessHost::FromID(worker_process_id); + scoped_refptr<DevToolsAgentHost> agent_host( + GetDevToolsAgentHostForWorker(worker_process_id, worker_route_id)); + DevToolsManagerImpl::GetInstance()->Inspect(rph->GetBrowserContext(), + agent_host.get()); + } else if (info->state() == WORKER_PAUSED_FOR_REATTACH) { + info->agent_host()->ReattachToWorker(id); + info->set_state(WORKER_INSPECTED); + } +} + +void EmbeddedWorkerDevToolsManager::RemoveInspectedWorkerData( + EmbeddedWorkerDevToolsAgentHost* agent_host) { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); + const WorkerId id(agent_host->worker_id()); + scoped_ptr<WorkerInfo> worker_info = workers_.take_and_erase(id); + if (worker_info) { + DCHECK_EQ(worker_info->agent_host(), agent_host); + if (worker_info->state() == WORKER_TERMINATED) + return; + DCHECK_EQ(worker_info->state(), WORKER_INSPECTED); + worker_info->set_agent_host(NULL); + worker_info->set_state(WORKER_UNINSPECTED); + workers_.set(id, worker_info.Pass()); + return; + } + for (WorkerInfoMap::iterator it = workers_.begin(); it != workers_.end(); + ++it) { + if (it->second->agent_host() == agent_host) { + DCHECK_EQ(WORKER_PAUSED_FOR_REATTACH, it->second->state()); + SendMessageToWorker( + it->first, + new DevToolsAgentMsg_ResumeWorkerContext(it->first.second)); + it->second->set_agent_host(NULL); + it->second->set_state(WORKER_UNINSPECTED); + return; + } + } +} + +EmbeddedWorkerDevToolsManager::WorkerInfoMap::iterator +EmbeddedWorkerDevToolsManager::FindExistingSharedWorkerInfo( + const SharedWorkerInstance& instance) { + WorkerInfoMap::iterator it = workers_.begin(); + for (; it != workers_.end(); ++it) { + if (it->second->Matches(instance)) + break; + } + return it; +} + +EmbeddedWorkerDevToolsManager::WorkerInfoMap::iterator +EmbeddedWorkerDevToolsManager::FindExistingServiceWorkerInfo( + const ServiceWorkerIdentifier& service_worker_id) { + WorkerInfoMap::iterator it = workers_.begin(); + for (; it != workers_.end(); ++it) { + if (it->second->Matches(service_worker_id)) + break; + } + return it; +} + +void EmbeddedWorkerDevToolsManager::MoveToPausedState( + const WorkerId& id, + const WorkerInfoMap::iterator& it) { + DCHECK_EQ(WORKER_TERMINATED, it->second->state()); + scoped_ptr<WorkerInfo> info = workers_.take_and_erase(it); + info->set_state(WORKER_PAUSED_FOR_REATTACH); + workers_.set(id, info.Pass()); +} + +void EmbeddedWorkerDevToolsManager::ResetForTesting() { + workers_.clear(); +} + +} // namespace content diff --git a/chromium/content/browser/devtools/embedded_worker_devtools_manager.h b/chromium/content/browser/devtools/embedded_worker_devtools_manager.h new file mode 100644 index 00000000000..3b15c8f2099 --- /dev/null +++ b/chromium/content/browser/devtools/embedded_worker_devtools_manager.h @@ -0,0 +1,138 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CONTENT_BROWSER_DEVTOOLS_EMBEDDED_WORKER_DEVTOOLS_MANAGER_H_ +#define CONTENT_BROWSER_DEVTOOLS_EMBEDDED_WORKER_DEVTOOLS_MANAGER_H_ + +#include "base/basictypes.h" +#include "base/containers/scoped_ptr_hash_map.h" +#include "base/gtest_prod_util.h" +#include "base/memory/scoped_vector.h" +#include "base/memory/singleton.h" +#include "base/strings/string16.h" +#include "content/browser/shared_worker/shared_worker_instance.h" +#include "content/common/content_export.h" + +namespace content { + +class DevToolsAgentHost; +class ServiceWorkerContextCore; + +// EmbeddedWorkerDevToolsManager is used instead of WorkerDevToolsManager when +// "enable-embedded-shared-worker" flag is set. +// This class lives on UI thread. +class CONTENT_EXPORT EmbeddedWorkerDevToolsManager { + public: + typedef std::pair<int, int> WorkerId; + class EmbeddedWorkerDevToolsAgentHost; + + class ServiceWorkerIdentifier { + public: + ServiceWorkerIdentifier( + const ServiceWorkerContextCore* const service_worker_context, + int64 service_worker_version_id); + explicit ServiceWorkerIdentifier(const ServiceWorkerIdentifier& other); + ~ServiceWorkerIdentifier() {} + + bool Matches(const ServiceWorkerIdentifier& other) const; + + private: + const ServiceWorkerContextCore* const service_worker_context_; + const int64 service_worker_version_id_; + }; + + // Returns the EmbeddedWorkerDevToolsManager singleton. + static EmbeddedWorkerDevToolsManager* GetInstance(); + + DevToolsAgentHost* GetDevToolsAgentHostForWorker(int worker_process_id, + int worker_route_id); + DevToolsAgentHost* GetDevToolsAgentHostForServiceWorker( + const ServiceWorkerIdentifier& service_worker_id); + + // Returns true when the worker must be paused on start because a DevTool + // window for the same former SharedWorkerInstance is still opened. + bool SharedWorkerCreated(int worker_process_id, + int worker_route_id, + const SharedWorkerInstance& instance); + // Returns true when the worker must be paused on start because a DevTool + // window for the same former ServiceWorkerIdentifier is still opened or + // debug-on-start is enabled in chrome://serviceworker-internals. + bool ServiceWorkerCreated(int worker_process_id, + int worker_route_id, + const ServiceWorkerIdentifier& service_worker_id); + void WorkerContextStarted(int worker_process_id, int worker_route_id); + void WorkerDestroyed(int worker_process_id, int worker_route_id); + + void set_debug_service_worker_on_start(bool debug_on_start) { + debug_service_worker_on_start_ = debug_on_start; + } + bool debug_service_worker_on_start() const { + return debug_service_worker_on_start_; + } + + private: + friend struct DefaultSingletonTraits<EmbeddedWorkerDevToolsManager>; + friend class EmbeddedWorkerDevToolsManagerTest; + FRIEND_TEST_ALL_PREFIXES(EmbeddedWorkerDevToolsManagerTest, BasicTest); + FRIEND_TEST_ALL_PREFIXES(EmbeddedWorkerDevToolsManagerTest, AttachTest); + + enum WorkerState { + WORKER_UNINSPECTED, + WORKER_INSPECTED, + WORKER_TERMINATED, + WORKER_PAUSED_FOR_DEBUG_ON_START, + WORKER_PAUSED_FOR_REATTACH, + }; + + class WorkerInfo { + public: + // Creates WorkerInfo for SharedWorker. + explicit WorkerInfo(const SharedWorkerInstance& instance); + // Creates WorkerInfo for ServiceWorker. + explicit WorkerInfo(const ServiceWorkerIdentifier& service_worker_id); + ~WorkerInfo(); + + WorkerState state() { return state_; } + void set_state(WorkerState new_state) { state_ = new_state; } + EmbeddedWorkerDevToolsAgentHost* agent_host() { return agent_host_; } + void set_agent_host(EmbeddedWorkerDevToolsAgentHost* agent_host) { + agent_host_ = agent_host; + } + bool Matches(const SharedWorkerInstance& other); + bool Matches(const ServiceWorkerIdentifier& other); + + private: + scoped_ptr<SharedWorkerInstance> shared_worker_instance_; + scoped_ptr<ServiceWorkerIdentifier> service_worker_id_; + WorkerState state_; + EmbeddedWorkerDevToolsAgentHost* agent_host_; + }; + + typedef base::ScopedPtrHashMap<WorkerId, WorkerInfo> WorkerInfoMap; + + EmbeddedWorkerDevToolsManager(); + virtual ~EmbeddedWorkerDevToolsManager(); + + void RemoveInspectedWorkerData(EmbeddedWorkerDevToolsAgentHost* agent_host); + + WorkerInfoMap::iterator FindExistingSharedWorkerInfo( + const SharedWorkerInstance& instance); + WorkerInfoMap::iterator FindExistingServiceWorkerInfo( + const ServiceWorkerIdentifier& service_worker_id); + + void MoveToPausedState(const WorkerId& id, const WorkerInfoMap::iterator& it); + + // Resets to its initial state as if newly created. + void ResetForTesting(); + + WorkerInfoMap workers_; + + bool debug_service_worker_on_start_; + + DISALLOW_COPY_AND_ASSIGN(EmbeddedWorkerDevToolsManager); +}; + +} // namespace content + +#endif // CONTENT_BROWSER_DEVTOOLS_EMBEDDED_WORKER_DEVTOOLS_MANAGER_H_ diff --git a/chromium/content/browser/devtools/embedded_worker_devtools_manager_unittest.cc b/chromium/content/browser/devtools/embedded_worker_devtools_manager_unittest.cc new file mode 100644 index 00000000000..69b23052425 --- /dev/null +++ b/chromium/content/browser/devtools/embedded_worker_devtools_manager_unittest.cc @@ -0,0 +1,272 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "content/browser/devtools/embedded_worker_devtools_manager.h" + +#include "base/memory/scoped_ptr.h" +#include "base/message_loop/message_loop.h" +#include "base/run_loop.h" +#include "content/browser/browser_thread_impl.h" +#include "content/browser/devtools/devtools_manager_impl.h" +#include "content/browser/shared_worker/shared_worker_instance.h" +#include "content/browser/worker_host/worker_storage_partition.h" +#include "content/public/browser/devtools_agent_host.h" +#include "content/public/browser/devtools_client_host.h" +#include "content/public/test/test_browser_context.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace content { +namespace { + +class TestDevToolsClientHost : public DevToolsClientHost { + public: + TestDevToolsClientHost() {} + virtual ~TestDevToolsClientHost() {} + virtual void DispatchOnInspectorFrontend( + const std::string& message) OVERRIDE {} + virtual void InspectedContentsClosing() OVERRIDE {} + virtual void ReplacedWithAnotherClient() OVERRIDE {} + + private: + DISALLOW_COPY_AND_ASSIGN(TestDevToolsClientHost); +}; +} + +class EmbeddedWorkerDevToolsManagerTest : public testing::Test { + public: + EmbeddedWorkerDevToolsManagerTest() + : ui_thread_(BrowserThread::UI, &message_loop_), + browser_context_(new TestBrowserContext()), + partition_( + new WorkerStoragePartition(browser_context_->GetRequestContext(), + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL)), + partition_id_(*partition_.get()) {} + + protected: + virtual void SetUp() OVERRIDE { + manager_ = EmbeddedWorkerDevToolsManager::GetInstance(); + } + virtual void TearDown() OVERRIDE { + EmbeddedWorkerDevToolsManager::GetInstance()->ResetForTesting(); + } + + void CheckWorkerState(int worker_process_id, + int worker_route_id, + EmbeddedWorkerDevToolsManager::WorkerState state) { + const EmbeddedWorkerDevToolsManager::WorkerId id(worker_process_id, + worker_route_id); + EmbeddedWorkerDevToolsManager::WorkerInfoMap::iterator it = + manager_->workers_.find(id); + EXPECT_TRUE(manager_->workers_.end() != it); + EXPECT_EQ(state, it->second->state()); + } + + void CheckWorkerNotExist(int worker_process_id, int worker_route_id) { + const EmbeddedWorkerDevToolsManager::WorkerId id(worker_process_id, + worker_route_id); + EXPECT_TRUE(manager_->workers_.end() == manager_->workers_.find(id)); + } + + void CheckWorkerCount(size_t size) { + EXPECT_EQ(size, manager_->workers_.size()); + } + + void RegisterDevToolsClientHostFor(DevToolsAgentHost* agent_host, + DevToolsClientHost* client_host) { + DevToolsManagerImpl::GetInstance()->RegisterDevToolsClientHostFor( + agent_host, client_host); + } + + void ClientHostClosing(DevToolsClientHost* client_host) { + DevToolsManagerImpl::GetInstance()->ClientHostClosing(client_host); + } + + base::MessageLoopForIO message_loop_; + BrowserThreadImpl ui_thread_; + scoped_ptr<TestBrowserContext> browser_context_; + scoped_ptr<WorkerStoragePartition> partition_; + const WorkerStoragePartitionId partition_id_; + EmbeddedWorkerDevToolsManager* manager_; +}; + +TEST_F(EmbeddedWorkerDevToolsManagerTest, BasicTest) { + scoped_refptr<DevToolsAgentHost> agent_host; + + SharedWorkerInstance instance1(GURL("http://example.com/w.js"), + base::string16(), + base::string16(), + blink::WebContentSecurityPolicyTypeReport, + browser_context_->GetResourceContext(), + partition_id_); + + agent_host = manager_->GetDevToolsAgentHostForWorker(1, 1); + EXPECT_FALSE(agent_host.get()); + + // Created -> Started -> Destroyed + CheckWorkerNotExist(1, 1); + manager_->SharedWorkerCreated(1, 1, instance1); + CheckWorkerState(1, 1, EmbeddedWorkerDevToolsManager::WORKER_UNINSPECTED); + manager_->WorkerContextStarted(1, 1); + CheckWorkerState(1, 1, EmbeddedWorkerDevToolsManager::WORKER_UNINSPECTED); + manager_->WorkerDestroyed(1, 1); + CheckWorkerNotExist(1, 1); + + // Created -> GetDevToolsAgentHost -> Started -> Destroyed + CheckWorkerNotExist(1, 2); + manager_->SharedWorkerCreated(1, 2, instance1); + CheckWorkerState(1, 2, EmbeddedWorkerDevToolsManager::WORKER_UNINSPECTED); + agent_host = manager_->GetDevToolsAgentHostForWorker(1, 2); + EXPECT_TRUE(agent_host.get()); + CheckWorkerState(1, 2, EmbeddedWorkerDevToolsManager::WORKER_INSPECTED); + EXPECT_EQ(agent_host.get(), manager_->GetDevToolsAgentHostForWorker(1, 2)); + manager_->WorkerContextStarted(1, 2); + CheckWorkerState(1, 2, EmbeddedWorkerDevToolsManager::WORKER_INSPECTED); + manager_->WorkerDestroyed(1, 2); + CheckWorkerState(1, 2, EmbeddedWorkerDevToolsManager::WORKER_TERMINATED); + agent_host = NULL; + CheckWorkerNotExist(1, 2); + + // Created -> Started -> GetDevToolsAgentHost -> Destroyed + CheckWorkerNotExist(1, 3); + manager_->SharedWorkerCreated(1, 3, instance1); + CheckWorkerState(1, 3, EmbeddedWorkerDevToolsManager::WORKER_UNINSPECTED); + manager_->WorkerContextStarted(1, 3); + CheckWorkerState(1, 3, EmbeddedWorkerDevToolsManager::WORKER_UNINSPECTED); + agent_host = manager_->GetDevToolsAgentHostForWorker(1, 3); + EXPECT_TRUE(agent_host.get()); + CheckWorkerState(1, 3, EmbeddedWorkerDevToolsManager::WORKER_INSPECTED); + manager_->WorkerDestroyed(1, 3); + CheckWorkerState(1, 3, EmbeddedWorkerDevToolsManager::WORKER_TERMINATED); + agent_host = NULL; + CheckWorkerNotExist(1, 3); + + // Created -> Destroyed + CheckWorkerNotExist(1, 4); + manager_->SharedWorkerCreated(1, 4, instance1); + CheckWorkerState(1, 4, EmbeddedWorkerDevToolsManager::WORKER_UNINSPECTED); + manager_->WorkerDestroyed(1, 4); + CheckWorkerNotExist(1, 4); + + // Created -> GetDevToolsAgentHost -> Destroyed + CheckWorkerNotExist(1, 5); + manager_->SharedWorkerCreated(1, 5, instance1); + CheckWorkerState(1, 5, EmbeddedWorkerDevToolsManager::WORKER_UNINSPECTED); + agent_host = manager_->GetDevToolsAgentHostForWorker(1, 5); + EXPECT_TRUE(agent_host.get()); + CheckWorkerState(1, 5, EmbeddedWorkerDevToolsManager::WORKER_INSPECTED); + manager_->WorkerDestroyed(1, 5); + CheckWorkerState(1, 5, EmbeddedWorkerDevToolsManager::WORKER_TERMINATED); + agent_host = NULL; + CheckWorkerNotExist(1, 5); + + // Created -> GetDevToolsAgentHost -> Free agent_host -> Destroyed + CheckWorkerNotExist(1, 6); + manager_->SharedWorkerCreated(1, 6, instance1); + CheckWorkerState(1, 6, EmbeddedWorkerDevToolsManager::WORKER_UNINSPECTED); + agent_host = manager_->GetDevToolsAgentHostForWorker(1, 6); + EXPECT_TRUE(agent_host.get()); + CheckWorkerState(1, 6, EmbeddedWorkerDevToolsManager::WORKER_INSPECTED); + agent_host = NULL; + manager_->WorkerDestroyed(1, 6); + CheckWorkerNotExist(1, 6); +} + +TEST_F(EmbeddedWorkerDevToolsManagerTest, AttachTest) { + scoped_refptr<DevToolsAgentHost> agent_host1; + scoped_refptr<DevToolsAgentHost> agent_host2; + + SharedWorkerInstance instance1(GURL("http://example.com/w1.js"), + base::string16(), + base::string16(), + blink::WebContentSecurityPolicyTypeReport, + browser_context_->GetResourceContext(), + partition_id_); + SharedWorkerInstance instance2(GURL("http://example.com/w2.js"), + base::string16(), + base::string16(), + blink::WebContentSecurityPolicyTypeReport, + browser_context_->GetResourceContext(), + partition_id_); + + // Created -> GetDevToolsAgentHost -> Register -> Started -> Destroyed + scoped_ptr<TestDevToolsClientHost> client_host1(new TestDevToolsClientHost()); + CheckWorkerNotExist(2, 1); + manager_->SharedWorkerCreated(2, 1, instance1); + CheckWorkerState(2, 1, EmbeddedWorkerDevToolsManager::WORKER_UNINSPECTED); + agent_host1 = manager_->GetDevToolsAgentHostForWorker(2, 1); + EXPECT_TRUE(agent_host1.get()); + CheckWorkerState(2, 1, EmbeddedWorkerDevToolsManager::WORKER_INSPECTED); + EXPECT_EQ(agent_host1.get(), manager_->GetDevToolsAgentHostForWorker(2, 1)); + RegisterDevToolsClientHostFor(agent_host1.get(), client_host1.get()); + CheckWorkerState(2, 1, EmbeddedWorkerDevToolsManager::WORKER_INSPECTED); + manager_->WorkerContextStarted(2, 1); + CheckWorkerState(2, 1, EmbeddedWorkerDevToolsManager::WORKER_INSPECTED); + manager_->WorkerDestroyed(2, 1); + CheckWorkerState(2, 1, EmbeddedWorkerDevToolsManager::WORKER_TERMINATED); + EXPECT_EQ(agent_host1.get(), manager_->GetDevToolsAgentHostForWorker(2, 1)); + + // Created -> Started -> GetDevToolsAgentHost -> Register -> Destroyed + scoped_ptr<TestDevToolsClientHost> client_host2(new TestDevToolsClientHost()); + manager_->SharedWorkerCreated(2, 2, instance2); + CheckWorkerState(2, 2, EmbeddedWorkerDevToolsManager::WORKER_UNINSPECTED); + manager_->WorkerContextStarted(2, 2); + CheckWorkerState(2, 2, EmbeddedWorkerDevToolsManager::WORKER_UNINSPECTED); + agent_host2 = manager_->GetDevToolsAgentHostForWorker(2, 2); + EXPECT_TRUE(agent_host2.get()); + EXPECT_NE(agent_host1.get(), agent_host2.get()); + EXPECT_EQ(agent_host2.get(), manager_->GetDevToolsAgentHostForWorker(2, 2)); + CheckWorkerState(2, 2, EmbeddedWorkerDevToolsManager::WORKER_INSPECTED); + RegisterDevToolsClientHostFor(agent_host2.get(), client_host2.get()); + CheckWorkerState(2, 2, EmbeddedWorkerDevToolsManager::WORKER_INSPECTED); + manager_->WorkerDestroyed(2, 2); + CheckWorkerState(2, 2, EmbeddedWorkerDevToolsManager::WORKER_TERMINATED); + EXPECT_EQ(agent_host2.get(), manager_->GetDevToolsAgentHostForWorker(2, 2)); + + // Re-created -> Started -> ClientHostClosing -> Destroyed + CheckWorkerState(2, 1, EmbeddedWorkerDevToolsManager::WORKER_TERMINATED); + manager_->SharedWorkerCreated(2, 3, instance1); + CheckWorkerNotExist(2, 1); + CheckWorkerState( + 2, 3, EmbeddedWorkerDevToolsManager::WORKER_PAUSED_FOR_REATTACH); + EXPECT_EQ(agent_host1.get(), manager_->GetDevToolsAgentHostForWorker(2, 3)); + manager_->WorkerContextStarted(2, 3); + CheckWorkerState(2, 3, EmbeddedWorkerDevToolsManager::WORKER_INSPECTED); + ClientHostClosing(client_host1.get()); + manager_->WorkerDestroyed(2, 3); + CheckWorkerState(2, 3, EmbeddedWorkerDevToolsManager::WORKER_TERMINATED); + agent_host1 = NULL; + CheckWorkerNotExist(2, 3); + + // Re-created -> Destroyed + CheckWorkerState(2, 2, EmbeddedWorkerDevToolsManager::WORKER_TERMINATED); + manager_->SharedWorkerCreated(2, 4, instance2); + CheckWorkerNotExist(2, 2); + CheckWorkerState( + 2, 4, EmbeddedWorkerDevToolsManager::WORKER_PAUSED_FOR_REATTACH); + EXPECT_EQ(agent_host2.get(), manager_->GetDevToolsAgentHostForWorker(2, 4)); + manager_->WorkerDestroyed(2, 4); + CheckWorkerNotExist(2, 4); + CheckWorkerState(2, 2, EmbeddedWorkerDevToolsManager::WORKER_TERMINATED); + + // Re-created -> ClientHostClosing -> Destroyed + manager_->SharedWorkerCreated(2, 5, instance2); + CheckWorkerNotExist(2, 2); + CheckWorkerState( + 2, 5, EmbeddedWorkerDevToolsManager::WORKER_PAUSED_FOR_REATTACH); + EXPECT_EQ(agent_host2.get(), manager_->GetDevToolsAgentHostForWorker(2, 5)); + ClientHostClosing(client_host2.get()); + CheckWorkerCount(1); + agent_host2 = NULL; + CheckWorkerCount(1); + manager_->WorkerDestroyed(2, 5); + CheckWorkerCount(0); +} + +} // namespace content diff --git a/chromium/content/browser/devtools/forwarding_agent_host.cc b/chromium/content/browser/devtools/forwarding_agent_host.cc new file mode 100644 index 00000000000..f1524e1b7e1 --- /dev/null +++ b/chromium/content/browser/devtools/forwarding_agent_host.cc @@ -0,0 +1,41 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "content/browser/devtools/forwarding_agent_host.h" + +#include "content/browser/devtools/devtools_manager_impl.h" + +namespace content { + +ForwardingAgentHost::ForwardingAgentHost( + DevToolsExternalAgentProxyDelegate* delegate) + : delegate_(delegate) { +} + +ForwardingAgentHost::~ForwardingAgentHost() { +} + +void ForwardingAgentHost::DispatchOnClientHost(const std::string& message) { + DevToolsManagerImpl::GetInstance()->DispatchOnInspectorFrontend( + this, message); +} + +void ForwardingAgentHost::ConnectionClosed() { + NotifyCloseListener(); +} + +void ForwardingAgentHost::Attach() { + delegate_->Attach(this); +} + +void ForwardingAgentHost::Detach() { + delegate_->Detach(); +} + +void ForwardingAgentHost::DispatchOnInspectorBackend( + const std::string& message) { + delegate_->SendMessageToBackend(message); +} + +} // content diff --git a/chromium/content/browser/devtools/forwarding_agent_host.h b/chromium/content/browser/devtools/forwarding_agent_host.h new file mode 100644 index 00000000000..81e4aed5419 --- /dev/null +++ b/chromium/content/browser/devtools/forwarding_agent_host.h @@ -0,0 +1,39 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CONTENT_BROWSER_DEVTOOLS_FORWARDING_AGENT_HOST_H +#define CONTENT_BROWSER_DEVTOOLS_FORWARDING_AGENT_HOST_H + +#include "base/memory/ref_counted.h" +#include "base/memory/scoped_ptr.h" +#include "content/browser/devtools/devtools_agent_host_impl.h" +#include "content/public/browser/devtools_external_agent_proxy.h" +#include "content/public/browser/devtools_external_agent_proxy_delegate.h" + +namespace content { + +class ForwardingAgentHost + : public DevToolsAgentHostImpl, + public DevToolsExternalAgentProxy { + public: + ForwardingAgentHost(DevToolsExternalAgentProxyDelegate* delegate); + + private: + virtual ~ForwardingAgentHost(); + + // DevToolsExternalAgentProxy implementation. + virtual void DispatchOnClientHost(const std::string& message) OVERRIDE; + virtual void ConnectionClosed() OVERRIDE; + + // DevToolsAgentHostImpl implementation. + virtual void Attach() OVERRIDE; + virtual void Detach() OVERRIDE; + virtual void DispatchOnInspectorBackend(const std::string& message) OVERRIDE; + + scoped_ptr<DevToolsExternalAgentProxyDelegate> delegate_; +}; + +} // namespace content + +#endif // CONTENT_BROWSER_DEVTOOLS_FORWARDING_AGENT_HOST_H diff --git a/chromium/content/browser/devtools/ipc_devtools_agent_host.cc b/chromium/content/browser/devtools/ipc_devtools_agent_host.cc index c7cd3c386f8..294a679c7f6 100644 --- a/chromium/content/browser/devtools/ipc_devtools_agent_host.cc +++ b/chromium/content/browser/devtools/ipc_devtools_agent_host.cc @@ -9,7 +9,7 @@ namespace content { void IPCDevToolsAgentHost::Attach() { - SendMessageToAgent(new DevToolsAgentMsg_Attach(MSG_ROUTING_NONE)); + SendMessageToAgent(new DevToolsAgentMsg_Attach(MSG_ROUTING_NONE, GetId())); OnClientAttached(); } @@ -26,7 +26,7 @@ void IPCDevToolsAgentHost::DispatchOnInspectorBackend( void IPCDevToolsAgentHost::InspectElement(int x, int y) { SendMessageToAgent(new DevToolsAgentMsg_InspectElement(MSG_ROUTING_NONE, - x, y)); + GetId(), x, y)); } IPCDevToolsAgentHost::~IPCDevToolsAgentHost() { @@ -34,8 +34,7 @@ IPCDevToolsAgentHost::~IPCDevToolsAgentHost() { void IPCDevToolsAgentHost::Reattach(const std::string& saved_agent_state) { SendMessageToAgent(new DevToolsAgentMsg_Reattach( - MSG_ROUTING_NONE, - saved_agent_state)); + MSG_ROUTING_NONE, GetId(), saved_agent_state)); OnClientAttached(); } diff --git a/chromium/content/browser/devtools/render_view_devtools_agent_host.cc b/chromium/content/browser/devtools/render_view_devtools_agent_host.cc index 39ced5eb581..82df7ed2f0d 100644 --- a/chromium/content/browser/devtools/render_view_devtools_agent_host.cc +++ b/chromium/content/browser/devtools/render_view_devtools_agent_host.cc @@ -8,6 +8,7 @@ #include "base/lazy_instance.h" #include "content/browser/child_process_security_policy_impl.h" #include "content/browser/devtools/devtools_manager_impl.h" +#include "content/browser/devtools/devtools_power_handler.h" #include "content/browser/devtools/devtools_protocol.h" #include "content/browser/devtools/devtools_protocol_constants.h" #include "content/browser/devtools/devtools_tracing_handler.h" @@ -19,6 +20,7 @@ #include "content/common/devtools_messages.h" #include "content/common/view_messages.h" #include "content/public/browser/content_browser_client.h" +#include "content/public/browser/devtools_manager_delegate.h" #include "content/public/browser/notification_service.h" #include "content/public/browser/notification_types.h" #include "content/public/browser/render_widget_host_iterator.h" @@ -35,6 +37,22 @@ typedef std::vector<RenderViewDevToolsAgentHost*> Instances; namespace { base::LazyInstance<Instances>::Leaky g_instances = LAZY_INSTANCE_INITIALIZER; +//Returns RenderViewDevToolsAgentHost attached to any of RenderViewHost +//instances associated with |web_contents| +static RenderViewDevToolsAgentHost* FindAgentHost(WebContents* web_contents) { + if (g_instances == NULL) + return NULL; + RenderViewHostDelegate* delegate = + static_cast<WebContentsImpl*>(web_contents); + for (Instances::iterator it = g_instances.Get().begin(); + it != g_instances.Get().end(); ++it) { + RenderViewHost* rvh = (*it)->render_view_host(); + if (rvh && rvh->GetDelegate() == delegate) + return *it; + } + return NULL; +} + static RenderViewDevToolsAgentHost* FindAgentHost(RenderViewHost* rvh) { if (g_instances == NULL) return NULL; @@ -48,6 +66,14 @@ static RenderViewDevToolsAgentHost* FindAgentHost(RenderViewHost* rvh) { } // namespace +scoped_refptr<DevToolsAgentHost> +DevToolsAgentHost::GetOrCreateFor(WebContents* web_contents) { + RenderViewDevToolsAgentHost* result = FindAgentHost(web_contents); + if (!result) + result = new RenderViewDevToolsAgentHost(web_contents->GetRenderViewHost()); + return result; +} + // static scoped_refptr<DevToolsAgentHost> DevToolsAgentHost::GetOrCreateFor(RenderViewHost* rvh) { @@ -96,10 +122,20 @@ std::vector<RenderViewHost*> DevToolsAgentHost::GetValidRenderViewHosts() { RenderViewHost* rvh = RenderViewHost::From(widget); WebContents* web_contents = WebContents::FromRenderViewHost(rvh); + if (!web_contents) + continue; + // Don't report a RenderViewHost if it is not the current RenderViewHost - // for some WebContents. - if (!web_contents || rvh != web_contents->GetRenderViewHost()) + // for some WebContents (this filters out pre-render RVHs and similar). + // However report a RenderViewHost created for an out of process iframe. + // TODO (kaznacheev): Revisit this when it is clear how OOP iframes + // interact with pre-rendering. + // TODO (kaznacheev): GetMainFrame() call is a temporary hack. Iterate over + // all RenderFrameHost instances when multiple OOP frames are supported. + if (rvh != web_contents->GetRenderViewHost() && + !rvh->GetMainFrame()->IsCrossProcessSubframe()) { continue; + } result.push_back(rvh); } @@ -117,18 +153,28 @@ void RenderViewDevToolsAgentHost::OnCancelPendingNavigation( agent_host->ConnectRenderViewHost(current); } -RenderViewDevToolsAgentHost::RenderViewDevToolsAgentHost( - RenderViewHost* rvh) +// static +bool RenderViewDevToolsAgentHost::DispatchIPCMessage( + RenderViewHost* source, + const IPC::Message& message) { + RenderViewDevToolsAgentHost* agent_host = FindAgentHost(source); + return agent_host && agent_host->DispatchIPCMessage(message); +} + +RenderViewDevToolsAgentHost::RenderViewDevToolsAgentHost(RenderViewHost* rvh) : render_view_host_(NULL), overrides_handler_(new RendererOverridesHandler(this)), - tracing_handler_(new DevToolsTracingHandler()) - { + tracing_handler_( + new DevToolsTracingHandler(DevToolsTracingHandler::Renderer)), + power_handler_(new DevToolsPowerHandler()), + reattaching_(false) { SetRenderViewHost(rvh); DevToolsProtocol::Notifier notifier(base::Bind( &RenderViewDevToolsAgentHost::OnDispatchOnInspectorFrontend, base::Unretained(this))); overrides_handler_->SetNotifier(notifier); tracing_handler_->SetNotifier(notifier); + power_handler_->SetNotifier(notifier); g_instances.Get().push_back(this); AddRef(); // Balanced in RenderViewHostDestroyed. } @@ -140,14 +186,30 @@ RenderViewHost* RenderViewDevToolsAgentHost::GetRenderViewHost() { void RenderViewDevToolsAgentHost::DispatchOnInspectorBackend( const std::string& message) { std::string error_message; + + scoped_ptr<base::DictionaryValue> message_dict( + DevToolsProtocol::ParseMessage(message, &error_message)); scoped_refptr<DevToolsProtocol::Command> command = - DevToolsProtocol::ParseCommand(message, &error_message); + DevToolsProtocol::ParseCommand(message_dict.get(), &error_message); if (command) { - scoped_refptr<DevToolsProtocol::Response> overridden_response = - overrides_handler_->HandleCommand(command); + scoped_refptr<DevToolsProtocol::Response> overridden_response; + + DevToolsManagerDelegate* delegate = + DevToolsManagerImpl::GetInstance()->delegate(); + if (delegate) { + scoped_ptr<base::DictionaryValue> overridden_response_value( + delegate->HandleCommand(this, message_dict.get())); + if (overridden_response_value) + overridden_response = DevToolsProtocol::ParseResponse( + overridden_response_value.get()); + } + if (!overridden_response) + overridden_response = overrides_handler_->HandleCommand(command); if (!overridden_response) overridden_response = tracing_handler_->HandleCommand(command); + if (!overridden_response) + overridden_response = power_handler_->HandleCommand(command); if (overridden_response) { if (!overridden_response->is_async_promise()) OnDispatchOnInspectorFrontend(overridden_response->Serialize()); @@ -169,12 +231,17 @@ void RenderViewDevToolsAgentHost::OnClientAttached() { if (!render_view_host_) return; - ChildProcessSecurityPolicyImpl::GetInstance()->GrantReadRawCookies( - render_view_host_->GetProcess()->GetID()); + InnerOnClientAttached(); // TODO(kaznacheev): Move this call back to DevToolsManagerImpl when // extensions::ProcessManager no longer relies on this notification. - DevToolsManagerImpl::GetInstance()->NotifyObservers(this, true); + if (!reattaching_) + DevToolsManagerImpl::GetInstance()->NotifyObservers(this, true); +} + +void RenderViewDevToolsAgentHost::InnerOnClientAttached() { + ChildProcessSecurityPolicyImpl::GetInstance()->GrantReadRawCookies( + render_view_host_->GetProcess()->GetID()); #if defined(OS_ANDROID) power_save_blocker_.reset( @@ -194,6 +261,7 @@ void RenderViewDevToolsAgentHost::OnClientDetached() { power_save_blocker_.reset(); #endif overrides_handler_->OnClientDetached(); + tracing_handler_->OnClientDetached(); ClientDetachedFromRenderer(); } @@ -201,6 +269,15 @@ void RenderViewDevToolsAgentHost::ClientDetachedFromRenderer() { if (!render_view_host_) return; + InnerClientDetachedFromRenderer(); + + // TODO(kaznacheev): Move this call back to DevToolsManagerImpl when + // extensions::ProcessManager no longer relies on this notification. + if (!reattaching_) + DevToolsManagerImpl::GetInstance()->NotifyObservers(this, false); +} + +void RenderViewDevToolsAgentHost::InnerClientDetachedFromRenderer() { bool process_has_agents = false; RenderProcessHost* render_process_host = render_view_host_->GetProcess(); for (Instances::iterator it = g_instances.Get().begin(); @@ -217,10 +294,6 @@ void RenderViewDevToolsAgentHost::ClientDetachedFromRenderer() { ChildProcessSecurityPolicyImpl::GetInstance()->RevokeReadRawCookies( render_process_host->GetID()); } - - // TODO(kaznacheev): Move this call back to DevToolsManagerImpl when - // extensions::ProcessManager no longer relies on this notification. - DevToolsManagerImpl::GetInstance()->NotifyObservers(this, false); } RenderViewDevToolsAgentHost::~RenderViewDevToolsAgentHost() { @@ -240,8 +313,7 @@ void RenderViewDevToolsAgentHost::AboutToNavigateRenderView( render_view_host_)->render_view_termination_status() == base::TERMINATION_STATUS_STILL_RUNNING) return; - DisconnectRenderViewHost(); - ConnectRenderViewHost(dest_rvh); + ReattachToRenderViewHost(dest_rvh); } void RenderViewDevToolsAgentHost::RenderViewHostChanged( @@ -250,11 +322,19 @@ void RenderViewDevToolsAgentHost::RenderViewHostChanged( if (new_host != render_view_host_) { // AboutToNavigateRenderView was not called for renderer-initiated // navigation. - DisconnectRenderViewHost(); - ConnectRenderViewHost(new_host); + ReattachToRenderViewHost(new_host); } } +void +RenderViewDevToolsAgentHost::ReattachToRenderViewHost(RenderViewHost* rvh) { + DCHECK(!reattaching_); + reattaching_ = true; + DisconnectRenderViewHost(); + ConnectRenderViewHost(rvh); + reattaching_ = false; +} + void RenderViewDevToolsAgentHost::RenderViewDeleted(RenderViewHost* rvh) { if (rvh != render_view_host_) return; @@ -272,6 +352,9 @@ void RenderViewDevToolsAgentHost::RenderProcessGone( case base::TERMINATION_STATUS_ABNORMAL_TERMINATION: case base::TERMINATION_STATUS_PROCESS_WAS_KILLED: case base::TERMINATION_STATUS_PROCESS_CRASHED: +#if defined(OS_ANDROID) + case base::TERMINATION_STATUS_OOM_PROTECTED: +#endif RenderViewCrashed(); break; default: @@ -341,7 +424,7 @@ void RenderViewDevToolsAgentHost::RenderViewCrashed() { DispatchOnInspectorFrontend(this, notification->Serialize()); } -bool RenderViewDevToolsAgentHost::OnMessageReceived( +bool RenderViewDevToolsAgentHost::DispatchIPCMessage( const IPC::Message& msg) { if (!render_view_host_) return false; @@ -352,9 +435,6 @@ bool RenderViewDevToolsAgentHost::OnMessageReceived( OnDispatchOnInspectorFrontend) IPC_MESSAGE_HANDLER(DevToolsHostMsg_SaveAgentRuntimeState, OnSaveAgentRuntimeState) - IPC_MESSAGE_HANDLER(DevToolsHostMsg_ClearBrowserCache, OnClearBrowserCache) - IPC_MESSAGE_HANDLER(DevToolsHostMsg_ClearBrowserCookies, - OnClearBrowserCookies) IPC_MESSAGE_HANDLER_GENERIC(ViewHostMsg_SwapCompositorFrame, handled = false; OnSwapCompositorFrame(msg)) IPC_MESSAGE_UNHANDLED(handled = false) @@ -392,14 +472,4 @@ void RenderViewDevToolsAgentHost::OnDispatchOnInspectorFrontend( this, message); } -void RenderViewDevToolsAgentHost::OnClearBrowserCache() { - if (render_view_host_) - GetContentClient()->browser()->ClearCache(render_view_host_); -} - -void RenderViewDevToolsAgentHost::OnClearBrowserCookies() { - if (render_view_host_) - GetContentClient()->browser()->ClearCookies(render_view_host_); -} - } // namespace content diff --git a/chromium/content/browser/devtools/render_view_devtools_agent_host.h b/chromium/content/browser/devtools/render_view_devtools_agent_host.h index 88ba70cc81a..f4e9baf4a5f 100644 --- a/chromium/content/browser/devtools/render_view_devtools_agent_host.h +++ b/chromium/content/browser/devtools/render_view_devtools_agent_host.h @@ -22,6 +22,7 @@ class CompositorFrameMetadata; namespace content { +class DevToolsPowerHandler; class DevToolsTracingHandler; class RendererOverridesHandler; class RenderViewHost; @@ -38,6 +39,9 @@ class CONTENT_EXPORT RenderViewDevToolsAgentHost static void OnCancelPendingNavigation(RenderViewHost* pending, RenderViewHost* current); + static bool DispatchIPCMessage(RenderViewHost* source, + const IPC::Message& message); + RenderViewDevToolsAgentHost(RenderViewHost*); RenderViewHost* render_view_host() { return render_view_host_; } @@ -68,13 +72,16 @@ class CONTENT_EXPORT RenderViewDevToolsAgentHost virtual void RenderViewDeleted(RenderViewHost* rvh) OVERRIDE; virtual void RenderProcessGone(base::TerminationStatus status) OVERRIDE; virtual void DidAttachInterstitialPage() OVERRIDE; - virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE; // NotificationObserver overrides: virtual void Observe(int type, const NotificationSource& source, const NotificationDetails& details) OVERRIDE; + void ReattachToRenderViewHost(RenderViewHost* rvh); + + bool DispatchIPCMessage(const IPC::Message& message); + void SetRenderViewHost(RenderViewHost* rvh); void ClearRenderViewHost(); @@ -83,19 +90,22 @@ class CONTENT_EXPORT RenderViewDevToolsAgentHost void OnDispatchOnInspectorFrontend(const std::string& message); void OnSaveAgentRuntimeState(const std::string& state); - void OnClearBrowserCache(); - void OnClearBrowserCookies(); void ClientDetachedFromRenderer(); + void InnerOnClientAttached(); + void InnerClientDetachedFromRenderer(); + RenderViewHost* render_view_host_; scoped_ptr<RendererOverridesHandler> overrides_handler_; scoped_ptr<DevToolsTracingHandler> tracing_handler_; + scoped_ptr<DevToolsPowerHandler> power_handler_; #if defined(OS_ANDROID) scoped_ptr<PowerSaveBlockerImpl> power_save_blocker_; #endif std::string state_; NotificationRegistrar registrar_; + bool reattaching_; DISALLOW_COPY_AND_ASSIGN(RenderViewDevToolsAgentHost); }; diff --git a/chromium/content/browser/devtools/renderer_overrides_handler.cc b/chromium/content/browser/devtools/renderer_overrides_handler.cc index 4901f34cc12..7370275cd45 100644 --- a/chromium/content/browser/devtools/renderer_overrides_handler.cc +++ b/chromium/content/browser/devtools/renderer_overrides_handler.cc @@ -13,6 +13,7 @@ #include "base/bind_helpers.h" #include "base/files/file_path.h" #include "base/strings/string16.h" +#include "base/thread_task_runner_handle.h" #include "base/values.h" #include "content/browser/child_process_security_policy_impl.h" #include "content/browser/devtools/devtools_protocol_constants.h" @@ -20,9 +21,10 @@ #include "content/browser/renderer_host/dip_util.h" #include "content/browser/renderer_host/render_view_host_delegate.h" #include "content/browser/renderer_host/render_view_host_impl.h" +#include "content/browser/renderer_host/render_widget_host_view_base.h" #include "content/common/view_messages.h" -#include "content/port/browser/render_widget_host_view_port.h" #include "content/public/browser/browser_thread.h" +#include "content/public/browser/content_browser_client.h" #include "content/public/browser/devtools_agent_host.h" #include "content/public/browser/javascript_dialog_manager.h" #include "content/public/browser/navigation_controller.h" @@ -41,6 +43,8 @@ #include "third_party/WebKit/public/web/WebInputEvent.h" #include "ui/gfx/codec/jpeg_codec.h" #include "ui/gfx/codec/png_codec.h" +#include "ui/gfx/display.h" +#include "ui/gfx/screen.h" #include "ui/gfx/size_conversions.h" #include "ui/snapshot/snapshot.h" #include "url/gurl.h" @@ -91,6 +95,16 @@ RendererOverridesHandler::RendererOverridesHandler(DevToolsAgentHost* agent) &RendererOverridesHandler::GrantPermissionsForSetFileInputFiles, base::Unretained(this))); RegisterCommandHandler( + devtools::Network::clearBrowserCache::kName, + base::Bind( + &RendererOverridesHandler::ClearBrowserCache, + base::Unretained(this))); + RegisterCommandHandler( + devtools::Network::clearBrowserCookies::kName, + base::Bind( + &RendererOverridesHandler::ClearBrowserCookies, + base::Unretained(this))); + RegisterCommandHandler( devtools::Page::disable::kName, base::Bind( &RendererOverridesHandler::PageDisable, base::Unretained(this))); @@ -192,19 +206,22 @@ void RendererOverridesHandler::InnerSwapCompositorFrame() { double scale = 1; ParseCaptureParameters(screencast_command_.get(), &format, &quality, &scale); - RenderWidgetHostViewPort* view_port = - RenderWidgetHostViewPort::FromRWHV(host->GetView()); + const gfx::Display& display = + gfx::Screen::GetNativeScreen()->GetPrimaryDisplay(); + float device_scale_factor = display.device_scale_factor(); gfx::Rect view_bounds = host->GetView()->GetViewBounds(); - gfx::Size snapshot_size = gfx::ToFlooredSize( - gfx::ScaleSize(view_bounds.size(), scale)); + gfx::Size snapshot_size(gfx::ToCeiledSize( + gfx::ScaleSize(view_bounds.size(), scale / device_scale_factor))); - view_port->CopyFromCompositingSurface( + RenderWidgetHostViewBase* view = static_cast<RenderWidgetHostViewBase*>( + host->GetView()); + view->CopyFromCompositingSurface( view_bounds, snapshot_size, - base::Bind(&RendererOverridesHandler::ScreenshotCaptured, + base::Bind(&RendererOverridesHandler::ScreencastFrameCaptured, weak_factory_.GetWeakPtr(), - scoped_refptr<DevToolsProtocol::Command>(), format, quality, - last_compositor_frame_metadata_)); + format, quality, last_compositor_frame_metadata_), + SkBitmap::kARGB_8888_Config); } void RendererOverridesHandler::ParseCaptureParameters( @@ -218,13 +235,13 @@ void RendererOverridesHandler::ParseCaptureParameters( double max_height = -1; base::DictionaryValue* params = command->params(); if (params) { - params->GetString(devtools::Page::captureScreenshot::kParamFormat, + params->GetString(devtools::Page::startScreencast::kParamFormat, format); - params->GetInteger(devtools::Page::captureScreenshot::kParamQuality, + params->GetInteger(devtools::Page::startScreencast::kParamQuality, quality); - params->GetDouble(devtools::Page::captureScreenshot::kParamMaxWidth, + params->GetDouble(devtools::Page::startScreencast::kParamMaxWidth, &max_width); - params->GetDouble(devtools::Page::captureScreenshot::kParamMaxHeight, + params->GetDouble(devtools::Page::startScreencast::kParamMaxHeight, &max_height); } @@ -246,6 +263,20 @@ void RendererOverridesHandler::ParseCaptureParameters( *scale = 5; } +base::DictionaryValue* RendererOverridesHandler::CreateScreenshotResponse( + const std::vector<unsigned char>& png_data) { + std::string base_64_data; + base::Base64Encode( + base::StringPiece(reinterpret_cast<const char*>(&png_data[0]), + png_data.size()), + &base_64_data); + + base::DictionaryValue* response = new base::DictionaryValue(); + response->SetString( + devtools::Page::captureScreenshot::kResponseData, base_64_data); + return response; +} + // DOM agent handlers -------------------------------------------------------- scoped_refptr<DevToolsProtocol::Response> @@ -272,6 +303,23 @@ RendererOverridesHandler::GrantPermissionsForSetFileInputFiles( } +// Network agent handlers ---------------------------------------------------- + +scoped_refptr<DevToolsProtocol::Response> +RendererOverridesHandler::ClearBrowserCache( + scoped_refptr<DevToolsProtocol::Command> command) { + GetContentClient()->browser()->ClearCache(agent_->GetRenderViewHost()); + return command->SuccessResponse(NULL); +} + +scoped_refptr<DevToolsProtocol::Response> +RendererOverridesHandler::ClearBrowserCookies( + scoped_refptr<DevToolsProtocol::Command> command) { + GetContentClient()->browser()->ClearCookies(agent_->GetRenderViewHost()); + return command->SuccessResponse(NULL); +} + + // Page agent handlers ------------------------------------------------------- scoped_refptr<DevToolsProtocol::Response> @@ -306,7 +354,7 @@ RendererOverridesHandler::PageHandleJavaScriptDialog( web_contents->GetDelegate()->GetJavaScriptDialogManager(); if (manager && manager->HandleJavaScriptDialog( web_contents, accept, prompt_override_ptr)) { - return NULL; + return command->SuccessResponse(new base::DictionaryValue()); } } } @@ -367,7 +415,7 @@ RendererOverridesHandler::PageGetNavigationHistory( result->SetInteger( devtools::Page::getNavigationHistory::kResponseCurrentIndex, controller.GetCurrentEntryIndex()); - ListValue* entries = new ListValue(); + base::ListValue* entries = new base::ListValue(); for (int i = 0; i != controller.GetEntryCount(); ++i) { const NavigationEntry* entry = controller.GetEntryAtIndex(i); base::DictionaryValue* entry_value = new base::DictionaryValue(); @@ -426,44 +474,41 @@ RendererOverridesHandler::PageCaptureScreenshot( if (!host->GetView()) return command->InternalErrorResponse("Unable to access the view"); - std::string format; - int quality = kDefaultScreenshotQuality; - double scale = 1; - ParseCaptureParameters(command.get(), &format, &quality, &scale); - gfx::Rect view_bounds = host->GetView()->GetViewBounds(); - gfx::Size snapshot_size = gfx::ToFlooredSize( - gfx::ScaleSize(view_bounds.size(), scale)); - - // Grab screen pixels if available for current platform. - // TODO(pfeldman): support format, scale and quality in ui::GrabViewSnapshot. - std::vector<unsigned char> png; - bool is_unscaled_png = scale == 1 && format == kPng; - if (is_unscaled_png && ui::GrabViewSnapshot(host->GetView()->GetNativeView(), - &png, - gfx::Rect(snapshot_size))) { - std::string base64_data; - base::Base64Encode( - base::StringPiece(reinterpret_cast<char*>(&*png.begin()), png.size()), - &base64_data); - base::DictionaryValue* result = new base::DictionaryValue(); - result->SetString( - devtools::Page::captureScreenshot::kResponseData, base64_data); - return command->SuccessResponse(result); + gfx::Rect snapshot_bounds(view_bounds.size()); + gfx::Size snapshot_size = snapshot_bounds.size(); + + std::vector<unsigned char> png_data; + if (ui::GrabViewSnapshot(host->GetView()->GetNativeView(), + &png_data, + snapshot_bounds)) { + if (png_data.size()) + return command->SuccessResponse(CreateScreenshotResponse(png_data)); + else + return command->InternalErrorResponse("Unable to capture screenshot"); } - // Fallback to copying from compositing surface. - RenderWidgetHostViewPort* view_port = - RenderWidgetHostViewPort::FromRWHV(host->GetView()); - - view_port->CopyFromCompositingSurface( - view_bounds, snapshot_size, + ui::GrabViewSnapshotAsync( + host->GetView()->GetNativeView(), + snapshot_bounds, + base::ThreadTaskRunnerHandle::Get(), base::Bind(&RendererOverridesHandler::ScreenshotCaptured, - weak_factory_.GetWeakPtr(), command, format, quality, - last_compositor_frame_metadata_)); + weak_factory_.GetWeakPtr(), command)); return command->AsyncResponsePromise(); } +void RendererOverridesHandler::ScreenshotCaptured( + scoped_refptr<DevToolsProtocol::Command> command, + scoped_refptr<base::RefCountedBytes> png_data) { + if (png_data) { + SendAsyncResponse( + command->SuccessResponse(CreateScreenshotResponse(png_data->data()))); + } else { + SendAsyncResponse( + command->InternalErrorResponse("Unable to capture screenshot")); + } +} + scoped_refptr<DevToolsProtocol::Response> RendererOverridesHandler::PageCanScreencast( scoped_refptr<DevToolsProtocol::Command> command) { @@ -497,18 +542,14 @@ RendererOverridesHandler::PageStopScreencast( return command->SuccessResponse(NULL); } -void RendererOverridesHandler::ScreenshotCaptured( - scoped_refptr<DevToolsProtocol::Command> command, +void RendererOverridesHandler::ScreencastFrameCaptured( const std::string& format, int quality, const cc::CompositorFrameMetadata& metadata, bool success, const SkBitmap& bitmap) { if (!success) { - if (command) { - SendAsyncResponse( - command->InternalErrorResponse("Unable to capture screenshot")); - } else if (capture_retry_count_) { + if (capture_retry_count_) { --capture_retry_count_; base::MessageLoop::current()->PostDelayedTask( FROM_HERE, @@ -541,13 +582,8 @@ void RendererOverridesHandler::ScreenshotCaptured( encoded = false; } - if (!encoded) { - if (command) { - SendAsyncResponse( - command->InternalErrorResponse("Unable to encode screenshot")); - } + if (!encoded) return; - } std::string base_64_data; base::Base64Encode( @@ -593,20 +629,11 @@ void RendererOverridesHandler::ScreenshotCaptured( response_metadata->Set( devtools::Page::ScreencastFrameMetadata::kParamViewport, viewport); - if (command) { - response->Set(devtools::Page::captureScreenshot::kResponseMetadata, - response_metadata); - } else { - response->Set(devtools::Page::screencastFrame::kParamMetadata, - response_metadata); - } + response->Set(devtools::Page::screencastFrame::kParamMetadata, + response_metadata); } - if (command) { - SendAsyncResponse(command->SuccessResponse(response)); - } else { - SendNotification(devtools::Page::screencastFrame::kName, response); - } + SendNotification(devtools::Page::screencastFrame::kName, response); } // Quota and Usage ------------------------------------------ @@ -906,6 +933,7 @@ RendererOverridesHandler::InputDispatchGestureEvent( agent_->GetRenderViewHost()); blink::WebGestureEvent event; ParseGenericInputParams(params, &event); + event.sourceDevice = blink::WebGestureDeviceTouchscreen; std::string type; if (params->GetString(devtools::Input::dispatchGestureEvent::kParamType, diff --git a/chromium/content/browser/devtools/renderer_overrides_handler.h b/chromium/content/browser/devtools/renderer_overrides_handler.h index cce32767c39..0f7f8bc6cba 100644 --- a/chromium/content/browser/devtools/renderer_overrides_handler.h +++ b/chromium/content/browser/devtools/renderer_overrides_handler.h @@ -7,6 +7,7 @@ #include "base/basictypes.h" #include "base/compiler_specific.h" +#include "base/memory/ref_counted_memory.h" #include "base/memory/scoped_ptr.h" #include "base/memory/weak_ptr.h" #include "base/time/time.h" @@ -43,12 +44,20 @@ class CONTENT_EXPORT RendererOverridesHandler void ParseCaptureParameters(DevToolsProtocol::Command* command, std::string* format, int* quality, double* scale); + base::DictionaryValue* CreateScreenshotResponse( + const std::vector<unsigned char>& png_data); // DOM domain. scoped_refptr<DevToolsProtocol::Response> GrantPermissionsForSetFileInputFiles( scoped_refptr<DevToolsProtocol::Command> command); + // Network domain. + scoped_refptr<DevToolsProtocol::Response> ClearBrowserCache( + scoped_refptr<DevToolsProtocol::Command> command); + scoped_refptr<DevToolsProtocol::Response> ClearBrowserCookies( + scoped_refptr<DevToolsProtocol::Command> command); + // Page domain. scoped_refptr<DevToolsProtocol::Response> PageDisable( scoped_refptr<DevToolsProtocol::Command> command); @@ -75,6 +84,9 @@ class CONTENT_EXPORT RendererOverridesHandler void ScreenshotCaptured( scoped_refptr<DevToolsProtocol::Command> command, + scoped_refptr<base::RefCountedBytes> png_data); + + void ScreencastFrameCaptured( const std::string& format, int quality, const cc::CompositorFrameMetadata& metadata, diff --git a/chromium/content/browser/devtools/renderer_overrides_handler_browsertest.cc b/chromium/content/browser/devtools/renderer_overrides_handler_browsertest.cc index 24dd9621341..d869d9d6e6c 100644 --- a/chromium/content/browser/devtools/renderer_overrides_handler_browsertest.cc +++ b/chromium/content/browser/devtools/renderer_overrides_handler_browsertest.cc @@ -8,9 +8,9 @@ #include "content/browser/devtools/renderer_overrides_handler.h" #include "content/public/browser/devtools_agent_host.h" #include "content/public/browser/web_contents.h" +#include "content/public/test/content_browser_test.h" +#include "content/public/test/content_browser_test_utils.h" #include "content/shell/browser/shell.h" -#include "content/test/content_browser_test.h" -#include "content/test/content_browser_test_utils.h" namespace content { @@ -18,14 +18,15 @@ class RendererOverridesHandlerTest : public ContentBrowserTest { protected: scoped_refptr<DevToolsProtocol::Response> SendCommand( const std::string& method, - DictionaryValue* params) { + base::DictionaryValue* params) { scoped_ptr<RendererOverridesHandler> handler(CreateHandler()); scoped_refptr<DevToolsProtocol::Command> command( DevToolsProtocol::CreateCommand(1, method, params)); return handler->HandleCommand(command); } - void SendAsyncCommand(const std::string& method, DictionaryValue* params) { + void SendAsyncCommand(const std::string& method, + base::DictionaryValue* params) { scoped_ptr<RendererOverridesHandler> handler(CreateHandler()); scoped_refptr<DevToolsProtocol::Command> command( DevToolsProtocol::CreateCommand(1, method, params)); @@ -84,7 +85,7 @@ class RendererOverridesHandlerTest : public ContentBrowserTest { }; IN_PROC_BROWSER_TEST_F(RendererOverridesHandlerTest, QueryUsageAndQuota) { - DictionaryValue* params = new DictionaryValue(); + base::DictionaryValue* params = new base::DictionaryValue(); params->SetString("securityOrigin", "http://example.com"); SendAsyncCommand("Page.queryUsageAndQuota", params); diff --git a/chromium/content/browser/devtools/tethering_handler.cc b/chromium/content/browser/devtools/tethering_handler.cc index d3e787d0c01..9b3b7fa005a 100644 --- a/chromium/content/browser/devtools/tethering_handler.cc +++ b/chromium/content/browser/devtools/tethering_handler.cc @@ -149,7 +149,7 @@ class SocketPump : public net::StreamListenSocket::Delegate { } void SelfDestruct() { - if (wire_buffer_->offset() != wire_buffer_size_) { + if (wire_buffer_ && wire_buffer_->offset() != wire_buffer_size_) { pending_destruction_ = true; return; } diff --git a/chromium/content/browser/devtools/worker_devtools_manager.cc b/chromium/content/browser/devtools/worker_devtools_manager.cc index f0608815f33..0658c353c64 100644 --- a/chromium/content/browser/devtools/worker_devtools_manager.cc +++ b/chromium/content/browser/devtools/worker_devtools_manager.cc @@ -12,6 +12,7 @@ #include "content/browser/devtools/devtools_manager_impl.h" #include "content/browser/devtools/devtools_protocol.h" #include "content/browser/devtools/devtools_protocol_constants.h" +#include "content/browser/devtools/embedded_worker_devtools_manager.h" #include "content/browser/devtools/ipc_devtools_agent_host.h" #include "content/browser/devtools/worker_devtools_message_filter.h" #include "content/browser/worker_host/worker_service_impl.h" @@ -27,19 +28,13 @@ namespace content { scoped_refptr<DevToolsAgentHost> DevToolsAgentHost::GetForWorker( int worker_process_id, int worker_route_id) { - return WorkerDevToolsManager::GetDevToolsAgentHostForWorker( - worker_process_id, - worker_route_id); -} - -// Called on the UI thread. -// static -bool DevToolsAgentHost::HasForWorker( - int worker_process_id, - int worker_route_id) { - return WorkerDevToolsManager::HasDevToolsAgentHostForWorker( - worker_process_id, - worker_route_id); + if (WorkerService::EmbeddedSharedWorkerEnabled()) { + return EmbeddedWorkerDevToolsManager::GetInstance() + ->GetDevToolsAgentHostForWorker(worker_process_id, worker_route_id); + } else { + return WorkerDevToolsManager::GetDevToolsAgentHostForWorker( + worker_process_id, worker_route_id); + } } namespace { @@ -217,6 +212,7 @@ struct WorkerDevToolsManager::InspectedWorker { // static WorkerDevToolsManager* WorkerDevToolsManager::GetInstance() { + DCHECK(!WorkerService::EmbeddedSharedWorkerEnabled()); DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); return Singleton<WorkerDevToolsManager>::get(); } @@ -225,6 +221,7 @@ WorkerDevToolsManager* WorkerDevToolsManager::GetInstance() { DevToolsAgentHost* WorkerDevToolsManager::GetDevToolsAgentHostForWorker( int worker_process_id, int worker_route_id) { + DCHECK(!WorkerService::EmbeddedSharedWorkerEnabled()); WorkerId id(worker_process_id, worker_route_id); AgentHosts::iterator it = g_agent_map.Get().find(id); if (it == g_agent_map.Get().end()) @@ -232,21 +229,13 @@ DevToolsAgentHost* WorkerDevToolsManager::GetDevToolsAgentHostForWorker( return it->second; } -// static -bool WorkerDevToolsManager::HasDevToolsAgentHostForWorker( - int worker_process_id, - int worker_route_id) { - WorkerId id(worker_process_id, worker_route_id); - return g_agent_map.Get().find(id) != g_agent_map.Get().end(); -} - WorkerDevToolsManager::WorkerDevToolsManager() { } WorkerDevToolsManager::~WorkerDevToolsManager() { } -void WorkerDevToolsManager::WorkerCreated( +bool WorkerDevToolsManager::WorkerCreated( WorkerProcessHost* worker, const WorkerProcessHost::WorkerInstance& instance) { for (TerminatedInspectedWorkers::iterator it = terminated_workers_.begin(); @@ -254,14 +243,13 @@ void WorkerDevToolsManager::WorkerCreated( if (instance.Matches(it->worker_url, it->worker_name, instance.partition(), instance.resource_context())) { - worker->Send(new DevToolsAgentMsg_PauseWorkerContextOnStart( - instance.worker_route_id())); WorkerId new_worker_id(worker->GetData().id, instance.worker_route_id()); paused_workers_[new_worker_id] = it->old_worker_id; terminated_workers_.erase(it); - return; + return true; } } + return false; } void WorkerDevToolsManager::WorkerDestroyed( diff --git a/chromium/content/browser/devtools/worker_devtools_manager.h b/chromium/content/browser/devtools/worker_devtools_manager.h index 8a9a7084226..73916c30fe2 100644 --- a/chromium/content/browser/devtools/worker_devtools_manager.h +++ b/chromium/content/browser/devtools/worker_devtools_manager.h @@ -19,6 +19,7 @@ namespace content { class DevToolsAgentHost; // All methods are supposed to be called on the IO thread. +// This class is not used when "enable-embedded-shared-worker" flag is set. class WorkerDevToolsManager { public: typedef std::pair<int, int> WorkerId; @@ -32,11 +33,6 @@ class WorkerDevToolsManager { int worker_process_id, int worker_route_id); - // Called on the UI thread. - static bool HasDevToolsAgentHostForWorker( - int worker_process_id, - int worker_route_id); - void ForwardToDevToolsClient(int worker_process_id, int worker_route_id, const std::string& message); @@ -45,9 +41,9 @@ class WorkerDevToolsManager { const std::string& state); // Called on the IO thread. - void WorkerCreated( - WorkerProcessHost* process, - const WorkerProcessHost::WorkerInstance& instance); + // Returns true when the worker must be paused on start. + bool WorkerCreated(WorkerProcessHost* process, + const WorkerProcessHost::WorkerInstance& instance); void WorkerDestroyed(WorkerProcessHost* process, int worker_route_id); void WorkerContextStarted(WorkerProcessHost* process, int worker_route_id); diff --git a/chromium/content/browser/devtools/worker_devtools_message_filter.cc b/chromium/content/browser/devtools/worker_devtools_message_filter.cc index 3f5553f120c..23c068b5405 100644 --- a/chromium/content/browser/devtools/worker_devtools_message_filter.cc +++ b/chromium/content/browser/devtools/worker_devtools_message_filter.cc @@ -12,7 +12,8 @@ namespace content { WorkerDevToolsMessageFilter::WorkerDevToolsMessageFilter( int worker_process_host_id) - : worker_process_host_id_(worker_process_host_id), + : BrowserMessageFilter(DevToolsMsgStart), + worker_process_host_id_(worker_process_host_id), current_routing_id_(0) { } @@ -20,18 +21,16 @@ WorkerDevToolsMessageFilter::~WorkerDevToolsMessageFilter() { } bool WorkerDevToolsMessageFilter::OnMessageReceived( - const IPC::Message& message, - bool* message_was_ok) { + const IPC::Message& message) { bool handled = true; current_routing_id_ = message.routing_id(); - IPC_BEGIN_MESSAGE_MAP_EX(WorkerDevToolsMessageFilter, message, - *message_was_ok) + IPC_BEGIN_MESSAGE_MAP(WorkerDevToolsMessageFilter, message) IPC_MESSAGE_HANDLER(DevToolsClientMsg_DispatchOnInspectorFrontend, OnDispatchOnInspectorFrontend) IPC_MESSAGE_HANDLER(DevToolsHostMsg_SaveAgentRuntimeState, OnSaveAgentRumtimeState) IPC_MESSAGE_UNHANDLED(handled = false) - IPC_END_MESSAGE_MAP_EX() + IPC_END_MESSAGE_MAP() return handled; } diff --git a/chromium/content/browser/devtools/worker_devtools_message_filter.h b/chromium/content/browser/devtools/worker_devtools_message_filter.h index 73ba6f8442a..c80658e8dbf 100644 --- a/chromium/content/browser/devtools/worker_devtools_message_filter.h +++ b/chromium/content/browser/devtools/worker_devtools_message_filter.h @@ -18,8 +18,7 @@ class WorkerDevToolsMessageFilter : public BrowserMessageFilter { virtual ~WorkerDevToolsMessageFilter(); // BrowserMessageFilter implementation. - virtual bool OnMessageReceived(const IPC::Message& message, - bool* message_was_ok) OVERRIDE; + virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE; // Message handlers. void OnDispatchOnInspectorFrontend(const std::string& message); void OnSaveAgentRumtimeState(const std::string& state); |