Delay default apps installation on Chrome OS for first time sign-in
[chromium-blink-merge.git] / build / android / tombstones.py
blobfd060ad5175f4ede192ade78ab4b15696051ccbb
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 multiprocessing
14 import os
15 import re
16 import subprocess
17 import sys
18 import optparse
20 from pylib import android_commands
21 from pylib.device import device_utils
24 def _ListTombstones(device):
25 """List the tombstone files on the device.
27 Args:
28 device: An instance of DeviceUtils.
30 Yields:
31 Tuples of (tombstone filename, date time of file on device).
32 """
33 lines = device.RunShellCommand('TZ=UTC su -c ls -a -l /data/tombstones')
34 for line in lines:
35 if 'tombstone' in line and not 'No such file or directory' in line:
36 details = line.split()
37 t = datetime.datetime.strptime(details[-3] + ' ' + details[-2],
38 '%Y-%m-%d %H:%M')
39 yield details[-1], t
42 def _GetDeviceDateTime(device):
43 """Determine the date time on the device.
45 Args:
46 device: An instance of DeviceUtils.
48 Returns:
49 A datetime instance.
50 """
51 device_now_string = device.RunShellCommand('TZ=UTC date')
52 return datetime.datetime.strptime(
53 device_now_string[0], '%a %b %d %H:%M:%S %Z %Y')
56 def _GetTombstoneData(device, tombstone_file):
57 """Retrieve the tombstone data from the device
59 Args:
60 device: An instance of DeviceUtils.
61 tombstone_file: the tombstone to retrieve
63 Returns:
64 A list of lines
65 """
66 return device.ReadFile('/data/tombstones/' + tombstone_file, as_root=True)
69 def _EraseTombstone(device, tombstone_file):
70 """Deletes a tombstone from the device.
72 Args:
73 device: An instance of DeviceUtils.
74 tombstone_file: the tombstone to delete.
75 """
76 return device.RunShellCommand(
77 'rm /data/tombstones/' + tombstone_file, as_root=True)
80 def _DeviceAbiToArch(device_abi):
81 # The order of this list is significant to find the more specific match (e.g.,
82 # arm64) before the less specific (e.g., arm).
83 arches = ['arm64', 'arm', 'x86_64', 'x86_64', 'x86', 'mips']
84 for arch in arches:
85 if arch in device_abi:
86 return arch
87 raise RuntimeError('Unknown device ABI: %s' % device_abi)
89 def _ResolveSymbols(tombstone_data, include_stack, device_abi):
90 """Run the stack tool for given tombstone input.
92 Args:
93 tombstone_data: a list of strings of tombstone data.
94 include_stack: boolean whether to include stack data in output.
95 device_abi: the default ABI of the device which generated the tombstone.
97 Yields:
98 A string for each line of resolved stack output.
99 """
100 # Check if the tombstone data has an ABI listed, if so use this in preference
101 # to the device's default ABI.
102 for line in tombstone_data:
103 found_abi = re.search('ABI: \'(.+?)\'', line)
104 if found_abi:
105 device_abi = found_abi.group(1)
106 arch = _DeviceAbiToArch(device_abi)
107 if not arch:
108 return
110 stack_tool = os.path.join(os.path.dirname(__file__), '..', '..',
111 'third_party', 'android_platform', 'development',
112 'scripts', 'stack')
113 proc = subprocess.Popen([stack_tool, '--arch', arch], stdin=subprocess.PIPE,
114 stdout=subprocess.PIPE)
115 output = proc.communicate(input='\n'.join(tombstone_data))[0]
116 for line in output.split('\n'):
117 if not include_stack and 'Stack Data:' in line:
118 break
119 yield line
122 def _ResolveTombstone(tombstone):
123 lines = []
124 lines += [tombstone['file'] + ' created on ' + str(tombstone['time']) +
125 ', about this long ago: ' +
126 (str(tombstone['device_now'] - tombstone['time']) +
127 ' Device: ' + tombstone['serial'])]
128 print '\n'.join(lines)
129 print 'Resolving...'
130 lines += _ResolveSymbols(tombstone['data'], tombstone['stack'],
131 tombstone['device_abi'])
132 return lines
135 def _ResolveTombstones(jobs, tombstones):
136 """Resolve a list of tombstones.
138 Args:
139 jobs: the number of jobs to use with multiprocess.
140 tombstones: a list of tombstones.
142 if not tombstones:
143 print 'No device attached? Or no tombstones?'
144 return
145 if len(tombstones) == 1:
146 data = _ResolveTombstone(tombstones[0])
147 else:
148 pool = multiprocessing.Pool(processes=jobs)
149 data = pool.map(_ResolveTombstone, tombstones)
150 data = ['\n'.join(d) for d in data]
151 print '\n'.join(data)
154 def _GetTombstonesForDevice(device, options):
155 """Returns a list of tombstones on a given device.
157 Args:
158 device: An instance of DeviceUtils.
159 options: command line arguments from OptParse
161 ret = []
162 all_tombstones = list(_ListTombstones(device))
163 if not all_tombstones:
164 print 'No device attached? Or no tombstones?'
165 return ret
167 # Sort the tombstones in date order, descending
168 all_tombstones.sort(cmp=lambda a, b: cmp(b[1], a[1]))
170 # Only resolve the most recent unless --all-tombstones given.
171 tombstones = all_tombstones if options.all_tombstones else [all_tombstones[0]]
173 device_now = _GetDeviceDateTime(device)
174 for tombstone_file, tombstone_time in tombstones:
175 ret += [{'serial': str(device),
176 'device_abi': device.GetProp('ro.product.cpu.abi'),
177 'device_now': device_now,
178 'time': tombstone_time,
179 'file': tombstone_file,
180 'stack': options.stack,
181 'data': _GetTombstoneData(device, tombstone_file)}]
183 # Erase all the tombstones if desired.
184 if options.wipe_tombstones:
185 for tombstone_file, _ in all_tombstones:
186 _EraseTombstone(device, tombstone_file)
188 return ret
191 def main():
192 parser = optparse.OptionParser()
193 parser.add_option('--device',
194 help='The serial number of the device. If not specified '
195 'will use all devices.')
196 parser.add_option('-a', '--all-tombstones', action='store_true',
197 help="""Resolve symbols for all tombstones, rather than just
198 the most recent""")
199 parser.add_option('-s', '--stack', action='store_true',
200 help='Also include symbols for stack data')
201 parser.add_option('-w', '--wipe-tombstones', action='store_true',
202 help='Erase all tombstones from device after processing')
203 parser.add_option('-j', '--jobs', type='int',
204 default=4,
205 help='Number of jobs to use when processing multiple '
206 'crash stacks.')
207 options, _ = parser.parse_args()
209 if options.device:
210 devices = [options.device]
211 else:
212 devices = android_commands.GetAttachedDevices()
214 tombstones = []
215 for device_serial in devices:
216 device = device_utils.DeviceUtils(device_serial)
217 tombstones += _GetTombstonesForDevice(device, options)
219 _ResolveTombstones(options.jobs, tombstones)
221 if __name__ == '__main__':
222 sys.exit(main())