| Index: build/android/pylib/forwarder.py
|
| diff --git a/build/android/pylib/forwarder.py b/build/android/pylib/forwarder.py
|
| index f5cde9e29da230201fa3c4ec48408c8319f5cb3c..965823ee4dace1d0e3a33e64ecb95220771e9d24 100644
|
| --- a/build/android/pylib/forwarder.py
|
| +++ b/build/android/pylib/forwarder.py
|
| @@ -6,6 +6,7 @@ import logging
|
| import os
|
| import re
|
| import sys
|
| +import threading
|
| import time
|
|
|
| import android_commands
|
| @@ -21,7 +22,7 @@ def _MakeBinaryPath(build_type, binary_name):
|
|
|
|
|
| class Forwarder(object):
|
| - """Class to manage port forwards from the device to the host."""
|
| + """Thread-safe class to manage port forwards from the device to the host."""
|
|
|
| # Unix Abstract socket path:
|
| _DEVICE_ADB_CONTROL_PORT = 'chrome_device_forwarder'
|
| @@ -45,7 +46,9 @@ class Forwarder(object):
|
| assert build_type in ('Release', 'Debug')
|
| self._adb = adb
|
| self._host_to_device_port_map = dict()
|
| - self._device_process = None
|
| + self._device_initialized = False
|
| + self._host_adb_control_port = 0
|
| + self._lock = threading.Lock()
|
| self._host_forwarder_path = _MakeBinaryPath(build_type, 'host_forwarder')
|
| self._device_forwarder_path_on_host = os.path.join(
|
| cmd_helper.OutDirectory.get(), build_type, 'forwarder_dist')
|
| @@ -67,23 +70,58 @@ class Forwarder(object):
|
| Raises:
|
| Exception on failure to forward the port.
|
| """
|
| + with self._lock:
|
| + self._InitDeviceLocked(tool)
|
| + self._InitHostLocked()
|
| + redirection_commands = [
|
| + '%d:%d:%d:%s' % (self._host_adb_control_port, device, host,
|
| + host_name) for device, host in port_pairs]
|
| + logging.info('Command format: <ADB port>:<Device port>' +
|
| + '[:<Forward to port>:<Forward to address>]')
|
| + logging.info('Forwarding using commands: %s', redirection_commands)
|
| +
|
| + for redirection_command in redirection_commands:
|
| + try:
|
| + (exit_code, output) = cmd_helper.GetCmdStatusAndOutput(
|
| + [self._host_forwarder_path, redirection_command])
|
| + except OSError as e:
|
| + if e.errno == 2:
|
| + raise Exception('Unable to start host forwarder. Make sure you have'
|
| + ' built host_forwarder.')
|
| + else: raise
|
| + if exit_code != 0:
|
| + raise Exception('%s exited with %d:\n%s' % (
|
| + self._host_forwarder_path, exit_code, '\n'.join(output)))
|
| + tokens = output.split(':')
|
| + if len(tokens) != 2:
|
| + raise Exception('Unexpected host forwarder output "%s", ' +
|
| + 'expected "device_port:host_port"' % output)
|
| + device_port = int(tokens[0])
|
| + host_port = int(tokens[1])
|
| + self._host_to_device_port_map[host_port] = device_port
|
| + logging.info('Forwarding device port: %d to host port: %d.',
|
| + device_port, host_port)
|
| +
|
| + def _InitHostLocked(self):
|
| + """Initializes the host forwarder process (only once)."""
|
| + if self._host_adb_control_port:
|
| + return
|
| self._host_adb_control_port = ports.AllocateTestServerPort()
|
| if not self._host_adb_control_port:
|
| raise Exception('Failed to allocate a TCP port in the host machine.')
|
| - self._adb.PushIfNeeded(
|
| - self._device_forwarder_path_on_host, Forwarder._DEVICE_FORWARDER_FOLDER)
|
| - redirection_commands = [
|
| - '%d:%d:%d:%s' % (self._host_adb_control_port, device, host,
|
| - host_name) for device, host in port_pairs]
|
| - logging.info('Command format: <ADB port>:<Device port>' +
|
| - '[:<Forward to port>:<Forward to address>]')
|
| - logging.info('Forwarding using commands: %s', redirection_commands)
|
| if cmd_helper.RunCmd(
|
| ['adb', '-s', self._adb._adb.GetSerialNumber(), 'forward',
|
| 'tcp:%s' % self._host_adb_control_port,
|
| 'localabstract:%s' % Forwarder._DEVICE_ADB_CONTROL_PORT]) != 0:
|
| raise Exception('Error while running adb forward.')
|
|
|
| + def _InitDeviceLocked(self, tool):
|
| + """Initializes the device forwarder process (only once)."""
|
| + if self._device_initialized:
|
| + return
|
| + self._adb.PushIfNeeded(
|
| + self._device_forwarder_path_on_host,
|
| + Forwarder._DEVICE_FORWARDER_FOLDER)
|
| (exit_code, output) = self._adb.GetShellCommandStatusAndOutput(
|
| '%s %s %s %s' % (Forwarder._LD_LIBRARY_PATH, tool.GetUtilWrapper(),
|
| Forwarder._DEVICE_FORWARDER_PATH,
|
| @@ -91,40 +129,31 @@ class Forwarder(object):
|
| if exit_code != 0:
|
| raise Exception(
|
| 'Failed to start device forwarder:\n%s' % '\n'.join(output))
|
| + self._device_initialized = True
|
| +
|
| + def UnmapDevicePort(self, device_port):
|
| + """Unmaps a previously forwarded device port.
|
|
|
| - for redirection_command in redirection_commands:
|
| - try:
|
| - (exit_code, output) = cmd_helper.GetCmdStatusAndOutput(
|
| - [self._host_forwarder_path, redirection_command])
|
| - except OSError as e:
|
| - if e.errno == 2:
|
| - raise Exception('Unable to start host forwarder. Make sure you have '
|
| - 'built host_forwarder.')
|
| - else: raise
|
| + Args:
|
| + device_port: A previously forwarded port (through Run()).
|
| + """
|
| + with self._lock:
|
| + # Please note the minus sign below.
|
| + redirection_command = '%d:-%d' % (
|
| + self._host_adb_control_port, device_port)
|
| + (exit_code, output) = cmd_helper.GetCmdStatusAndOutput(
|
| + [self._host_forwarder_path, redirection_command])
|
| if exit_code != 0:
|
| raise Exception('%s exited with %d:\n%s' % (
|
| self._host_forwarder_path, exit_code, '\n'.join(output)))
|
| - tokens = output.split(':')
|
| - if len(tokens) != 2:
|
| - raise Exception('Unexpected host forwarder output "%s", ' +
|
| - 'expected "device_port:host_port"' % output)
|
| - device_port = int(tokens[0])
|
| - host_port = int(tokens[1])
|
| - self._host_to_device_port_map[host_port] = device_port
|
| - logging.info('Forwarding device port: %d to host port: %d.', device_port,
|
| - host_port)
|
| -
|
| - def UnmapDevicePort(self, device_port):
|
| - # Please note the minus sign below.
|
| - redirection_command = '%d:-%d' % (self._host_adb_control_port, device_port)
|
| - (exit_code, output) = cmd_helper.GetCmdStatusAndOutput(
|
| - [self._host_forwarder_path, redirection_command])
|
| - if exit_code != 0:
|
| - raise Exception('%s exited with %d:\n%s' % (
|
| - self._host_forwarder_path, exit_code, '\n'.join(output)))
|
|
|
| @staticmethod
|
| def KillHost(build_type):
|
| + """Kills the forwarder process running on the host.
|
| +
|
| + Args:
|
| + build_type: 'Release' or 'Debug'
|
| + """
|
| logging.info('Killing host_forwarder.')
|
| host_forwarder_path = _MakeBinaryPath(build_type, 'host_forwarder')
|
| assert os.path.exists(host_forwarder_path), 'Please build forwarder2'
|
| @@ -139,6 +168,13 @@ class Forwarder(object):
|
|
|
| @staticmethod
|
| def KillDevice(adb, tool):
|
| + """Kills the forwarder process running on the device.
|
| +
|
| + Args:
|
| + adb: Instance of AndroidCommands for talking to the device.
|
| + tool: Wrapper tool (e.g. valgrind) that can be used to execute the device
|
| + forwarder (see valgrind_tools.py).
|
| + """
|
| logging.info('Killing device_forwarder.')
|
| if not adb.FileExistsOnDevice(Forwarder._DEVICE_FORWARDER_PATH):
|
| return
|
| @@ -156,11 +192,12 @@ class Forwarder(object):
|
| raise Exception('Timed out while killing device_forwarder')
|
|
|
| def DevicePortForHostPort(self, host_port):
|
| - """Get the device port that corresponds to a given host port."""
|
| - return self._host_to_device_port_map.get(host_port)
|
| + """Returns the device port that corresponds to a given host port."""
|
| + with self._lock:
|
| + return self._host_to_device_port_map.get(host_port)
|
|
|
| + # Deprecated.
|
| def Close(self):
|
| - """Terminate the forwarder process."""
|
| - if self._device_process:
|
| - self._device_process.close()
|
| - self._device_process = None
|
| + """Terminates the forwarder process."""
|
| + # TODO(pliard): Remove references in client code.
|
| + pass
|
|
|