Chromium Code Reviews| Index: third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/port/android.py |
| diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/port/android.py b/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/port/android.py |
| index bc33ead3014fca5e31d9fdb03e8d050b30da7b4d..b8024fff58c78ae10218dd1e84055a9fe6e3b7e0 100644 |
| --- a/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/port/android.py |
| +++ b/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/port/android.py |
| @@ -26,6 +26,7 @@ |
| # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
| # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| +import itertools |
| import logging |
| import os |
| import re |
| @@ -267,7 +268,7 @@ class AndroidPort(base.Port): |
| self._version = 'icecreamsandwich' |
| self._host_port = factory.PortFactory(host).get(**kwargs) |
| - self._server_process_constructor = self._android_server_process_constructor |
| + self.server_process_constructor = self._android_server_process_constructor |
| if not self.get_option('disable_breakpad'): |
| self._dump_reader = DumpReaderAndroid(host, self._build_path()) |
| @@ -609,9 +610,7 @@ class ChromiumAndroidDriver(driver.Driver): |
| def __init__(self, port, worker_number, pixel_tests, driver_details, android_devices, no_timeout=False): |
| super(ChromiumAndroidDriver, self).__init__(port, worker_number, pixel_tests, no_timeout) |
| - self._in_fifo_path = driver_details.device_fifo_directory() + 'stdin.fifo' |
| - self._out_fifo_path = driver_details.device_fifo_directory() + 'test.fifo' |
| - self._err_fifo_path = driver_details.device_fifo_directory() + 'stderr.fifo' |
| + self._write_stdin_process = None |
| self._read_stdout_process = None |
| self._read_stderr_process = None |
| self._original_kptr_restrict = None |
| @@ -826,7 +825,7 @@ class ChromiumAndroidDriver(driver.Driver): |
| return '%s\n%s' % (' '.join(last_tombstone), tombstone_contents) |
| def _get_logcat(self): |
| - return list(self._device.adb.Logcat(dump=True, logcat_format='threadtime')) |
| + return '\n'.join(self._device.adb.Logcat(dump=True, logcat_format='threadtime')) |
| def _setup_performance(self): |
| # Disable CPU scaling and drop ram cache to reduce noise in tests |
| @@ -877,18 +876,6 @@ class ChromiumAndroidDriver(driver.Driver): |
| return True |
| return False |
| - def _all_pipes_created(self): |
| - return self._device.PathExists( |
| - [self._in_fifo_path, self._out_fifo_path, self._err_fifo_path]) |
| - |
| - def _remove_all_pipes(self): |
| - self._device.RunShellCommand( |
| - ['rm', '-f', self._in_fifo_path, self._out_fifo_path, self._err_fifo_path], |
| - check_return=True) |
| - return (not self._device.PathExists(self._in_fifo_path) and |
| - not self._device.PathExists(self._out_fifo_path) and |
| - not self._device.PathExists(self._err_fifo_path)) |
| - |
| def start(self, pixel_tests, per_test_args, deadline): |
| # We override the default start() so that we can call _android_driver_cmd_line() |
| # instead of cmd_line(). |
| @@ -915,7 +902,7 @@ class ChromiumAndroidDriver(driver.Driver): |
| except ScriptError as e: |
| self._abort('ScriptError("%s") in _start()' % str(e)) |
| - self._log_error('Failed to start the content_shell application. Retries=%d. Log:%s' % (retries, self._get_logcat())) |
| + self._log_error('Failed to start the content_shell application. Retries=%d. Log:\n%s' % (retries, self._get_logcat())) |
| self.stop() |
| time.sleep(2) |
| self._abort('Failed to start the content_shell application multiple times. Giving up.') |
| @@ -923,6 +910,41 @@ class ChromiumAndroidDriver(driver.Driver): |
| def _start_once(self, pixel_tests, per_test_args): |
| super(ChromiumAndroidDriver, self)._start(pixel_tests, per_test_args, wait_for_ready=False) |
| + self._device.adb.Logcat(clear=True) |
| + |
| + self._device.RunShellCommand( |
| + ['rm', '-rf', self._driver_details.device_crash_dumps_directory()], |
| + check_return=True) |
| + self._device.RunShellCommand( |
| + ['mkdir', self._driver_details.device_crash_dumps_directory()], |
| + check_return=True) |
| + self._device.RunShellCommand( |
| + ['chmod', '-R', '777', self._driver_details.device_crash_dumps_directory()], |
| + check_return=True) |
| + |
| + # Read back the shell prompt to ensure adb shell ready. |
|
qyearsley
2016/12/02 23:35:22
s/ensure adb shell ready/ensure adb shell is ready
jbudorick
2016/12/05 14:30:38
Done.
|
| + deadline = time.time() + DRIVER_START_STOP_TIMEOUT_SECS |
| + self._server_process.start() |
| + self._read_prompt(deadline) |
| + self._log_debug('Interactive shell started') |
| + |
| + # Start a process to read from the stdout fifo of the test driver and print to stdout. |
| + self._read_stdout_process, stdout_port = self._start_netcat( |
| + 'ReadStdout', read_from_stdin=False) |
| + self._log_debug('Redirecting stdout to port %d' % stdout_port) |
| + |
| + # Start a process to read from the stderr fifo of the test driver and print to stdout. |
|
qyearsley
2016/12/02 23:35:22
What is the meaning of fifo in this context?
jbudorick
2016/12/05 14:30:38
It means that I didn't update this comment or the
|
| + self._read_stderr_process, stderr_port = self._start_netcat( |
| + 'ReadStderr', first_port=stdout_port + 1, read_from_stdin=False) |
| + self._log_debug('Redirecting stderr to port %d' % stderr_port) |
| + |
| + self._write_stdin_process, stdin_port = self._start_netcat( |
| + 'WriteStdin', first_port=stderr_port + 1) |
| + self._log_debug('Redirecting stdin to port %d' % stdin_port) |
| + |
| + # Combine the stdout and stderr pipes into self._server_process. |
| + self._replace_server_process_streams() |
| + |
| # We delay importing forwarder as long as possible because it uses fcntl, |
| # which isn't available on windows. |
| from devil.android import forwarder |
| @@ -931,8 +953,9 @@ class ChromiumAndroidDriver(driver.Driver): |
| forwarder.Forwarder.Map( |
| [(p, p) for p in FORWARD_PORTS.split()], |
| self._device) |
| - |
| - self._device.adb.Logcat(clear=True) |
| + forwarder.Forwarder.Map( |
| + [(0, stdout_port), (0, stderr_port), (0, stdin_port)], |
| + self._device) |
| cmd_line_file_path = self._driver_details.command_line_file() |
| original_cmd_line_file_path = cmd_line_file_path + '.orig' |
| @@ -945,21 +968,18 @@ class ChromiumAndroidDriver(driver.Driver): |
| ['mv', cmd_line_file_path, original_cmd_line_file_path], |
| check_return=True) |
| + stream_port_args = [ |
| + '--android-stderr-port=%s' % forwarder.Forwarder.DevicePortForHostPort(stderr_port), |
| + '--android-stdin-port=%s' % forwarder.Forwarder.DevicePortForHostPort(stdin_port), |
| + '--android-stdout-port=%s' % forwarder.Forwarder.DevicePortForHostPort(stdout_port), |
| + ] |
| + cmd_line_contents = self._android_driver_cmd_line(pixel_tests, per_test_args + stream_port_args) |
| self._device.WriteFile( |
| self._driver_details.command_line_file(), |
| - ' '.join(self._android_driver_cmd_line(pixel_tests, per_test_args))) |
| + ' '.join(cmd_line_contents)) |
| + self._log_debug('Command-line file contents: %s' % ' '.join(cmd_line_contents)) |
| self._created_cmd_line = True |
| - self._device.RunShellCommand( |
| - ['rm', '-rf', self._driver_details.device_crash_dumps_directory()], |
| - check_return=True) |
| - self._device.RunShellCommand( |
| - ['mkdir', self._driver_details.device_crash_dumps_directory()], |
| - check_return=True) |
| - self._device.RunShellCommand( |
| - ['chmod', '-R', '777', self._driver_details.device_crash_dumps_directory()], |
| - check_return=True) |
| - |
| try: |
| self._device.StartActivity( |
| intent.Intent( |
| @@ -969,62 +989,32 @@ class ChromiumAndroidDriver(driver.Driver): |
| self._log_error('Failed to start the content_shell application. Exception:\n' + str(exc)) |
| return False |
| - if not ChromiumAndroidDriver._loop_with_timeout(self._all_pipes_created, DRIVER_START_STOP_TIMEOUT_SECS): |
| - return False |
| - |
| - # Read back the shell prompt to ensure adb shell ready. |
| - deadline = time.time() + DRIVER_START_STOP_TIMEOUT_SECS |
| - self._server_process.start() |
| - self._read_prompt(deadline) |
| - self._log_debug('Interactive shell started') |
| - |
| - # Start a process to read from the stdout fifo of the test driver and print to stdout. |
| - self._log_debug('Redirecting stdout to ' + self._out_fifo_path) |
| - self._read_stdout_process = self._port._server_process_constructor( |
| - self._port, 'ReadStdout', |
| - [self._device.adb.GetAdbPath(), '-s', self._device.serial, 'shell', 'cat', self._out_fifo_path]) |
| - self._read_stdout_process.start() |
| - |
| - # Start a process to read from the stderr fifo of the test driver and print to stdout. |
| - self._log_debug('Redirecting stderr to ' + self._err_fifo_path) |
| - self._read_stderr_process = self._port._server_process_constructor( |
| - self._port, 'ReadStderr', |
| - [self._device.adb.GetAdbPath(), '-s', self._device.serial, 'shell', 'cat', self._err_fifo_path]) |
| - self._read_stderr_process.start() |
| - |
| - self._log_debug('Redirecting stdin to ' + self._in_fifo_path) |
| - self._server_process.write('cat >%s\n' % self._in_fifo_path) |
| - |
| - # Combine the stdout and stderr pipes into self._server_process. |
| - self._server_process.replace_outputs(self._read_stdout_process._proc.stdout, self._read_stderr_process._proc.stdout) |
| - |
| - def deadlock_detector(processes, normal_startup_event): |
| - if not ChromiumAndroidDriver._loop_with_timeout(lambda: normal_startup_event.is_set(), DRIVER_START_STOP_TIMEOUT_SECS): |
| - # If normal_startup_event is not set in time, the main thread must be blocked at |
| - # reading/writing the fifo. Kill the fifo reading/writing processes to let the |
| - # main thread escape from the deadlocked state. After that, the main thread will |
| - # treat this as a crash. |
| - self._log_error('Deadlock detected. Processes killed.') |
| - for i in processes: |
| - i.kill() |
| - |
| - # Start a thread to kill the pipe reading/writing processes on deadlock of the fifos during startup. |
| - normal_startup_event = threading.Event() |
| - threading.Thread( |
| - name='DeadlockDetector', |
| - target=deadlock_detector, |
| - args=([self._server_process, self._read_stdout_process, self._read_stderr_process], normal_startup_event)).start() |
| - |
| - # The test driver might crash during startup or when the deadlock detector hits |
| - # a deadlock and kills the fifo reading/writing processes. |
| + # The test driver might crash during startup. |
| if not self._wait_for_server_process_output(self._server_process, deadline, '#READY'): |
| return False |
| - # Inform the deadlock detector that the startup is successful without deadlock. |
| - normal_startup_event.set() |
| self._log_debug("content_shell is ready") |
| return True |
| + def _start_netcat(self, server_name, first_port=10201, read_from_stdin=True): |
| + for i in itertools.count(first_port, 65536): |
| + nc_cmd = ['nc', '-l', str(i)] |
| + if not read_from_stdin: |
| + nc_cmd.append('-d') |
| + proc = self._port.server_process_constructor(self._port, server_name, nc_cmd) |
| + proc.start() |
| + self._port.host.executive.wait_limited(proc.pid(), limit_in_seconds=1) |
| + if self._port.host.executive.check_running_pid(proc.pid()): |
| + return (proc, i) |
| + |
| + def _replace_server_process_streams(self): |
| + # pylint: disable=protected-access |
| + self._server_process.replace_input( |
| + self._write_stdin_process._proc.stdin) |
| + self._server_process.replace_outputs( |
| + self._read_stdout_process._proc.stdout, |
| + self._read_stderr_process._proc.stdout) |
| + |
| def _pid_on_target(self): |
| pids = self._device.GetPids(self._driver_details.package_name()) |
| return pids.get(self._driver_details.package_name()) |
| @@ -1035,6 +1025,10 @@ class ChromiumAndroidDriver(driver.Driver): |
| # FIXME: crbug.com/305040. Figure out if it's really hanging (and why). |
| self._device.ForceStop(self._driver_details.package_name()) |
| + if self._write_stdin_process: |
| + self._write_stdin_process.kill() |
| + self._write_stdin_process = None |
| + |
| if self._read_stdout_process: |
| self._read_stdout_process.kill() |
| self._read_stdout_process = None |
| @@ -1052,10 +1046,6 @@ class ChromiumAndroidDriver(driver.Driver): |
| super(ChromiumAndroidDriver, self).stop() |
| - if self._android_devices.is_device_prepared(self._device.serial): |
| - if not ChromiumAndroidDriver._loop_with_timeout(self._remove_all_pipes, DRIVER_START_STOP_TIMEOUT_SECS): |
| - self._abort('Failed to remove fifo files. May be locked.') |
| - |
| self._clean_up_cmd_line() |
| def _pull_crash_dumps_from_device(self): |