| OLD | NEW |
| 1 # Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 # Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| 2 # Use of this source code is governed by a BSD-style license that can be | 2 # Use of this source code is governed by a BSD-style license that can be |
| 3 # found in the LICENSE file. | 3 # found in the LICENSE file. |
| 4 | 4 |
| 5 import logging | 5 import logging |
| 6 import os | 6 import os |
| 7 import re | 7 import re |
| 8 import sys | 8 import sys |
| 9 import threading | 9 import threading |
| 10 import time | 10 import time |
| 11 | 11 |
| 12 import android_commands | 12 import android_commands |
| 13 import cmd_helper | 13 import cmd_helper |
| 14 import constants | 14 import constants |
| 15 import ports |
| 15 | 16 |
| 16 from pylib import pexpect | 17 from pylib import pexpect |
| 17 | 18 |
| 18 | 19 |
| 19 def _MakeBinaryPath(build_type, binary_name): | 20 def _MakeBinaryPath(build_type, binary_name): |
| 20 return os.path.join(cmd_helper.OutDirectory.get(), build_type, binary_name) | 21 return os.path.join(cmd_helper.OutDirectory.get(), build_type, binary_name) |
| 21 | 22 |
| 22 | 23 |
| 23 class Forwarder(object): | 24 class Forwarder(object): |
| 24 """Thread-safe class to manage port forwards from the device to the host.""" | 25 """Thread-safe class to manage port forwards from the device to the host.""" |
| 25 | 26 |
| 27 # Unix Abstract socket path: |
| 28 _DEVICE_ADB_CONTROL_PORT = 'chrome_device_forwarder' |
| 29 _TIMEOUT_SECS = 30 |
| 30 |
| 26 _DEVICE_FORWARDER_FOLDER = (constants.TEST_EXECUTABLE_DIR + | 31 _DEVICE_FORWARDER_FOLDER = (constants.TEST_EXECUTABLE_DIR + |
| 27 '/forwarder/') | 32 '/forwarder/') |
| 28 _DEVICE_FORWARDER_PATH = (constants.TEST_EXECUTABLE_DIR + | 33 _DEVICE_FORWARDER_PATH = (constants.TEST_EXECUTABLE_DIR + |
| 29 '/forwarder/device_forwarder') | 34 '/forwarder/device_forwarder') |
| 30 _LD_LIBRARY_PATH = 'LD_LIBRARY_PATH=%s' % _DEVICE_FORWARDER_FOLDER | 35 _LD_LIBRARY_PATH = 'LD_LIBRARY_PATH=%s' % _DEVICE_FORWARDER_FOLDER |
| 31 | 36 |
| 32 def __init__(self, adb, build_type): | 37 def __init__(self, adb, build_type): |
| 33 """Forwards TCP ports on the device back to the host. | 38 """Forwards TCP ports on the device back to the host. |
| 34 | 39 |
| 35 Works like adb forward, but in reverse. | 40 Works like adb forward, but in reverse. |
| (...skipping 22 matching lines...) Expand all Loading... |
| 58 get the number of the assigned port using the | 63 get the number of the assigned port using the |
| 59 DevicePortForHostPort method. | 64 DevicePortForHostPort method. |
| 60 tool: Tool class to use to get wrapper, if necessary, for executing the | 65 tool: Tool class to use to get wrapper, if necessary, for executing the |
| 61 forwarder (see valgrind_tools.py). | 66 forwarder (see valgrind_tools.py). |
| 62 | 67 |
| 63 Raises: | 68 Raises: |
| 64 Exception on failure to forward the port. | 69 Exception on failure to forward the port. |
| 65 """ | 70 """ |
| 66 with self._lock: | 71 with self._lock: |
| 67 self._InitDeviceLocked(tool) | 72 self._InitDeviceLocked(tool) |
| 73 self._InitHostLocked() |
| 68 host_name = '127.0.0.1' | 74 host_name = '127.0.0.1' |
| 69 redirection_commands = [ | 75 redirection_commands = [ |
| 70 ['--serial-id=' + self._adb.Adb().GetSerialNumber(), '--map', | 76 '%d:%d:%d:%s' % (self._host_adb_control_port, device, host, |
| 71 str(device), str(host)] for device, host in port_pairs] | 77 host_name) for device, host in port_pairs] |
| 78 logging.info('Command format: <ADB port>:<Device port>' + |
| 79 '[:<Forward to port>:<Forward to address>]') |
| 72 logging.info('Forwarding using commands: %s', redirection_commands) | 80 logging.info('Forwarding using commands: %s', redirection_commands) |
| 73 | 81 |
| 74 for redirection_command in redirection_commands: | 82 for redirection_command in redirection_commands: |
| 75 try: | 83 try: |
| 76 (exit_code, output) = cmd_helper.GetCmdStatusAndOutput( | 84 (exit_code, output) = cmd_helper.GetCmdStatusAndOutput( |
| 77 [self._host_forwarder_path] + redirection_command) | 85 [self._host_forwarder_path, redirection_command]) |
| 78 except OSError as e: | 86 except OSError as e: |
| 79 if e.errno == 2: | 87 if e.errno == 2: |
| 80 raise Exception('Unable to start host forwarder. Make sure you have' | 88 raise Exception('Unable to start host forwarder. Make sure you have' |
| 81 ' built host_forwarder.') | 89 ' built host_forwarder.') |
| 82 else: raise | 90 else: raise |
| 83 if exit_code != 0: | 91 if exit_code != 0: |
| 84 raise Exception('%s exited with %d:\n%s' % ( | 92 raise Exception('%s exited with %d:\n%s' % ( |
| 85 self._host_forwarder_path, exit_code, '\n'.join(output))) | 93 self._host_forwarder_path, exit_code, '\n'.join(output))) |
| 86 tokens = output.split(':') | 94 tokens = output.split(':') |
| 87 if len(tokens) != 2: | 95 if len(tokens) != 2: |
| 88 raise Exception('Unexpected host forwarder output "%s", ' + | 96 raise Exception('Unexpected host forwarder output "%s", ' + |
| 89 'expected "device_port:host_port"' % output) | 97 'expected "device_port:host_port"' % output) |
| 90 device_port = int(tokens[0]) | 98 device_port = int(tokens[0]) |
| 91 host_port = int(tokens[1]) | 99 host_port = int(tokens[1]) |
| 92 self._host_to_device_port_map[host_port] = device_port | 100 self._host_to_device_port_map[host_port] = device_port |
| 93 logging.info('Forwarding device port: %d to host port: %d.', | 101 logging.info('Forwarding device port: %d to host port: %d.', |
| 94 device_port, host_port) | 102 device_port, host_port) |
| 95 | 103 |
| 104 def _InitHostLocked(self): |
| 105 """Initializes the host forwarder process (only once).""" |
| 106 if self._host_adb_control_port: |
| 107 return |
| 108 self._host_adb_control_port = ports.AllocateTestServerPort() |
| 109 if not self._host_adb_control_port: |
| 110 raise Exception('Failed to allocate a TCP port in the host machine.') |
| 111 if cmd_helper.RunCmd( |
| 112 ['adb', '-s', self._adb._adb.GetSerialNumber(), 'forward', |
| 113 'tcp:%s' % self._host_adb_control_port, |
| 114 'localabstract:%s' % Forwarder._DEVICE_ADB_CONTROL_PORT]) != 0: |
| 115 raise Exception('Error while running adb forward.') |
| 116 |
| 96 def _InitDeviceLocked(self, tool): | 117 def _InitDeviceLocked(self, tool): |
| 97 """Initializes the device forwarder process (only once).""" | 118 """Initializes the device forwarder process (only once).""" |
| 98 if self._device_initialized: | 119 if self._device_initialized: |
| 99 return | 120 return |
| 100 self._adb.PushIfNeeded( | 121 self._adb.PushIfNeeded( |
| 101 self._device_forwarder_path_on_host, | 122 self._device_forwarder_path_on_host, |
| 102 Forwarder._DEVICE_FORWARDER_FOLDER) | 123 Forwarder._DEVICE_FORWARDER_FOLDER) |
| 103 (exit_code, output) = self._adb.GetShellCommandStatusAndOutput( | 124 (exit_code, output) = self._adb.GetShellCommandStatusAndOutput( |
| 104 '%s %s %s' % (Forwarder._LD_LIBRARY_PATH, tool.GetUtilWrapper(), | 125 '%s %s %s %s' % (Forwarder._LD_LIBRARY_PATH, tool.GetUtilWrapper(), |
| 105 Forwarder._DEVICE_FORWARDER_PATH)) | 126 Forwarder._DEVICE_FORWARDER_PATH, |
| 127 Forwarder._DEVICE_ADB_CONTROL_PORT)) |
| 106 if exit_code != 0: | 128 if exit_code != 0: |
| 107 raise Exception( | 129 raise Exception( |
| 108 'Failed to start device forwarder:\n%s' % '\n'.join(output)) | 130 'Failed to start device forwarder:\n%s' % '\n'.join(output)) |
| 109 self._device_initialized = True | 131 self._device_initialized = True |
| 110 | 132 |
| 111 def UnmapDevicePort(self, device_port): | 133 def UnmapDevicePort(self, device_port): |
| 112 """Unmaps a previously forwarded device port. | 134 """Unmaps a previously forwarded device port. |
| 113 | 135 |
| 114 Args: | 136 Args: |
| 115 device_port: A previously forwarded port (through Run()). | 137 device_port: A previously forwarded port (through Run()). |
| 116 """ | 138 """ |
| 117 with self._lock: | 139 with self._lock: |
| 118 redirection_command = [ | 140 # Please note the minus sign below. |
| 119 '--serial-id=' + self._adb.Adb().GetSerialNumber(), '--unmap', | 141 redirection_command = '%d:-%d' % ( |
| 120 str(device_port)] | 142 self._host_adb_control_port, device_port) |
| 121 (exit_code, output) = cmd_helper.GetCmdStatusAndOutput( | 143 (exit_code, output) = cmd_helper.GetCmdStatusAndOutput( |
| 122 [self._host_forwarder_path] + redirection_command) | 144 [self._host_forwarder_path, redirection_command]) |
| 123 if exit_code != 0: | 145 if exit_code != 0: |
| 124 raise Exception('%s exited with %d:\n%s' % ( | 146 raise Exception('%s exited with %d:\n%s' % ( |
| 125 self._host_forwarder_path, exit_code, '\n'.join(output))) | 147 self._host_forwarder_path, exit_code, '\n'.join(output))) |
| 126 | 148 |
| 127 @staticmethod | 149 @staticmethod |
| 128 def KillHost(build_type): | 150 def KillHost(build_type): |
| 129 """Kills the forwarder process running on the host. | 151 """Kills the forwarder process running on the host. |
| 130 | 152 |
| 131 Args: | 153 Args: |
| 132 build_type: 'Release' or 'Debug' | 154 build_type: 'Release' or 'Debug' |
| 133 """ | 155 """ |
| 134 logging.info('Killing host_forwarder.') | 156 logging.info('Killing host_forwarder.') |
| 135 host_forwarder_path = _MakeBinaryPath(build_type, 'host_forwarder') | 157 host_forwarder_path = _MakeBinaryPath(build_type, 'host_forwarder') |
| 136 assert os.path.exists(host_forwarder_path), 'Please build forwarder2' | 158 assert os.path.exists(host_forwarder_path), 'Please build forwarder2' |
| 137 (exit_code, output) = cmd_helper.GetCmdStatusAndOutput( | 159 (exit_code, output) = cmd_helper.GetCmdStatusAndOutput( |
| 138 [host_forwarder_path, '--kill-server']) | 160 [host_forwarder_path, 'kill-server']) |
| 139 if exit_code != 0: | 161 if exit_code != 0: |
| 140 (exit_code, output) = cmd_helper.GetCmdStatusAndOutput( | 162 (exit_code, output) = cmd_helper.GetCmdStatusAndOutput( |
| 141 ['pkill', 'host_forwarder']) | 163 ['pkill', 'host_forwarder']) |
| 142 if exit_code != 0: | 164 if exit_code != 0: |
| 143 raise Exception('%s exited with %d:\n%s' % ( | 165 raise Exception('%s exited with %d:\n%s' % ( |
| 144 host_forwarder_path, exit_code, '\n'.join(output))) | 166 host_forwarder_path, exit_code, '\n'.join(output))) |
| 145 | 167 |
| 146 @staticmethod | 168 @staticmethod |
| 147 def KillDevice(adb, tool): | 169 def KillDevice(adb, tool): |
| 148 """Kills the forwarder process running on the device. | 170 """Kills the forwarder process running on the device. |
| 149 | 171 |
| 150 Args: | 172 Args: |
| 151 adb: Instance of AndroidCommands for talking to the device. | 173 adb: Instance of AndroidCommands for talking to the device. |
| 152 tool: Wrapper tool (e.g. valgrind) that can be used to execute the device | 174 tool: Wrapper tool (e.g. valgrind) that can be used to execute the device |
| 153 forwarder (see valgrind_tools.py). | 175 forwarder (see valgrind_tools.py). |
| 154 """ | 176 """ |
| 155 logging.info('Killing device_forwarder.') | 177 logging.info('Killing device_forwarder.') |
| 156 if not adb.FileExistsOnDevice(Forwarder._DEVICE_FORWARDER_PATH): | 178 if not adb.FileExistsOnDevice(Forwarder._DEVICE_FORWARDER_PATH): |
| 157 return | 179 return |
| 158 (exit_code, output) = adb.GetShellCommandStatusAndOutput( | 180 (exit_code, output) = adb.GetShellCommandStatusAndOutput( |
| 159 '%s %s --kill-server' % (tool.GetUtilWrapper(), | 181 '%s %s kill-server' % (tool.GetUtilWrapper(), |
| 160 Forwarder._DEVICE_FORWARDER_PATH)) | 182 Forwarder._DEVICE_FORWARDER_PATH)) |
| 161 # TODO(pliard): Remove the following call to KillAllBlocking() when we are | 183 # TODO(pliard): Remove the following call to KillAllBlocking() when we are |
| 162 # sure that the old version of device_forwarder (not supporting | 184 # sure that the old version of device_forwarder (not supporting |
| 163 # 'kill-server') is not running on the bots anymore. | 185 # 'kill-server') is not running on the bots anymore. |
| 164 timeout_sec = 5 | 186 timeout_sec = 5 |
| 165 processes_killed = adb.KillAllBlocking('device_forwarder', timeout_sec) | 187 processes_killed = adb.KillAllBlocking('device_forwarder', timeout_sec) |
| 166 if not processes_killed: | 188 if not processes_killed: |
| 167 pids = adb.ExtractPid('device_forwarder') | 189 pids = adb.ExtractPid('device_forwarder') |
| 168 if pids: | 190 if pids: |
| 169 raise Exception('Timed out while killing device_forwarder') | 191 raise Exception('Timed out while killing device_forwarder') |
| 170 | 192 |
| 171 def DevicePortForHostPort(self, host_port): | 193 def DevicePortForHostPort(self, host_port): |
| 172 """Returns the device port that corresponds to a given host port.""" | 194 """Returns the device port that corresponds to a given host port.""" |
| 173 with self._lock: | 195 with self._lock: |
| 174 return self._host_to_device_port_map.get(host_port) | 196 return self._host_to_device_port_map.get(host_port) |
| 175 | 197 |
| 176 # Deprecated. | 198 # Deprecated. |
| 177 def Close(self): | 199 def Close(self): |
| 178 """Terminates the forwarder process.""" | 200 """Terminates the forwarder process.""" |
| 179 # TODO(pliard): Remove references in client code. | 201 # TODO(pliard): Remove references in client code. |
| 180 pass | 202 pass |
| OLD | NEW |