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

Side by Side Diff: third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/port/android.py

Issue 2540603004: [Android] Redirect std{in,out,err} to sockets for layout tests. (Closed)
Patch Set: rebase Created 3 years, 11 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
OLDNEW
1 # Copyright (C) 2012 Google Inc. All rights reserved. 1 # Copyright (C) 2012 Google Inc. All rights reserved.
2 # 2 #
3 # Redistribution and use in source and binary forms, with or without 3 # Redistribution and use in source and binary forms, with or without
4 # modification, are permitted provided that the following conditions are 4 # modification, are permitted provided that the following conditions are
5 # met: 5 # met:
6 # 6 #
7 # * Redistributions of source code must retain the above copyright 7 # * Redistributions of source code must retain the above copyright
8 # notice, this list of conditions and the following disclaimer. 8 # notice, this list of conditions and the following disclaimer.
9 # * Redistributions in binary form must reproduce the above 9 # * Redistributions in binary form must reproduce the above
10 # copyright notice, this list of conditions and the following disclaimer 10 # copyright notice, this list of conditions and the following disclaimer
11 # in the documentation and/or other materials provided with the 11 # in the documentation and/or other materials provided with the
12 # distribution. 12 # distribution.
13 # * Neither the name of Google Inc. nor the names of its 13 # * Neither the name of Google Inc. nor the names of its
14 # contributors may be used to endorse or promote products derived from 14 # contributors may be used to endorse or promote products derived from
15 # this software without specific prior written permission. 15 # this software without specific prior written permission.
16 # 16 #
17 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 17 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18 # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 18 # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19 # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 19 # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
20 # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 20 # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
21 # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 21 # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
22 # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 22 # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
23 # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 28
29 import itertools
29 import logging 30 import logging
30 import os 31 import os
31 import re 32 import re
32 import sys 33 import sys
33 import threading 34 import threading
34 import time 35 import time
35 36
36 from multiprocessing.pool import ThreadPool 37 from multiprocessing.pool import ThreadPool
37 38
38 from webkitpy.common.system.executive import ScriptError 39 from webkitpy.common.system.executive import ScriptError
(...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after
114 # See webkit/support/platform_support_android.cc for the other side of this brid ge. 115 # See webkit/support/platform_support_android.cc for the other side of this brid ge.
115 PERF_TEST_PATH_PREFIX = '/all-perf-tests' 116 PERF_TEST_PATH_PREFIX = '/all-perf-tests'
116 LAYOUT_TEST_PATH_PREFIX = '/all-tests' 117 LAYOUT_TEST_PATH_PREFIX = '/all-tests'
117 118
118 # All ports the Android forwarder to forward. 119 # All ports the Android forwarder to forward.
119 # 8000, 8080 and 8443 are for http/https tests. 120 # 8000, 8080 and 8443 are for http/https tests.
120 # 8880 and 9323 are for websocket tests 121 # 8880 and 9323 are for websocket tests
121 # (see http_server.py, apache_http_server.py and websocket_server.py). 122 # (see http_server.py, apache_http_server.py and websocket_server.py).
122 FORWARD_PORTS = '8000 8080 8443 8880 9323' 123 FORWARD_PORTS = '8000 8080 8443 8880 9323'
123 124
125 # We start netcat processes for each of the three stdio streams. In doing so,
126 # we attempt to use ports starting from 10201. This starting value is
127 # completely arbitrary.
128 FIRST_NETCAT_PORT = 10201
129
124 MS_TRUETYPE_FONTS_DIR = '/usr/share/fonts/truetype/msttcorefonts/' 130 MS_TRUETYPE_FONTS_DIR = '/usr/share/fonts/truetype/msttcorefonts/'
125 MS_TRUETYPE_FONTS_PACKAGE = 'ttf-mscorefonts-installer' 131 MS_TRUETYPE_FONTS_PACKAGE = 'ttf-mscorefonts-installer'
126 132
127 # Timeout in seconds to wait for starting/stopping the driver. 133 # Timeout in seconds to wait for starting/stopping the driver.
128 DRIVER_START_STOP_TIMEOUT_SECS = 10 134 DRIVER_START_STOP_TIMEOUT_SECS = 10
129 135
130 HOST_FONT_FILES = [ 136 HOST_FONT_FILES = [
131 [[MS_TRUETYPE_FONTS_DIR], 'Arial.ttf', MS_TRUETYPE_FONTS_PACKAGE], 137 [[MS_TRUETYPE_FONTS_DIR], 'Arial.ttf', MS_TRUETYPE_FONTS_PACKAGE],
132 [[MS_TRUETYPE_FONTS_DIR], 'Arial_Bold.ttf', MS_TRUETYPE_FONTS_PACKAGE], 138 [[MS_TRUETYPE_FONTS_DIR], 'Arial_Bold.ttf', MS_TRUETYPE_FONTS_PACKAGE],
133 [[MS_TRUETYPE_FONTS_DIR], 'Arial_Bold_Italic.ttf', MS_TRUETYPE_FONTS_PACKAGE ], 139 [[MS_TRUETYPE_FONTS_DIR], 'Arial_Bold_Italic.ttf', MS_TRUETYPE_FONTS_PACKAGE ],
(...skipping 157 matching lines...) Expand 10 before | Expand all | Expand 10 after
291 BUILD_REQUIREMENTS_URL = 'https://www.chromium.org/developers/how-tos/androi d-build-instructions' 297 BUILD_REQUIREMENTS_URL = 'https://www.chromium.org/developers/how-tos/androi d-build-instructions'
292 298
293 def __init__(self, host, port_name, **kwargs): 299 def __init__(self, host, port_name, **kwargs):
294 _import_android_packages_if_necessary() 300 _import_android_packages_if_necessary()
295 super(AndroidPort, self).__init__(host, port_name, **kwargs) 301 super(AndroidPort, self).__init__(host, port_name, **kwargs)
296 302
297 self._operating_system = 'android' 303 self._operating_system = 'android'
298 self._version = 'icecreamsandwich' 304 self._version = 'icecreamsandwich'
299 305
300 self._host_port = factory.PortFactory(host).get(**kwargs) 306 self._host_port = factory.PortFactory(host).get(**kwargs)
301 self._server_process_constructor = self._android_server_process_construc tor 307 self.server_process_constructor = self._android_server_process_construct or
302 308
303 if not self.get_option('disable_breakpad'): 309 if not self.get_option('disable_breakpad'):
304 self._dump_reader = DumpReaderAndroid(host, self._build_path()) 310 self._dump_reader = DumpReaderAndroid(host, self._build_path())
305 311
306 if self.driver_name() != self.CONTENT_SHELL_NAME: 312 if self.driver_name() != self.CONTENT_SHELL_NAME:
307 raise AssertionError('Layout tests on Android only support content_s hell as the driver.') 313 raise AssertionError('Layout tests on Android only support content_s hell as the driver.')
308 314
309 self._driver_details = ContentShellDriverDetails() 315 self._driver_details = ContentShellDriverDetails()
310 316
311 # Initialize the AndroidDevices class which tracks available devices. 317 # Initialize the AndroidDevices class which tracks available devices.
(...skipping 321 matching lines...) Expand 10 before | Expand all | Expand 10 after
633 639
634 perfhost_display_patch = perfhost_path if perfhost_path else 'perfhost_l inux' 640 perfhost_display_patch = perfhost_path if perfhost_path else 'perfhost_l inux'
635 _log.debug("To view the full profile, run:") 641 _log.debug("To view the full profile, run:")
636 _log.debug(' '.join([perfhost_display_patch] + perfhost_report_command)) 642 _log.debug(' '.join([perfhost_display_patch] + perfhost_report_command))
637 643
638 644
639 class ChromiumAndroidDriver(driver.Driver): 645 class ChromiumAndroidDriver(driver.Driver):
640 646
641 def __init__(self, port, worker_number, pixel_tests, driver_details, android _devices, no_timeout=False): 647 def __init__(self, port, worker_number, pixel_tests, driver_details, android _devices, no_timeout=False):
642 super(ChromiumAndroidDriver, self).__init__(port, worker_number, pixel_t ests, no_timeout) 648 super(ChromiumAndroidDriver, self).__init__(port, worker_number, pixel_t ests, no_timeout)
643 self._in_fifo_path = driver_details.device_fifo_directory() + 'stdin.fif o' 649 self._write_stdin_process = None
644 self._out_fifo_path = driver_details.device_fifo_directory() + 'test.fif o'
645 self._err_fifo_path = driver_details.device_fifo_directory() + 'stderr.f ifo'
646 self._read_stdout_process = None 650 self._read_stdout_process = None
647 self._read_stderr_process = None 651 self._read_stderr_process = None
648 self._original_kptr_restrict = None 652 self._original_kptr_restrict = None
649 653
650 self._android_devices = android_devices 654 self._android_devices = android_devices
651 self._device = android_devices.get_device(port._executive, worker_number ) # pylint: disable=protected-access 655 self._device = android_devices.get_device(port._executive, worker_number ) # pylint: disable=protected-access
652 self._driver_details = driver_details 656 self._driver_details = driver_details
653 self._debug_logging = self._port._debug_logging 657 self._debug_logging = self._port._debug_logging
654 self._created_cmd_line = False 658 self._created_cmd_line = False
655 self._device_failed = False 659 self._device_failed = False
(...skipping 194 matching lines...) Expand 10 before | Expand all | Expand 10 after
850 return '' 854 return ''
851 855
852 # Use Android tool vendor/google/tools/stack to convert the raw 856 # Use Android tool vendor/google/tools/stack to convert the raw
853 # stack trace into a human readable format, if needed. 857 # stack trace into a human readable format, if needed.
854 # It takes a long time, so don't do it here. 858 # It takes a long time, so don't do it here.
855 tombstone_contents = self._device.ReadFile( 859 tombstone_contents = self._device.ReadFile(
856 '/data/tombstones/%s' % last_tombstone[6]) 860 '/data/tombstones/%s' % last_tombstone[6])
857 return '%s\n%s' % (' '.join(last_tombstone), tombstone_contents) 861 return '%s\n%s' % (' '.join(last_tombstone), tombstone_contents)
858 862
859 def _get_logcat(self): 863 def _get_logcat(self):
860 return list(self._device.adb.Logcat(dump=True, logcat_format='threadtime ')) 864 return '\n'.join(self._device.adb.Logcat(dump=True, logcat_format='threa dtime'))
861 865
862 def _setup_performance(self): 866 def _setup_performance(self):
863 # Disable CPU scaling and drop ram cache to reduce noise in tests 867 # Disable CPU scaling and drop ram cache to reduce noise in tests
864 perf_control.PerfControl(self._device).SetPerfProfilingMode() 868 perf_control.PerfControl(self._device).SetPerfProfilingMode()
865 869
866 def _teardown_performance(self): 870 def _teardown_performance(self):
867 perf_control.PerfControl(self._device).SetDefaultPerfMode() 871 perf_control.PerfControl(self._device).SetDefaultPerfMode()
868 872
869 def _get_crash_log(self, stdout, stderr, newer_than): 873 def _get_crash_log(self, stdout, stderr, newer_than):
870 if not stdout: 874 if not stdout:
(...skipping 30 matching lines...) Expand all
901 return driver.Driver.cmd_line(self, pixel_tests, per_test_args) 905 return driver.Driver.cmd_line(self, pixel_tests, per_test_args)
902 906
903 @staticmethod 907 @staticmethod
904 def _loop_with_timeout(condition, timeout_secs): 908 def _loop_with_timeout(condition, timeout_secs):
905 deadline = time.time() + timeout_secs 909 deadline = time.time() + timeout_secs
906 while time.time() < deadline: 910 while time.time() < deadline:
907 if condition(): 911 if condition():
908 return True 912 return True
909 return False 913 return False
910 914
911 def _all_pipes_created(self):
912 return self._device.PathExists(
913 [self._in_fifo_path, self._out_fifo_path, self._err_fifo_path])
914
915 def _remove_all_pipes(self):
916 self._device.RunShellCommand(
917 ['rm', '-f', self._in_fifo_path, self._out_fifo_path, self._err_fifo _path],
918 check_return=True)
919 return (not self._device.PathExists(self._in_fifo_path) and
920 not self._device.PathExists(self._out_fifo_path) and
921 not self._device.PathExists(self._err_fifo_path))
922
923 def start(self, pixel_tests, per_test_args, deadline): 915 def start(self, pixel_tests, per_test_args, deadline):
924 # We override the default start() so that we can call _android_driver_cm d_line() 916 # We override the default start() so that we can call _android_driver_cm d_line()
925 # instead of cmd_line(). 917 # instead of cmd_line().
926 new_cmd_line = self._android_driver_cmd_line(pixel_tests, per_test_args) 918 new_cmd_line = self._android_driver_cmd_line(pixel_tests, per_test_args)
927 919
928 # Since _android_driver_cmd_line() is different than cmd_line() we need to provide 920 # Since _android_driver_cmd_line() is different than cmd_line() we need to provide
929 # our own mechanism for detecting when the process should be stopped. 921 # our own mechanism for detecting when the process should be stopped.
930 if self._current_cmd_line is None: 922 if self._current_cmd_line is None:
931 self._current_android_cmd_line = None 923 self._current_android_cmd_line = None
932 if new_cmd_line != self._current_android_cmd_line: 924 if new_cmd_line != self._current_android_cmd_line:
933 self.stop() 925 self.stop()
934 self._current_android_cmd_line = new_cmd_line 926 self._current_android_cmd_line = new_cmd_line
935 927
936 super(ChromiumAndroidDriver, self).start(pixel_tests, per_test_args, dea dline) 928 super(ChromiumAndroidDriver, self).start(pixel_tests, per_test_args, dea dline)
937 929
938 def _start(self, pixel_tests, per_test_args): 930 def _start(self, pixel_tests, per_test_args):
939 if not self._android_devices.is_device_prepared(self._device.serial): 931 if not self._android_devices.is_device_prepared(self._device.serial):
940 raise driver.DeviceFailure("%s is not prepared in _start()" % self._ device.serial) 932 raise driver.DeviceFailure("%s is not prepared in _start()" % self._ device.serial)
941 933
942 for retries in range(3): 934 for retries in range(3):
943 try: 935 try:
944 if self._start_once(pixel_tests, per_test_args): 936 if self._start_once(pixel_tests, per_test_args):
945 return 937 return
946 except ScriptError as error: 938 except ScriptError as error:
947 self._abort('ScriptError("%s") in _start()' % error) 939 self._abort('ScriptError("%s") in _start()' % error)
948 940
949 self._log_error('Failed to start the content_shell application. Retr ies=%d. Log:%s' % (retries, self._get_logcat())) 941 self._log_error('Failed to start the content_shell application. Retr ies=%d. Log:\n%s' % (retries, self._get_logcat()))
950 self.stop() 942 self.stop()
951 time.sleep(2) 943 time.sleep(2)
952 self._abort('Failed to start the content_shell application multiple time s. Giving up.') 944 self._abort('Failed to start the content_shell application multiple time s. Giving up.')
953 945
954 def _start_once(self, pixel_tests, per_test_args): 946 def _start_once(self, pixel_tests, per_test_args):
955 super(ChromiumAndroidDriver, self)._start(pixel_tests, per_test_args, wa it_for_ready=False) 947 super(ChromiumAndroidDriver, self)._start(pixel_tests, per_test_args, wa it_for_ready=False)
956 948
949 self._device.adb.Logcat(clear=True)
950
951 self._create_device_crash_dumps_directory()
952
953 # Read back the shell prompt to ensure adb shell is ready.
954 deadline = time.time() + DRIVER_START_STOP_TIMEOUT_SECS
955 self._server_process.start()
956 self._read_prompt(deadline)
957 self._log_debug('Interactive shell started')
958
959 # Start a netcat process to which the test driver will connect to write stdout.
960 self._read_stdout_process, stdout_port = self._start_netcat(
961 'ReadStdout', read_from_stdin=False)
962 self._log_debug('Redirecting stdout to port %d' % stdout_port)
963
964 # Start a netcat process to which the test driver will connect to write stderr.
965 self._read_stderr_process, stderr_port = self._start_netcat(
966 'ReadStderr', first_port=stdout_port + 1, read_from_stdin=False)
967 self._log_debug('Redirecting stderr to port %d' % stderr_port)
968
969 # Start a netcat process to which the test driver will connect to read s tdin.
970 self._write_stdin_process, stdin_port = self._start_netcat(
971 'WriteStdin', first_port=stderr_port + 1)
972 self._log_debug('Redirecting stdin to port %d' % stdin_port)
973
974 # Combine the stdin, stdout, and stderr pipes into self._server_process.
975 self._replace_server_process_streams()
976
957 # We delay importing forwarder as long as possible because it uses fcntl , 977 # We delay importing forwarder as long as possible because it uses fcntl ,
958 # which isn't available on windows. 978 # which isn't available on windows.
959 from devil.android import forwarder 979 from devil.android import forwarder
960 980
961 self._log_debug('Starting forwarder') 981 self._log_debug('Starting forwarder')
962 forwarder.Forwarder.Map( 982 forwarder.Forwarder.Map(
963 [(p, p) for p in FORWARD_PORTS.split()], 983 [(p, p) for p in FORWARD_PORTS.split()],
964 self._device) 984 self._device)
965 985 forwarder.Forwarder.Map(
966 self._device.adb.Logcat(clear=True) 986 [(forwarder.DYNAMIC_DEVICE_PORT, p)
987 for p in (stdout_port, stderr_port, stdin_port)],
988 self._device)
967 989
968 cmd_line_file_path = self._driver_details.command_line_file() 990 cmd_line_file_path = self._driver_details.command_line_file()
969 original_cmd_line_file_path = cmd_line_file_path + '.orig' 991 original_cmd_line_file_path = cmd_line_file_path + '.orig'
970 if (self._device.PathExists(cmd_line_file_path) 992 if (self._device.PathExists(cmd_line_file_path)
971 and not self._device.PathExists(original_cmd_line_file_path)): 993 and not self._device.PathExists(original_cmd_line_file_path)):
972 # We check for both the normal path and the backup because we do not want to step 994 # We check for both the normal path and the backup because we do not want to step
973 # on the backup. Otherwise, we'd clobber the backup whenever we chan ged the 995 # on the backup. Otherwise, we'd clobber the backup whenever we chan ged the
974 # command line during the run. 996 # command line during the run.
975 self._device.RunShellCommand( 997 self._device.RunShellCommand(
976 ['mv', cmd_line_file_path, original_cmd_line_file_path], 998 ['mv', cmd_line_file_path, original_cmd_line_file_path],
977 check_return=True) 999 check_return=True)
978 1000
1001 stream_port_args = [
1002 '--android-stderr-port=%s' % forwarder.Forwarder.DevicePortForHostPo rt(stderr_port),
1003 '--android-stdin-port=%s' % forwarder.Forwarder.DevicePortForHostPor t(stdin_port),
1004 '--android-stdout-port=%s' % forwarder.Forwarder.DevicePortForHostPo rt(stdout_port),
1005 ]
1006 cmd_line_contents = self._android_driver_cmd_line(pixel_tests, per_test_ args + stream_port_args)
979 self._device.WriteFile( 1007 self._device.WriteFile(
980 self._driver_details.command_line_file(), 1008 self._driver_details.command_line_file(),
981 ' '.join(self._android_driver_cmd_line(pixel_tests, per_test_args))) 1009 ' '.join(cmd_line_contents))
1010 self._log_debug('Command-line file contents: %s' % ' '.join(cmd_line_con tents))
982 self._created_cmd_line = True 1011 self._created_cmd_line = True
983 1012
984 self._device.RunShellCommand(
985 ['rm', '-rf', self._driver_details.device_crash_dumps_directory()],
986 check_return=True)
987 self._device.RunShellCommand(
988 ['mkdir', self._driver_details.device_crash_dumps_directory()],
989 check_return=True)
990 self._device.RunShellCommand(
991 ['chmod', '-R', '777', self._driver_details.device_crash_dumps_direc tory()],
992 check_return=True)
993
994 try: 1013 try:
995 self._device.StartActivity( 1014 self._device.StartActivity(
996 intent.Intent( 1015 intent.Intent(
997 component=self._driver_details.activity_name(), 1016 component=self._driver_details.activity_name(),
998 extras={'RunInSubThread': None})) 1017 extras={'RunInSubThread': None}))
999 except device_errors.CommandFailedError as exc: 1018 except device_errors.CommandFailedError as exc:
1000 self._log_error('Failed to start the content_shell application. Exce ption:\n' + str(exc)) 1019 self._log_error('Failed to start the content_shell application. Exce ption:\n' + str(exc))
1001 return False 1020 return False
1002 1021
1003 if not ChromiumAndroidDriver._loop_with_timeout(self._all_pipes_created, DRIVER_START_STOP_TIMEOUT_SECS): 1022 # The test driver might crash during startup.
1004 return False
1005
1006 # Read back the shell prompt to ensure adb shell ready.
1007 deadline = time.time() + DRIVER_START_STOP_TIMEOUT_SECS
1008 self._server_process.start()
1009 self._read_prompt(deadline)
1010 self._log_debug('Interactive shell started')
1011
1012 # Start a process to read from the stdout fifo of the test driver and pr int to stdout.
1013 self._log_debug('Redirecting stdout to ' + self._out_fifo_path)
1014 self._read_stdout_process = self._port._server_process_constructor(
1015 self._port, 'ReadStdout',
1016 [self._device.adb.GetAdbPath(), '-s', self._device.serial, 'shell', 'cat', self._out_fifo_path])
1017 self._read_stdout_process.start()
1018
1019 # Start a process to read from the stderr fifo of the test driver and pr int to stdout.
1020 self._log_debug('Redirecting stderr to ' + self._err_fifo_path)
1021 self._read_stderr_process = self._port._server_process_constructor(
1022 self._port, 'ReadStderr',
1023 [self._device.adb.GetAdbPath(), '-s', self._device.serial, 'shell', 'cat', self._err_fifo_path])
1024 self._read_stderr_process.start()
1025
1026 self._log_debug('Redirecting stdin to ' + self._in_fifo_path)
1027 self._server_process.write('cat >%s\n' % self._in_fifo_path)
1028
1029 # Combine the stdout and stderr pipes into self._server_process.
1030 self._server_process.replace_outputs(self._read_stdout_process._proc.std out, self._read_stderr_process._proc.stdout)
1031
1032 def deadlock_detector(processes, normal_startup_event):
1033 if not ChromiumAndroidDriver._loop_with_timeout(lambda: normal_start up_event.is_set(), DRIVER_START_STOP_TIMEOUT_SECS):
1034 # If normal_startup_event is not set in time, the main thread mu st be blocked at
1035 # reading/writing the fifo. Kill the fifo reading/writing proces ses to let the
1036 # main thread escape from the deadlocked state. After that, the main thread will
1037 # treat this as a crash.
1038 self._log_error('Deadlock detected. Processes killed.')
1039 for i in processes:
1040 i.kill()
1041
1042 # Start a thread to kill the pipe reading/writing processes on deadlock of the fifos during startup.
1043 normal_startup_event = threading.Event()
1044 threading.Thread(
1045 name='DeadlockDetector',
1046 target=deadlock_detector,
1047 args=([self._server_process, self._read_stdout_process, self._read_s tderr_process], normal_startup_event)).start()
1048
1049 # The test driver might crash during startup or when the deadlock detect or hits
1050 # a deadlock and kills the fifo reading/writing processes.
1051 if not self._wait_for_server_process_output(self._server_process, deadli ne, '#READY'): 1023 if not self._wait_for_server_process_output(self._server_process, deadli ne, '#READY'):
1052 return False 1024 return False
1053 1025
1054 # Inform the deadlock detector that the startup is successful without de adlock.
1055 normal_startup_event.set()
1056 self._log_debug("content_shell is ready") 1026 self._log_debug("content_shell is ready")
1057 return True 1027 return True
1058 1028
1029 def _create_device_crash_dumps_directory(self):
1030 self._device.RunShellCommand(
1031 ['rm', '-rf', self._driver_details.device_crash_dumps_directory()],
1032 check_return=True)
1033 self._device.RunShellCommand(
1034 ['mkdir', self._driver_details.device_crash_dumps_directory()],
1035 check_return=True)
1036 self._device.RunShellCommand(
1037 ['chmod', '-R', '777', self._driver_details.device_crash_dumps_direc tory()],
1038 check_return=True)
1039
1040 def _start_netcat(self, server_name, first_port=FIRST_NETCAT_PORT, read_from _stdin=True):
1041 for i in itertools.count(first_port, 65536):
1042 nc_cmd = ['nc', '-l', str(i)]
1043 if not read_from_stdin:
1044 nc_cmd.append('-d')
1045 proc = self._port.server_process_constructor(self._port, server_name , nc_cmd)
1046 proc.start()
1047 self._port.host.executive.wait_limited(proc.pid(), limit_in_seconds= 1)
1048 if self._port.host.executive.check_running_pid(proc.pid()):
1049 return (proc, i)
1050
1051 raise Exception(
1052 'Unable to find a port for netcat process %s' % server_name)
1053
1054 def _replace_server_process_streams(self):
1055 # pylint: disable=protected-access
1056 self._server_process.replace_input(
1057 self._write_stdin_process._proc.stdin)
1058 self._server_process.replace_outputs(
1059 self._read_stdout_process._proc.stdout,
1060 self._read_stderr_process._proc.stdout)
1061
1059 def _pid_on_target(self): 1062 def _pid_on_target(self):
1060 pids = self._device.GetPids(self._driver_details.package_name()) 1063 pids = self._device.GetPids(self._driver_details.package_name())
1061 return pids.get(self._driver_details.package_name()) 1064 return pids.get(self._driver_details.package_name())
1062 1065
1063 def stop(self): 1066 def stop(self):
1064 if not self._device_failed: 1067 if not self._device_failed:
1065 # Do not try to stop the application if there's something wrong with the device; adb may hang. 1068 # Do not try to stop the application if there's something wrong with the device; adb may hang.
1066 # FIXME: crbug.com/305040. Figure out if it's really hanging (and wh y). 1069 # FIXME: crbug.com/305040. Figure out if it's really hanging (and wh y).
1067 self._device.ForceStop(self._driver_details.package_name()) 1070 self._device.ForceStop(self._driver_details.package_name())
1068 1071
1072 if self._write_stdin_process:
1073 self._write_stdin_process.kill()
1074 self._write_stdin_process = None
1075
1069 if self._read_stdout_process: 1076 if self._read_stdout_process:
1070 self._read_stdout_process.kill() 1077 self._read_stdout_process.kill()
1071 self._read_stdout_process = None 1078 self._read_stdout_process = None
1072 1079
1073 if self._read_stderr_process: 1080 if self._read_stderr_process:
1074 self._read_stderr_process.kill() 1081 self._read_stderr_process.kill()
1075 self._read_stderr_process = None 1082 self._read_stderr_process = None
1076 1083
1077 # We delay importing forwarder as long as possible because it uses fcntl , 1084 # We delay importing forwarder as long as possible because it uses fcntl ,
1078 # which isn't available on windows. 1085 # which isn't available on windows.
1079 from devil.android import forwarder 1086 from devil.android import forwarder
1080 1087
1081 forwarder.Forwarder.KillDevice(self._device) 1088 forwarder.Forwarder.KillDevice(self._device)
1082 forwarder.Forwarder.KillHost() 1089 forwarder.Forwarder.KillHost()
1083 1090
1084 super(ChromiumAndroidDriver, self).stop() 1091 super(ChromiumAndroidDriver, self).stop()
1085 1092
1086 if self._android_devices.is_device_prepared(self._device.serial):
1087 if not ChromiumAndroidDriver._loop_with_timeout(self._remove_all_pip es, DRIVER_START_STOP_TIMEOUT_SECS):
1088 self._abort('Failed to remove fifo files. May be locked.')
1089
1090 self._clean_up_cmd_line() 1093 self._clean_up_cmd_line()
1091 1094
1092 def _pull_crash_dumps_from_device(self): 1095 def _pull_crash_dumps_from_device(self):
1093 result = [] 1096 result = []
1094 if not self._device.PathExists(self._driver_details.device_crash_dumps_d irectory()): 1097 if not self._device.PathExists(self._driver_details.device_crash_dumps_d irectory()):
1095 return result 1098 return result
1096 dumps = self._device.ListDirectory( 1099 dumps = self._device.ListDirectory(
1097 self._driver_details.device_crash_dumps_directory()) 1100 self._driver_details.device_crash_dumps_directory())
1098 for dump in dumps: 1101 for dump in dumps:
1099 device_dump = '%s/%s' % (self._driver_details.device_crash_dumps_dir ectory(), dump) 1102 device_dump = '%s/%s' % (self._driver_details.device_crash_dumps_dir ectory(), dump)
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after
1140 return command 1143 return command
1141 1144
1142 def _read_prompt(self, deadline): 1145 def _read_prompt(self, deadline):
1143 last_char = '' 1146 last_char = ''
1144 while True: 1147 while True:
1145 current_char = self._server_process.read_stdout(deadline, 1) 1148 current_char = self._server_process.read_stdout(deadline, 1)
1146 if current_char == ' ': 1149 if current_char == ' ':
1147 if last_char in ('#', '$'): 1150 if last_char in ('#', '$'):
1148 return 1151 return
1149 last_char = current_char 1152 last_char = current_char
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698