Chromium Code Reviews| 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 argparse | 12 import argparse |
| 13 import datetime | 13 import datetime |
| 14 import logging | 14 import logging |
| 15 import multiprocessing | 15 import multiprocessing |
| 16 import os | 16 import os |
| 17 import re | |
| 18 import subprocess | |
| 19 import sys | 17 import sys |
| 20 | 18 |
| 21 import devil_chromium | 19 import devil_chromium |
| 22 | 20 |
| 23 from devil.android import device_blacklist | 21 from devil.android import device_blacklist |
| 24 from devil.android import device_errors | 22 from devil.android import device_errors |
| 25 from devil.android import device_utils | 23 from devil.android import device_utils |
| 26 from devil.utils import run_tests_helper | 24 from devil.utils import run_tests_helper |
| 27 from pylib import constants | 25 from pylib import constants |
| 26 from pylib.symbols import stack_symbolizer | |
| 28 | 27 |
| 29 | 28 |
| 30 _TZ_UTC = {'TZ': 'UTC'} | 29 _TZ_UTC = {'TZ': 'UTC'} |
| 31 | 30 |
| 32 | 31 |
| 33 def _ListTombstones(device): | 32 def _ListTombstones(device): |
| 34 """List the tombstone files on the device. | 33 """List the tombstone files on the device. |
| 35 | 34 |
| 36 Args: | 35 Args: |
| 37 device: An instance of DeviceUtils. | 36 device: An instance of DeviceUtils. |
| (...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 89 | 88 |
| 90 Args: | 89 Args: |
| 91 device: An instance of DeviceUtils. | 90 device: An instance of DeviceUtils. |
| 92 tombstone_file: the tombstone to delete. | 91 tombstone_file: the tombstone to delete. |
| 93 """ | 92 """ |
| 94 return device.RunShellCommand( | 93 return device.RunShellCommand( |
| 95 ['rm', '/data/tombstones/' + tombstone_file], | 94 ['rm', '/data/tombstones/' + tombstone_file], |
| 96 as_root=True, check_return=True) | 95 as_root=True, check_return=True) |
| 97 | 96 |
| 98 | 97 |
| 99 def _DeviceAbiToArch(device_abi): | 98 def _ResolveTombstone(args): |
| 100 # The order of this list is significant to find the more specific match (e.g., | 99 tombstone = args[0] |
| 101 # arm64) before the less specific (e.g., arm). | 100 tombstone_symbolizer = args[1] |
| 102 arches = ['arm64', 'arm', 'x86_64', 'x86_64', 'x86', 'mips'] | |
| 103 for arch in arches: | |
| 104 if arch in device_abi: | |
| 105 return arch | |
| 106 raise RuntimeError('Unknown device ABI: %s' % device_abi) | |
| 107 | |
| 108 | |
| 109 def _ResolveSymbols(tombstone_data, include_stack, device_abi): | |
| 110 """Run the stack tool for given tombstone input. | |
| 111 | |
| 112 Args: | |
| 113 tombstone_data: a list of strings of tombstone data. | |
| 114 include_stack: boolean whether to include stack data in output. | |
| 115 device_abi: the default ABI of the device which generated the tombstone. | |
| 116 | |
| 117 Yields: | |
| 118 A string for each line of resolved stack output. | |
| 119 """ | |
| 120 # Check if the tombstone data has an ABI listed, if so use this in preference | |
| 121 # to the device's default ABI. | |
| 122 for line in tombstone_data: | |
| 123 found_abi = re.search('ABI: \'(.+?)\'', line) | |
| 124 if found_abi: | |
| 125 device_abi = found_abi.group(1) | |
| 126 arch = _DeviceAbiToArch(device_abi) | |
| 127 if not arch: | |
| 128 return | |
| 129 | |
| 130 stack_tool = os.path.join(os.path.dirname(__file__), '..', '..', | |
| 131 'third_party', 'android_platform', 'development', | |
| 132 'scripts', 'stack') | |
| 133 cmd = [stack_tool, '--arch', arch, '--output-directory', | |
| 134 constants.GetOutDirectory()] | |
| 135 proc = subprocess.Popen(cmd, stdin=subprocess.PIPE, stdout=subprocess.PIPE) | |
| 136 output = proc.communicate(input='\n'.join(tombstone_data))[0] | |
| 137 for line in output.split('\n'): | |
| 138 if not include_stack and 'Stack Data:' in line: | |
| 139 break | |
| 140 yield line | |
| 141 | |
| 142 | |
| 143 def _ResolveTombstone(tombstone): | |
| 144 lines = [] | 101 lines = [] |
| 145 lines += [tombstone['file'] + ' created on ' + str(tombstone['time']) + | 102 lines += [tombstone['file'] + ' created on ' + str(tombstone['time']) + |
| 146 ', about this long ago: ' + | 103 ', about this long ago: ' + |
| 147 (str(tombstone['device_now'] - tombstone['time']) + | 104 (str(tombstone['device_now'] - tombstone['time']) + |
| 148 ' Device: ' + tombstone['serial'])] | 105 ' Device: ' + tombstone['serial'])] |
| 149 logging.info('\n'.join(lines)) | 106 logging.info('\n'.join(lines)) |
| 150 logging.info('Resolving...') | 107 logging.info('Resolving...') |
| 151 lines += _ResolveSymbols(tombstone['data'], tombstone['stack'], | 108 lines += tombstone_symbolizer.ResolveSymbols( |
| 152 tombstone['device_abi']) | 109 tombstone['data'], |
| 110 tombstone['device_abi'], | |
| 111 tombstone['stack']) | |
| 153 return lines | 112 return lines |
| 154 | 113 |
| 155 | 114 |
| 156 def _ResolveTombstones(jobs, tombstones): | 115 def _ResolveTombstones(jobs, tombstones, tombstone_symbolizer): |
| 157 """Resolve a list of tombstones. | 116 """Resolve a list of tombstones. |
| 158 | 117 |
| 159 Args: | 118 Args: |
| 160 jobs: the number of jobs to use with multiprocess. | 119 jobs: the number of jobs to use with multiprocess. |
| 161 tombstones: a list of tombstones. | 120 tombstones: a list of tombstones. |
| 162 """ | 121 """ |
| 163 if not tombstones: | 122 if not tombstones: |
| 164 logging.warning('No tombstones to resolve.') | 123 logging.warning('No tombstones to resolve.') |
| 165 return [] | 124 return [] |
| 125 tombstone_symbolizer.UnzipAPKIfNecessary() | |
| 166 if len(tombstones) == 1: | 126 if len(tombstones) == 1: |
| 167 data = [_ResolveTombstone(tombstones[0])] | 127 data = [_ResolveTombstone([tombstones[0], tombstone_symbolizer])] |
| 168 else: | 128 else: |
| 169 pool = multiprocessing.Pool(processes=jobs) | 129 pool = multiprocessing.Pool(processes=jobs) |
| 170 data = pool.map(_ResolveTombstone, tombstones) | 130 data = pool.map( |
| 131 _ResolveTombstone, | |
| 132 [[tombstone, tombstone_symbolizer] for tombstone in tombstones]) | |
|
agrieve
2017/07/26 01:26:10
Tombstone symbolizer has a __del__ method that del
BigBossZhiling
2017/07/26 17:36:27
Done.
| |
| 171 resolved_tombstones = [] | 133 resolved_tombstones = [] |
| 172 for tombstone in data: | 134 for tombstone in data: |
| 173 resolved_tombstones.extend(tombstone) | 135 resolved_tombstones.extend(tombstone) |
| 174 return resolved_tombstones | 136 return resolved_tombstones |
| 175 | 137 |
| 176 | 138 |
| 177 def _GetTombstonesForDevice(device, resolve_all_tombstones, | 139 def _GetTombstonesForDevice(device, resolve_all_tombstones, |
| 178 include_stack_symbols, | 140 include_stack_symbols, |
| 179 wipe_tombstones): | 141 wipe_tombstones): |
| 180 """Returns a list of tombstones on a given device. | 142 """Returns a list of tombstones on a given device. |
| (...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 229 """ | 191 """ |
| 230 all_tombstones = list(_ListTombstones(device)) | 192 all_tombstones = list(_ListTombstones(device)) |
| 231 if not all_tombstones: | 193 if not all_tombstones: |
| 232 logging.warning('No tombstones to clear.') | 194 logging.warning('No tombstones to clear.') |
| 233 | 195 |
| 234 for tombstone_file, _ in all_tombstones: | 196 for tombstone_file, _ in all_tombstones: |
| 235 _EraseTombstone(device, tombstone_file) | 197 _EraseTombstone(device, tombstone_file) |
| 236 | 198 |
| 237 | 199 |
| 238 def ResolveTombstones(device, resolve_all_tombstones, include_stack_symbols, | 200 def ResolveTombstones(device, resolve_all_tombstones, include_stack_symbols, |
| 239 wipe_tombstones, jobs=4): | 201 wipe_tombstones, jobs=4, |
| 202 apk_under_test=None, enable_relocation_packing=None, | |
| 203 tombstone_symbolizer=None): | |
| 240 """Resolve tombstones in the device. | 204 """Resolve tombstones in the device. |
| 241 | 205 |
| 242 Args: | 206 Args: |
| 243 device: An instance of DeviceUtils. | 207 device: An instance of DeviceUtils. |
| 244 resolve_all_tombstone: Whether to resolve every tombstone. | 208 resolve_all_tombstone: Whether to resolve every tombstone. |
| 245 include_stack_symbols: Whether to include symbols for stack data. | 209 include_stack_symbols: Whether to include symbols for stack data. |
| 246 wipe_tombstones: Whether to wipe tombstones. | 210 wipe_tombstones: Whether to wipe tombstones. |
| 247 jobs: Number of jobs to use when processing multiple crash stacks. | 211 jobs: Number of jobs to use when processing multiple crash stacks. |
| 248 | 212 |
| 249 Returns: | 213 Returns: |
| 250 A list of resolved tombstones. | 214 A list of resolved tombstones. |
| 251 """ | 215 """ |
| 252 return _ResolveTombstones(jobs, | 216 return _ResolveTombstones(jobs, |
| 253 _GetTombstonesForDevice(device, | 217 _GetTombstonesForDevice(device, |
| 254 resolve_all_tombstones, | 218 resolve_all_tombstones, |
| 255 include_stack_symbols, | 219 include_stack_symbols, |
| 256 wipe_tombstones)) | 220 wipe_tombstones), |
| 221 (tombstone_symbolizer | |
| 222 or stack_symbolizer.Symbolizer( | |
| 223 apk_under_test, | |
| 224 enable_relocation_packing))) | |
| 257 | 225 |
| 258 | 226 |
| 259 def main(): | 227 def main(): |
| 260 custom_handler = logging.StreamHandler(sys.stdout) | 228 custom_handler = logging.StreamHandler(sys.stdout) |
| 261 custom_handler.setFormatter(run_tests_helper.CustomFormatter()) | 229 custom_handler.setFormatter(run_tests_helper.CustomFormatter()) |
| 262 logging.getLogger().addHandler(custom_handler) | 230 logging.getLogger().addHandler(custom_handler) |
| 263 logging.getLogger().setLevel(logging.INFO) | 231 logging.getLogger().setLevel(logging.INFO) |
| 264 | 232 |
| 265 parser = argparse.ArgumentParser() | 233 parser = argparse.ArgumentParser() |
| 266 parser.add_argument('--device', | 234 parser.add_argument('--device', |
| (...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 306 for device in devices: | 274 for device in devices: |
| 307 resolved_tombstones = ResolveTombstones( | 275 resolved_tombstones = ResolveTombstones( |
| 308 device, args.all_tombstones, | 276 device, args.all_tombstones, |
| 309 args.stack, args.wipe_tombstones, args.jobs) | 277 args.stack, args.wipe_tombstones, args.jobs) |
| 310 for line in resolved_tombstones: | 278 for line in resolved_tombstones: |
| 311 logging.info(line) | 279 logging.info(line) |
| 312 | 280 |
| 313 | 281 |
| 314 if __name__ == '__main__': | 282 if __name__ == '__main__': |
| 315 sys.exit(main()) | 283 sys.exit(main()) |
| OLD | NEW |