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:

committed by
Commit Bot

parent
6a11499014
commit
6f96b9d264
content/shell/tools
docs
@ -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
|
Reference in New Issue
Block a user