Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(368)

Side by Side Diff: build/android/pylib/forwarder.py

Issue 15151003: Use a single Python Forwarder instance for each base test runner instance. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 7 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
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 time 10 import time
10 11
11 import android_commands 12 import android_commands
12 import cmd_helper 13 import cmd_helper
13 import constants 14 import constants
14 import ports 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 """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
26 # Unix Abstract socket path: 27 # Unix Abstract socket path:
27 _DEVICE_ADB_CONTROL_PORT = 'chrome_device_forwarder' 28 _DEVICE_ADB_CONTROL_PORT = 'chrome_device_forwarder'
28 _TIMEOUT_SECS = 30 29 _TIMEOUT_SECS = 30
29 30
30 _DEVICE_FORWARDER_FOLDER = (constants.TEST_EXECUTABLE_DIR + 31 _DEVICE_FORWARDER_FOLDER = (constants.TEST_EXECUTABLE_DIR +
31 '/forwarder/') 32 '/forwarder/')
32 _DEVICE_FORWARDER_PATH = (constants.TEST_EXECUTABLE_DIR + 33 _DEVICE_FORWARDER_PATH = (constants.TEST_EXECUTABLE_DIR +
33 '/forwarder/device_forwarder') 34 '/forwarder/device_forwarder')
34 _LD_LIBRARY_PATH = 'LD_LIBRARY_PATH=%s' % _DEVICE_FORWARDER_FOLDER 35 _LD_LIBRARY_PATH = 'LD_LIBRARY_PATH=%s' % _DEVICE_FORWARDER_FOLDER
35 36
36 def __init__(self, adb, build_type): 37 def __init__(self, adb, build_type):
37 """Forwards TCP ports on the device back to the host. 38 """Forwards TCP ports on the device back to the host.
38 39
39 Works like adb forward, but in reverse. 40 Works like adb forward, but in reverse.
40 41
41 Args: 42 Args:
42 adb: Instance of AndroidCommands for talking to the device. 43 adb: Instance of AndroidCommands for talking to the device.
43 build_type: 'Release' or 'Debug'. 44 build_type: 'Release' or 'Debug'.
44 """ 45 """
45 assert build_type in ('Release', 'Debug') 46 assert build_type in ('Release', 'Debug')
46 self._adb = adb 47 self._adb = adb
47 self._host_to_device_port_map = dict() 48 self._host_to_device_port_map = dict()
48 self._device_process = None 49 self._device_initialized = False
50 self._host_adb_control_port = 0
51 self._lock = threading.Lock()
49 self._host_forwarder_path = _MakeBinaryPath(build_type, 'host_forwarder') 52 self._host_forwarder_path = _MakeBinaryPath(build_type, 'host_forwarder')
50 self._device_forwarder_path_on_host = os.path.join( 53 self._device_forwarder_path_on_host = os.path.join(
51 cmd_helper.OutDirectory.get(), build_type, 'forwarder_dist') 54 cmd_helper.OutDirectory.get(), build_type, 'forwarder_dist')
52 55
53 def Run(self, port_pairs, tool, host_name): 56 def Run(self, port_pairs, tool, host_name):
54 """Runs the forwarder. 57 """Runs the forwarder.
55 58
56 Args: 59 Args:
57 port_pairs: A list of tuples (device_port, host_port) to forward. Note 60 port_pairs: A list of tuples (device_port, host_port) to forward. Note
58 that you can specify 0 as a device_port, in which case a 61 that you can specify 0 as a device_port, in which case a
59 port will by dynamically assigned on the device. You can 62 port will by dynamically assigned on the device. You can
60 get the number of the assigned port using the 63 get the number of the assigned port using the
61 DevicePortForHostPort method. 64 DevicePortForHostPort method.
62 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
63 forwarder (see valgrind_tools.py). 66 forwarder (see valgrind_tools.py).
64 host_name: Address to forward to, must be addressable from the 67 host_name: Address to forward to, must be addressable from the
65 host machine. Usually use loopback '127.0.0.1'. 68 host machine. Usually use loopback '127.0.0.1'.
66 69
67 Raises: 70 Raises:
68 Exception on failure to forward the port. 71 Exception on failure to forward the port.
69 """ 72 """
73 with self._lock:
74 self._InitDeviceLocked(tool)
75 self._InitHostLocked()
76 redirection_commands = [
77 '%d:%d:%d:%s' % (self._host_adb_control_port, device, host,
78 host_name) 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)
82
83 for redirection_command in redirection_commands:
84 try:
85 (exit_code, output) = cmd_helper.GetCmdStatusAndOutput(
86 [self._host_forwarder_path, redirection_command])
87 except OSError as e:
88 if e.errno == 2:
89 raise Exception('Unable to start host forwarder. Make sure you have'
90 ' built host_forwarder.')
91 else: raise
92 if exit_code != 0:
93 raise Exception('%s exited with %d:\n%s' % (
94 self._host_forwarder_path, exit_code, '\n'.join(output)))
95 tokens = output.split(':')
96 if len(tokens) != 2:
97 raise Exception('Unexpected host forwarder output "%s", ' +
98 'expected "device_port:host_port"' % output)
99 device_port = int(tokens[0])
100 host_port = int(tokens[1])
101 self._host_to_device_port_map[host_port] = device_port
102 logging.info('Forwarding device port: %d to host port: %d.',
103 device_port, host_port)
104
105 def _InitHostLocked(self):
106 if self._host_adb_control_port:
107 return
70 self._host_adb_control_port = ports.AllocateTestServerPort() 108 self._host_adb_control_port = ports.AllocateTestServerPort()
71 if not self._host_adb_control_port: 109 if not self._host_adb_control_port:
72 raise Exception('Failed to allocate a TCP port in the host machine.') 110 raise Exception('Failed to allocate a TCP port in the host machine.')
73 self._adb.PushIfNeeded(
74 self._device_forwarder_path_on_host, Forwarder._DEVICE_FORWARDER_FOLDER)
75 redirection_commands = [
76 '%d:%d:%d:%s' % (self._host_adb_control_port, device, host,
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>]')
80 logging.info('Forwarding using commands: %s', redirection_commands)
81 if cmd_helper.RunCmd( 111 if cmd_helper.RunCmd(
82 ['adb', '-s', self._adb._adb.GetSerialNumber(), 'forward', 112 ['adb', '-s', self._adb._adb.GetSerialNumber(), 'forward',
83 'tcp:%s' % self._host_adb_control_port, 113 'tcp:%s' % self._host_adb_control_port,
84 'localabstract:%s' % Forwarder._DEVICE_ADB_CONTROL_PORT]) != 0: 114 'localabstract:%s' % Forwarder._DEVICE_ADB_CONTROL_PORT]) != 0:
85 raise Exception('Error while running adb forward.') 115 raise Exception('Error while running adb forward.')
86 116
117 def _InitDeviceLocked(self, tool):
118 if self._device_initialized:
119 return
120 self._adb.PushIfNeeded(
121 self._device_forwarder_path_on_host,
122 Forwarder._DEVICE_FORWARDER_FOLDER)
87 (exit_code, output) = self._adb.GetShellCommandStatusAndOutput( 123 (exit_code, output) = self._adb.GetShellCommandStatusAndOutput(
88 '%s %s %s %s' % (Forwarder._LD_LIBRARY_PATH, tool.GetUtilWrapper(), 124 '%s %s %s %s' % (Forwarder._LD_LIBRARY_PATH, tool.GetUtilWrapper(),
89 Forwarder._DEVICE_FORWARDER_PATH, 125 Forwarder._DEVICE_FORWARDER_PATH,
90 Forwarder._DEVICE_ADB_CONTROL_PORT)) 126 Forwarder._DEVICE_ADB_CONTROL_PORT))
91 if exit_code != 0: 127 if exit_code != 0:
92 raise Exception( 128 raise Exception(
93 'Failed to start device forwarder:\n%s' % '\n'.join(output)) 129 'Failed to start device forwarder:\n%s' % '\n'.join(output))
130 self._device_initialized = True
94 131
95 for redirection_command in redirection_commands: 132 def UnmapDevicePort(self, device_port):
frankf 2013/05/15 17:24:30 Please add docstring for all methods here.
Philippe 2013/05/15 17:57:41 Done.
96 try: 133 with self._lock:
97 (exit_code, output) = cmd_helper.GetCmdStatusAndOutput( 134 # Please note the minus sign below.
98 [self._host_forwarder_path, redirection_command]) 135 redirection_command = '%d:-%d' % (
99 except OSError as e: 136 self._host_adb_control_port, device_port)
100 if e.errno == 2: 137 (exit_code, output) = cmd_helper.GetCmdStatusAndOutput(
101 raise Exception('Unable to start host forwarder. Make sure you have ' 138 [self._host_forwarder_path, redirection_command])
102 'built host_forwarder.')
103 else: raise
104 if exit_code != 0: 139 if exit_code != 0:
105 raise Exception('%s exited with %d:\n%s' % ( 140 raise Exception('%s exited with %d:\n%s' % (
106 self._host_forwarder_path, exit_code, '\n'.join(output))) 141 self._host_forwarder_path, exit_code, '\n'.join(output)))
107 tokens = output.split(':')
108 if len(tokens) != 2:
109 raise Exception('Unexpected host forwarder output "%s", ' +
110 'expected "device_port:host_port"' % output)
111 device_port = int(tokens[0])
112 host_port = int(tokens[1])
113 self._host_to_device_port_map[host_port] = device_port
114 logging.info('Forwarding device port: %d to host port: %d.', device_port,
115 host_port)
116
117 def UnmapDevicePort(self, device_port):
118 # Please note the minus sign below.
119 redirection_command = '%d:-%d' % (self._host_adb_control_port, device_port)
120 (exit_code, output) = cmd_helper.GetCmdStatusAndOutput(
121 [self._host_forwarder_path, redirection_command])
122 if exit_code != 0:
123 raise Exception('%s exited with %d:\n%s' % (
124 self._host_forwarder_path, exit_code, '\n'.join(output)))
125 142
126 @staticmethod 143 @staticmethod
127 def KillHost(build_type): 144 def KillHost(build_type):
128 logging.info('Killing host_forwarder.') 145 logging.info('Killing host_forwarder.')
129 host_forwarder_path = _MakeBinaryPath(build_type, 'host_forwarder') 146 host_forwarder_path = _MakeBinaryPath(build_type, 'host_forwarder')
130 assert os.path.exists(host_forwarder_path), 'Please build forwarder2' 147 assert os.path.exists(host_forwarder_path), 'Please build forwarder2'
131 (exit_code, output) = cmd_helper.GetCmdStatusAndOutput( 148 (exit_code, output) = cmd_helper.GetCmdStatusAndOutput(
132 [host_forwarder_path, 'kill-server']) 149 [host_forwarder_path, 'kill-server'])
133 if exit_code != 0: 150 if exit_code != 0:
134 (exit_code, output) = cmd_helper.GetCmdStatusAndOutput( 151 (exit_code, output) = cmd_helper.GetCmdStatusAndOutput(
(...skipping 15 matching lines...) Expand all
150 # 'kill-server') is not running on the bots anymore. 167 # 'kill-server') is not running on the bots anymore.
151 timeout_sec = 5 168 timeout_sec = 5
152 processes_killed = adb.KillAllBlocking('device_forwarder', timeout_sec) 169 processes_killed = adb.KillAllBlocking('device_forwarder', timeout_sec)
153 if not processes_killed: 170 if not processes_killed:
154 pids = adb.ExtractPid('device_forwarder') 171 pids = adb.ExtractPid('device_forwarder')
155 if pids: 172 if pids:
156 raise Exception('Timed out while killing device_forwarder') 173 raise Exception('Timed out while killing device_forwarder')
157 174
158 def DevicePortForHostPort(self, host_port): 175 def DevicePortForHostPort(self, host_port):
159 """Get the device port that corresponds to a given host port.""" 176 """Get the device port that corresponds to a given host port."""
160 return self._host_to_device_port_map.get(host_port) 177 with self._lock:
178 return self._host_to_device_port_map.get(host_port)
161 179
180 # Deprecated.
162 def Close(self): 181 def Close(self):
163 """Terminate the forwarder process.""" 182 """Terminate the forwarder process."""
164 if self._device_process: 183 # TODO(pliard): Remove references in client code.
165 self._device_process.close() 184 pass
bulach 2013/05/14 18:21:53 we should chat about this :) there's Telemetry (to
Philippe 2013/05/15 08:32:23 Yeah, I will update them in a separate CL if you a
166 self._device_process = None
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698