1342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch#!/usr/bin/env python
2342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch#
3342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch# Copyright 2013 The Chromium Authors. All rights reserved.
4342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch# Use of this source code is governed by a BSD-style license that can be
5342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch# found in the LICENSE file.
6342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch#
7342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch# Find the most recent tombstone file(s) on all connected devices
8342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch# and prints their stacks.
9342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch#
10342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch# Assumes tombstone file was created with current symbols.
11342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch
12342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdochimport datetime
13342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdochimport logging
14342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdochimport multiprocessing
15342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdochimport os
16342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdochimport re
17342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdochimport subprocess
18342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdochimport sys
19342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdochimport optparse
20342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch
21342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdochimport devil_chromium
22342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch
23342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdochfrom devil.android import device_blacklist
24342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdochfrom devil.android import device_errors
25342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdochfrom devil.android import device_utils
26342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdochfrom devil.utils import run_tests_helper
27342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdochfrom pylib import constants
28342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch
29342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch_TZ_UTC = {'TZ': 'UTC'}
30342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch
31342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdochdef _ListTombstones(device):
32342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch  """List the tombstone files on the device.
33342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch
34342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch  Args:
35342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch    device: An instance of DeviceUtils.
36342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch
37342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch  Yields:
38342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch    Tuples of (tombstone filename, date time of file on device).
39342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch  """
40342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch  try:
41342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch    if not device.PathExists('/data/tombstones', as_root=True):
42342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch      return
43342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch    # TODO(perezju): Introduce a DeviceUtils.Ls() method (crbug.com/552376).
44342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch    lines = device.RunShellCommand(
45342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch        ['ls', '-a', '-l', '/data/tombstones'],
46342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch        as_root=True, check_return=True, env=_TZ_UTC)
47342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch    for line in lines:
48342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch      if 'tombstone' in line:
49342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch        details = line.split()
50342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch        t = datetime.datetime.strptime(details[-3] + ' ' + details[-2],
51342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch                                       '%Y-%m-%d %H:%M')
52342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch        yield details[-1], t
53342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch  except device_errors.CommandFailedError:
54342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch    logging.exception('Could not retrieve tombstones.')
55342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch  except device_errors.CommandTimeoutError:
56342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch    logging.exception('Timed out retrieving tombstones.')
57342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch
58342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch
59342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdochdef _GetDeviceDateTime(device):
60342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch  """Determine the date time on the device.
61342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch
62342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch  Args:
63342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch    device: An instance of DeviceUtils.
64342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch
65342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch  Returns:
66342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch    A datetime instance.
67342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch  """
68342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch  device_now_string = device.RunShellCommand(
69342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch      ['date'], check_return=True, env=_TZ_UTC)
70342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch  return datetime.datetime.strptime(
71342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch      device_now_string[0], '%a %b %d %H:%M:%S %Z %Y')
72342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch
73342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch
74342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdochdef _GetTombstoneData(device, tombstone_file):
75342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch  """Retrieve the tombstone data from the device
76342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch
77342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch  Args:
78342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch    device: An instance of DeviceUtils.
79342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch    tombstone_file: the tombstone to retrieve
80342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch
81342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch  Returns:
82342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch    A list of lines
83342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch  """
84342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch  return device.ReadFile(
85342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch      '/data/tombstones/' + tombstone_file, as_root=True).splitlines()
86342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch
87342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch
88342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdochdef _EraseTombstone(device, tombstone_file):
89342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch  """Deletes a tombstone from the device.
90342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch
91342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch  Args:
92342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch    device: An instance of DeviceUtils.
93342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch    tombstone_file: the tombstone to delete.
94342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch  """
95342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch  return device.RunShellCommand(
96342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch      ['rm', '/data/tombstones/' + tombstone_file],
97342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch      as_root=True, check_return=True)
98342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch
99342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch
100342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdochdef _DeviceAbiToArch(device_abi):
101342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch  # The order of this list is significant to find the more specific match (e.g.,
102342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch  # arm64) before the less specific (e.g., arm).
103342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch  arches = ['arm64', 'arm', 'x86_64', 'x86_64', 'x86', 'mips']
104342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch  for arch in arches:
105342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch    if arch in device_abi:
106342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch      return arch
107342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch  raise RuntimeError('Unknown device ABI: %s' % device_abi)
108342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch
109342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdochdef _ResolveSymbols(tombstone_data, include_stack, device_abi):
110342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch  """Run the stack tool for given tombstone input.
111342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch
112342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch  Args:
113342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch    tombstone_data: a list of strings of tombstone data.
114342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch    include_stack: boolean whether to include stack data in output.
115342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch    device_abi: the default ABI of the device which generated the tombstone.
116342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch
117342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch  Yields:
118342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch    A string for each line of resolved stack output.
119342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch  """
120342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch  # Check if the tombstone data has an ABI listed, if so use this in preference
121342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch  # to the device's default ABI.
122342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch  for line in tombstone_data:
123342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch    found_abi = re.search('ABI: \'(.+?)\'', line)
124342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch    if found_abi:
125342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch      device_abi = found_abi.group(1)
126342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch  arch = _DeviceAbiToArch(device_abi)
127342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch  if not arch:
128342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch    return
129342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch
130342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch  stack_tool = os.path.join(os.path.dirname(__file__), '..', '..',
131342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch                            'third_party', 'android_platform', 'development',
132342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch                            'scripts', 'stack')
133342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch  cmd = [stack_tool, '--arch', arch, '--output-directory',
134342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch         constants.GetOutDirectory()]
135342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch  proc = subprocess.Popen(cmd, stdin=subprocess.PIPE, stdout=subprocess.PIPE)
136342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch  output = proc.communicate(input='\n'.join(tombstone_data))[0]
137342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch  for line in output.split('\n'):
138342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch    if not include_stack and 'Stack Data:' in line:
139342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch      break
140342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch    yield line
141342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch
142342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch
143342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdochdef _ResolveTombstone(tombstone):
144342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch  lines = []
145342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch  lines += [tombstone['file'] + ' created on ' + str(tombstone['time']) +
146342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch            ', about this long ago: ' +
147342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch            (str(tombstone['device_now'] - tombstone['time']) +
148342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch            ' Device: ' + tombstone['serial'])]
149342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch  logging.info('\n'.join(lines))
150342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch  logging.info('Resolving...')
151342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch  lines += _ResolveSymbols(tombstone['data'], tombstone['stack'],
152342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch                           tombstone['device_abi'])
153342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch  return lines
154342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch
155342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch
156342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdochdef _ResolveTombstones(jobs, tombstones):
157342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch  """Resolve a list of tombstones.
158342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch
159342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch  Args:
160342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch    jobs: the number of jobs to use with multiprocess.
161342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch    tombstones: a list of tombstones.
162342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch  """
163342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch  if not tombstones:
164342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch    logging.warning('No tombstones to resolve.')
165342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch    return
166342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch  if len(tombstones) == 1:
167342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch    data = [_ResolveTombstone(tombstones[0])]
168342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch  else:
169342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch    pool = multiprocessing.Pool(processes=jobs)
170342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch    data = pool.map(_ResolveTombstone, tombstones)
171342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch  for tombstone in data:
172342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch    for line in tombstone:
173342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch      logging.info(line)
174342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch
175342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch
176342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdochdef _GetTombstonesForDevice(device, options):
177342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch  """Returns a list of tombstones on a given device.
178342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch
179342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch  Args:
180342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch    device: An instance of DeviceUtils.
181342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch    options: command line arguments from OptParse
182342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch  """
183342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch  ret = []
184342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch  all_tombstones = list(_ListTombstones(device))
185342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch  if not all_tombstones:
186342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch    logging.warning('No tombstones.')
187342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch    return ret
188342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch
189342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch  # Sort the tombstones in date order, descending
190342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch  all_tombstones.sort(cmp=lambda a, b: cmp(b[1], a[1]))
191342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch
192342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch  # Only resolve the most recent unless --all-tombstones given.
193342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch  tombstones = all_tombstones if options.all_tombstones else [all_tombstones[0]]
194342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch
195342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch  device_now = _GetDeviceDateTime(device)
196342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch  try:
197342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch    for tombstone_file, tombstone_time in tombstones:
198342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch      ret += [{'serial': str(device),
199342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch               'device_abi': device.product_cpu_abi,
200342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch               'device_now': device_now,
201342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch               'time': tombstone_time,
202342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch               'file': tombstone_file,
203342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch               'stack': options.stack,
204342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch               'data': _GetTombstoneData(device, tombstone_file)}]
205342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch  except device_errors.CommandFailedError:
206342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch    for line in device.RunShellCommand(
207342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch        ['ls', '-a', '-l', '/data/tombstones'],
208342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch        as_root=True, check_return=True, env=_TZ_UTC, timeout=60):
209342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch      logging.info('%s: %s', str(device), line)
210342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch    raise
211342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch
212342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch  # Erase all the tombstones if desired.
213342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch  if options.wipe_tombstones:
214342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch    for tombstone_file, _ in all_tombstones:
215342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch      _EraseTombstone(device, tombstone_file)
216342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch
217342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch  return ret
218342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch
219342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch
220342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdochdef main():
221342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch  custom_handler = logging.StreamHandler(sys.stdout)
222342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch  custom_handler.setFormatter(run_tests_helper.CustomFormatter())
223342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch  logging.getLogger().addHandler(custom_handler)
224342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch  logging.getLogger().setLevel(logging.INFO)
225342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch
226342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch  parser = optparse.OptionParser()
227342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch  parser.add_option('--device',
228342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch                    help='The serial number of the device. If not specified '
229342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch                         'will use all devices.')
230342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch  parser.add_option('--blacklist-file', help='Device blacklist JSON file.')
231342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch  parser.add_option('-a', '--all-tombstones', action='store_true',
232342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch                    help="""Resolve symbols for all tombstones, rather than just
233342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch                         the most recent""")
234342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch  parser.add_option('-s', '--stack', action='store_true',
235342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch                    help='Also include symbols for stack data')
236342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch  parser.add_option('-w', '--wipe-tombstones', action='store_true',
237342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch                    help='Erase all tombstones from device after processing')
238342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch  parser.add_option('-j', '--jobs', type='int',
239342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch                    default=4,
240342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch                    help='Number of jobs to use when processing multiple '
241342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch                         'crash stacks.')
242342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch  parser.add_option('--output-directory',
243342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch                    help='Path to the root build directory.')
244342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch  options, _ = parser.parse_args()
245342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch
246342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch  devil_chromium.Initialize()
247342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch
248342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch  blacklist = (device_blacklist.Blacklist(options.blacklist_file)
249342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch               if options.blacklist_file
250342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch               else None)
251342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch
252342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch  if options.output_directory:
253342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch    constants.SetOutputDirectory(options.output_directory)
254342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch  # Do an up-front test that the output directory is known.
255342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch  constants.CheckOutputDirectory()
256342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch
257342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch  if options.device:
258342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch    devices = [device_utils.DeviceUtils(options.device)]
259342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch  else:
260342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch    devices = device_utils.DeviceUtils.HealthyDevices(blacklist)
261342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch
262342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch  # This must be done serially because strptime can hit a race condition if
263342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch  # used for the first time in a multithreaded environment.
264342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch  # http://bugs.python.org/issue7980
265342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch  tombstones = []
266342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch  for device in devices:
267342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch    tombstones += _GetTombstonesForDevice(device, options)
268342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch
269342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch  _ResolveTombstones(options.jobs, tombstones)
270342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch
271342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch
272342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdochif __name__ == '__main__':
273342c50ce1624b485728b9a4fc41d8bbf37eb46cfBen Murdoch  sys.exit(main())
274