summaryrefslogtreecommitdiffstats
path: root/third_party/libwebrtc/build/android/tombstones.py
diff options
context:
space:
mode:
Diffstat (limited to '')
-rwxr-xr-xthird_party/libwebrtc/build/android/tombstones.py280
1 files changed, 280 insertions, 0 deletions
diff --git a/third_party/libwebrtc/build/android/tombstones.py b/third_party/libwebrtc/build/android/tombstones.py
new file mode 100755
index 0000000000..ae478bf689
--- /dev/null
+++ b/third_party/libwebrtc/build/android/tombstones.py
@@ -0,0 +1,280 @@
+#!/usr/bin/env vpython3
+#
+# Copyright 2013 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+#
+# Find the most recent tombstone file(s) on all connected devices
+# and prints their stacks.
+#
+# Assumes tombstone file was created with current symbols.
+
+import argparse
+import datetime
+import logging
+import os
+import sys
+
+from multiprocessing.pool import ThreadPool
+
+import devil_chromium
+
+from devil.android import device_denylist
+from devil.android import device_errors
+from devil.android import device_utils
+from devil.utils import run_tests_helper
+from pylib import constants
+from pylib.symbols import stack_symbolizer
+
+
+_TZ_UTC = {'TZ': 'UTC'}
+
+
+def _ListTombstones(device):
+ """List the tombstone files on the device.
+
+ Args:
+ device: An instance of DeviceUtils.
+
+ Yields:
+ Tuples of (tombstone filename, date time of file on device).
+ """
+ try:
+ if not device.PathExists('/data/tombstones', as_root=True):
+ return
+ entries = device.StatDirectory('/data/tombstones', as_root=True)
+ for entry in entries:
+ if 'tombstone' in entry['filename']:
+ yield (entry['filename'],
+ datetime.datetime.fromtimestamp(entry['st_mtime']))
+ except device_errors.CommandFailedError:
+ logging.exception('Could not retrieve tombstones.')
+ except device_errors.DeviceUnreachableError:
+ logging.exception('Device unreachable retrieving tombstones.')
+ except device_errors.CommandTimeoutError:
+ logging.exception('Timed out retrieving tombstones.')
+
+
+def _GetDeviceDateTime(device):
+ """Determine the date time on the device.
+
+ Args:
+ device: An instance of DeviceUtils.
+
+ Returns:
+ A datetime instance.
+ """
+ device_now_string = device.RunShellCommand(
+ ['date'], check_return=True, env=_TZ_UTC)
+ return datetime.datetime.strptime(
+ device_now_string[0], '%a %b %d %H:%M:%S %Z %Y')
+
+
+def _GetTombstoneData(device, tombstone_file):
+ """Retrieve the tombstone data from the device
+
+ Args:
+ device: An instance of DeviceUtils.
+ tombstone_file: the tombstone to retrieve
+
+ Returns:
+ A list of lines
+ """
+ return device.ReadFile(
+ '/data/tombstones/' + tombstone_file, as_root=True).splitlines()
+
+
+def _EraseTombstone(device, tombstone_file):
+ """Deletes a tombstone from the device.
+
+ Args:
+ device: An instance of DeviceUtils.
+ tombstone_file: the tombstone to delete.
+ """
+ return device.RunShellCommand(
+ ['rm', '/data/tombstones/' + tombstone_file],
+ as_root=True, check_return=True)
+
+
+def _ResolveTombstone(args):
+ tombstone = args[0]
+ tombstone_symbolizer = args[1]
+ lines = []
+ lines += [tombstone['file'] + ' created on ' + str(tombstone['time']) +
+ ', about this long ago: ' +
+ (str(tombstone['device_now'] - tombstone['time']) +
+ ' Device: ' + tombstone['serial'])]
+ logging.info('\n'.join(lines))
+ logging.info('Resolving...')
+ lines += tombstone_symbolizer.ExtractAndResolveNativeStackTraces(
+ tombstone['data'],
+ tombstone['device_abi'],
+ tombstone['stack'])
+ return lines
+
+
+def _ResolveTombstones(jobs, tombstones, tombstone_symbolizer):
+ """Resolve a list of tombstones.
+
+ Args:
+ jobs: the number of jobs to use with multithread.
+ tombstones: a list of tombstones.
+ """
+ if not tombstones:
+ logging.warning('No tombstones to resolve.')
+ return []
+ if len(tombstones) == 1:
+ data = [_ResolveTombstone([tombstones[0], tombstone_symbolizer])]
+ else:
+ pool = ThreadPool(jobs)
+ data = pool.map(
+ _ResolveTombstone,
+ [[tombstone, tombstone_symbolizer] for tombstone in tombstones])
+ pool.close()
+ pool.join()
+ resolved_tombstones = []
+ for tombstone in data:
+ resolved_tombstones.extend(tombstone)
+ return resolved_tombstones
+
+
+def _GetTombstonesForDevice(device, resolve_all_tombstones,
+ include_stack_symbols,
+ wipe_tombstones):
+ """Returns a list of tombstones on a given device.
+
+ Args:
+ device: An instance of DeviceUtils.
+ resolve_all_tombstone: Whether to resolve every tombstone.
+ include_stack_symbols: Whether to include symbols for stack data.
+ wipe_tombstones: Whether to wipe tombstones.
+ """
+ ret = []
+ all_tombstones = list(_ListTombstones(device))
+ if not all_tombstones:
+ logging.warning('No tombstones.')
+ return ret
+
+ # Sort the tombstones in date order, descending
+ all_tombstones.sort(key=lambda a: a[1], reverse=True)
+
+ # Only resolve the most recent unless --all-tombstones given.
+ tombstones = all_tombstones if resolve_all_tombstones else [all_tombstones[0]]
+
+ device_now = _GetDeviceDateTime(device)
+ try:
+ for tombstone_file, tombstone_time in tombstones:
+ ret += [{'serial': str(device),
+ 'device_abi': device.product_cpu_abi,
+ 'device_now': device_now,
+ 'time': tombstone_time,
+ 'file': tombstone_file,
+ 'stack': include_stack_symbols,
+ 'data': _GetTombstoneData(device, tombstone_file)}]
+ except device_errors.CommandFailedError:
+ for entry in device.StatDirectory(
+ '/data/tombstones', as_root=True, timeout=60):
+ logging.info('%s: %s', str(device), entry)
+ raise
+
+ # Erase all the tombstones if desired.
+ if wipe_tombstones:
+ for tombstone_file, _ in all_tombstones:
+ _EraseTombstone(device, tombstone_file)
+
+ return ret
+
+
+def ClearAllTombstones(device):
+ """Clear all tombstones in the device.
+
+ Args:
+ device: An instance of DeviceUtils.
+ """
+ all_tombstones = list(_ListTombstones(device))
+ if not all_tombstones:
+ logging.warning('No tombstones to clear.')
+
+ for tombstone_file, _ in all_tombstones:
+ _EraseTombstone(device, tombstone_file)
+
+
+def ResolveTombstones(device, resolve_all_tombstones, include_stack_symbols,
+ wipe_tombstones, jobs=4, apk_under_test=None,
+ tombstone_symbolizer=None):
+ """Resolve tombstones in the device.
+
+ Args:
+ device: An instance of DeviceUtils.
+ resolve_all_tombstone: Whether to resolve every tombstone.
+ include_stack_symbols: Whether to include symbols for stack data.
+ wipe_tombstones: Whether to wipe tombstones.
+ jobs: Number of jobs to use when processing multiple crash stacks.
+
+ Returns:
+ A list of resolved tombstones.
+ """
+ return _ResolveTombstones(jobs,
+ _GetTombstonesForDevice(device,
+ resolve_all_tombstones,
+ include_stack_symbols,
+ wipe_tombstones),
+ (tombstone_symbolizer
+ or stack_symbolizer.Symbolizer(apk_under_test)))
+
+
+def main():
+ custom_handler = logging.StreamHandler(sys.stdout)
+ custom_handler.setFormatter(run_tests_helper.CustomFormatter())
+ logging.getLogger().addHandler(custom_handler)
+ logging.getLogger().setLevel(logging.INFO)
+
+ parser = argparse.ArgumentParser()
+ parser.add_argument('--device',
+ help='The serial number of the device. If not specified '
+ 'will use all devices.')
+ parser.add_argument('--denylist-file', help='Device denylist JSON file.')
+ parser.add_argument('-a', '--all-tombstones', action='store_true',
+ help='Resolve symbols for all tombstones, rather than '
+ 'just the most recent.')
+ parser.add_argument('-s', '--stack', action='store_true',
+ help='Also include symbols for stack data')
+ parser.add_argument('-w', '--wipe-tombstones', action='store_true',
+ help='Erase all tombstones from device after processing')
+ parser.add_argument('-j', '--jobs', type=int,
+ default=4,
+ help='Number of jobs to use when processing multiple '
+ 'crash stacks.')
+ parser.add_argument('--output-directory',
+ help='Path to the root build directory.')
+ parser.add_argument('--adb-path', type=os.path.abspath,
+ help='Path to the adb binary.')
+ args = parser.parse_args()
+
+ if args.output_directory:
+ constants.SetOutputDirectory(args.output_directory)
+
+ devil_chromium.Initialize(output_directory=constants.GetOutDirectory(),
+ adb_path=args.adb_path)
+
+ denylist = (device_denylist.Denylist(args.denylist_file)
+ if args.denylist_file else None)
+
+ if args.device:
+ devices = [device_utils.DeviceUtils(args.device)]
+ else:
+ devices = device_utils.DeviceUtils.HealthyDevices(denylist)
+
+ # This must be done serially because strptime can hit a race condition if
+ # used for the first time in a multithreaded environment.
+ # http://bugs.python.org/issue7980
+ for device in devices:
+ resolved_tombstones = ResolveTombstones(
+ device, args.all_tombstones,
+ args.stack, args.wipe_tombstones, args.jobs)
+ for line in resolved_tombstones:
+ logging.info(line)
+
+
+if __name__ == '__main__':
+ sys.exit(main())