| 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 re |
| 16 import subprocess | 16 import subprocess |
| 17 import sys | 17 import sys |
| 18 import optparse | 18 import optparse |
| 19 | 19 |
| 20 from pylib import android_commands | 20 from pylib import android_commands |
| 21 from pylib.device import device_errors |
| 21 from pylib.device import device_utils | 22 from pylib.device import device_utils |
| 22 | 23 |
| 23 | 24 |
| 25 _TZ_UTC = {'TZ': 'UTC'} |
| 26 |
| 24 def _ListTombstones(device): | 27 def _ListTombstones(device): |
| 25 """List the tombstone files on the device. | 28 """List the tombstone files on the device. |
| 26 | 29 |
| 27 Args: | 30 Args: |
| 28 device: An instance of DeviceUtils. | 31 device: An instance of DeviceUtils. |
| 29 | 32 |
| 30 Yields: | 33 Yields: |
| 31 Tuples of (tombstone filename, date time of file on device). | 34 Tuples of (tombstone filename, date time of file on device). |
| 32 """ | 35 """ |
| 33 lines = device.RunShellCommand('TZ=UTC su -c ls -a -l /data/tombstones') | 36 lines = device.RunShellCommand( |
| 37 ['ls', '-a', '-l', '/data/tombstones'], |
| 38 as_root=True, check_return=True, env=_TZ_UTC, timeout=60) |
| 34 for line in lines: | 39 for line in lines: |
| 35 if 'tombstone' in line and not 'No such file or directory' in line: | 40 if 'tombstone' in line and not 'No such file or directory' in line: |
| 36 details = line.split() | 41 details = line.split() |
| 37 t = datetime.datetime.strptime(details[-3] + ' ' + details[-2], | 42 t = datetime.datetime.strptime(details[-3] + ' ' + details[-2], |
| 38 '%Y-%m-%d %H:%M') | 43 '%Y-%m-%d %H:%M') |
| 39 yield details[-1], t | 44 yield details[-1], t |
| 40 | 45 |
| 41 | 46 |
| 42 def _GetDeviceDateTime(device): | 47 def _GetDeviceDateTime(device): |
| 43 """Determine the date time on the device. | 48 """Determine the date time on the device. |
| 44 | 49 |
| 45 Args: | 50 Args: |
| 46 device: An instance of DeviceUtils. | 51 device: An instance of DeviceUtils. |
| 47 | 52 |
| 48 Returns: | 53 Returns: |
| 49 A datetime instance. | 54 A datetime instance. |
| 50 """ | 55 """ |
| 51 device_now_string = device.RunShellCommand('TZ=UTC date') | 56 device_now_string = device.RunShellCommand( |
| 57 ['date'], check_return=True, env=_TZ_UTC) |
| 52 return datetime.datetime.strptime( | 58 return datetime.datetime.strptime( |
| 53 device_now_string[0], '%a %b %d %H:%M:%S %Z %Y') | 59 device_now_string[0], '%a %b %d %H:%M:%S %Z %Y') |
| 54 | 60 |
| 55 | 61 |
| 56 def _GetTombstoneData(device, tombstone_file): | 62 def _GetTombstoneData(device, tombstone_file): |
| 57 """Retrieve the tombstone data from the device | 63 """Retrieve the tombstone data from the device |
| 58 | 64 |
| 59 Args: | 65 Args: |
| 60 device: An instance of DeviceUtils. | 66 device: An instance of DeviceUtils. |
| 61 tombstone_file: the tombstone to retrieve | 67 tombstone_file: the tombstone to retrieve |
| 62 | 68 |
| 63 Returns: | 69 Returns: |
| 64 A list of lines | 70 A list of lines |
| 65 """ | 71 """ |
| 66 return device.ReadFile( | 72 return device.ReadFile( |
| 67 '/data/tombstones/' + tombstone_file, as_root=True).splitlines() | 73 '/data/tombstones/' + tombstone_file, as_root=True).splitlines() |
| 68 | 74 |
| 69 | 75 |
| 70 def _EraseTombstone(device, tombstone_file): | 76 def _EraseTombstone(device, tombstone_file): |
| 71 """Deletes a tombstone from the device. | 77 """Deletes a tombstone from the device. |
| 72 | 78 |
| 73 Args: | 79 Args: |
| 74 device: An instance of DeviceUtils. | 80 device: An instance of DeviceUtils. |
| 75 tombstone_file: the tombstone to delete. | 81 tombstone_file: the tombstone to delete. |
| 76 """ | 82 """ |
| 77 return device.RunShellCommand( | 83 return device.RunShellCommand( |
| 78 'rm /data/tombstones/' + tombstone_file, as_root=True) | 84 ['rm', '/data/tombstones/' + tombstone_file], |
| 85 as_root=True, check_return=True) |
| 79 | 86 |
| 80 | 87 |
| 81 def _DeviceAbiToArch(device_abi): | 88 def _DeviceAbiToArch(device_abi): |
| 82 # The order of this list is significant to find the more specific match (e.g., | 89 # The order of this list is significant to find the more specific match (e.g., |
| 83 # arm64) before the less specific (e.g., arm). | 90 # arm64) before the less specific (e.g., arm). |
| 84 arches = ['arm64', 'arm', 'x86_64', 'x86_64', 'x86', 'mips'] | 91 arches = ['arm64', 'arm', 'x86_64', 'x86_64', 'x86', 'mips'] |
| 85 for arch in arches: | 92 for arch in arches: |
| 86 if arch in device_abi: | 93 if arch in device_abi: |
| 87 return arch | 94 return arch |
| 88 raise RuntimeError('Unknown device ABI: %s' % device_abi) | 95 raise RuntimeError('Unknown device ABI: %s' % device_abi) |
| (...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 165 print 'No device attached? Or no tombstones?' | 172 print 'No device attached? Or no tombstones?' |
| 166 return ret | 173 return ret |
| 167 | 174 |
| 168 # Sort the tombstones in date order, descending | 175 # Sort the tombstones in date order, descending |
| 169 all_tombstones.sort(cmp=lambda a, b: cmp(b[1], a[1])) | 176 all_tombstones.sort(cmp=lambda a, b: cmp(b[1], a[1])) |
| 170 | 177 |
| 171 # Only resolve the most recent unless --all-tombstones given. | 178 # Only resolve the most recent unless --all-tombstones given. |
| 172 tombstones = all_tombstones if options.all_tombstones else [all_tombstones[0]] | 179 tombstones = all_tombstones if options.all_tombstones else [all_tombstones[0]] |
| 173 | 180 |
| 174 device_now = _GetDeviceDateTime(device) | 181 device_now = _GetDeviceDateTime(device) |
| 175 for tombstone_file, tombstone_time in tombstones: | 182 try: |
| 176 ret += [{'serial': str(device), | 183 for tombstone_file, tombstone_time in tombstones: |
| 177 'device_abi': device.product_cpu_abi, | 184 ret += [{'serial': str(device), |
| 178 'device_now': device_now, | 185 'device_abi': device.product_cpu_abi, |
| 179 'time': tombstone_time, | 186 'device_now': device_now, |
| 180 'file': tombstone_file, | 187 'time': tombstone_time, |
| 181 'stack': options.stack, | 188 'file': tombstone_file, |
| 182 'data': _GetTombstoneData(device, tombstone_file)}] | 189 'stack': options.stack, |
| 190 'data': _GetTombstoneData(device, tombstone_file)}] |
| 191 except device_errors.CommandFailedError: |
| 192 for line in device.RunShellCommand( |
| 193 ['ls', '-a', '-l', '/data/tombstones'], |
| 194 as_root=True, check_return=True, env=_TZ_UTC, timeout=60): |
| 195 print '%s: %s' % (str(device), line) |
| 196 raise |
| 183 | 197 |
| 184 # Erase all the tombstones if desired. | 198 # Erase all the tombstones if desired. |
| 185 if options.wipe_tombstones: | 199 if options.wipe_tombstones: |
| 186 for tombstone_file, _ in all_tombstones: | 200 for tombstone_file, _ in all_tombstones: |
| 187 _EraseTombstone(device, tombstone_file) | 201 _EraseTombstone(device, tombstone_file) |
| 188 | 202 |
| 189 return ret | 203 return ret |
| 190 | 204 |
| 191 | 205 |
| 192 def main(): | 206 def main(): |
| (...skipping 21 matching lines...) Expand all Loading... |
| 214 | 228 |
| 215 tombstones = [] | 229 tombstones = [] |
| 216 for device_serial in devices: | 230 for device_serial in devices: |
| 217 device = device_utils.DeviceUtils(device_serial) | 231 device = device_utils.DeviceUtils(device_serial) |
| 218 tombstones += _GetTombstonesForDevice(device, options) | 232 tombstones += _GetTombstonesForDevice(device, options) |
| 219 | 233 |
| 220 _ResolveTombstones(options.jobs, tombstones) | 234 _ResolveTombstones(options.jobs, tombstones) |
| 221 | 235 |
| 222 if __name__ == '__main__': | 236 if __name__ == '__main__': |
| 223 sys.exit(main()) | 237 sys.exit(main()) |
| OLD | NEW |