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 # pylint: disable=W0212 | 5 # pylint: disable=W0212 |
6 | 6 |
7 import fcntl | 7 import fcntl |
8 import logging | 8 import logging |
9 import os | 9 import os |
10 import psutil | 10 import psutil |
11 | 11 |
12 from pylib import cmd_helper | 12 from pylib import cmd_helper |
13 from pylib import constants | 13 from pylib import constants |
14 from pylib import valgrind_tools | 14 from pylib import valgrind_tools |
15 | 15 |
| 16 # TODO(jbudorick) Remove once telemetry gets switched over. |
| 17 import pylib.android_commands |
| 18 import pylib.device.device_utils |
| 19 |
16 | 20 |
17 def _GetProcessStartTime(pid): | 21 def _GetProcessStartTime(pid): |
18 return psutil.Process(pid).create_time | 22 return psutil.Process(pid).create_time |
19 | 23 |
20 | 24 |
21 class _FileLock(object): | 25 class _FileLock(object): |
22 """With statement-aware implementation of a file lock. | 26 """With statement-aware implementation of a file lock. |
23 | 27 |
24 File locks are needed for cross-process synchronization when the | 28 File locks are needed for cross-process synchronization when the |
25 multiprocessing Python module is used. | 29 multiprocessing Python module is used. |
(...skipping 27 matching lines...) Expand all Loading... |
53 _HOST_FORWARDER_LOG = '/tmp/host_forwarder_log' | 57 _HOST_FORWARDER_LOG = '/tmp/host_forwarder_log' |
54 | 58 |
55 _instance = None | 59 _instance = None |
56 | 60 |
57 @staticmethod | 61 @staticmethod |
58 def UseMultiprocessing(): | 62 def UseMultiprocessing(): |
59 """Tells the forwarder that multiprocessing is used.""" | 63 """Tells the forwarder that multiprocessing is used.""" |
60 os.environ[Forwarder._MULTIPROCESSING_ENV_VAR] = '1' | 64 os.environ[Forwarder._MULTIPROCESSING_ENV_VAR] = '1' |
61 | 65 |
62 @staticmethod | 66 @staticmethod |
63 def Map(port_pairs, adb, tool=None): | 67 def Map(port_pairs, device, tool=None): |
64 """Runs the forwarder. | 68 """Runs the forwarder. |
65 | 69 |
66 Args: | 70 Args: |
67 port_pairs: A list of tuples (device_port, host_port) to forward. Note | 71 port_pairs: A list of tuples (device_port, host_port) to forward. Note |
68 that you can specify 0 as a device_port, in which case a | 72 that you can specify 0 as a device_port, in which case a |
69 port will by dynamically assigned on the device. You can | 73 port will by dynamically assigned on the device. You can |
70 get the number of the assigned port using the | 74 get the number of the assigned port using the |
71 DevicePortForHostPort method. | 75 DevicePortForHostPort method. |
72 adb: An AndroidCommands instance. | 76 device: A DeviceUtils instance. |
73 tool: Tool class to use to get wrapper, if necessary, for executing the | 77 tool: Tool class to use to get wrapper, if necessary, for executing the |
74 forwarder (see valgrind_tools.py). | 78 forwarder (see valgrind_tools.py). |
75 | 79 |
76 Raises: | 80 Raises: |
77 Exception on failure to forward the port. | 81 Exception on failure to forward the port. |
78 """ | 82 """ |
| 83 # TODO(jbudorick) Remove once telemetry gets switched over. |
| 84 if isinstance(device, pylib.android_commands.AndroidCommands): |
| 85 device = pylib.device.device_utils.DeviceUtils(device) |
79 if not tool: | 86 if not tool: |
80 tool = valgrind_tools.CreateTool(None, adb) | 87 tool = valgrind_tools.CreateTool(None, device) |
81 with _FileLock(Forwarder._LOCK_PATH): | 88 with _FileLock(Forwarder._LOCK_PATH): |
82 instance = Forwarder._GetInstanceLocked(tool) | 89 instance = Forwarder._GetInstanceLocked(tool) |
83 instance._InitDeviceLocked(adb, tool) | 90 instance._InitDeviceLocked(device, tool) |
84 | 91 |
85 device_serial = adb.Adb().GetSerialNumber() | 92 device_serial = device.old_interface.Adb().GetSerialNumber() |
86 redirection_commands = [ | 93 redirection_commands = [ |
87 ['--serial-id=' + device_serial, '--map', str(device), | 94 ['--serial-id=' + device_serial, '--map', str(device), |
88 str(host)] for device, host in port_pairs] | 95 str(host)] for device, host in port_pairs] |
89 logging.info('Forwarding using commands: %s', redirection_commands) | 96 logging.info('Forwarding using commands: %s', redirection_commands) |
90 | 97 |
91 for redirection_command in redirection_commands: | 98 for redirection_command in redirection_commands: |
92 try: | 99 try: |
93 (exit_code, output) = cmd_helper.GetCmdStatusAndOutput( | 100 (exit_code, output) = cmd_helper.GetCmdStatusAndOutput( |
94 [instance._host_forwarder_path] + redirection_command) | 101 [instance._host_forwarder_path] + redirection_command) |
95 except OSError as e: | 102 except OSError as e: |
(...skipping 10 matching lines...) Expand all Loading... |
106 'expected "device_port:host_port"') % output) | 113 'expected "device_port:host_port"') % output) |
107 device_port = int(tokens[0]) | 114 device_port = int(tokens[0]) |
108 host_port = int(tokens[1]) | 115 host_port = int(tokens[1]) |
109 serial_with_port = (device_serial, device_port) | 116 serial_with_port = (device_serial, device_port) |
110 instance._device_to_host_port_map[serial_with_port] = host_port | 117 instance._device_to_host_port_map[serial_with_port] = host_port |
111 instance._host_to_device_port_map[host_port] = serial_with_port | 118 instance._host_to_device_port_map[host_port] = serial_with_port |
112 logging.info('Forwarding device port: %d to host port: %d.', | 119 logging.info('Forwarding device port: %d to host port: %d.', |
113 device_port, host_port) | 120 device_port, host_port) |
114 | 121 |
115 @staticmethod | 122 @staticmethod |
116 def UnmapDevicePort(device_port, adb): | 123 def UnmapDevicePort(device_port, device): |
117 """Unmaps a previously forwarded device port. | 124 """Unmaps a previously forwarded device port. |
118 | 125 |
119 Args: | 126 Args: |
120 adb: An AndroidCommands instance. | 127 device: A DeviceUtils instance. |
121 device_port: A previously forwarded port (through Map()). | 128 device_port: A previously forwarded port (through Map()). |
122 """ | 129 """ |
| 130 # TODO(jbudorick) Remove once telemetry gets switched over. |
| 131 if isinstance(device, pylib.android_commands.AndroidCommands): |
| 132 device = pylib.device.device_utils.DeviceUtils(device) |
123 with _FileLock(Forwarder._LOCK_PATH): | 133 with _FileLock(Forwarder._LOCK_PATH): |
124 Forwarder._UnmapDevicePortLocked(device_port, adb) | 134 Forwarder._UnmapDevicePortLocked(device_port, device) |
125 | 135 |
126 @staticmethod | 136 @staticmethod |
127 def UnmapAllDevicePorts(adb): | 137 def UnmapAllDevicePorts(device): |
128 """Unmaps all the previously forwarded ports for the provided device. | 138 """Unmaps all the previously forwarded ports for the provided device. |
129 | 139 |
130 Args: | 140 Args: |
131 adb: An AndroidCommands instance. | 141 device: A DeviceUtils instance. |
132 port_pairs: A list of tuples (device_port, host_port) to unmap. | 142 port_pairs: A list of tuples (device_port, host_port) to unmap. |
133 """ | 143 """ |
134 with _FileLock(Forwarder._LOCK_PATH): | 144 with _FileLock(Forwarder._LOCK_PATH): |
135 if not Forwarder._instance: | 145 if not Forwarder._instance: |
136 return | 146 return |
137 adb_serial = adb.Adb().GetSerialNumber() | 147 adb_serial = device.old_interface.Adb().GetSerialNumber() |
138 if adb_serial not in Forwarder._instance._initialized_devices: | 148 if adb_serial not in Forwarder._instance._initialized_devices: |
139 return | 149 return |
140 port_map = Forwarder._GetInstanceLocked( | 150 port_map = Forwarder._GetInstanceLocked( |
141 None)._device_to_host_port_map | 151 None)._device_to_host_port_map |
142 for (device_serial, device_port) in port_map.keys(): | 152 for (device_serial, device_port) in port_map.keys(): |
143 if adb_serial == device_serial: | 153 if adb_serial == device_serial: |
144 Forwarder._UnmapDevicePortLocked(device_port, adb) | 154 Forwarder._UnmapDevicePortLocked(device_port, device) |
145 # There are no more ports mapped, kill the device_forwarder. | 155 # There are no more ports mapped, kill the device_forwarder. |
146 tool = valgrind_tools.CreateTool(None, adb) | 156 tool = valgrind_tools.CreateTool(None, device) |
147 Forwarder._KillDeviceLocked(adb, tool) | 157 Forwarder._KillDeviceLocked(device, tool) |
148 Forwarder._instance._initialized_devices.remove(adb_serial) | 158 Forwarder._instance._initialized_devices.remove(adb_serial) |
149 | 159 |
150 | 160 |
151 @staticmethod | 161 @staticmethod |
152 def DevicePortForHostPort(host_port): | 162 def DevicePortForHostPort(host_port): |
153 """Returns the device port that corresponds to a given host port.""" | 163 """Returns the device port that corresponds to a given host port.""" |
154 with _FileLock(Forwarder._LOCK_PATH): | 164 with _FileLock(Forwarder._LOCK_PATH): |
155 (_device_serial, device_port) = Forwarder._GetInstanceLocked( | 165 (_device_serial, device_port) = Forwarder._GetInstanceLocked( |
156 None)._host_to_device_port_map.get(host_port) | 166 None)._host_to_device_port_map.get(host_port) |
157 return device_port | 167 return device_port |
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
198 self._device_to_host_port_map = dict() | 208 self._device_to_host_port_map = dict() |
199 self._host_to_device_port_map = dict() | 209 self._host_to_device_port_map = dict() |
200 self._host_forwarder_path = os.path.join( | 210 self._host_forwarder_path = os.path.join( |
201 constants.GetOutDirectory(), 'host_forwarder') | 211 constants.GetOutDirectory(), 'host_forwarder') |
202 assert os.path.exists(self._host_forwarder_path), 'Please build forwarder2' | 212 assert os.path.exists(self._host_forwarder_path), 'Please build forwarder2' |
203 self._device_forwarder_path_on_host = os.path.join( | 213 self._device_forwarder_path_on_host = os.path.join( |
204 constants.GetOutDirectory(), 'forwarder_dist') | 214 constants.GetOutDirectory(), 'forwarder_dist') |
205 self._InitHostLocked() | 215 self._InitHostLocked() |
206 | 216 |
207 @staticmethod | 217 @staticmethod |
208 def _UnmapDevicePortLocked(device_port, adb): | 218 def _UnmapDevicePortLocked(device_port, device): |
209 """Internal method used by UnmapDevicePort(). | 219 """Internal method used by UnmapDevicePort(). |
210 | 220 |
211 Note that the global lock must be acquired before calling this method. | 221 Note that the global lock must be acquired before calling this method. |
212 """ | 222 """ |
213 instance = Forwarder._GetInstanceLocked(None) | 223 instance = Forwarder._GetInstanceLocked(None) |
214 serial = adb.Adb().GetSerialNumber() | 224 serial = device.old_interface.Adb().GetSerialNumber() |
215 serial_with_port = (serial, device_port) | 225 serial_with_port = (serial, device_port) |
216 if not serial_with_port in instance._device_to_host_port_map: | 226 if not serial_with_port in instance._device_to_host_port_map: |
217 logging.error('Trying to unmap non-forwarded port %d' % device_port) | 227 logging.error('Trying to unmap non-forwarded port %d' % device_port) |
218 return | 228 return |
219 redirection_command = ['--serial-id=' + serial, '--unmap', str(device_port)] | 229 redirection_command = ['--serial-id=' + serial, '--unmap', str(device_port)] |
220 (exit_code, output) = cmd_helper.GetCmdStatusAndOutput( | 230 (exit_code, output) = cmd_helper.GetCmdStatusAndOutput( |
221 [instance._host_forwarder_path] + redirection_command) | 231 [instance._host_forwarder_path] + redirection_command) |
222 if exit_code != 0: | 232 if exit_code != 0: |
223 logging.error('%s exited with %d:\n%s' % ( | 233 logging.error('%s exited with %d:\n%s' % ( |
224 instance._host_forwarder_path, exit_code, '\n'.join(output))) | 234 instance._host_forwarder_path, exit_code, '\n'.join(output))) |
(...skipping 28 matching lines...) Expand all Loading... |
253 if pid_with_start_time: | 263 if pid_with_start_time: |
254 (pid, process_start_time) = pid_with_start_time.split(':') | 264 (pid, process_start_time) = pid_with_start_time.split(':') |
255 if pid == str(pid_for_lock): | 265 if pid == str(pid_for_lock): |
256 if process_start_time == str(_GetProcessStartTime(pid_for_lock)): | 266 if process_start_time == str(_GetProcessStartTime(pid_for_lock)): |
257 return | 267 return |
258 self._KillHostLocked() | 268 self._KillHostLocked() |
259 pid_file.seek(0) | 269 pid_file.seek(0) |
260 pid_file.write( | 270 pid_file.write( |
261 '%s:%s' % (pid_for_lock, str(_GetProcessStartTime(pid_for_lock)))) | 271 '%s:%s' % (pid_for_lock, str(_GetProcessStartTime(pid_for_lock)))) |
262 | 272 |
263 def _InitDeviceLocked(self, adb, tool): | 273 def _InitDeviceLocked(self, device, tool): |
264 """Initializes the device_forwarder daemon for a specific device (once). | 274 """Initializes the device_forwarder daemon for a specific device (once). |
265 | 275 |
266 Note that the global lock must be acquired before calling this method. This | 276 Note that the global lock must be acquired before calling this method. This |
267 method kills any existing device_forwarder daemon on the device that could | 277 method kills any existing device_forwarder daemon on the device that could |
268 be stale, pushes the latest version of the daemon (to the device) and starts | 278 be stale, pushes the latest version of the daemon (to the device) and starts |
269 it. | 279 it. |
270 | 280 |
271 Args: | 281 Args: |
272 adb: An AndroidCommands instance. | 282 device: A DeviceUtils instance. |
273 tool: Tool class to use to get wrapper, if necessary, for executing the | 283 tool: Tool class to use to get wrapper, if necessary, for executing the |
274 forwarder (see valgrind_tools.py). | 284 forwarder (see valgrind_tools.py). |
275 """ | 285 """ |
276 device_serial = adb.Adb().GetSerialNumber() | 286 device_serial = device.old_interface.Adb().GetSerialNumber() |
277 if device_serial in self._initialized_devices: | 287 if device_serial in self._initialized_devices: |
278 return | 288 return |
279 Forwarder._KillDeviceLocked(adb, tool) | 289 Forwarder._KillDeviceLocked(device, tool) |
280 adb.PushIfNeeded( | 290 device.old_interface.PushIfNeeded( |
281 self._device_forwarder_path_on_host, | 291 self._device_forwarder_path_on_host, |
282 Forwarder._DEVICE_FORWARDER_FOLDER) | 292 Forwarder._DEVICE_FORWARDER_FOLDER) |
283 (exit_code, output) = adb.GetShellCommandStatusAndOutput( | 293 (exit_code, output) = device.old_interface.GetShellCommandStatusAndOutput( |
284 '%s %s %s' % (Forwarder._LD_LIBRARY_PATH, tool.GetUtilWrapper(), | 294 '%s %s %s' % (Forwarder._LD_LIBRARY_PATH, tool.GetUtilWrapper(), |
285 Forwarder._DEVICE_FORWARDER_PATH)) | 295 Forwarder._DEVICE_FORWARDER_PATH)) |
286 if exit_code != 0: | 296 if exit_code != 0: |
287 raise Exception( | 297 raise Exception( |
288 'Failed to start device forwarder:\n%s' % '\n'.join(output)) | 298 'Failed to start device forwarder:\n%s' % '\n'.join(output)) |
289 self._initialized_devices.add(device_serial) | 299 self._initialized_devices.add(device_serial) |
290 | 300 |
291 def _KillHostLocked(self): | 301 def _KillHostLocked(self): |
292 """Kills the forwarder process running on the host. | 302 """Kills the forwarder process running on the host. |
293 | 303 |
294 Note that the global lock must be acquired before calling this method. | 304 Note that the global lock must be acquired before calling this method. |
295 """ | 305 """ |
296 logging.info('Killing host_forwarder.') | 306 logging.info('Killing host_forwarder.') |
297 (exit_code, output) = cmd_helper.GetCmdStatusAndOutput( | 307 (exit_code, output) = cmd_helper.GetCmdStatusAndOutput( |
298 [self._host_forwarder_path, '--kill-server']) | 308 [self._host_forwarder_path, '--kill-server']) |
299 if exit_code != 0: | 309 if exit_code != 0: |
300 (exit_code, output) = cmd_helper.GetCmdStatusAndOutput( | 310 (exit_code, output) = cmd_helper.GetCmdStatusAndOutput( |
301 ['pkill', '-9', 'host_forwarder']) | 311 ['pkill', '-9', 'host_forwarder']) |
302 if exit_code != 0: | 312 if exit_code != 0: |
303 raise Exception('%s exited with %d:\n%s' % ( | 313 raise Exception('%s exited with %d:\n%s' % ( |
304 self._host_forwarder_path, exit_code, '\n'.join(output))) | 314 self._host_forwarder_path, exit_code, '\n'.join(output))) |
305 | 315 |
306 @staticmethod | 316 @staticmethod |
307 def _KillDeviceLocked(adb, tool): | 317 def _KillDeviceLocked(device, tool): |
308 """Kills the forwarder process running on the device. | 318 """Kills the forwarder process running on the device. |
309 | 319 |
310 Note that the global lock must be acquired before calling this method. | 320 Note that the global lock must be acquired before calling this method. |
311 | 321 |
312 Args: | 322 Args: |
313 adb: Instance of AndroidCommands for talking to the device. | 323 device: Instance of DeviceUtils for talking to the device. |
314 tool: Wrapper tool (e.g. valgrind) that can be used to execute the device | 324 tool: Wrapper tool (e.g. valgrind) that can be used to execute the device |
315 forwarder (see valgrind_tools.py). | 325 forwarder (see valgrind_tools.py). |
316 """ | 326 """ |
317 logging.info('Killing device_forwarder.') | 327 logging.info('Killing device_forwarder.') |
318 if not adb.FileExistsOnDevice(Forwarder._DEVICE_FORWARDER_PATH): | 328 if not device.old_interface.FileExistsOnDevice( |
| 329 Forwarder._DEVICE_FORWARDER_PATH): |
319 return | 330 return |
320 adb.GetShellCommandStatusAndOutput( | 331 device.old_interface.GetShellCommandStatusAndOutput( |
321 '%s %s --kill-server' % (tool.GetUtilWrapper(), | 332 '%s %s --kill-server' % (tool.GetUtilWrapper(), |
322 Forwarder._DEVICE_FORWARDER_PATH)) | 333 Forwarder._DEVICE_FORWARDER_PATH)) |
323 # TODO(pliard): Remove the following call to KillAllBlocking() when we are | 334 # TODO(pliard): Remove the following call to KillAllBlocking() when we are |
324 # sure that the old version of device_forwarder (not supporting | 335 # sure that the old version of device_forwarder (not supporting |
325 # 'kill-server') is not running on the bots anymore. | 336 # 'kill-server') is not running on the bots anymore. |
326 timeout_sec = 5 | 337 timeout_sec = 5 |
327 processes_killed = adb.KillAllBlocking('device_forwarder', timeout_sec) | 338 processes_killed = device.old_interface.KillAllBlocking( |
| 339 'device_forwarder', timeout_sec) |
328 if not processes_killed: | 340 if not processes_killed: |
329 pids = adb.ExtractPid('device_forwarder') | 341 pids = device.old_interface.ExtractPid('device_forwarder') |
330 if pids: | 342 if pids: |
331 raise Exception('Timed out while killing device_forwarder') | 343 raise Exception('Timed out while killing device_forwarder') |
OLD | NEW |