| OLD | NEW |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 |
| OLD | NEW |