Make Chromium port for Android use hardware gpu path default.
[WebKit-https.git] / Tools / Scripts / webkitpy / layout_tests / port / chromium_android.py
1 #!/usr/bin/env python
2 # Copyright (C) 2012 Google Inc. All rights reserved.
3 #
4 # Redistribution and use in source and binary forms, with or without
5 # modification, are permitted provided that the following conditions are
6 # met:
7 #
8 #     * Redistributions of source code must retain the above copyright
9 # notice, this list of conditions and the following disclaimer.
10 #     * Redistributions in binary form must reproduce the above
11 # copyright notice, this list of conditions and the following disclaimer
12 # in the documentation and/or other materials provided with the
13 # distribution.
14 #     * Neither the name of Google Inc. nor the names of its
15 # contributors may be used to endorse or promote products derived from
16 # this software without specific prior written permission.
17 #
18 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21 # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22 # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23 # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24 # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29
30 import logging
31 import re
32 import signal
33 import time
34
35 from webkitpy.layout_tests.port import base
36 from webkitpy.layout_tests.port import chromium
37 from webkitpy.layout_tests.port import factory
38
39
40 _log = logging.getLogger(__name__)
41
42
43 # The root directory for test resources, which has the same structure as the
44 # source root directory of Chromium.
45 # This path is defined in base/base_paths_android.cc and
46 # webkit/support/platform_support_android.cc.
47 DEVICE_SOURCE_ROOT_DIR = '/data/local/tmp/'
48
49 DEVICE_DRT_DIR = '/data/drt/'
50 DEVICE_DRT_PATH = DEVICE_DRT_DIR + 'DumpRenderTree'
51 DEVICE_DRT_STDERR = DEVICE_DRT_DIR + 'DumpRenderTree.stderr'
52 DEVICE_FORWARDER_PATH = DEVICE_DRT_DIR + 'forwarder'
53 DEVICE_DRT_STAMP_PATH = DEVICE_DRT_DIR + 'DumpRenderTree.stamp'
54
55 # This only works for single core devices so far.
56 # FIXME: Find a solution for multi-core devices.
57 SCALING_GOVERNOR = "/sys/devices/system/cpu/cpu0/cpufreq/scaling_governor"
58
59 # All the test cases are still served to DumpRenderTree through file protocol,
60 # but we use a file-to-http feature to bridge the file request to host's http
61 # server to get the real test files and corresponding resources.
62 TEST_PATH_PREFIX = '/all-tests'
63
64 # All ports the Android forwarder to forward.
65 # 8000, 8080 and 8443 are for http/https tests.
66 # 8880 and 9323 are for websocket tests
67 # (see http_server.py, apache_http_server.py and websocket_server.py).
68 FORWARD_PORTS = '8000 8080 8443 8880 9323'
69
70 MS_TRUETYPE_FONTS_DIR = '/usr/share/fonts/truetype/msttcorefonts/'
71
72 # List of fonts that layout tests expect, copied from DumpRenderTree/gtk/TestShellGtk.cpp.
73 HOST_FONT_FILES = [
74     [MS_TRUETYPE_FONTS_DIR, 'Arial.ttf'],
75     [MS_TRUETYPE_FONTS_DIR, 'Arial_Bold.ttf'],
76     [MS_TRUETYPE_FONTS_DIR, 'Arial_Bold_Italic.ttf'],
77     [MS_TRUETYPE_FONTS_DIR, 'Arial_Italic.ttf'],
78     [MS_TRUETYPE_FONTS_DIR, 'Comic_Sans_MS.ttf'],
79     [MS_TRUETYPE_FONTS_DIR, 'Comic_Sans_MS_Bold.ttf'],
80     [MS_TRUETYPE_FONTS_DIR, 'Courier_New.ttf'],
81     [MS_TRUETYPE_FONTS_DIR, 'Courier_New_Bold.ttf'],
82     [MS_TRUETYPE_FONTS_DIR, 'Courier_New_Bold_Italic.ttf'],
83     [MS_TRUETYPE_FONTS_DIR, 'Courier_New_Italic.ttf'],
84     [MS_TRUETYPE_FONTS_DIR, 'Georgia.ttf'],
85     [MS_TRUETYPE_FONTS_DIR, 'Georgia_Bold.ttf'],
86     [MS_TRUETYPE_FONTS_DIR, 'Georgia_Bold_Italic.ttf'],
87     [MS_TRUETYPE_FONTS_DIR, 'Georgia_Italic.ttf'],
88     [MS_TRUETYPE_FONTS_DIR, 'Impact.ttf'],
89     [MS_TRUETYPE_FONTS_DIR, 'Trebuchet_MS.ttf'],
90     [MS_TRUETYPE_FONTS_DIR, 'Trebuchet_MS_Bold.ttf'],
91     [MS_TRUETYPE_FONTS_DIR, 'Trebuchet_MS_Bold_Italic.ttf'],
92     [MS_TRUETYPE_FONTS_DIR, 'Trebuchet_MS_Italic.ttf'],
93     [MS_TRUETYPE_FONTS_DIR, 'Times_New_Roman.ttf'],
94     [MS_TRUETYPE_FONTS_DIR, 'Times_New_Roman_Bold.ttf'],
95     [MS_TRUETYPE_FONTS_DIR, 'Times_New_Roman_Bold_Italic.ttf'],
96     [MS_TRUETYPE_FONTS_DIR, 'Times_New_Roman_Italic.ttf'],
97     [MS_TRUETYPE_FONTS_DIR, 'Verdana.ttf'],
98     [MS_TRUETYPE_FONTS_DIR, 'Verdana_Bold.ttf'],
99     [MS_TRUETYPE_FONTS_DIR, 'Verdana_Bold_Italic.ttf'],
100     [MS_TRUETYPE_FONTS_DIR, 'Verdana_Italic.ttf'],
101     # The Microsoft font EULA
102     ['/usr/share/doc/ttf-mscorefonts-installer/', 'READ_ME!.gz'],
103     ['/usr/share/fonts/truetype/ttf-dejavu/', 'DejaVuSans.ttf'],
104 ]
105 # Should increase this version after changing HOST_FONT_FILES.
106 FONT_FILES_VERSION = 1
107
108 DEVICE_FONTS_DIR = DEVICE_DRT_DIR + 'fonts/'
109 DEVICE_FIRST_FALLBACK_FONT = '/system/fonts/DroidNaskh-Regular.ttf'
110
111 # The layout tests directory on device, which has two usages:
112 # 1. as a virtual path in file urls that will be bridged to HTTP.
113 # 2. pointing to some files that are pushed to the device for tests that
114 # don't work on file-over-http (e.g. blob protocol tests).
115 DEVICE_LAYOUT_TESTS_DIR = (DEVICE_SOURCE_ROOT_DIR + 'third_party/WebKit/LayoutTests/')
116 FILE_TEST_URI_PREFIX = 'file://' + DEVICE_LAYOUT_TESTS_DIR
117
118 # Test resources that need to be accessed as files directly.
119 # Each item can be the relative path of a directory or a file.
120 TEST_RESOURCES_TO_PUSH = [
121     # Blob tests need to access files directly.
122     'editing/pasteboard/resources',
123     'fast/files/resources',
124     'http/tests/local/resources',
125     'http/tests/local/formdata/resources',
126     # User style URLs are accessed as local files in webkit_support.
127     'http/tests/security/resources/cssStyle.css',
128     # Media tests need to access audio/video as files.
129     'media/content',
130     'compositing/resources/video.mp4',
131 ]
132
133
134 class ChromiumAndroidPort(chromium.ChromiumPort):
135     port_name = 'chromium-android'
136
137     FALLBACK_PATHS = [
138         'chromium-android',
139         'chromium-linux',
140         'chromium-win',
141         'chromium',
142         'win',
143         'mac',
144     ]
145
146     def __init__(self, host, port_name, **kwargs):
147         chromium.ChromiumPort.__init__(self, host, port_name, **kwargs)
148
149         # The Chromium port for Android always uses the hardware GPU path.
150         self._options.enable_hardware_gpu = True
151
152         self._operating_system = 'android'
153         self._version = 'icecreamsandwich'
154         self._original_governor = None
155         self._android_base_dir = None
156
157         self._host_port = factory.PortFactory(host).get('chromium', **kwargs)
158
159         self._adb_command = ['adb']
160         adb_args = self.get_option('adb_args')
161         if adb_args:
162             self._adb_command += shlex.split(adb_args)
163         self._drt_retry_after_killed = 0
164
165     def default_test_timeout_ms(self):
166         # Android platform has less computing power than desktop platforms.
167         # Using 10 seconds allows us to pass most slow tests which are not
168         # marked as slow tests on desktop platforms.
169         return 10 * 1000
170
171     def default_child_processes(self):
172         # Currently we only use one process, but it might be helpful to use
173         # more that one process in the future to improve performance.
174         return 1
175
176     def baseline_search_path(self):
177         return map(self._webkit_baseline_path, self.FALLBACK_PATHS)
178
179     def check_build(self, needs_http):
180         return self._host_port.check_build(needs_http)
181
182     def check_sys_deps(self, needs_http):
183         for (font_dir, font_file) in HOST_FONT_FILES:
184             font_path = font_dir + font_file
185             if not self._check_file_exists(font_path, 'font file'):
186                 _log.error('You are missing %s. Try installing msttcorefonts. '
187                            'See build instructions.' % font_path)
188                 return False
189         return True
190
191     def test_expectations(self):
192         # Automatically apply all expectation rules of chromium-linux to
193         # chromium-android.
194         # FIXME: This is a temporary measure to reduce the manual work when
195         # updating WebKit. This method should be removed when we merge
196         # test_expectations_android.txt into test_expectations.txt.
197         expectations = chromium.ChromiumPort.test_expectations(self)
198         return expectations.replace('LINUX ', 'LINUX ANDROID ')
199
200     def start_http_server(self, additional_dirs=None):
201         # The http server runs during the whole testing period, so ignore this call.
202         pass
203
204     def stop_http_server(self):
205         # Same as start_http_server().
206         pass
207
208     def start_helper(self):
209         self._setup_performance()
210         # Required by webkit_support::GetWebKitRootDirFilePath().
211         # Other directories will be created automatically by adb push.
212         self._run_adb_command(['shell', 'mkdir', '-p',
213                                DEVICE_SOURCE_ROOT_DIR + 'chrome'])
214
215         self._push_executable()
216         self._push_fonts()
217         self._setup_system_font_for_test()
218         self._synchronize_datetime()
219
220         # Start the HTTP server so that the device can access the test cases.
221         chromium.ChromiumPort.start_http_server(self, additional_dirs={TEST_PATH_PREFIX: self.layout_tests_dir()})
222
223         _log.debug('Starting forwarder')
224         cmd = self._run_adb_command(['shell', '%s %s' % (DEVICE_FORWARDER_PATH, FORWARD_PORTS)])
225
226     def stop_helper(self):
227         self._restore_system_font()
228         # Leave the forwarder and tests httpd server there because they are
229         # useful for debugging and do no harm to subsequent tests.
230         self._teardown_performance()
231
232     def skipped_tests(self, test_list):
233         return base.Port._real_tests(self, [
234             # Canvas tests are run as virtual gpu tests.
235             'fast/canvas',
236             'canvas/philip',
237         ])
238
239     def _build_path(self, *comps):
240         return self._host_port._build_path(*comps)
241
242     def _path_to_apache(self):
243         return self._host_port._path_to_apache()
244
245     def _path_to_apache_config_file(self):
246         return self._host_port._path_to_apache_config_file()
247
248     def _path_to_driver(self, configuration=None):
249         # Returns the host path to driver which will be pushed to the device.
250         if not configuration:
251             configuration = self.get_option('configuration')
252         return self._build_path(configuration, 'DumpRenderTree')
253
254     def _path_to_helper(self):
255         return self._build_path(self.get_option('configuration'), 'forwarder')
256
257     def _path_to_image_diff(self):
258         return self._host_port._path_to_image_diff()
259
260     def _path_to_lighttpd(self):
261         return self._host_port._path_to_lighttpd()
262
263     def _path_to_lighttpd_modules(self):
264         return self._host_port._path_to_lighttpd_modules()
265
266     def _path_to_lighttpd_php(self):
267         return self._host_port._path_to_lighttpd_php()
268
269     def _path_to_wdiff(self):
270         return self._host_port._path_to_wdiff()
271
272     def _shut_down_http_server(self, pid):
273         return self._host_port._shut_down_http_server(pid)
274
275     def _driver_class(self):
276         return ChromiumAndroidDriver
277
278     def _push_executable(self):
279         drt_host_path = self._path_to_driver()
280         forwarder_host_path = self._path_to_helper()
281         drt_jar_host_path = drt_host_path + '.jar'
282         host_stamp = int(float(max(os.stat(drt_host_path).st_mtime,
283                                    os.stat(forwarder_host_path).st_mtime,
284                                    os.stat(drt_jar_host_path).st_mtime)))
285         device_stamp = int(float(self._run_adb_command([
286             'shell', 'cat %s 2>/dev/null || echo 0' % DEVICE_DRT_STAMP_PATH])))
287         if device_stamp < host_stamp:
288             _log.debug('Pushing executable')
289             self._kill_device_process(DEVICE_FORWARDER_PATH)
290             self._push_to_device(forwarder_host_path, DEVICE_FORWARDER_PATH)
291             self._push_to_device(drt_host_path, DEVICE_DRT_PATH)
292             self._push_to_device(drt_host_path + '.pak', DEVICE_DRT_PATH + '.pak')
293             self._push_to_device(drt_host_path + '_resources', DEVICE_DRT_PATH + '_resources')
294             self._push_to_device(drt_jar_host_path, DEVICE_DRT_PATH + '.jar')
295             # Version control of test resources is dependent on executables,
296             # because we will always rebuild executables when resources are
297             # updated.
298             self._push_test_resources()
299             self._run_adb_command(['shell', 'echo %d >%s' % (host_stamp, DEVICE_DRT_STAMP_PATH)])
300
301     def _push_fonts(self):
302         if not self._check_version(DEVICE_FONTS_DIR, FONT_FILES_VERSION):
303             _log.debug('Pushing fonts')
304             path_to_ahem_font = self._build_path(self.get_option('configuration'), 'AHEM____.TTF')
305             self._push_to_device(path_to_ahem_font, DEVICE_FONTS_DIR + 'AHEM____.TTF')
306             for (host_dir, font_file) in HOST_FONT_FILES:
307                 self._push_to_device(host_dir + font_file, DEVICE_FONTS_DIR + font_file)
308             self._update_version(DEVICE_FONTS_DIR, FONT_FILES_VERSION)
309
310     def _setup_system_font_for_test(self):
311         # The DejaVu font implicitly used by some CSS 2.1 tests should be added
312         # into the font fallback list of the system. DroidNaskh-Regular.ttf is
313         # the first font in Android Skia's font fallback list. Fortunately the
314         # DejaVu font also contains Naskh glyphs.
315         # First remount /system in read/write mode.
316         self._run_adb_command(['remount'])
317         self._copy_device_file(DEVICE_FONTS_DIR + 'DejaVuSans.ttf', DEVICE_FIRST_FALLBACK_FONT)
318
319     def _restore_system_font(self):
320         # First remount /system in read/write mode.
321         self._run_adb_command(['remount'])
322         self._push_to_device(os.environ['OUT'] + DEVICE_FIRST_FALLBACK_FONT, DEVICE_FIRST_FALLBACK_FONT)
323
324     def _push_test_resources(self):
325         _log.debug('Pushing test resources')
326         for resource in TEST_RESOURCES_TO_PUSH:
327             self._push_to_device(self.layout_tests_dir() + '/' + resource, DEVICE_LAYOUT_TESTS_DIR + resource)
328
329     def _synchronize_datetime(self):
330         # The date/time between host and device may not be synchronized.
331         # We need to make them synchronized, otherwise tests might fail.
332         try:
333             # Get seconds since 1970-01-01 00:00:00 UTC.
334             host_datetime = self._executive.run_command(['date', '-u', '+%s'])
335         except:
336             # Reset to 1970-01-01 00:00:00 UTC.
337             host_datetime = 0
338         self._run_adb_command(['shell', 'date -u %s' % (host_datetime)])
339
340     def _check_version(self, dir, version):
341         assert(dir.endswith('/'))
342         try:
343             device_version = int(self._run_adb_command(['shell', 'cat %sVERSION || echo 0' % dir]))
344             return device_version == version
345         except:
346             return False
347
348     def _update_version(self, dir, version):
349         self._run_adb_command(['shell', 'echo %d > %sVERSION' % (version, dir)])
350
351     def _run_adb_command(self, cmd, ignore_error=False):
352         if ignore_error:
353             error_handler = self._executive.ignore_error
354         else:
355             error_handler = None
356         return self._executive.run_command(self._adb_command + cmd, error_handler=error_handler)
357
358     def _copy_device_file(self, from_file, to_file, ignore_error=False):
359         # 'cp' is unavailable on Android, so use 'dd' instead.
360         return self._run_adb_command(['shell', 'dd', 'if=' + from_file, 'of=' + to_file], ignore_error)
361
362     def _push_to_device(self, host_path, device_path, ignore_error=False):
363         return self._run_adb_command(['push', host_path, device_path], ignore_error)
364
365     def _pull_from_device(self, device_path, host_path, ignore_error=False):
366         return self._run_adb_command(['pull', device_path, host_path], ignore_error)
367
368     def _kill_device_process(self, name):
369         ps_result = self._run_adb_command(['shell', 'ps']).split('\n')
370         for line in ps_result:
371             if line.find(name) > 0:
372                 pid = line.split()[1]
373                 self._run_adb_command(['shell', 'kill', pid])
374
375     def get_stderr(self):
376         return self._run_adb_command(['shell', 'cat', DEVICE_DRT_STDERR], ignore_error=True)
377
378     def get_last_stacktrace(self):
379         tombstones = self._run_adb_command(['shell', 'ls', '-n', '/data/tombstones'])
380         if not tombstones:
381             _log.error('DRT crashed, but no tombstone found!')
382             return ''
383         tombstones = tombstones.rstrip().split('\n')
384         last_tombstone = tombstones[0].split()
385         for tombstone in tombstones[1:]:
386             # Format of fields:
387             # 0          1      2      3     4          5     6
388             # permission uid    gid    size  date       time  filename
389             # -rw------- 1000   1000   45859 2011-04-13 06:00 tombstone_00
390             fields = tombstone.split()
391             if (fields[4] + fields[5] >= last_tombstone[4] + last_tombstone[5]):
392                 last_tombstone = fields
393             else:
394                 break
395
396         # Use Android tool vendor/google/tools/stack to convert the raw
397         # stack trace into a human readable format, if needed.
398         # It takes a long time, so don't do it here.
399         return self._run_adb_command(['shell', 'cat', '/data/tombstones/' + last_tombstone[6]])
400
401     def _setup_performance(self):
402         # Disable CPU scaling and drop ram cache to reduce noise in tests
403         if not self._original_governor:
404             self._original_governor = self._run_adb_command(['shell', 'cat', SCALING_GOVERNOR])
405             self._run_adb_command(['shell', 'echo', 'performance', '>', SCALING_GOVERNOR])
406
407     def _teardown_performance(self):
408         if self._original_governor:
409             self._run_adb_command(['shell', 'echo', self._original_governor, SCALING_GOVERNOR])
410         self._original_governor = None
411
412
413 class ChromiumAndroidDriver(chromium.ChromiumDriver):
414     def __init__(self, port, worker_number, pixel_tests, no_timeout=False):
415         chromium.ChromiumDriver.__init__(self, port, worker_number, pixel_tests, no_timeout)
416         self._device_image_path = None
417         self._drt_return_parser = re.compile('#DRT_RETURN (\d+)')
418
419     def _start(self, pixel_tests, per_test_args):
420         # Convert the original command line into to two parts:
421         # - the 'adb shell' command line to start an interactive adb shell;
422         # - the DumpRenderTree command line to send to the adb shell.
423         original_cmd = self.cmd_line(pixel_tests, per_test_args)
424         shell_cmd = []
425         drt_args = []
426         path_to_driver = self._port._path_to_driver()
427         reading_args_before_driver = True
428         for param in original_cmd:
429             if reading_args_before_driver:
430                 if param == path_to_driver:
431                     reading_args_before_driver = False
432                 else:
433                     shell_cmd.append(param)
434             else:
435                 if param.startswith('--pixel-tests='):
436                     if not self._device_image_path:
437                         self._device_image_path = DEVICE_DRT_DIR + self._port.host.filesystem.basename(self._image_path)
438                     param = '--pixel-tests=' + self._device_image_path
439                 drt_args.append(param)
440
441         shell_cmd += self._port._adb_command
442         shell_cmd.append('shell')
443         retries = 0
444         while True:
445             _log.debug('Starting adb shell for DumpRenderTree: ' + ' '.join(shell_cmd))
446             executive = self._port.host.executive
447             self._proc = executive.popen(shell_cmd, stdin=executive.PIPE, stdout=executive.PIPE, stderr=executive.STDOUT,
448                                          close_fds=True, universal_newlines=True)
449             # Read back the shell prompt to ensure adb shell ready.
450             self._read_prompt()
451             # Some tests rely on this to produce proper number format etc.,
452             # e.g. fast/speech/input-appearance-numberandspeech.html.
453             self._write_command_and_read_line("export LC_CTYPE='en_US'\n")
454             self._write_command_and_read_line("export CLASSPATH='/data/drt/DumpRenderTree.jar'\n")
455
456             # When DumpRenderTree crashes, the Android debuggerd will stop the
457             # process before dumping stack to log/tombstone file and terminating
458             # the process. Sleep 1 second (long enough for debuggerd to dump
459             # stack) before exiting the shell to ensure the process has quit,
460             # otherwise the exit will fail because "You have stopped jobs".
461             drt_cmd = '%s %s 2>%s;echo "#DRT_RETURN $?";sleep 1;exit\n' % (DEVICE_DRT_PATH, ' '.join(drt_args), DEVICE_DRT_STDERR)
462             _log.debug('Starting DumpRenderTree: ' + drt_cmd)
463
464             # Wait until DRT echos '#READY'.
465             output = ''
466             (line, crash) = self._write_command_and_read_line(drt_cmd)
467             while not crash and line.rstrip() != '#READY':
468                 if line == '':  # EOF or crashed
469                     crash = True
470                 else:
471                     output += line
472                     (line, crash) = self._write_command_and_read_line()
473
474             if crash:
475                 # Sometimes the device is in unstable state (may be out of
476                 # memory?) and kills DumpRenderTree just after it is started.
477                 # Try to stop and start it again.
478                 _log.error('Failed to start DumpRenderTree: \n%s\n%s\n' % (output, self._port.get_stderr()))
479                 self.stop()
480                 retries += 1
481                 if retries > 2:
482                     raise AssertionError('Failed multiple times to start DumpRenderTree')
483             else:
484                 return
485
486     def run_test(self, driver_input):
487         driver_output = chromium.ChromiumDriver.run_test(self, driver_input)
488
489         drt_return = self._get_drt_return_value(driver_output.error)
490         if drt_return is not None:
491             _log.debug('DumpRenderTree return value: %d' % drt_return)
492         # FIXME: Retrieve stderr from the target.
493         if driver_output.crash:
494             # When Android is OOM, it sends a SIGKILL signal to DRT. DRT
495             # is stopped silently and regarded as crashed. Re-run the test for
496             # such crash.
497             if drt_return == 128 + signal.SIGKILL:
498                 self._port._drt_retry_after_killed += 1
499                 if self._port._drt_retry_after_killed > 10:
500                     raise AssertionError('DumpRenderTree is killed by Android for too many times!')
501                 _log.error('DumpRenderTree is killed by SIGKILL. Retry the test (%d).' % self._port._drt_retry_after_killed)
502                 self.stop()
503                 # Sleep 10 seconds to let system recover.
504                 time.sleep(10)
505                 return self.run_test(driver_input)
506             # Fetch the stack trace from the tombstone file.
507             # FIXME: sometimes the crash doesn't really happen so that no
508             # tombstone is generated. In that case we fetch the wrong stack
509             # trace.
510             driver_output.error += self._port.get_last_stacktrace().encode('ascii', 'ignore')
511             driver_output.error += self._port._run_adb_command(['logcat', '-d']).encode('ascii', 'ignore')
512         return driver_output
513
514     def stop(self):
515         _log.debug('Stopping DumpRenderTree')
516         if self._proc:
517             # Send an explicit QUIT command because closing the pipe can't let
518             # DumpRenderTree on Android quit immediately.
519             try:
520                 self._proc.stdin.write('QUIT\n')
521             except IOError:
522                 # The pipe has already been closed, indicating abnormal
523                 # situation occurred. Wait a while to allow the device to
524                 # recover. *fingers crossed*
525                 time.sleep(1)
526         chromium.ChromiumDriver.stop(self)
527
528     def _test_shell_command(self, uri, timeout_ms, checksum):
529         if uri.startswith('file:///'):
530             # Convert the host uri to a device uri. See comment of
531             # DEVICE_LAYOUT_TESTS_DIR for details.
532             # Not overriding Port.filename_to_uri() because we don't want the
533             # links in the html report point to device paths.
534             uri = FILE_TEST_URI_PREFIX + self.uri_to_test(uri)
535         return chromium.ChromiumDriver._test_shell_command(self, uri, timeout_ms, checksum)
536
537     def _write_command_and_read_line(self, input=None):
538         (line, crash) = chromium.ChromiumDriver._write_command_and_read_line(self, input)
539         url_marker = '#URL:'
540         if not crash and line.startswith(url_marker) and line.find(FILE_TEST_URI_PREFIX) == len(url_marker):
541             # Convert the device test uri back to host uri otherwise
542             # chromium.ChromiumDriver.run_test() will complain.
543             line = '#URL:file://%s/%s' % (self._port.layout_tests_dir(), line[len(url_marker) + len(FILE_TEST_URI_PREFIX):])
544         if not crash and self._has_crash_hint(line):
545             crash = True
546         return (line, crash)
547
548     def _output_image(self):
549         if self._image_path:
550             _log.debug('pulling from device: %s to %s' % (self._device_image_path, self._image_path))
551             self._port._pull_from_device(self._device_image_path, self._image_path, ignore_error=True)
552         return chromium.ChromiumDriver._output_image(self)
553
554     def _has_crash_hint(self, line):
555         # When DRT crashes, it sends a signal to Android Debuggerd, like
556         # SIGSEGV, SIGFPE, etc. When Debuggerd receives the signal, it stops DRT
557         # (which causes Shell to output a message), and dumps the stack strace.
558         # We use the Shell output as a crash hint.
559         return line is not None and line.find('[1] + Stopped (signal)') >= 0
560
561     def _get_drt_return_value(self, error):
562         return_match = self._drt_return_parser.search(error)
563         return None if (return_match is None) else int(return_match.group(1))
564
565     def _read_prompt(self):
566         last_char = ''
567         while True:
568             current_char = self._proc.stdout.read(1)
569             if current_char == ' ':
570                 if last_char == '#':
571                     return
572                 if last_char == '$':
573                     raise AssertionError('Adbd is not running as root')
574             last_char = current_char