Clang roll script: fix the fix
[chromium-blink-merge.git] / build / android / tombstones.py
blob5cbca85f7b0dcf17b143aefddda94a057d5f5f30
1 #!/usr/bin/env python
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.
7 # Find the most recent tombstone file(s) on all connected devices
8 # and prints their stacks.
10 # Assumes tombstone file was created with current symbols.
12 import datetime
13 import logging
14 import multiprocessing
15 import os
16 import subprocess
17 import sys
18 import optparse
20 from pylib import android_commands
23 def _ListTombstones(adb):
24 """List the tombstone files on the device.
26 Args:
27 adb: An instance of AndroidCommands.
29 Yields:
30 Tuples of (tombstone filename, date time of file on device).
31 """
32 lines = adb.RunShellCommand('TZ=UTC su -c ls -a -l /data/tombstones')
33 for line in lines:
34 if 'tombstone' in line and not 'No such file or directory' in line:
35 details = line.split()
36 t = datetime.datetime.strptime(details[-3] + ' ' + details[-2],
37 '%Y-%m-%d %H:%M')
38 yield details[-1], t
41 def _GetDeviceDateTime(adb):
42 """Determine the date time on the device.
44 Args:
45 adb: An instance of AndroidCommands.
47 Returns:
48 A datetime instance.
49 """
50 device_now_string = adb.RunShellCommand('TZ=UTC date')
51 return datetime.datetime.strptime(
52 device_now_string[0], '%a %b %d %H:%M:%S %Z %Y')
55 def _GetTombstoneData(adb, tombstone_file):
56 """Retrieve the tombstone data from the device
58 Args:
59 tombstone_file: the tombstone to retrieve
61 Returns:
62 A list of lines
63 """
64 return adb.GetProtectedFileContents('/data/tombstones/' + tombstone_file)
67 def _EraseTombstone(adb, tombstone_file):
68 """Deletes a tombstone from the device.
70 Args:
71 tombstone_file: the tombstone to delete.
72 """
73 return adb.RunShellCommandWithSU('rm /data/tombstones/' + tombstone_file)
76 def _ResolveSymbols(tombstone_data, include_stack):
77 """Run the stack tool for given tombstone input.
79 Args:
80 tombstone_data: a list of strings of tombstone data.
81 include_stack: boolean whether to include stack data in output.
83 Yields:
84 A string for each line of resolved stack output.
85 """
86 stack_tool = os.path.join(os.path.dirname(__file__), '..', '..',
87 'third_party', 'android_platform', 'development',
88 'scripts', 'stack')
89 proc = subprocess.Popen(stack_tool, stdin=subprocess.PIPE,
90 stdout=subprocess.PIPE)
91 output = proc.communicate(input='\n'.join(tombstone_data))[0]
92 for line in output.split('\n'):
93 if not include_stack and 'Stack Data:' in line:
94 break
95 yield line
98 def _ResolveTombstone(tombstone):
99 lines = []
100 lines += [tombstone['file'] + ' created on ' + str(tombstone['time']) +
101 ', about this long ago: ' +
102 (str(tombstone['device_now'] - tombstone['time']) +
103 ' Device: ' + tombstone['serial'])]
104 print '\n'.join(lines)
105 print 'Resolving...'
106 lines += _ResolveSymbols(tombstone['data'], tombstone['stack'])
107 return lines
110 def _ResolveTombstones(jobs, tombstones):
111 """Resolve a list of tombstones.
113 Args:
114 jobs: the number of jobs to use with multiprocess.
115 tombstones: a list of tombstones.
117 if not tombstones:
118 print 'No device attached? Or no tombstones?'
119 return
120 if len(tombstones) == 1:
121 data = _ResolveTombstone(tombstones[0])
122 else:
123 pool = multiprocessing.Pool(processes=jobs)
124 data = pool.map(_ResolveTombstone, tombstones)
125 data = ['\n'.join(d) for d in data]
126 print '\n'.join(data)
129 def _GetTombstonesForDevice(adb, options):
130 """Returns a list of tombstones on a given adb connection.
132 Args:
133 adb: An instance of Androidcommands.
134 options: command line arguments from OptParse
136 ret = []
137 all_tombstones = list(_ListTombstones(adb))
138 if not all_tombstones:
139 print 'No device attached? Or no tombstones?'
140 return ret
142 # Sort the tombstones in date order, descending
143 all_tombstones.sort(cmp=lambda a, b: cmp(b[1], a[1]))
145 # Only resolve the most recent unless --all-tombstones given.
146 tombstones = all_tombstones if options.all_tombstones else [all_tombstones[0]]
148 device_now = _GetDeviceDateTime(adb)
149 for tombstone_file, tombstone_time in tombstones:
150 ret += [{'serial': adb.Adb().GetSerialNumber(),
151 'device_now': device_now,
152 'time': tombstone_time,
153 'file': tombstone_file,
154 'stack': options.stack,
155 'data': _GetTombstoneData(adb, tombstone_file)}]
157 # Erase all the tombstones if desired.
158 if options.wipe_tombstones:
159 for tombstone_file, _ in all_tombstones:
160 _EraseTombstone(adb, tombstone_file)
162 return ret
164 def main():
165 parser = optparse.OptionParser()
166 parser.add_option('--device',
167 help='The serial number of the device. If not specified '
168 'will use all devices.')
169 parser.add_option('-a', '--all-tombstones', action='store_true',
170 help="""Resolve symbols for all tombstones, rather than just
171 the most recent""")
172 parser.add_option('-s', '--stack', action='store_true',
173 help='Also include symbols for stack data')
174 parser.add_option('-w', '--wipe-tombstones', action='store_true',
175 help='Erase all tombstones from device after processing')
176 parser.add_option('-j', '--jobs', type='int',
177 default=4,
178 help='Number of jobs to use when processing multiple '
179 'crash stacks.')
180 options, args = parser.parse_args()
182 if options.device:
183 devices = [options.device]
184 else:
185 devices = android_commands.GetAttachedDevices()
187 tombstones = []
188 for device in devices:
189 adb = android_commands.AndroidCommands(device)
190 tombstones += _GetTombstonesForDevice(adb, options)
192 _ResolveTombstones(options.jobs, tombstones)
194 if __name__ == '__main__':
195 sys.exit(main())