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