Chromium Code Reviews| 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 20 matching lines...) Expand all Loading... | |
| 45 device: An instance of DeviceUtils. | 46 device: An instance of DeviceUtils. |
| 46 | 47 |
| 47 Returns: | 48 Returns: |
| 48 A datetime instance. | 49 A datetime instance. |
| 49 """ | 50 """ |
| 50 device_now_string = device.RunShellCommand('TZ=UTC date') | 51 device_now_string = device.RunShellCommand('TZ=UTC date') |
| 51 return datetime.datetime.strptime( | 52 return datetime.datetime.strptime( |
| 52 device_now_string[0], '%a %b %d %H:%M:%S %Z %Y') | 53 device_now_string[0], '%a %b %d %H:%M:%S %Z %Y') |
| 53 | 54 |
| 54 | 55 |
| 56 def _GetDeviceArch(device): | |
|
jbudorick
2014/07/25 14:19:02
This function isn't needed.
| |
| 57 """Get CPU architecture of the device. | |
| 58 | |
| 59 Args: | |
| 60 device: An instance of DeviceUtils. | |
| 61 | |
| 62 Returns: | |
| 63 CPU architecture string. | |
| 64 """ | |
| 65 lines = device.RunShellCommand('getprop') | |
| 66 for line in lines: | |
| 67 if 'ro.product.cpu.abi' in line: | |
| 68 return re.sub('[\[\]]', '', line.split(':')[1].strip()) | |
| 69 | |
| 70 | |
| 55 def _GetTombstoneData(device, tombstone_file): | 71 def _GetTombstoneData(device, tombstone_file): |
| 56 """Retrieve the tombstone data from the device | 72 """Retrieve the tombstone data from the device |
| 57 | 73 |
| 58 Args: | 74 Args: |
| 59 device: An instance of DeviceUtils. | 75 device: An instance of DeviceUtils. |
| 60 tombstone_file: the tombstone to retrieve | 76 tombstone_file: the tombstone to retrieve |
| 61 | 77 |
| 62 Returns: | 78 Returns: |
| 63 A list of lines | 79 A list of lines |
| 64 """ | 80 """ |
| 65 return device.ReadFile('/data/tombstones/' + tombstone_file, as_root=True) | 81 return device.ReadFile('/data/tombstones/' + tombstone_file, as_root=True) |
| 66 | 82 |
| 67 | 83 |
| 68 def _EraseTombstone(device, tombstone_file): | 84 def _EraseTombstone(device, tombstone_file): |
| 69 """Deletes a tombstone from the device. | 85 """Deletes a tombstone from the device. |
| 70 | 86 |
| 71 Args: | 87 Args: |
| 72 device: An instance of DeviceUtils. | 88 device: An instance of DeviceUtils. |
| 73 tombstone_file: the tombstone to delete. | 89 tombstone_file: the tombstone to delete. |
| 74 """ | 90 """ |
| 75 return device.RunShellCommand( | 91 return device.RunShellCommand( |
| 76 'rm /data/tombstones/' + tombstone_file, as_root=True) | 92 'rm /data/tombstones/' + tombstone_file, as_root=True) |
| 77 | 93 |
| 78 | 94 |
| 79 def _ResolveSymbols(tombstone_data, include_stack): | 95 def _ResolveSymbols(tombstone_data, include_stack, arch): |
| 80 """Run the stack tool for given tombstone input. | 96 """Run the stack tool for given tombstone input. |
| 81 | 97 |
| 82 Args: | 98 Args: |
| 83 tombstone_data: a list of strings of tombstone data. | 99 tombstone_data: a list of strings of tombstone data. |
| 84 include_stack: boolean whether to include stack data in output. | 100 include_stack: boolean whether to include stack data in output. |
|
jbudorick
2014/07/25 14:19:02
Please add a description for arch here.
| |
| 85 | 101 |
| 86 Yields: | 102 Yields: |
| 87 A string for each line of resolved stack output. | 103 A string for each line of resolved stack output. |
| 88 """ | 104 """ |
| 89 stack_tool = os.path.join(os.path.dirname(__file__), '..', '..', | 105 stack_tool = os.path.join(os.path.dirname(__file__), '..', '..', |
| 90 'third_party', 'android_platform', 'development', | 106 'third_party', 'android_platform', 'development', |
| 91 'scripts', 'stack') | 107 'scripts', 'stack') |
| 92 proc = subprocess.Popen(stack_tool, stdin=subprocess.PIPE, | 108 proc = subprocess.Popen([stack_tool, '--arch', arch], stdin=subprocess.PIPE, |
| 93 stdout=subprocess.PIPE) | 109 stdout=subprocess.PIPE) |
| 94 output = proc.communicate(input='\n'.join(tombstone_data))[0] | 110 output = proc.communicate(input='\n'.join(tombstone_data))[0] |
| 95 for line in output.split('\n'): | 111 for line in output.split('\n'): |
| 96 if not include_stack and 'Stack Data:' in line: | 112 if not include_stack and 'Stack Data:' in line: |
| 97 break | 113 break |
| 98 yield line | 114 yield line |
| 99 | 115 |
| 100 | 116 |
| 101 def _ResolveTombstone(tombstone): | 117 def _ResolveTombstone(tombstone): |
| 102 lines = [] | 118 lines = [] |
| 103 lines += [tombstone['file'] + ' created on ' + str(tombstone['time']) + | 119 lines += [tombstone['file'] + ' created on ' + str(tombstone['time']) + |
| 104 ', about this long ago: ' + | 120 ', about this long ago: ' + |
| 105 (str(tombstone['device_now'] - tombstone['time']) + | 121 (str(tombstone['device_now'] - tombstone['time']) + |
| 106 ' Device: ' + tombstone['serial'])] | 122 ' Device: ' + tombstone['serial'])] |
| 107 print '\n'.join(lines) | 123 print '\n'.join(lines) |
| 108 print 'Resolving...' | 124 print 'Resolving...' |
| 109 lines += _ResolveSymbols(tombstone['data'], tombstone['stack']) | 125 lines += _ResolveSymbols(tombstone['data'], tombstone['stack'], |
| 126 tombstone['arch']) | |
| 110 return lines | 127 return lines |
| 111 | 128 |
| 112 | 129 |
| 113 def _ResolveTombstones(jobs, tombstones): | 130 def _ResolveTombstones(jobs, tombstones): |
| 114 """Resolve a list of tombstones. | 131 """Resolve a list of tombstones. |
| 115 | 132 |
| 116 Args: | 133 Args: |
| 117 jobs: the number of jobs to use with multiprocess. | 134 jobs: the number of jobs to use with multiprocess. |
| 118 tombstones: a list of tombstones. | 135 tombstones: a list of tombstones. |
| 119 """ | 136 """ |
| (...skipping 24 matching lines...) Expand all Loading... | |
| 144 | 161 |
| 145 # Sort the tombstones in date order, descending | 162 # Sort the tombstones in date order, descending |
| 146 all_tombstones.sort(cmp=lambda a, b: cmp(b[1], a[1])) | 163 all_tombstones.sort(cmp=lambda a, b: cmp(b[1], a[1])) |
| 147 | 164 |
| 148 # Only resolve the most recent unless --all-tombstones given. | 165 # Only resolve the most recent unless --all-tombstones given. |
| 149 tombstones = all_tombstones if options.all_tombstones else [all_tombstones[0]] | 166 tombstones = all_tombstones if options.all_tombstones else [all_tombstones[0]] |
| 150 | 167 |
| 151 device_now = _GetDeviceDateTime(device) | 168 device_now = _GetDeviceDateTime(device) |
| 152 for tombstone_file, tombstone_time in tombstones: | 169 for tombstone_file, tombstone_time in tombstones: |
| 153 ret += [{'serial': str(device), | 170 ret += [{'serial': str(device), |
| 171 'arch': _GetDeviceArch(device), | |
|
jbudorick
2014/07/25 14:19:02
_GetDeviceArch(device)
should be replaced by
d
| |
| 154 'device_now': device_now, | 172 'device_now': device_now, |
| 155 'time': tombstone_time, | 173 'time': tombstone_time, |
| 156 'file': tombstone_file, | 174 'file': tombstone_file, |
| 157 'stack': options.stack, | 175 'stack': options.stack, |
| 158 'data': _GetTombstoneData(device, tombstone_file)}] | 176 'data': _GetTombstoneData(device, tombstone_file)}] |
| 159 | 177 |
| 160 # Erase all the tombstones if desired. | 178 # Erase all the tombstones if desired. |
| 161 if options.wipe_tombstones: | 179 if options.wipe_tombstones: |
| 162 for tombstone_file, _ in all_tombstones: | 180 for tombstone_file, _ in all_tombstones: |
| 163 _EraseTombstone(device, tombstone_file) | 181 _EraseTombstone(device, tombstone_file) |
| 164 | 182 |
| 165 return ret | 183 return ret |
| 166 | 184 |
| 185 | |
| 167 def main(): | 186 def main(): |
| 168 parser = optparse.OptionParser() | 187 parser = optparse.OptionParser() |
| 169 parser.add_option('--device', | 188 parser.add_option('--device', |
| 170 help='The serial number of the device. If not specified ' | 189 help='The serial number of the device. If not specified ' |
| 171 'will use all devices.') | 190 'will use all devices.') |
| 172 parser.add_option('-a', '--all-tombstones', action='store_true', | 191 parser.add_option('-a', '--all-tombstones', action='store_true', |
| 173 help="""Resolve symbols for all tombstones, rather than just | 192 help="""Resolve symbols for all tombstones, rather than just |
| 174 the most recent""") | 193 the most recent""") |
| 175 parser.add_option('-s', '--stack', action='store_true', | 194 parser.add_option('-s', '--stack', action='store_true', |
| 176 help='Also include symbols for stack data') | 195 help='Also include symbols for stack data') |
| (...skipping 12 matching lines...) Expand all Loading... | |
| 189 | 208 |
| 190 tombstones = [] | 209 tombstones = [] |
| 191 for device_serial in devices: | 210 for device_serial in devices: |
| 192 device = device_utils.DeviceUtils(device_serial) | 211 device = device_utils.DeviceUtils(device_serial) |
| 193 tombstones += _GetTombstonesForDevice(device, options) | 212 tombstones += _GetTombstonesForDevice(device, options) |
| 194 | 213 |
| 195 _ResolveTombstones(options.jobs, tombstones) | 214 _ResolveTombstones(options.jobs, tombstones) |
| 196 | 215 |
| 197 if __name__ == '__main__': | 216 if __name__ == '__main__': |
| 198 sys.exit(main()) | 217 sys.exit(main()) |
| OLD | NEW |