summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--build/android/pylib/base_test_runner.py4
-rw-r--r--build/android/pylib/forwarder.py127
-rw-r--r--build/android/pylib/run_java_tests.py15
-rw-r--r--tools/android/forwarder2/host_controller.cc4
-rw-r--r--tools/android/forwarder2/socket.cc24
5 files changed, 120 insertions, 54 deletions
diff --git a/build/android/pylib/base_test_runner.py b/build/android/pylib/base_test_runner.py
index a69d024..26ddc17 100644
--- a/build/android/pylib/base_test_runner.py
+++ b/build/android/pylib/base_test_runner.py
@@ -137,7 +137,7 @@ class BaseTestRunner(object):
# Sometimes the forwarder device port may be already used. We have to kill
# all forwarder processes to ensure that the forwarder can be started since
# currently we can not associate the specified port to related pid.
- self.adb.KillAll('forwarder')
+ self.adb.KillAll('device_forwarder')
if self._forwarder:
self._forwarder.Close()
self._forwarder = Forwarder(
@@ -168,7 +168,7 @@ class BaseTestRunner(object):
if self._forwarder or self._spawner_forwarder:
# Kill all forwarders on the device and then kill the process on the host
# (if it exists)
- self.adb.KillAll('forwarder')
+ self.adb.KillAll('device_forwarder')
if self._forwarder:
self._forwarder.Close()
if self._spawner_forwarder:
diff --git a/build/android/pylib/forwarder.py b/build/android/pylib/forwarder.py
index 03b16f1..925b0c9 100644
--- a/build/android/pylib/forwarder.py
+++ b/build/android/pylib/forwarder.py
@@ -9,12 +9,17 @@ import re
import sys
import android_commands
+import cmd_helper
import constants
+import ports
class Forwarder(object):
"""Class to manage port forwards from the device to the host."""
- _FORWARDER_PATH = constants.TEST_EXECUTABLE_DIR + '/forwarder'
+ _DEVICE_FORWARDER_PATH = constants.TEST_EXECUTABLE_DIR + '/device_forwarder'
+
+ # Unix Abstract socket path:
+ _DEVICE_ADB_CONTROL_PORT = 'chrome_device_forwarder'
_TIMEOUT_SECS = 30
def __init__(self, adb, port_pairs, tool, host_name, build_type):
@@ -40,67 +45,125 @@ class Forwarder(object):
"""
self._adb = adb
self._host_to_device_port_map = dict()
- self._process = None
+ self._host_process = None
+ self._device_process = None
+ self._adb_forward_process = None
+
+ self._host_adb_control_port = ports.AllocateTestServerPort()
adb.PushIfNeeded(
- os.path.join(constants.CHROME_DIR, 'out', build_type, 'forwarder'),
- Forwarder._FORWARDER_PATH)
+ os.path.join(constants.CHROME_DIR, 'out', build_type,
+ 'device_forwarder'),
+ Forwarder._DEVICE_FORWARDER_PATH)
+ self._host_forwarder_path = os.path.join(constants.CHROME_DIR,
+ 'out',
+ build_type,
+ 'host_forwarder')
forward_string = ['%d:%d:%s' %
(device, host, host_name) for device, host in port_pairs]
-
- # Kill off any existing forwarders on conflicting non-dynamically allocated
- # ports.
+ logging.info('Forwarding ports: %s', forward_string)
+ # Kill off any existing device forwarders on conflicting non-dynamically
+ # allocated ports.
for device_port, _ in port_pairs:
if device_port != 0:
self._KillForwardersUsingDevicePort(device_port)
- logging.info('Forwarding ports: %s' % (forward_string))
- process = pexpect.spawn(
- 'adb', ['-s', adb._adb.GetSerialNumber(),
- 'shell', '%s %s -D %s' % (
- tool.GetUtilWrapper(), Forwarder._FORWARDER_PATH,
- ' '.join(forward_string))])
+ # Kill any existing host forwarders.
+ cmd_helper.RunCmd(['killall', 'host_forwarder'])
+ self._adb_forward_process = pexpect.spawn(
+ 'adb', ['-s',
+ adb._adb.GetSerialNumber(),
+ 'forward',
+ 'tcp:%s' % self._host_adb_control_port,
+ 'localabstract:%s' % Forwarder._DEVICE_ADB_CONTROL_PORT])
+ self._device_process = pexpect.spawn(
+ 'adb', ['-s',
+ adb._adb.GetSerialNumber(),
+ 'shell',
+ '%s %s -D --adb_sock=%s' % (
+ tool.GetUtilWrapper(),
+ Forwarder._DEVICE_FORWARDER_PATH,
+ Forwarder._DEVICE_ADB_CONTROL_PORT)])
+
+ device_success_re = re.compile('Starting Device Forwarder.')
+ device_failure_re = re.compile('.*:ERROR:(.*)')
+ index = self._device_process.expect([device_success_re,
+ device_failure_re,
+ pexpect.EOF,
+ pexpect.TIMEOUT],
+ Forwarder._TIMEOUT_SECS)
+ if index == 1:
+ # Failure
+ error_msg = str(self._device_process.match.group(1))
+ logging.error(self._device_process.before)
+ self._CloseProcess()
+ raise Exception('Failed to start Device Forwarder with Error: %s' %
+ error_msg)
+ elif index == 2:
+ logging.error(self._device_process.before)
+ self._CloseProcess()
+ raise Exception('Unexpected EOF while trying to start Device Forwarder.')
+ elif index == 3:
+ logging.error(self._device_process.before)
+ self._CloseProcess()
+ raise Exception('Timeout while trying start Device Forwarder')
+
+ self._host_process = pexpect.spawn(self._host_forwarder_path,
+ ['--adb_port=%s' % (
+ self._host_adb_control_port),
+ ' '.join(forward_string)])
# Read the output of the command to determine which device ports where
# forwarded to which host ports (necessary if
- success_re = re.compile('Forwarding device port (\d+) to host (\d+):')
- failure_re = re.compile('Couldn\'t start forwarder server for port spec: '
- '(\d+):(\d+)')
+ host_success_re = re.compile('Forwarding device port (\d+) to host (\d+):')
+ host_failure_re = re.compile('Couldn\'t start forwarder server for port '
+ 'spec: (\d+):(\d+)')
for pair in port_pairs:
- index = process.expect([success_re, failure_re, pexpect.EOF,
- pexpect.TIMEOUT],
- Forwarder._TIMEOUT_SECS)
+ index = self._host_process.expect([host_success_re,
+ host_failure_re,
+ pexpect.EOF,
+ pexpect.TIMEOUT],
+ Forwarder._TIMEOUT_SECS)
if index == 0:
# Success
- device_port = int(process.match.group(1))
- host_port = int(process.match.group(2))
+ device_port = int(self._host_process.match.group(1))
+ host_port = int(self._host_process.match.group(2))
self._host_to_device_port_map[host_port] = device_port
logging.info("Forwarding device port: %d to host port: %d." %
(device_port, host_port))
elif index == 1:
# Failure
- device_port = int(process.match.group(1))
- host_port = int(process.match.group(2))
- process.close()
+ device_port = int(self._host_process.match.group(1))
+ host_port = int(self._host_process.match.group(2))
+ self._CloseProcess()
raise Exception('Failed to forward port %d to %d' % (device_port,
host_port))
elif index == 2:
- logging.error(process.before)
- process.close()
+ logging.error(self._host_process.before)
+ self._CloseProcess()
raise Exception('Unexpected EOF while trying to forward ports %s' %
port_pairs)
elif index == 3:
- logging.error(process.before)
- process.close()
+ logging.error(self._host_process.before)
+ self._CloseProcess()
raise Exception('Timeout while trying to forward ports %s' % port_pairs)
- self._process = process
+ def _CloseProcess(self):
+ if self._host_process:
+ self._host_process.close()
+ if self._device_process:
+ self._device_process.close()
+ if self._adb_forward_process:
+ self._adb_forward_process.close()
+ self._host_process = None
+ self._device_process = None
+ self._adb_forward_process = None
def _KillForwardersUsingDevicePort(self, device_port):
"""Check if the device port is in use and if it is try to terminate the
forwarder process (if any) that may already be forwarding it"""
processes = self._adb.ProcessesUsingDevicePort(device_port)
for pid, name in processes:
- if name == 'forwarder':
+ if name == 'device_forwarder':
logging.warning(
'Killing forwarder process with pid %d using device_port %d' % (
pid, device_port))
@@ -116,6 +179,4 @@ class Forwarder(object):
def Close(self):
"""Terminate the forwarder process."""
- if self._process:
- self._process.close()
- self._process = None
+ self._CloseProcess()
diff --git a/build/android/pylib/run_java_tests.py b/build/android/pylib/run_java_tests.py
index bf51bad..825a92c 100644
--- a/build/android/pylib/run_java_tests.py
+++ b/build/android/pylib/run_java_tests.py
@@ -130,8 +130,7 @@ class TestRunner(BaseTestRunner):
self.ports_to_forward = ports_to_forward
self.test_results = TestResults()
- # List of forwarders created by this instance of TestRunner.
- self.forwarders = []
+ self.forwarder = None
if self.coverage:
if os.path.exists(TestRunner._COVERAGE_MERGED_FILENAME):
@@ -277,19 +276,17 @@ class TestRunner(BaseTestRunner):
self.LaunchTestHttpServer(os.path.join(constants.CHROME_DIR),
(constants.LIGHTTPD_RANDOM_PORT_FIRST +
self.shard_index))
-
if self.ports_to_forward:
- for port in self.ports_to_forward:
- self.forwarders.append(Forwarder(
- self.adb, [(port, port)], self.tool, '127.0.0.1', self.build_type))
+ port_pairs = [(port, port) for port in self.ports_to_forward]
+ self.forwarder = Forwarder(
+ self.adb, port_pairs, self.tool, '127.0.0.1', self.build_type)
self.CopyTestFilesOnce()
self.flags.AddFlags(['--enable-test-intents'])
def TearDown(self):
"""Cleans up the test harness and saves outstanding data from test run."""
- if self.forwarders:
- for forwarder in self.forwarders:
- forwarder.Close()
+ if self.forwarder:
+ self.forwarder.Close()
self.GenerateCoverageReportIfNeeded()
super(TestRunner, self).TearDown()
diff --git a/tools/android/forwarder2/host_controller.cc b/tools/android/forwarder2/host_controller.cc
index 0507c11..98e487f 100644
--- a/tools/android/forwarder2/host_controller.cc
+++ b/tools/android/forwarder2/host_controller.cc
@@ -68,7 +68,9 @@ bool HostController::Connect() {
return false;
}
// Send the command to the device start listening to the "device_forward_port"
- SendCommand(command::LISTEN, device_port_, &adb_control_socket_);
+ bool send_command_success = SendCommand(
+ command::LISTEN, device_port_, &adb_control_socket_);
+ CHECK(send_command_success);
int device_port_allocated;
command::Type command;
if (!ReadCommand(&adb_control_socket_, &device_port_allocated, &command) ||
diff --git a/tools/android/forwarder2/socket.cc b/tools/android/forwarder2/socket.cc
index 898afc3d..5c26a44 100644
--- a/tools/android/forwarder2/socket.cc
+++ b/tools/android/forwarder2/socket.cc
@@ -36,6 +36,10 @@
namespace {
const int kNoTimeout = -1;
const int kConnectTimeOut = 10; // Seconds.
+
+bool FamilyIsTCP(int family) {
+ return family == AF_INET || family == AF_INET6;
+}
} // namespace
namespace forwarder2 {
@@ -129,7 +133,6 @@ bool Socket::InitUnixSocket(const std::string& path, bool abstract) {
abstract_ = abstract;
family_ = PF_UNIX;
addr_.addr_un.sun_family = family_;
-
if (abstract) {
// Copied from net/base/unix_domain_socket_posix.cc
// Convert the path given into abstract socket name. It must start with
@@ -143,14 +146,12 @@ bool Socket::InitUnixSocket(const std::string& path, bool abstract) {
memcpy(addr_.addr_un.sun_path, path.c_str(), path.size());
addr_len_ = sizeof(sockaddr_un);
}
-
addr_ptr_ = reinterpret_cast<sockaddr*>(&addr_.addr_un);
return InitSocketInternal();
}
bool Socket::InitTcpSocket(const std::string& host, int port) {
port_ = port;
-
if (host.empty()) {
// Use localhost: INADDR_LOOPBACK
family_ = AF_INET;
@@ -159,8 +160,7 @@ bool Socket::InitTcpSocket(const std::string& host, int port) {
} else if (!Resolve(host)) {
return false;
}
- CHECK(family_ == AF_INET || family_ == AF_INET6)
- << "Invalid socket family.";
+ CHECK(FamilyIsTCP(family_)) << "Invalid socket family.";
if (family_ == AF_INET) {
addr_.addr4.sin_port = htons(port_);
addr_ptr_ = reinterpret_cast<sockaddr*>(&addr_.addr4);
@@ -180,7 +180,7 @@ bool Socket::BindAndListen() {
SetSocketError();
return false;
}
- if (port_ == 0) {
+ if (port_ == 0 && FamilyIsTCP(family_)) {
SockAddr addr;
memset(&addr, 0, sizeof(addr));
socklen_t addrlen = 0;
@@ -225,19 +225,25 @@ bool Socket::Accept(Socket* new_socket) {
}
bool Socket::Connect() {
- // Set non-block because we use select.
- fcntl(socket_, F_SETFL, fcntl(socket_, F_GETFL) | O_NONBLOCK);
+ // Set non-block because we use select for connect.
+ const int flags = fcntl(socket_, F_GETFL);
+ DCHECK(!(flags & O_NONBLOCK));
+ fcntl(socket_, F_SETFL, flags | O_NONBLOCK);
errno = 0;
if (HANDLE_EINTR(connect(socket_, addr_ptr_, addr_len_)) < 0 &&
errno != EINPROGRESS) {
SetSocketError();
+ PRESERVE_ERRNO_HANDLE_EINTR(fcntl(socket_, F_SETFL, flags));
return false;
}
// Wait for connection to complete, or receive a notification.
if (!WaitForEvent(WRITE, kConnectTimeOut)) {
SetSocketError();
+ PRESERVE_ERRNO_HANDLE_EINTR(fcntl(socket_, F_SETFL, flags));
return false;
}
+ // Disable non-block since our code assumes blocking semantics.
+ fcntl(socket_, F_SETFL, flags);
return true;
}
@@ -271,7 +277,7 @@ bool Socket::Resolve(const std::string& host) {
}
int Socket::GetPort() {
- if (family_ != AF_INET && family_ != AF_INET6) {
+ if (!FamilyIsTCP(family_)) {
LOG(ERROR) << "Can't call GetPort() on an unix domain socket.";
return 0;
}