blob: 6e711ffb8554ffce12750279dd72d2e32e88e9b0 [file] [log] [blame]
[email protected]e8044252013-07-11 16:17:561#!/usr/bin/env python
2#
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
5# found in the LICENSE file.
6#
7# Find the most recent tombstone file(s) on all connected devices
8# and prints their stacks.
9#
10# Assumes tombstone file was created with current symbols.
11
jbudorick3e0f4b22016-05-28 04:49:4712import argparse
[email protected]e8044252013-07-11 16:17:5613import datetime
jbudorick8e79ceb2015-03-19 16:28:1114import logging
[email protected]e8044252013-07-11 16:17:5615import os
[email protected]e8044252013-07-11 16:17:5616import sys
[email protected]e8044252013-07-11 16:17:5617
hzl55fc2af2017-07-27 08:24:5018from multiprocessing.pool import ThreadPool
19
jbudorick0c2a94a2015-12-04 14:27:4320import devil_chromium
21
jbudorick061629442015-09-03 18:00:5722from devil.android import device_blacklist
23from devil.android import device_errors
24from devil.android import device_utils
jbudorick061629442015-09-03 18:00:5725from devil.utils import run_tests_helper
agrieve32dbc2002016-02-06 02:37:5426from pylib import constants
hzl55fc2af2017-07-27 08:24:5027from pylib.symbols import stack_symbolizer
[email protected]e8044252013-07-11 16:17:5628
perezju5ad37222016-06-09 16:35:0429
jbudorick2b4779f32015-03-13 15:50:4130_TZ_UTC = {'TZ': 'UTC'}
31
perezju5ad37222016-06-09 16:35:0432
[email protected]044d79b2014-04-10 19:37:3033def _ListTombstones(device):
[email protected]e8044252013-07-11 16:17:5634 """List the tombstone files on the device.
35
36 Args:
[email protected]044d79b2014-04-10 19:37:3037 device: An instance of DeviceUtils.
[email protected]e8044252013-07-11 16:17:5638
39 Yields:
40 Tuples of (tombstone filename, date time of file on device).
41 """
jbudorick8e79ceb2015-03-19 16:28:1142 try:
jbudorickc693a8d2016-01-15 02:14:2643 if not device.PathExists('/data/tombstones', as_root=True):
primianob5bcd43a2015-11-06 16:48:4544 return
perezju5ad37222016-06-09 16:35:0445 entries = device.StatDirectory('/data/tombstones', as_root=True)
46 for entry in entries:
47 if 'tombstone' in entry['filename']:
48 yield (entry['filename'],
49 datetime.datetime.fromtimestamp(entry['st_mtime']))
jbudorick8e79ceb2015-03-19 16:28:1150 except device_errors.CommandFailedError:
51 logging.exception('Could not retrieve tombstones.')
perezju46865bb32017-04-13 12:19:5152 except device_errors.DeviceUnreachableError:
53 logging.exception('Device unreachable retrieving tombstones.')
jbudorick6d9a867e2015-08-09 18:21:5454 except device_errors.CommandTimeoutError:
55 logging.exception('Timed out retrieving tombstones.')
[email protected]e8044252013-07-11 16:17:5656
57
[email protected]044d79b2014-04-10 19:37:3058def _GetDeviceDateTime(device):
[email protected]e8044252013-07-11 16:17:5659 """Determine the date time on the device.
60
61 Args:
[email protected]044d79b2014-04-10 19:37:3062 device: An instance of DeviceUtils.
[email protected]e8044252013-07-11 16:17:5663
64 Returns:
65 A datetime instance.
66 """
jbudorick2b4779f32015-03-13 15:50:4167 device_now_string = device.RunShellCommand(
68 ['date'], check_return=True, env=_TZ_UTC)
[email protected]e8044252013-07-11 16:17:5669 return datetime.datetime.strptime(
70 device_now_string[0], '%a %b %d %H:%M:%S %Z %Y')
71
72
[email protected]044d79b2014-04-10 19:37:3073def _GetTombstoneData(device, tombstone_file):
[email protected]e8044252013-07-11 16:17:5674 """Retrieve the tombstone data from the device
75
76 Args:
[email protected]044d79b2014-04-10 19:37:3077 device: An instance of DeviceUtils.
[email protected]e8044252013-07-11 16:17:5678 tombstone_file: the tombstone to retrieve
79
80 Returns:
81 A list of lines
82 """
perezju7138148b2015-01-26 10:10:0083 return device.ReadFile(
84 '/data/tombstones/' + tombstone_file, as_root=True).splitlines()
[email protected]e8044252013-07-11 16:17:5685
86
[email protected]044d79b2014-04-10 19:37:3087def _EraseTombstone(device, tombstone_file):
[email protected]e8044252013-07-11 16:17:5688 """Deletes a tombstone from the device.
89
90 Args:
[email protected]044d79b2014-04-10 19:37:3091 device: An instance of DeviceUtils.
[email protected]e8044252013-07-11 16:17:5692 tombstone_file: the tombstone to delete.
93 """
[email protected]f0f4b9732014-06-16 18:59:3094 return device.RunShellCommand(
jbudorick2b4779f32015-03-13 15:50:4195 ['rm', '/data/tombstones/' + tombstone_file],
96 as_root=True, check_return=True)
[email protected]e8044252013-07-11 16:17:5697
98
hzl55fc2af2017-07-27 08:24:5099def _ResolveTombstone(args):
100 tombstone = args[0]
101 tombstone_symbolizer = args[1]
[email protected]e8044252013-07-11 16:17:56102 lines = []
103 lines += [tombstone['file'] + ' created on ' + str(tombstone['time']) +
104 ', about this long ago: ' +
105 (str(tombstone['device_now'] - tombstone['time']) +
106 ' Device: ' + tombstone['serial'])]
jbudorick8e79ceb2015-03-19 16:28:11107 logging.info('\n'.join(lines))
108 logging.info('Resolving...')
hzl55fc2af2017-07-27 08:24:50109 lines += tombstone_symbolizer.ExtractAndResolveNativeStackTraces(
110 tombstone['data'],
111 tombstone['device_abi'],
112 tombstone['stack'])
[email protected]e8044252013-07-11 16:17:56113 return lines
114
115
hzl55fc2af2017-07-27 08:24:50116def _ResolveTombstones(jobs, tombstones, tombstone_symbolizer):
[email protected]e8044252013-07-11 16:17:56117 """Resolve a list of tombstones.
118
119 Args:
hzl55fc2af2017-07-27 08:24:50120 jobs: the number of jobs to use with multithread.
[email protected]e8044252013-07-11 16:17:56121 tombstones: a list of tombstones.
122 """
123 if not tombstones:
jbudorick8e79ceb2015-03-19 16:28:11124 logging.warning('No tombstones to resolve.')
hzl02ff9ee2016-08-15 23:22:57125 return []
hzl55fc2af2017-07-27 08:24:50126 tombstone_symbolizer.UnzipAPKIfNecessary()
[email protected]e8044252013-07-11 16:17:56127 if len(tombstones) == 1:
hzl55fc2af2017-07-27 08:24:50128 data = [_ResolveTombstone([tombstones[0], tombstone_symbolizer])]
[email protected]e8044252013-07-11 16:17:56129 else:
hzl55fc2af2017-07-27 08:24:50130 pool = ThreadPool(jobs)
131 data = pool.map(
132 _ResolveTombstone,
133 [[tombstone, tombstone_symbolizer] for tombstone in tombstones])
hzl02ff9ee2016-08-15 23:22:57134 resolved_tombstones = []
jbudorick8c1087b2015-05-18 21:06:57135 for tombstone in data:
hzl02ff9ee2016-08-15 23:22:57136 resolved_tombstones.extend(tombstone)
137 return resolved_tombstones
[email protected]e8044252013-07-11 16:17:56138
hzl15465f22016-12-14 23:14:46139
hzl02ff9ee2016-08-15 23:22:57140def _GetTombstonesForDevice(device, resolve_all_tombstones,
141 include_stack_symbols,
142 wipe_tombstones):
[email protected]044d79b2014-04-10 19:37:30143 """Returns a list of tombstones on a given device.
[email protected]e8044252013-07-11 16:17:56144
145 Args:
[email protected]044d79b2014-04-10 19:37:30146 device: An instance of DeviceUtils.
hzl02ff9ee2016-08-15 23:22:57147 resolve_all_tombstone: Whether to resolve every tombstone.
148 include_stack_symbols: Whether to include symbols for stack data.
149 wipe_tombstones: Whether to wipe tombstones.
[email protected]e8044252013-07-11 16:17:56150 """
151 ret = []
[email protected]044d79b2014-04-10 19:37:30152 all_tombstones = list(_ListTombstones(device))
[email protected]e8044252013-07-11 16:17:56153 if not all_tombstones:
jbudorick8e79ceb2015-03-19 16:28:11154 logging.warning('No tombstones.')
[email protected]e8044252013-07-11 16:17:56155 return ret
156
157 # Sort the tombstones in date order, descending
158 all_tombstones.sort(cmp=lambda a, b: cmp(b[1], a[1]))
159
160 # Only resolve the most recent unless --all-tombstones given.
hzl02ff9ee2016-08-15 23:22:57161 tombstones = all_tombstones if resolve_all_tombstones else [all_tombstones[0]]
[email protected]e8044252013-07-11 16:17:56162
[email protected]044d79b2014-04-10 19:37:30163 device_now = _GetDeviceDateTime(device)
jbudorickb9378232015-03-12 22:50:18164 try:
165 for tombstone_file, tombstone_time in tombstones:
166 ret += [{'serial': str(device),
167 'device_abi': device.product_cpu_abi,
168 'device_now': device_now,
169 'time': tombstone_time,
170 'file': tombstone_file,
hzl02ff9ee2016-08-15 23:22:57171 'stack': include_stack_symbols,
jbudorickb9378232015-03-12 22:50:18172 'data': _GetTombstoneData(device, tombstone_file)}]
173 except device_errors.CommandFailedError:
perezju5ad37222016-06-09 16:35:04174 for entry in device.StatDirectory(
175 '/data/tombstones', as_root=True, timeout=60):
176 logging.info('%s: %s', str(device), entry)
jbudorickb9378232015-03-12 22:50:18177 raise
[email protected]e8044252013-07-11 16:17:56178
179 # Erase all the tombstones if desired.
hzl02ff9ee2016-08-15 23:22:57180 if wipe_tombstones:
[email protected]e8044252013-07-11 16:17:56181 for tombstone_file, _ in all_tombstones:
[email protected]044d79b2014-04-10 19:37:30182 _EraseTombstone(device, tombstone_file)
[email protected]e8044252013-07-11 16:17:56183
184 return ret
185
hzl15465f22016-12-14 23:14:46186
hzl02ff9ee2016-08-15 23:22:57187def ClearAllTombstones(device):
188 """Clear all tombstones in the device.
189
190 Args:
191 device: An instance of DeviceUtils.
192 """
193 all_tombstones = list(_ListTombstones(device))
194 if not all_tombstones:
195 logging.warning('No tombstones to clear.')
196
197 for tombstone_file, _ in all_tombstones:
198 _EraseTombstone(device, tombstone_file)
199
hzl15465f22016-12-14 23:14:46200
hzl02ff9ee2016-08-15 23:22:57201def ResolveTombstones(device, resolve_all_tombstones, include_stack_symbols,
hzl55fc2af2017-07-27 08:24:50202 wipe_tombstones, jobs=4,
203 apk_under_test=None, enable_relocation_packing=None,
204 tombstone_symbolizer=None):
hzl02ff9ee2016-08-15 23:22:57205 """Resolve tombstones in the device.
206
207 Args:
208 device: An instance of DeviceUtils.
209 resolve_all_tombstone: Whether to resolve every tombstone.
210 include_stack_symbols: Whether to include symbols for stack data.
211 wipe_tombstones: Whether to wipe tombstones.
212 jobs: Number of jobs to use when processing multiple crash stacks.
hzl15465f22016-12-14 23:14:46213
214 Returns:
215 A list of resolved tombstones.
hzl02ff9ee2016-08-15 23:22:57216 """
217 return _ResolveTombstones(jobs,
218 _GetTombstonesForDevice(device,
219 resolve_all_tombstones,
220 include_stack_symbols,
hzl55fc2af2017-07-27 08:24:50221 wipe_tombstones),
222 (tombstone_symbolizer
223 or stack_symbolizer.Symbolizer(
224 apk_under_test,
225 enable_relocation_packing)))
[email protected]1d10a3062014-07-28 15:35:18226
hzl15465f22016-12-14 23:14:46227
[email protected]e8044252013-07-11 16:17:56228def main():
jbudorick8e79ceb2015-03-19 16:28:11229 custom_handler = logging.StreamHandler(sys.stdout)
230 custom_handler.setFormatter(run_tests_helper.CustomFormatter())
231 logging.getLogger().addHandler(custom_handler)
232 logging.getLogger().setLevel(logging.INFO)
233
jbudorick3e0f4b22016-05-28 04:49:47234 parser = argparse.ArgumentParser()
235 parser.add_argument('--device',
236 help='The serial number of the device. If not specified '
237 'will use all devices.')
238 parser.add_argument('--blacklist-file', help='Device blacklist JSON file.')
239 parser.add_argument('-a', '--all-tombstones', action='store_true',
240 help='Resolve symbols for all tombstones, rather than '
241 'just the most recent.')
242 parser.add_argument('-s', '--stack', action='store_true',
243 help='Also include symbols for stack data')
244 parser.add_argument('-w', '--wipe-tombstones', action='store_true',
245 help='Erase all tombstones from device after processing')
246 parser.add_argument('-j', '--jobs', type=int,
247 default=4,
248 help='Number of jobs to use when processing multiple '
249 'crash stacks.')
250 parser.add_argument('--output-directory',
251 help='Path to the root build directory.')
252 parser.add_argument('--adb-path', type=os.path.abspath,
253 help='Path to the adb binary.')
254 args = parser.parse_args()
[email protected]e8044252013-07-11 16:17:56255
jbudorick3e0f4b22016-05-28 04:49:47256 devil_chromium.Initialize(adb_path=args.adb_path)
jbudorickd28554a2016-01-11 16:22:59257
jbudorick3e0f4b22016-05-28 04:49:47258 blacklist = (device_blacklist.Blacklist(args.blacklist_file)
259 if args.blacklist_file
jbudoricka583ba32015-09-11 17:23:19260 else None)
jbudorickdde688fb2015-08-27 03:00:17261
jbudorick3e0f4b22016-05-28 04:49:47262 if args.output_directory:
263 constants.SetOutputDirectory(args.output_directory)
agrieve243a025a2016-02-12 19:11:02264 # Do an up-front test that the output directory is known.
265 constants.CheckOutputDirectory()
agrieve32dbc2002016-02-06 02:37:54266
jbudorick3e0f4b22016-05-28 04:49:47267 if args.device:
268 devices = [device_utils.DeviceUtils(args.device)]
[email protected]366198e02013-07-12 21:11:18269 else:
jbudorickdde688fb2015-08-27 03:00:17270 devices = device_utils.DeviceUtils.HealthyDevices(blacklist)
[email protected]366198e02013-07-12 21:11:18271
jbudorick8e79ceb2015-03-19 16:28:11272 # This must be done serially because strptime can hit a race condition if
273 # used for the first time in a multithreaded environment.
274 # http://bugs.python.org/issue7980
jbudorick119e4572015-04-24 17:20:03275 for device in devices:
hzl02ff9ee2016-08-15 23:22:57276 resolved_tombstones = ResolveTombstones(
277 device, args.all_tombstones,
278 args.stack, args.wipe_tombstones, args.jobs)
279 for line in resolved_tombstones:
280 logging.info(line)
jbudorick119e4572015-04-24 17:20:03281
hzl15465f22016-12-14 23:14:46282
[email protected]e8044252013-07-11 16:17:56283if __name__ == '__main__':
284 sys.exit(main())