0

Add Android support to breakpad_integration_test.py and update docs

Bug: crashpad:30
Change-Id: Id8ecfacafb2ea69fc254157c0ea2c9600440693f
Reviewed-on: https://chromium-review.googlesource.com/c/1157685
Commit-Queue: Joshua Peraza <jperaza@chromium.org>
Reviewed-by: Peter Beverloo <peter@chromium.org>
Cr-Commit-Position: refs/heads/master@{#631268}
This commit is contained in:
Joshua Peraza
2019-02-12 16:55:14 +00:00
committed by Commit Bot
parent 6a11499014
commit 6f96b9d264
3 changed files with 119 additions and 47 deletions

@ -25,17 +25,64 @@ CONCURRENT_TASKS=4
BREAKPAD_TOOLS_DIR = os.path.join(
os.path.dirname(__file__), '..', '..', '..',
'components', 'crash', 'content', 'tools')
ANDROID_CRASH_DIR = '/data/local/tmp/crashes'
def run_test(options, crash_dir, symbols_dir, additional_arguments = []):
def build_is_android(build_dir):
return os.path.isfile(os.path.join(build_dir, 'bin', 'content_shell_apk'))
def android_crash_dir_exists():
proc = subprocess.Popen(['adb', 'shell', 'ls', ANDROID_CRASH_DIR],
stdout=subprocess.PIPE, stderr=subprocess.PIPE)
[stdout, stderr] = proc.communicate()
not_found = 'No such file or directory'
return not_found not in stdout and not_found not in stderr
def get_android_dump(crash_dir):
global failure
print "# Run content_shell and make it crash."
cmd = [options.binary,
'--run-web-tests',
'chrome://crash',
'--enable-crash-reporter',
'--crash-dumps-dir=%s' % crash_dir]
cmd += additional_arguments
pending = ANDROID_CRASH_DIR + '/pending/'
for attempts in range(5):
proc = subprocess.Popen(
['adb', 'shell', 'ls', pending + '*.dmp'],
stdout=subprocess.PIPE, stderr=subprocess.PIPE)
dumps = [f for f in map(str.strip, proc.communicate()[0].split('\n'))
if f.endswith('.dmp')]
if len(dumps) > 0:
break
# Crashpad may still be writing the dump. Sleep and try again.
time.sleep(1)
if len(dumps) != 1:
failure = 'Expected 1 crash dump, found %d.' % len(dumps)
print dumps
raise Exception(failure)
subprocess.check_call(['adb', 'pull', dumps[0], crash_dir])
subprocess.check_call(['adb', 'shell', 'rm', pending + '*'])
return os.path.join(crash_dir, os.path.basename(dumps[0]))
def run_test(options, crash_dir, symbols_dir, platform,
additional_arguments = []):
global failure
print '# Run content_shell and make it crash.'
if platform == 'android':
cmd = [os.path.join(options.build_dir, 'bin', 'content_shell_apk'),
'launch',
'chrome://crash',
'--args=--enable-crash-reporter --crash-dumps-dir=%s ' %
ANDROID_CRASH_DIR + ' '.join(additional_arguments)]
else:
cmd = [options.binary,
'--run-web-tests',
'chrome://crash',
'--enable-crash-reporter',
'--crash-dumps-dir=%s' % crash_dir]
cmd += additional_arguments
if options.verbose:
print ' '.join(cmd)
failure = 'Failed to run content_shell.'
@ -47,21 +94,25 @@ def run_test(options, crash_dir, symbols_dir, additional_arguments = []):
with tempfile.TemporaryFile() as tmpfile:
subprocess.check_call(cmd, stdout=tmpfile, stderr=tmpfile)
print "# Retrieve crash dump."
dmp_dir = crash_dir
# TODO(crbug.com/782923): This test should not reach directly into the
# Crashpad database, but instead should use crashpad_database_util.
if sys.platform == 'darwin':
dmp_dir = os.path.join(dmp_dir, 'pending')
elif sys.platform == 'win32':
dmp_dir = os.path.join(dmp_dir, 'reports')
dmp_files = glob.glob(os.path.join(dmp_dir, '*.dmp'))
failure = 'Expected 1 crash dump, found %d.' % len(dmp_files)
if len(dmp_files) != 1:
raise Exception(failure)
dmp_file = dmp_files[0]
print '# Retrieve crash dump.'
if platform == 'android':
dmp_file = get_android_dump(crash_dir)
else:
dmp_dir = crash_dir
# TODO(crbug.com/782923): This test should not reach directly into the
# Crashpad database, but instead should use crashpad_database_util.
if platform == 'darwin':
dmp_dir = os.path.join(dmp_dir, 'pending')
elif platform == 'win32':
dmp_dir = os.path.join(dmp_dir, 'reports')
if sys.platform not in ('darwin', 'win32'):
dmp_files = glob.glob(os.path.join(dmp_dir, '*.dmp'))
failure = 'Expected 1 crash dump, found %d.' % len(dmp_files)
if len(dmp_files) != 1:
raise Exception(failure)
dmp_file = dmp_files[0]
if platform not in ('darwin', 'win32', 'android'):
minidump = os.path.join(crash_dir, 'minidump')
dmp_to_minidump = os.path.join(BREAKPAD_TOOLS_DIR, 'dmp2minidump.py')
cmd = [dmp_to_minidump, dmp_file, minidump]
@ -72,8 +123,8 @@ def run_test(options, crash_dir, symbols_dir, additional_arguments = []):
else:
minidump = dmp_file
print "# Symbolize crash dump."
if sys.platform == 'win32':
print '# Symbolize crash dump.'
if platform == 'win32':
cdb_exe = os.path.join(options.build_dir, 'cdb', 'cdb.exe')
cmd = [cdb_exe, '-y', options.build_dir, '-c', '.lines;.excr;k30;q',
'-z', dmp_file]
@ -137,19 +188,30 @@ def main():
(options, _) = parser.parse_args()
if not options.build_dir:
print "Required option --build-dir missing."
print 'Required option --build-dir missing.'
return 1
if not options.binary:
print "Required option --binary missing."
print 'Required option --binary missing.'
return 1
if not os.access(options.binary, os.X_OK):
print "Cannot find %s." % options.binary
print 'Cannot find %s.' % options.binary
return 1
failure = ''
if build_is_android(options.build_dir):
platform = 'android'
if android_crash_dir_exists():
print 'Android crash dir exists %s' % ANDROID_CRASH_DIR
return 1
subprocess.check_call(['adb', 'shell', 'mkdir', ANDROID_CRASH_DIR])
else:
platform = sys.platform
# Create a temporary directory to store the crash dumps and symbols in.
crash_dir = tempfile.mkdtemp()
symbols_dir = os.path.join(crash_dir, 'symbols')
@ -157,8 +219,8 @@ def main():
crash_service = None
try:
if sys.platform != 'win32':
print "# Generate symbols."
if platform != 'win32':
print '# Generate symbols.'
bins = [options.binary]
if options.additional_binary:
bins.append(options.additional_binary)
@ -176,15 +238,15 @@ def main():
failure = 'Failed to run generate_breakpad_symbols.py.'
subprocess.check_call(cmd)
print "# Running test without trap handler."
run_test(options, crash_dir, symbols_dir)
print "# Running test with trap handler."
run_test(options, crash_dir, symbols_dir,
print '# Running test without trap handler.'
run_test(options, crash_dir, symbols_dir, platform)
print '# Running test with trap handler.'
run_test(options, crash_dir, symbols_dir, platform,
additional_arguments =
['--enable-features=WebAssemblyTrapHandler'])
except:
print "FAIL: %s" % failure
print 'FAIL: %s' % failure
if options.json:
with open(options.json, 'w') as json_file:
json.dump([failure], json_file)
@ -192,7 +254,7 @@ def main():
return 1
else:
print "PASS: Breakpad integration test ran successfully."
print 'PASS: Breakpad integration test ran successfully.'
if options.json:
with open(options.json, 'w') as json_file:
json.dump([], json_file)
@ -206,6 +268,11 @@ def main():
shutil.rmtree(crash_dir)
except:
print 'Failed to delete temp directory "%s".' % crash_dir
if platform == 'android':
try:
subprocess.check_call(['adb', 'shell', 'rm', '-rf', ANDROID_CRASH_DIR])
except:
print 'Failed to delete android crash dir %s' % ANDROID_CRASH_DIR
if '__main__' == __name__:

@ -163,7 +163,7 @@ used when committed.
Running web tests by hand.
* [Web Platform Tests](testing/web_platform_tests.md) - Shared tests across
browser vendors
* [Using Breakpad with `content_shell`](testing/using_breakpad_with_content_shell.md) -
* [Using Crashpad with `content_shell`](testing/using_crashpad_with_content_shell.md) -
Capture stack traces on layout test crashes without an attached debugger
* [Test Descriptions](test_descriptions.md) - Unit test targets that can be
built, with associated desciptions.

@ -1,8 +1,9 @@
# Using breakpad with content shell
# Using crashpad with content shell
When running web tests, it is possible to use
[breakpad](../../third_party/breakpad/) to capture stack traces on crashes while
running without a debugger attached and with the sandbox enabled.
[crashpad](../third_party/crashpad/)/[breakpad](../../third_party/breakpad/) to
capture stack traces on crashes while running without a debugger attached and
with the sandbox enabled.
## Setup
@ -21,6 +22,12 @@ arguments](https://gn.googlesource.com/gn/+/master/docs/quick_start.md) before
building.
***
*** note
**Android:** Add `force_local_build_id = true` to your [gn build
arguments](https://gn.googlesource.com/gn/+/master/docs/quick_start.md) before
building.
***
Then, create a directory where the crash dumps will be stored:
* Linux/Mac:
@ -36,9 +43,9 @@ Then, create a directory where the crash dumps will be stored:
mkdir %TEMP%\crashes
```
## Running content shell with breakpad
## Running content shell with crashpad
Breakpad can be enabled by passing `--enable-crash-reporter` and
Crashpad can be enabled by passing `--enable-crash-reporter` and
`--crash-dumps-dir` to content shell:
* Linux:
@ -58,10 +65,9 @@ Breakpad can be enabled by passing `--enable-crash-reporter` and
```
* Android:
```bash
build/android/adb_install_apk.py out/Default/apks/ContentShell.apk
build/android/adb_content_shell_command_line --enable-crash-reporter \
--crash-dumps-dir=/data/local/tmp/crashes chrome://crash
build/android/adb_run_content_shell
out/Default/bin/content_shell_apk install
out/Default/bin/content_shell_apk launch chrome://crash
--args="--enable-crash-reporter --crash-dumps-dir=/data/local/tmp/crashes"
```
## Retrieving the crash dump
@ -75,8 +81,7 @@ Windows, this step can be skipped.
```
* Android:
```bash
adb pull $(adb shell ls /data/local/tmp/crashes/*) /tmp/chromium-renderer-minidump.dmp
components/breakpad/tools/dmp2minidump /tmp/chromium-renderer-minidump.dmp /tmp/minidump
adb pull $(adb shell ls /data/local/tmp/crashes/pending/*.dmp) /tmp/chromium-renderer-minidump.dmp
```
## Symbolizing the crash dump