Commit a0dea2e7 authored by mnaganov@chromium.org's avatar mnaganov@chromium.org

[Android] Use a "unique" remote debugging socket name on bind failure

When socket bind failure happens on enabling remote web debugging,
retry using a socket name with PID suffix to ensure uniquiness.
This allows several channels of Chrome to have remote web debugging
enabled simultaneously. Also, this preserves backwards compatibility,
as in the case of the single Chrome instance on a device, remote
debugging socket name is unchanged.

It seems easier to add retry functionality to UnixDomainSocket,
as DevToolsHttpHandler creation is heavily asynchronous.

BUG=222338

Review URL: https://chromiumcodereview.appspot.com/16093005

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@203132 0039d316-1c4b-4281-b951-d872f2087c98
parent 004df8a5
......@@ -30,6 +30,7 @@ AwDevToolsDelegate::AwDevToolsDelegate(content::BrowserContext* browser_context)
devtools_http_handler_ = content::DevToolsHttpHandler::Start(
new net::UnixDomainSocketWithAbstractNamespaceFactory(
base::StringPrintf(kSocketNameFormat, getpid()),
"",
base::Bind(&content::CanUserConnectToDevTools)),
"",
this);
......
......@@ -34,7 +34,7 @@ namespace {
const char kFrontEndURL[] =
"http://chrome-devtools-frontend.appspot.com/static/%s/devtools.html";
const char kDefaultSocketName[] = "chrome_devtools_remote";
const char kTetheringSocketName[] = "chrome_devtools_tethering_%d";
const char kTetheringSocketName[] = "chrome_devtools_tethering_%d_%d";
// Delegate implementation for the devtools http handler on android. A new
// instance of this gets created each time devtools is enabled.
......@@ -92,9 +92,11 @@ class DevToolsServerDelegate : public content::DevToolsHttpHandlerDelegate {
virtual scoped_refptr<net::StreamListenSocket> CreateSocketForTethering(
net::StreamListenSocket::Delegate* delegate,
std::string* name) OVERRIDE {
*name = base::StringPrintf(kTetheringSocketName, ++last_tethering_socket_);
*name = base::StringPrintf(
kTetheringSocketName, getpid(), ++last_tethering_socket_);
return net::UnixDomainSocket::CreateAndListenWithAbstractNamespace(
*name,
"",
delegate,
base::Bind(&content::CanUserConnectToDevTools));
}
......@@ -148,6 +150,7 @@ void DevToolsServer::Start() {
protocol_handler_ = content::DevToolsHttpHandler::Start(
new net::UnixDomainSocketWithAbstractNamespaceFactory(
socket_name_,
base::StringPrintf("%s_%d", socket_name_.c_str(), getpid()),
base::Bind(&content::CanUserConnectToDevTools)),
use_bundled_frontend_resources_ ?
"" :
......
......@@ -34,7 +34,7 @@ net::StreamListenSocketFactory* CreateSocketFactory() {
switches::kRemoteDebuggingSocketName);
}
return new net::UnixDomainSocketWithAbstractNamespaceFactory(
socket_name, base::Bind(&content::CanUserConnectToDevTools));
socket_name, "", base::Bind(&content::CanUserConnectToDevTools));
#else
// See if the user specified a port on the command line (useful for
// automation). If not, use an ephemeral port by specifying 0.
......
......@@ -55,10 +55,13 @@ UnixDomainSocket::AuthCallback NoAuthentication() {
// static
UnixDomainSocket* UnixDomainSocket::CreateAndListenInternal(
const std::string& path,
const std::string& fallback_path,
StreamListenSocket::Delegate* del,
const AuthCallback& auth_callback,
bool use_abstract_namespace) {
SocketDescriptor s = CreateAndBind(path, use_abstract_namespace);
if (s == kInvalidSocket && !fallback_path.empty())
s = CreateAndBind(fallback_path, use_abstract_namespace);
if (s == kInvalidSocket)
return NULL;
UnixDomainSocket* sock = new UnixDomainSocket(s, del, auth_callback);
......@@ -71,7 +74,7 @@ scoped_refptr<UnixDomainSocket> UnixDomainSocket::CreateAndListen(
const std::string& path,
StreamListenSocket::Delegate* del,
const AuthCallback& auth_callback) {
return CreateAndListenInternal(path, del, auth_callback, false);
return CreateAndListenInternal(path, "", del, auth_callback, false);
}
#if defined(SOCKET_ABSTRACT_NAMESPACE_SUPPORTED)
......@@ -79,10 +82,11 @@ scoped_refptr<UnixDomainSocket> UnixDomainSocket::CreateAndListen(
scoped_refptr<UnixDomainSocket>
UnixDomainSocket::CreateAndListenWithAbstractNamespace(
const std::string& path,
const std::string& fallback_path,
StreamListenSocket::Delegate* del,
const AuthCallback& auth_callback) {
return make_scoped_refptr(
CreateAndListenInternal(path, del, auth_callback, true));
CreateAndListenInternal(path, fallback_path, del, auth_callback, true));
}
#endif
......@@ -160,7 +164,8 @@ UnixDomainSocketFactory::~UnixDomainSocketFactory() {}
scoped_refptr<StreamListenSocket> UnixDomainSocketFactory::CreateAndListen(
StreamListenSocket::Delegate* delegate) const {
return UnixDomainSocket::CreateAndListen(path_, delegate, auth_callback_);
return UnixDomainSocket::CreateAndListen(
path_, delegate, auth_callback_);
}
#if defined(SOCKET_ABSTRACT_NAMESPACE_SUPPORTED)
......@@ -168,8 +173,10 @@ scoped_refptr<StreamListenSocket> UnixDomainSocketFactory::CreateAndListen(
UnixDomainSocketWithAbstractNamespaceFactory::
UnixDomainSocketWithAbstractNamespaceFactory(
const std::string& path,
const std::string& fallback_path,
const UnixDomainSocket::AuthCallback& auth_callback)
: UnixDomainSocketFactory(path, auth_callback) {}
: UnixDomainSocketFactory(path, auth_callback),
fallback_path_(fallback_path) {}
UnixDomainSocketWithAbstractNamespaceFactory::
~UnixDomainSocketWithAbstractNamespaceFactory() {}
......@@ -178,7 +185,7 @@ scoped_refptr<StreamListenSocket>
UnixDomainSocketWithAbstractNamespaceFactory::CreateAndListen(
StreamListenSocket::Delegate* delegate) const {
return UnixDomainSocket::CreateAndListenWithAbstractNamespace(
path_, delegate, auth_callback_);
path_, fallback_path_, delegate, auth_callback_);
}
#endif
......
......@@ -45,9 +45,11 @@ class NET_EXPORT UnixDomainSocket : public StreamListenSocket {
#if defined(SOCKET_ABSTRACT_NAMESPACE_SUPPORTED)
// Same as above except that the created socket uses the abstract namespace
// which is a Linux-only feature.
// which is a Linux-only feature. If |fallback_path| is not empty,
// make the second attempt with the provided fallback name.
static scoped_refptr<UnixDomainSocket> CreateAndListenWithAbstractNamespace(
const std::string& path,
const std::string& fallback_path,
StreamListenSocket::Delegate* del,
const AuthCallback& auth_callback);
#endif
......@@ -60,6 +62,7 @@ class NET_EXPORT UnixDomainSocket : public StreamListenSocket {
static UnixDomainSocket* CreateAndListenInternal(
const std::string& path,
const std::string& fallback_path,
StreamListenSocket::Delegate* del,
const AuthCallback& auth_callback,
bool use_abstract_namespace);
......@@ -103,6 +106,7 @@ class NET_EXPORT UnixDomainSocketWithAbstractNamespaceFactory
public:
UnixDomainSocketWithAbstractNamespaceFactory(
const std::string& path,
const std::string& fallback_path,
const UnixDomainSocket::AuthCallback& auth_callback);
virtual ~UnixDomainSocketWithAbstractNamespaceFactory();
......@@ -111,6 +115,8 @@ class NET_EXPORT UnixDomainSocketWithAbstractNamespaceFactory
StreamListenSocket::Delegate* delegate) const OVERRIDE;
private:
std::string fallback_path_;
DISALLOW_COPY_AND_ASSIGN(UnixDomainSocketWithAbstractNamespaceFactory);
};
#endif
......
......@@ -39,6 +39,7 @@ namespace net {
namespace {
const char kSocketFilename[] = "unix_domain_socket_for_testing";
const char kFallbackSocketName[] = "unix_domain_socket_for_testing_2";
const char kInvalidSocketPath[] = "/invalid/path";
const char kMsg[] = "hello";
......@@ -51,10 +52,14 @@ enum EventType {
EVENT_READ,
};
string MakeSocketPath() {
string MakeSocketPath(const string& socket_file_name) {
base::FilePath temp_dir;
file_util::GetTempDir(&temp_dir);
return temp_dir.Append(kSocketFilename).value();
return temp_dir.Append(socket_file_name).value();
}
string MakeSocketPath() {
return MakeSocketPath(kSocketFilename);
}
class EventManager : public base::RefCounted<EventManager> {
......@@ -254,8 +259,28 @@ TEST_F(UnixDomainSocketTestWithInvalidPath, CreateAndListenWithInvalidPath) {
TEST_F(UnixDomainSocketTestWithInvalidPath,
CreateAndListenWithAbstractNamespace) {
socket_ = UnixDomainSocket::CreateAndListenWithAbstractNamespace(
file_path_.value(), socket_delegate_.get(), MakeAuthCallback());
file_path_.value(), "", socket_delegate_.get(), MakeAuthCallback());
EXPECT_FALSE(socket_.get() == NULL);
}
TEST_F(UnixDomainSocketTest, TestFallbackName) {
scoped_refptr<UnixDomainSocket> existing_socket =
UnixDomainSocket::CreateAndListenWithAbstractNamespace(
file_path_.value(), "", socket_delegate_.get(), MakeAuthCallback());
EXPECT_FALSE(existing_socket.get() == NULL);
// First, try to bind socket with the same name with no fallback name.
socket_ =
UnixDomainSocket::CreateAndListenWithAbstractNamespace(
file_path_.value(), "", socket_delegate_.get(), MakeAuthCallback());
EXPECT_TRUE(socket_.get() == NULL);
// Now with a fallback name.
socket_ = UnixDomainSocket::CreateAndListenWithAbstractNamespace(
file_path_.value(),
MakeSocketPath(kFallbackSocketName),
socket_delegate_.get(),
MakeAuthCallback());
EXPECT_FALSE(socket_.get() == NULL);
existing_socket = NULL;
}
#endif
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment