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 multiprocessing | 13 import multiprocessing |
14 import os | 14 import os |
| 15 import re |
15 import subprocess | 16 import subprocess |
16 import sys | 17 import sys |
17 import optparse | 18 import optparse |
18 | 19 |
19 from pylib import android_commands | 20 from pylib import android_commands |
20 from pylib.device import device_utils | 21 from pylib.device import device_utils |
21 | 22 |
22 | 23 |
23 def _ListTombstones(device): | 24 def _ListTombstones(device): |
24 """List the tombstone files on the device. | 25 """List the tombstone files on the device. |
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
69 """Deletes a tombstone from the device. | 70 """Deletes a tombstone from the device. |
70 | 71 |
71 Args: | 72 Args: |
72 device: An instance of DeviceUtils. | 73 device: An instance of DeviceUtils. |
73 tombstone_file: the tombstone to delete. | 74 tombstone_file: the tombstone to delete. |
74 """ | 75 """ |
75 return device.RunShellCommand( | 76 return device.RunShellCommand( |
76 'rm /data/tombstones/' + tombstone_file, as_root=True) | 77 'rm /data/tombstones/' + tombstone_file, as_root=True) |
77 | 78 |
78 | 79 |
79 def _ResolveSymbols(tombstone_data, include_stack, arch): | 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) |
| 88 |
| 89 def _ResolveSymbols(tombstone_data, include_stack, device_abi): |
80 """Run the stack tool for given tombstone input. | 90 """Run the stack tool for given tombstone input. |
81 | 91 |
82 Args: | 92 Args: |
83 tombstone_data: a list of strings of tombstone data. | 93 tombstone_data: a list of strings of tombstone data. |
84 include_stack: boolean whether to include stack data in output. | 94 include_stack: boolean whether to include stack data in output. |
85 arch: the device architecture of tombstone data. | 95 device_abi: the default ABI of the device which generated the tombstone. |
86 | 96 |
87 Yields: | 97 Yields: |
88 A string for each line of resolved stack output. | 98 A string for each line of resolved stack output. |
89 """ | 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 |
| 109 |
90 stack_tool = os.path.join(os.path.dirname(__file__), '..', '..', | 110 stack_tool = os.path.join(os.path.dirname(__file__), '..', '..', |
91 'third_party', 'android_platform', 'development', | 111 'third_party', 'android_platform', 'development', |
92 'scripts', 'stack') | 112 'scripts', 'stack') |
93 proc = subprocess.Popen([stack_tool, '--arch', arch], stdin=subprocess.PIPE, | 113 proc = subprocess.Popen([stack_tool, '--arch', arch], stdin=subprocess.PIPE, |
94 stdout=subprocess.PIPE) | 114 stdout=subprocess.PIPE) |
95 output = proc.communicate(input='\n'.join(tombstone_data))[0] | 115 output = proc.communicate(input='\n'.join(tombstone_data))[0] |
96 for line in output.split('\n'): | 116 for line in output.split('\n'): |
97 if not include_stack and 'Stack Data:' in line: | 117 if not include_stack and 'Stack Data:' in line: |
98 break | 118 break |
99 yield line | 119 yield line |
100 | 120 |
101 | 121 |
102 def _ResolveTombstone(tombstone): | 122 def _ResolveTombstone(tombstone): |
103 lines = [] | 123 lines = [] |
104 lines += [tombstone['file'] + ' created on ' + str(tombstone['time']) + | 124 lines += [tombstone['file'] + ' created on ' + str(tombstone['time']) + |
105 ', about this long ago: ' + | 125 ', about this long ago: ' + |
106 (str(tombstone['device_now'] - tombstone['time']) + | 126 (str(tombstone['device_now'] - tombstone['time']) + |
107 ' Device: ' + tombstone['serial'])] | 127 ' Device: ' + tombstone['serial'])] |
108 print '\n'.join(lines) | 128 print '\n'.join(lines) |
109 print 'Resolving...' | 129 print 'Resolving...' |
110 lines += _ResolveSymbols(tombstone['data'], tombstone['stack'], | 130 lines += _ResolveSymbols(tombstone['data'], tombstone['stack'], |
111 tombstone['arch']) | 131 tombstone['device_abi']) |
112 return lines | 132 return lines |
113 | 133 |
114 | 134 |
115 def _ResolveTombstones(jobs, tombstones): | 135 def _ResolveTombstones(jobs, tombstones): |
116 """Resolve a list of tombstones. | 136 """Resolve a list of tombstones. |
117 | 137 |
118 Args: | 138 Args: |
119 jobs: the number of jobs to use with multiprocess. | 139 jobs: the number of jobs to use with multiprocess. |
120 tombstones: a list of tombstones. | 140 tombstones: a list of tombstones. |
121 """ | 141 """ |
(...skipping 24 matching lines...) Expand all Loading... |
146 | 166 |
147 # Sort the tombstones in date order, descending | 167 # Sort the tombstones in date order, descending |
148 all_tombstones.sort(cmp=lambda a, b: cmp(b[1], a[1])) | 168 all_tombstones.sort(cmp=lambda a, b: cmp(b[1], a[1])) |
149 | 169 |
150 # Only resolve the most recent unless --all-tombstones given. | 170 # Only resolve the most recent unless --all-tombstones given. |
151 tombstones = all_tombstones if options.all_tombstones else [all_tombstones[0]] | 171 tombstones = all_tombstones if options.all_tombstones else [all_tombstones[0]] |
152 | 172 |
153 device_now = _GetDeviceDateTime(device) | 173 device_now = _GetDeviceDateTime(device) |
154 for tombstone_file, tombstone_time in tombstones: | 174 for tombstone_file, tombstone_time in tombstones: |
155 ret += [{'serial': str(device), | 175 ret += [{'serial': str(device), |
156 'arch': device.GetProp('ro.product.cpu.abi'), | 176 'device_abi': device.GetProp('ro.product.cpu.abi'), |
157 'device_now': device_now, | 177 'device_now': device_now, |
158 'time': tombstone_time, | 178 'time': tombstone_time, |
159 'file': tombstone_file, | 179 'file': tombstone_file, |
160 'stack': options.stack, | 180 'stack': options.stack, |
161 'data': _GetTombstoneData(device, tombstone_file)}] | 181 'data': _GetTombstoneData(device, tombstone_file)}] |
162 | 182 |
163 # Erase all the tombstones if desired. | 183 # Erase all the tombstones if desired. |
164 if options.wipe_tombstones: | 184 if options.wipe_tombstones: |
165 for tombstone_file, _ in all_tombstones: | 185 for tombstone_file, _ in all_tombstones: |
166 _EraseTombstone(device, tombstone_file) | 186 _EraseTombstone(device, tombstone_file) |
(...skipping 26 matching lines...) Expand all Loading... |
193 | 213 |
194 tombstones = [] | 214 tombstones = [] |
195 for device_serial in devices: | 215 for device_serial in devices: |
196 device = device_utils.DeviceUtils(device_serial) | 216 device = device_utils.DeviceUtils(device_serial) |
197 tombstones += _GetTombstonesForDevice(device, options) | 217 tombstones += _GetTombstonesForDevice(device, options) |
198 | 218 |
199 _ResolveTombstones(options.jobs, tombstones) | 219 _ResolveTombstones(options.jobs, tombstones) |
200 | 220 |
201 if __name__ == '__main__': | 221 if __name__ == '__main__': |
202 sys.exit(main()) | 222 sys.exit(main()) |
OLD | NEW |