| OLD | NEW |
| 1 #!/usr/bin/env python | 1 #!/usr/bin/env python |
| 2 # | 2 # |
| 3 # Copyright 2013 The Chromium Authors. All rights reserved. | 3 # Copyright 2013 The Chromium Authors. All rights reserved. |
| 4 # Use of this source code is governed by a BSD-style license that can be | 4 # Use of this source code is governed by a BSD-style license that can be |
| 5 # found in the LICENSE file. | 5 # found in the LICENSE file. |
| 6 # | 6 # |
| 7 # Find the most recent tombstone file(s) on all connected devices | 7 # Find the most recent tombstone file(s) on all connected devices |
| 8 # and prints their stacks. | 8 # and prints their stacks. |
| 9 # | 9 # |
| 10 # Assumes tombstone file was created with current symbols. | 10 # Assumes tombstone file was created with current symbols. |
| 11 | 11 |
| 12 import datetime | 12 import datetime |
| 13 import logging | 13 import logging |
| 14 import multiprocessing | 14 import multiprocessing |
| 15 import os | 15 import os |
| 16 import re | 16 import re |
| 17 import subprocess | 17 import subprocess |
| 18 import sys | 18 import sys |
| 19 import optparse | 19 import optparse |
| 20 | 20 |
| 21 import devil_chromium | 21 import devil_chromium |
| 22 | 22 |
| 23 from devil.android import device_blacklist | 23 from devil.android import device_blacklist |
| 24 from devil.android import device_errors | 24 from devil.android import device_errors |
| 25 from devil.android import device_utils | 25 from devil.android import device_utils |
| 26 from devil.utils import run_tests_helper | 26 from devil.utils import run_tests_helper |
| 27 from pylib import constants |
| 27 | 28 |
| 28 _TZ_UTC = {'TZ': 'UTC'} | 29 _TZ_UTC = {'TZ': 'UTC'} |
| 29 | 30 |
| 30 def _ListTombstones(device): | 31 def _ListTombstones(device): |
| 31 """List the tombstone files on the device. | 32 """List the tombstone files on the device. |
| 32 | 33 |
| 33 Args: | 34 Args: |
| 34 device: An instance of DeviceUtils. | 35 device: An instance of DeviceUtils. |
| 35 | 36 |
| 36 Yields: | 37 Yields: |
| (...skipping 85 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 122 found_abi = re.search('ABI: \'(.+?)\'', line) | 123 found_abi = re.search('ABI: \'(.+?)\'', line) |
| 123 if found_abi: | 124 if found_abi: |
| 124 device_abi = found_abi.group(1) | 125 device_abi = found_abi.group(1) |
| 125 arch = _DeviceAbiToArch(device_abi) | 126 arch = _DeviceAbiToArch(device_abi) |
| 126 if not arch: | 127 if not arch: |
| 127 return | 128 return |
| 128 | 129 |
| 129 stack_tool = os.path.join(os.path.dirname(__file__), '..', '..', | 130 stack_tool = os.path.join(os.path.dirname(__file__), '..', '..', |
| 130 'third_party', 'android_platform', 'development', | 131 'third_party', 'android_platform', 'development', |
| 131 'scripts', 'stack') | 132 'scripts', 'stack') |
| 133 # --output-directory is passed implicitly via the CHROMIUM_OUTPUT_DIR |
| 134 # environment variable. |
| 132 proc = subprocess.Popen([stack_tool, '--arch', arch], stdin=subprocess.PIPE, | 135 proc = subprocess.Popen([stack_tool, '--arch', arch], stdin=subprocess.PIPE, |
| 133 stdout=subprocess.PIPE) | 136 stdout=subprocess.PIPE) |
| 134 output = proc.communicate(input='\n'.join(tombstone_data))[0] | 137 output = proc.communicate(input='\n'.join(tombstone_data))[0] |
| 135 for line in output.split('\n'): | 138 for line in output.split('\n'): |
| 136 if not include_stack and 'Stack Data:' in line: | 139 if not include_stack and 'Stack Data:' in line: |
| 137 break | 140 break |
| 138 yield line | 141 yield line |
| 139 | 142 |
| 140 | 143 |
| 141 def _ResolveTombstone(tombstone): | 144 def _ResolveTombstone(tombstone): |
| (...skipping 88 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 230 help="""Resolve symbols for all tombstones, rather than just | 233 help="""Resolve symbols for all tombstones, rather than just |
| 231 the most recent""") | 234 the most recent""") |
| 232 parser.add_option('-s', '--stack', action='store_true', | 235 parser.add_option('-s', '--stack', action='store_true', |
| 233 help='Also include symbols for stack data') | 236 help='Also include symbols for stack data') |
| 234 parser.add_option('-w', '--wipe-tombstones', action='store_true', | 237 parser.add_option('-w', '--wipe-tombstones', action='store_true', |
| 235 help='Erase all tombstones from device after processing') | 238 help='Erase all tombstones from device after processing') |
| 236 parser.add_option('-j', '--jobs', type='int', | 239 parser.add_option('-j', '--jobs', type='int', |
| 237 default=4, | 240 default=4, |
| 238 help='Number of jobs to use when processing multiple ' | 241 help='Number of jobs to use when processing multiple ' |
| 239 'crash stacks.') | 242 'crash stacks.') |
| 243 parser.add_option('--output-directory', |
| 244 help='Path to the root build directory.') |
| 240 options, _ = parser.parse_args() | 245 options, _ = parser.parse_args() |
| 241 | 246 |
| 242 devil_chromium.Initialize() | 247 devil_chromium.Initialize() |
| 243 | 248 |
| 244 blacklist = (device_blacklist.Blacklist(options.blacklist_file) | 249 blacklist = (device_blacklist.Blacklist(options.blacklist_file) |
| 245 if options.blacklist_file | 250 if options.blacklist_file |
| 246 else None) | 251 else None) |
| 247 | 252 |
| 253 constants.require_explicit_output_dir = True |
| 254 if options.output_directory: |
| 255 constants.SetOutputDirectory(options.output_directory) |
| 256 |
| 257 # Do an up-front test that the output directory is known. |
| 258 constants.GetOutDirectory() |
| 259 |
| 248 if options.device: | 260 if options.device: |
| 249 devices = [device_utils.DeviceUtils(options.device)] | 261 devices = [device_utils.DeviceUtils(options.device)] |
| 250 else: | 262 else: |
| 251 devices = device_utils.DeviceUtils.HealthyDevices(blacklist) | 263 devices = device_utils.DeviceUtils.HealthyDevices(blacklist) |
| 252 | 264 |
| 253 # This must be done serially because strptime can hit a race condition if | 265 # This must be done serially because strptime can hit a race condition if |
| 254 # used for the first time in a multithreaded environment. | 266 # used for the first time in a multithreaded environment. |
| 255 # http://bugs.python.org/issue7980 | 267 # http://bugs.python.org/issue7980 |
| 256 tombstones = [] | 268 tombstones = [] |
| 257 for device in devices: | 269 for device in devices: |
| 258 tombstones += _GetTombstonesForDevice(device, options) | 270 tombstones += _GetTombstonesForDevice(device, options) |
| 259 | 271 |
| 260 _ResolveTombstones(options.jobs, tombstones) | 272 _ResolveTombstones(options.jobs, tombstones) |
| 261 | 273 |
| 262 | 274 |
| 263 if __name__ == '__main__': | 275 if __name__ == '__main__': |
| 264 sys.exit(main()) | 276 sys.exit(main()) |
| OLD | NEW |