| 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 subprocess | 15 import subprocess |
| 16 import sys | 16 import sys |
| 17 import optparse | 17 import optparse |
| 18 | 18 |
| 19 from pylib import android_commands | 19 from pylib import android_commands |
| 20 from pylib.device import device_utils |
| 20 | 21 |
| 21 | 22 |
| 22 def _ListTombstones(adb): | 23 def _ListTombstones(device): |
| 23 """List the tombstone files on the device. | 24 """List the tombstone files on the device. |
| 24 | 25 |
| 25 Args: | 26 Args: |
| 26 adb: An instance of AndroidCommands. | 27 device: An instance of DeviceUtils. |
| 27 | 28 |
| 28 Yields: | 29 Yields: |
| 29 Tuples of (tombstone filename, date time of file on device). | 30 Tuples of (tombstone filename, date time of file on device). |
| 30 """ | 31 """ |
| 31 lines = adb.RunShellCommand('TZ=UTC su -c ls -a -l /data/tombstones') | 32 lines = device.old_interface.RunShellCommand( |
| 33 'TZ=UTC su -c ls -a -l /data/tombstones') |
| 32 for line in lines: | 34 for line in lines: |
| 33 if 'tombstone' in line and not 'No such file or directory' in line: | 35 if 'tombstone' in line and not 'No such file or directory' in line: |
| 34 details = line.split() | 36 details = line.split() |
| 35 t = datetime.datetime.strptime(details[-3] + ' ' + details[-2], | 37 t = datetime.datetime.strptime(details[-3] + ' ' + details[-2], |
| 36 '%Y-%m-%d %H:%M') | 38 '%Y-%m-%d %H:%M') |
| 37 yield details[-1], t | 39 yield details[-1], t |
| 38 | 40 |
| 39 | 41 |
| 40 def _GetDeviceDateTime(adb): | 42 def _GetDeviceDateTime(device): |
| 41 """Determine the date time on the device. | 43 """Determine the date time on the device. |
| 42 | 44 |
| 43 Args: | 45 Args: |
| 44 adb: An instance of AndroidCommands. | 46 device: An instance of DeviceUtils. |
| 45 | 47 |
| 46 Returns: | 48 Returns: |
| 47 A datetime instance. | 49 A datetime instance. |
| 48 """ | 50 """ |
| 49 device_now_string = adb.RunShellCommand('TZ=UTC date') | 51 device_now_string = device.old_interface.RunShellCommand('TZ=UTC date') |
| 50 return datetime.datetime.strptime( | 52 return datetime.datetime.strptime( |
| 51 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') |
| 52 | 54 |
| 53 | 55 |
| 54 def _GetTombstoneData(adb, tombstone_file): | 56 def _GetTombstoneData(device, tombstone_file): |
| 55 """Retrieve the tombstone data from the device | 57 """Retrieve the tombstone data from the device |
| 56 | 58 |
| 57 Args: | 59 Args: |
| 60 device: An instance of DeviceUtils. |
| 58 tombstone_file: the tombstone to retrieve | 61 tombstone_file: the tombstone to retrieve |
| 59 | 62 |
| 60 Returns: | 63 Returns: |
| 61 A list of lines | 64 A list of lines |
| 62 """ | 65 """ |
| 63 return adb.GetProtectedFileContents('/data/tombstones/' + tombstone_file) | 66 return device.old_interface.GetProtectedFileContents( |
| 67 '/data/tombstones/' + tombstone_file) |
| 64 | 68 |
| 65 | 69 |
| 66 def _EraseTombstone(adb, tombstone_file): | 70 def _EraseTombstone(device, tombstone_file): |
| 67 """Deletes a tombstone from the device. | 71 """Deletes a tombstone from the device. |
| 68 | 72 |
| 69 Args: | 73 Args: |
| 74 device: An instance of DeviceUtils. |
| 70 tombstone_file: the tombstone to delete. | 75 tombstone_file: the tombstone to delete. |
| 71 """ | 76 """ |
| 72 return adb.RunShellCommandWithSU('rm /data/tombstones/' + tombstone_file) | 77 return device.old_interface.RunShellCommandWithSU( |
| 78 'rm /data/tombstones/' + tombstone_file) |
| 73 | 79 |
| 74 | 80 |
| 75 def _ResolveSymbols(tombstone_data, include_stack): | 81 def _ResolveSymbols(tombstone_data, include_stack): |
| 76 """Run the stack tool for given tombstone input. | 82 """Run the stack tool for given tombstone input. |
| 77 | 83 |
| 78 Args: | 84 Args: |
| 79 tombstone_data: a list of strings of tombstone data. | 85 tombstone_data: a list of strings of tombstone data. |
| 80 include_stack: boolean whether to include stack data in output. | 86 include_stack: boolean whether to include stack data in output. |
| 81 | 87 |
| 82 Yields: | 88 Yields: |
| (...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 118 return | 124 return |
| 119 if len(tombstones) == 1: | 125 if len(tombstones) == 1: |
| 120 data = _ResolveTombstone(tombstones[0]) | 126 data = _ResolveTombstone(tombstones[0]) |
| 121 else: | 127 else: |
| 122 pool = multiprocessing.Pool(processes=jobs) | 128 pool = multiprocessing.Pool(processes=jobs) |
| 123 data = pool.map(_ResolveTombstone, tombstones) | 129 data = pool.map(_ResolveTombstone, tombstones) |
| 124 data = ['\n'.join(d) for d in data] | 130 data = ['\n'.join(d) for d in data] |
| 125 print '\n'.join(data) | 131 print '\n'.join(data) |
| 126 | 132 |
| 127 | 133 |
| 128 def _GetTombstonesForDevice(adb, options): | 134 def _GetTombstonesForDevice(device, options): |
| 129 """Returns a list of tombstones on a given adb connection. | 135 """Returns a list of tombstones on a given device. |
| 130 | 136 |
| 131 Args: | 137 Args: |
| 132 adb: An instance of Androidcommands. | 138 device: An instance of DeviceUtils. |
| 133 options: command line arguments from OptParse | 139 options: command line arguments from OptParse |
| 134 """ | 140 """ |
| 135 ret = [] | 141 ret = [] |
| 136 all_tombstones = list(_ListTombstones(adb)) | 142 all_tombstones = list(_ListTombstones(device)) |
| 137 if not all_tombstones: | 143 if not all_tombstones: |
| 138 print 'No device attached? Or no tombstones?' | 144 print 'No device attached? Or no tombstones?' |
| 139 return ret | 145 return ret |
| 140 | 146 |
| 141 # Sort the tombstones in date order, descending | 147 # Sort the tombstones in date order, descending |
| 142 all_tombstones.sort(cmp=lambda a, b: cmp(b[1], a[1])) | 148 all_tombstones.sort(cmp=lambda a, b: cmp(b[1], a[1])) |
| 143 | 149 |
| 144 # Only resolve the most recent unless --all-tombstones given. | 150 # Only resolve the most recent unless --all-tombstones given. |
| 145 tombstones = all_tombstones if options.all_tombstones else [all_tombstones[0]] | 151 tombstones = all_tombstones if options.all_tombstones else [all_tombstones[0]] |
| 146 | 152 |
| 147 device_now = _GetDeviceDateTime(adb) | 153 device_now = _GetDeviceDateTime(device) |
| 148 for tombstone_file, tombstone_time in tombstones: | 154 for tombstone_file, tombstone_time in tombstones: |
| 149 ret += [{'serial': adb.Adb().GetSerialNumber(), | 155 ret += [{'serial': device.old_interface.Adb().GetSerialNumber(), |
| 150 'device_now': device_now, | 156 'device_now': device_now, |
| 151 'time': tombstone_time, | 157 'time': tombstone_time, |
| 152 'file': tombstone_file, | 158 'file': tombstone_file, |
| 153 'stack': options.stack, | 159 'stack': options.stack, |
| 154 'data': _GetTombstoneData(adb, tombstone_file)}] | 160 'data': _GetTombstoneData(device, tombstone_file)}] |
| 155 | 161 |
| 156 # Erase all the tombstones if desired. | 162 # Erase all the tombstones if desired. |
| 157 if options.wipe_tombstones: | 163 if options.wipe_tombstones: |
| 158 for tombstone_file, _ in all_tombstones: | 164 for tombstone_file, _ in all_tombstones: |
| 159 _EraseTombstone(adb, tombstone_file) | 165 _EraseTombstone(device, tombstone_file) |
| 160 | 166 |
| 161 return ret | 167 return ret |
| 162 | 168 |
| 163 def main(): | 169 def main(): |
| 164 parser = optparse.OptionParser() | 170 parser = optparse.OptionParser() |
| 165 parser.add_option('--device', | 171 parser.add_option('--device', |
| 166 help='The serial number of the device. If not specified ' | 172 help='The serial number of the device. If not specified ' |
| 167 'will use all devices.') | 173 'will use all devices.') |
| 168 parser.add_option('-a', '--all-tombstones', action='store_true', | 174 parser.add_option('-a', '--all-tombstones', action='store_true', |
| 169 help="""Resolve symbols for all tombstones, rather than just | 175 help="""Resolve symbols for all tombstones, rather than just |
| 170 the most recent""") | 176 the most recent""") |
| 171 parser.add_option('-s', '--stack', action='store_true', | 177 parser.add_option('-s', '--stack', action='store_true', |
| 172 help='Also include symbols for stack data') | 178 help='Also include symbols for stack data') |
| 173 parser.add_option('-w', '--wipe-tombstones', action='store_true', | 179 parser.add_option('-w', '--wipe-tombstones', action='store_true', |
| 174 help='Erase all tombstones from device after processing') | 180 help='Erase all tombstones from device after processing') |
| 175 parser.add_option('-j', '--jobs', type='int', | 181 parser.add_option('-j', '--jobs', type='int', |
| 176 default=4, | 182 default=4, |
| 177 help='Number of jobs to use when processing multiple ' | 183 help='Number of jobs to use when processing multiple ' |
| 178 'crash stacks.') | 184 'crash stacks.') |
| 179 options, _ = parser.parse_args() | 185 options, _ = parser.parse_args() |
| 180 | 186 |
| 181 if options.device: | 187 if options.device: |
| 182 devices = [options.device] | 188 devices = [options.device] |
| 183 else: | 189 else: |
| 184 devices = android_commands.GetAttachedDevices() | 190 devices = android_commands.GetAttachedDevices() |
| 185 | 191 |
| 186 tombstones = [] | 192 tombstones = [] |
| 187 for device in devices: | 193 for device_serial in devices: |
| 188 adb = android_commands.AndroidCommands(device) | 194 device = device_utils.DeviceUtils(device_serial) |
| 189 tombstones += _GetTombstonesForDevice(adb, options) | 195 tombstones += _GetTombstonesForDevice(device, options) |
| 190 | 196 |
| 191 _ResolveTombstones(options.jobs, tombstones) | 197 _ResolveTombstones(options.jobs, tombstones) |
| 192 | 198 |
| 193 if __name__ == '__main__': | 199 if __name__ == '__main__': |
| 194 sys.exit(main()) | 200 sys.exit(main()) |
| OLD | NEW |