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