summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorkbr@chromium.org <kbr@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2014-06-04 22:27:20 +0000
committerkbr@chromium.org <kbr@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2014-06-04 22:27:20 +0000
commit0e60fce0f20f6b7cfadf52fb80cef888f007a2fe (patch)
treedd8a1bf349aac96d10904bf3854e46037bb0db95
parent9de395e4b2e4c7aed021813373544e219271b8f1 (diff)
downloadchromium_src-0e60fce0f20f6b7cfadf52fb80cef888f007a2fe.zip
chromium_src-0e60fce0f20f6b7cfadf52fb80cef888f007a2fe.tar.gz
chromium_src-0e60fce0f20f6b7cfadf52fb80cef888f007a2fe.tar.bz2
Support ephemeral ports in DevTools and Telemetry.
In DevTools, if port 0 is requested, query the HttpServer for the port actually used, and write the port to a well-known location: the file "DevToolsActivePort" in the user's profile directory. Currently this handshaking protocol is only implemented for Chromium, not content_shell, but this is the only scenario in which flakiness has been observed. Add a hidden command-line argument to Telemetry's desktop browser backend which uses this new code path. The bots will specify this argument. Telemetry must support browsers two releases back, so once Chrome 37 goes to the Stable channel, the old initialization path will be removed. Issue 379980 has been filed to remove the old code. Tested with and without the new --use-devtools-active-port command line argument with -v. Verified the new code path is taken. Once these changes are committed, the bots will begin verifying this new code. BUG=372560 NOTRY=true Review URL: https://codereview.chromium.org/315503002 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@274935 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--android_webview/native/aw_dev_tools_server.cc4
-rw-r--r--chrome/browser/android/dev_tools_server.cc4
-rw-r--r--chrome/browser/devtools/remote_debugging_server.cc14
-rw-r--r--content/browser/devtools/devtools_http_handler_impl.cc40
-rw-r--r--content/browser/devtools/devtools_http_handler_impl.h6
-rw-r--r--content/browser/devtools/devtools_http_handler_unittest.cc3
-rw-r--r--content/public/browser/devtools_http_handler.h8
-rw-r--r--content/shell/browser/shell_devtools_delegate.cc4
-rw-r--r--tools/telemetry/telemetry/core/backends/chrome/desktop_browser_backend.py33
-rw-r--r--tools/telemetry/telemetry/core/browser_options.py11
-rw-r--r--tools/telemetry/telemetry/core/browser_options_unittest.py7
11 files changed, 122 insertions, 12 deletions
diff --git a/android_webview/native/aw_dev_tools_server.cc b/android_webview/native/aw_dev_tools_server.cc
index 35b6455..6890655 100644
--- a/android_webview/native/aw_dev_tools_server.cc
+++ b/android_webview/native/aw_dev_tools_server.cc
@@ -6,6 +6,7 @@
#include "android_webview/native/aw_contents.h"
#include "base/bind.h"
+#include "base/files/file_path.h"
#include "base/json/json_writer.h"
#include "base/strings/stringprintf.h"
#include "base/strings/utf_string_conversions.h"
@@ -180,7 +181,8 @@ void AwDevToolsServer::Start() {
"",
base::Bind(&content::CanUserConnectToDevTools)),
base::StringPrintf(kFrontEndURL, content::GetWebKitRevision().c_str()),
- new AwDevToolsServerDelegate());
+ new AwDevToolsServerDelegate(),
+ base::FilePath());
}
void AwDevToolsServer::Stop() {
diff --git a/chrome/browser/android/dev_tools_server.cc b/chrome/browser/android/dev_tools_server.cc
index 091e901..ff1acd3 100644
--- a/chrome/browser/android/dev_tools_server.cc
+++ b/chrome/browser/android/dev_tools_server.cc
@@ -13,6 +13,7 @@
#include "base/callback.h"
#include "base/command_line.h"
#include "base/compiler_specific.h"
+#include "base/files/file_path.h"
#include "base/logging.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/stringprintf.h"
@@ -427,7 +428,8 @@ void DevToolsServer::Start() {
base::StringPrintf("%s_%d", socket_name_.c_str(), getpid()),
base::Bind(&content::CanUserConnectToDevTools)),
base::StringPrintf(kFrontEndURL, content::GetWebKitRevision().c_str()),
- new DevToolsServerDelegate());
+ new DevToolsServerDelegate(),
+ base::FilePath());
}
void DevToolsServer::Stop() {
diff --git a/chrome/browser/devtools/remote_debugging_server.cc b/chrome/browser/devtools/remote_debugging_server.cc
index 7c98d7f..211ff1a 100644
--- a/chrome/browser/devtools/remote_debugging_server.cc
+++ b/chrome/browser/devtools/remote_debugging_server.cc
@@ -4,8 +4,10 @@
#include "chrome/browser/devtools/remote_debugging_server.h"
+#include "base/path_service.h"
#include "chrome/browser/devtools/browser_list_tabcontents_provider.h"
#include "chrome/browser/ui/webui/devtools_ui.h"
+#include "chrome/common/chrome_paths.h"
#include "content/public/browser/devtools_http_handler.h"
#include "net/socket/tcp_listen_socket.h"
@@ -13,10 +15,20 @@ RemoteDebuggingServer::RemoteDebuggingServer(
chrome::HostDesktopType host_desktop_type,
const std::string& ip,
int port) {
+ base::FilePath output_dir;
+ if (!port) {
+ // The client requested an ephemeral port. Must write the selected
+ // port to a well-known location in the profile directory to
+ // bootstrap the connection process.
+ bool result = PathService::Get(chrome::DIR_USER_DATA, &output_dir);
+ DCHECK(result);
+ }
+
devtools_http_handler_ = content::DevToolsHttpHandler::Start(
new net::TCPListenSocketFactory(ip, port),
"",
- new BrowserListTabContentsProvider(host_desktop_type));
+ new BrowserListTabContentsProvider(host_desktop_type),
+ output_dir);
}
RemoteDebuggingServer::~RemoteDebuggingServer() {
diff --git a/content/browser/devtools/devtools_http_handler_impl.cc b/content/browser/devtools/devtools_http_handler_impl.cc
index 5a5bb09..113c2e5 100644
--- a/content/browser/devtools/devtools_http_handler_impl.cc
+++ b/content/browser/devtools/devtools_http_handler_impl.cc
@@ -5,6 +5,7 @@
#include "content/browser/devtools/devtools_http_handler_impl.h"
#include <algorithm>
+#include <sstream>
#include <utility>
#include "base/bind.h"
@@ -37,6 +38,7 @@
#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"
@@ -48,6 +50,9 @@ namespace content {
namespace {
+const base::FilePath::CharType kDevToolsActivePortFileName[] =
+ FILE_PATH_LITERAL("DevToolsActivePort");
+
const char kDevToolsHandlerThreadName[] = "Chrome_DevToolsHandlerThread";
const char kThumbUrlPrefix[] = "/thumb/";
@@ -150,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;
}
@@ -642,10 +649,12 @@ void DevToolsHttpHandlerImpl::OnCloseUI(int connection_id) {
DevToolsHttpHandlerImpl::DevToolsHttpHandlerImpl(
const net::StreamListenSocketFactory* socket_factory,
const std::string& frontend_url,
- DevToolsHttpHandlerDelegate* delegate)
+ DevToolsHttpHandlerDelegate* delegate,
+ const base::FilePath& active_port_output_directory)
: frontend_url_(frontend_url),
socket_factory_(socket_factory),
- delegate_(delegate) {
+ delegate_(delegate),
+ active_port_output_directory_(active_port_output_directory) {
if (frontend_url_.empty())
frontend_url_ = "/devtools/devtools.html";
@@ -656,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
@@ -675,6 +686,27 @@ 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::stringstream port_stream;
+ port_stream << endpoint.port();
+ std::string s = port_stream.str();
+ if (base::WriteFile(path, s.c_str(), s.length()) < 0) {
+ LOG(ERROR) << "Error writing DevTools active port to file";
+ }
+}
+
void DevToolsHttpHandlerImpl::SendJson(int connection_id,
net::HttpStatusCode status_code,
base::Value* value,
diff --git a/content/browser/devtools/devtools_http_handler_impl.h b/content/browser/devtools/devtools_http_handler_impl.h
index 8e9fe15..d55237d 100644
--- a/content/browser/devtools/devtools_http_handler_impl.h
+++ b/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,
@@ -119,6 +122,7 @@ class DevToolsHttpHandlerImpl
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_;
diff --git a/content/browser/devtools/devtools_http_handler_unittest.cc b/content/browser/devtools/devtools_http_handler_unittest.cc
index f3179f0..5cd189f 100644
--- a/content/browser/devtools/devtools_http_handler_unittest.cc
+++ b/content/browser/devtools/devtools_http_handler_unittest.cc
@@ -106,7 +106,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();
diff --git a/content/public/browser/devtools_http_handler.h b/content/public/browser/devtools_http_handler.h
index 4af5505..cdceff8 100644
--- a/content/public/browser/devtools_http_handler.h
+++ b/content/public/browser/devtools_http_handler.h
@@ -7,6 +7,7 @@
#include <string>
+#include "base/files/file_path.h"
#include "content/common/content_export.h"
class GURL;
@@ -34,10 +35,15 @@ class DevToolsHttpHandler {
const std::string& name);
// Takes ownership over |socket_factory| and |delegate|.
+ // If |active_port_output_directory| is non-empty, it is assumed the
+ // socket_factory was initialized with an ephemeral port (0). The
+ // port selected by the OS will be written to a well-known file in
+ // the output directory.
CONTENT_EXPORT static DevToolsHttpHandler* Start(
const net::StreamListenSocketFactory* socket_factory,
const std::string& frontend_url,
- DevToolsHttpHandlerDelegate* delegate);
+ DevToolsHttpHandlerDelegate* delegate,
+ const base::FilePath& active_port_output_directory);
// Called from the main thread in order to stop protocol handler.
// Automatically destroys the handler instance.
diff --git a/content/shell/browser/shell_devtools_delegate.cc b/content/shell/browser/shell_devtools_delegate.cc
index 6a8f09e..d316b2a 100644
--- a/content/shell/browser/shell_devtools_delegate.cc
+++ b/content/shell/browser/shell_devtools_delegate.cc
@@ -8,6 +8,7 @@
#include "base/bind.h"
#include "base/command_line.h"
+#include "base/files/file_path.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/stringprintf.h"
#include "base/strings/utf_string_conversions.h"
@@ -147,7 +148,8 @@ ShellDevToolsDelegate::ShellDevToolsDelegate(BrowserContext* browser_context)
frontend_url = base::StringPrintf(kFrontEndURL, GetWebKitRevision().c_str());
#endif
devtools_http_handler_ =
- DevToolsHttpHandler::Start(CreateSocketFactory(), frontend_url, this);
+ DevToolsHttpHandler::Start(CreateSocketFactory(), frontend_url, this,
+ base::FilePath());
}
ShellDevToolsDelegate::~ShellDevToolsDelegate() {
diff --git a/tools/telemetry/telemetry/core/backends/chrome/desktop_browser_backend.py b/tools/telemetry/telemetry/core/backends/chrome/desktop_browser_backend.py
index bfbc687..a9f1fa5 100644
--- a/tools/telemetry/telemetry/core/backends/chrome/desktop_browser_backend.py
+++ b/tools/telemetry/telemetry/core/backends/chrome/desktop_browser_backend.py
@@ -7,6 +7,7 @@ import glob
import heapq
import logging
import os
+import os.path
import shutil
import subprocess as subprocess
import sys
@@ -74,6 +75,20 @@ class DesktopBrowserBackend(chrome_browser_backend.ChromeBrowserBackend):
logging.info("Using profile directory:'%s'." % profile_dir)
shutil.rmtree(self._tmp_profile_dir)
shutil.copytree(profile_dir, self._tmp_profile_dir)
+ if self.browser_options.use_devtools_active_port:
+ # No matter whether we're using an existing profile directory or
+ # creating a new one, always delete the well-known file containing
+ # the active DevTools port number.
+ port_file = self._GetDevToolsActivePortPath()
+ if os.path.isfile(port_file):
+ try:
+ os.remove(port_file)
+ except Exception as e:
+ logging.critical('Unable to remove DevToolsActivePort file: %s' % e)
+ sys.exit(1)
+
+ def _GetDevToolsActivePortPath(self):
+ return os.path.join(self.profile_directory, 'DevToolsActivePort')
def _GetCrashServicePipeName(self):
# Ensure a unique pipe name by using the name of the temp dir.
@@ -119,11 +134,27 @@ class DesktopBrowserBackend(chrome_browser_backend.ChromeBrowserBackend):
if not self.IsBrowserRunning():
raise exceptions.ProcessGoneException(
"Return code: %d" % self._proc.returncode)
+ if self.browser_options.use_devtools_active_port:
+ # The Telemetry user selected the new code path to start DevTools on
+ # an ephemeral port. Wait for the well-known file containing the port
+ # number to exist.
+ port_file = self._GetDevToolsActivePortPath()
+ if not os.path.isfile(port_file):
+ # File isn't ready yet. Return false. Will retry.
+ return False
+ with open(port_file) as f:
+ port_string = f.read()
+ self._port = int(port_string)
+ logging.info('Discovered ephemeral port %s' % self._port)
return super(DesktopBrowserBackend, self).HasBrowserFinishedLaunching()
def GetBrowserStartupArgs(self):
args = super(DesktopBrowserBackend, self).GetBrowserStartupArgs()
- self._port = util.GetUnreservedAvailableLocalPort()
+ if self.browser_options.use_devtools_active_port:
+ self._port = 0
+ else:
+ self._port = util.GetUnreservedAvailableLocalPort()
+ logging.info('Requested remote debugging port: %d' % self._port)
args.append('--remote-debugging-port=%i' % self._port)
args.append('--enable-crash-reporter-for-testing')
args.append('--use-mock-keychain')
diff --git a/tools/telemetry/telemetry/core/browser_options.py b/tools/telemetry/telemetry/core/browser_options.py
index aefaa7f..9d3d20c 100644
--- a/tools/telemetry/telemetry/core/browser_options.py
+++ b/tools/telemetry/telemetry/core/browser_options.py
@@ -204,6 +204,11 @@ class BrowserOptions(object):
self.platform = None
+ # Whether to use the new code path for choosing an ephemeral port for
+ # DevTools. The bots set this to true. When Chrome 37 reaches stable,
+ # remove this setting and the old code path. http://crbug.com/379980
+ self.use_devtools_active_port = False
+
def __repr__(self):
return str(sorted(self.__dict__.items()))
@@ -244,6 +249,11 @@ class BrowserOptions(object):
group.add_option('--show-stdout',
action='store_true',
help='When possible, will display the stdout of the process')
+ # This hidden option is to be removed, and the older code path deleted,
+ # once Chrome 37 reaches Stable. http://crbug.com/379980
+ group.add_option('--use-devtools-active-port',
+ action='store_true',
+ help=optparse.SUPPRESS_HELP)
parser.add_option_group(group)
group = optparse.OptionGroup(parser, 'Compatibility options')
@@ -274,6 +284,7 @@ class BrowserOptions(object):
'profile_type',
'show_stdout',
'synthetic_gesture_source_type',
+ 'use_devtools_active_port',
]
for o in browser_options_list:
a = getattr(finder_options, o, None)
diff --git a/tools/telemetry/telemetry/core/browser_options_unittest.py b/tools/telemetry/telemetry/core/browser_options_unittest.py
index 8e5cb11..659ed0c 100644
--- a/tools/telemetry/telemetry/core/browser_options_unittest.py
+++ b/tools/telemetry/telemetry/core/browser_options_unittest.py
@@ -83,6 +83,13 @@ class BrowserOptionsTest(unittest.TestCase):
self.assertEquals(options.browser_options.extra_browser_args,
set(['--foo','--bar']))
+ def testUseDevToolsActivePort(self):
+ options = browser_options.BrowserFinderOptions()
+ parser = options.CreateParser()
+ parser.parse_args(['--use-devtools-active-port'])
+
+ self.assertEquals(options.browser_options.use_devtools_active_port, True)
+
def testMergeDefaultValues(self):
options = browser_options.BrowserFinderOptions()
options.already_true = True