xref: /aosp_15_r20/development/tools/monkey (revision 90c8c64db3049935a07c6143d7fd006e26f8ecca)
1*90c8c64dSAndroid Build Coastguard Worker#!/usr/bin/env python2.7
2*90c8c64dSAndroid Build Coastguard Worker
3*90c8c64dSAndroid Build Coastguard Workerimport argparse
4*90c8c64dSAndroid Build Coastguard Workerimport datetime
5*90c8c64dSAndroid Build Coastguard Workerimport os
6*90c8c64dSAndroid Build Coastguard Workerimport re
7*90c8c64dSAndroid Build Coastguard Workerimport subprocess
8*90c8c64dSAndroid Build Coastguard Workerimport sys
9*90c8c64dSAndroid Build Coastguard Workerimport threading
10*90c8c64dSAndroid Build Coastguard Workerimport time
11*90c8c64dSAndroid Build Coastguard Worker
12*90c8c64dSAndroid Build Coastguard WorkerQUIET = False
13*90c8c64dSAndroid Build Coastguard Worker
14*90c8c64dSAndroid Build Coastguard Worker# ANSI escape sequences
15*90c8c64dSAndroid Build Coastguard Workerif sys.stdout.isatty():
16*90c8c64dSAndroid Build Coastguard Worker  BOLD = "\033[1m"
17*90c8c64dSAndroid Build Coastguard Worker  RED = "\033[91m" + BOLD
18*90c8c64dSAndroid Build Coastguard Worker  GREEN = "\033[92m" + BOLD
19*90c8c64dSAndroid Build Coastguard Worker  YELLOW = "\033[93m" + BOLD
20*90c8c64dSAndroid Build Coastguard Worker  UNDERLINE = "\033[4m"
21*90c8c64dSAndroid Build Coastguard Worker  ENDCOLOR = "\033[0m"
22*90c8c64dSAndroid Build Coastguard Worker  CLEARLINE = "\033[K"
23*90c8c64dSAndroid Build Coastguard Worker  STDOUT_IS_TTY = True
24*90c8c64dSAndroid Build Coastguard Workerelse:
25*90c8c64dSAndroid Build Coastguard Worker  BOLD = ""
26*90c8c64dSAndroid Build Coastguard Worker  RED = ""
27*90c8c64dSAndroid Build Coastguard Worker  GREEN = ""
28*90c8c64dSAndroid Build Coastguard Worker  YELLOW = ""
29*90c8c64dSAndroid Build Coastguard Worker  UNDERLINE = ""
30*90c8c64dSAndroid Build Coastguard Worker  ENDCOLOR = ""
31*90c8c64dSAndroid Build Coastguard Worker  CLEARLINE = ""
32*90c8c64dSAndroid Build Coastguard Worker  STDOUT_IS_TTY = False
33*90c8c64dSAndroid Build Coastguard Worker
34*90c8c64dSAndroid Build Coastguard Workerdef PrintStatus(s):
35*90c8c64dSAndroid Build Coastguard Worker  """Prints a bold underlined status message"""
36*90c8c64dSAndroid Build Coastguard Worker  sys.stdout.write("\n")
37*90c8c64dSAndroid Build Coastguard Worker  sys.stdout.write(BOLD)
38*90c8c64dSAndroid Build Coastguard Worker  sys.stdout.write(UNDERLINE)
39*90c8c64dSAndroid Build Coastguard Worker  sys.stdout.write(s)
40*90c8c64dSAndroid Build Coastguard Worker  sys.stdout.write(ENDCOLOR)
41*90c8c64dSAndroid Build Coastguard Worker  sys.stdout.write("\n")
42*90c8c64dSAndroid Build Coastguard Worker
43*90c8c64dSAndroid Build Coastguard Worker
44*90c8c64dSAndroid Build Coastguard Workerdef PrintCommand(cmd, env=None):
45*90c8c64dSAndroid Build Coastguard Worker  """Prints a bold line of a shell command that is being run"""
46*90c8c64dSAndroid Build Coastguard Worker  if not QUIET:
47*90c8c64dSAndroid Build Coastguard Worker    sys.stdout.write(BOLD)
48*90c8c64dSAndroid Build Coastguard Worker    if env:
49*90c8c64dSAndroid Build Coastguard Worker      for k,v in env.iteritems():
50*90c8c64dSAndroid Build Coastguard Worker        if " " in v and "\"" not in v:
51*90c8c64dSAndroid Build Coastguard Worker          sys.stdout.write("%s=\"%s\" " % (k, v.replace("\"", "\\\"")))
52*90c8c64dSAndroid Build Coastguard Worker        else:
53*90c8c64dSAndroid Build Coastguard Worker          sys.stdout.write("%s=%s " % (k, v))
54*90c8c64dSAndroid Build Coastguard Worker    sys.stdout.write(" ".join(cmd))
55*90c8c64dSAndroid Build Coastguard Worker    sys.stdout.write(ENDCOLOR)
56*90c8c64dSAndroid Build Coastguard Worker    sys.stdout.write("\n")
57*90c8c64dSAndroid Build Coastguard Worker
58*90c8c64dSAndroid Build Coastguard Worker
59*90c8c64dSAndroid Build Coastguard Workerclass ExecutionException(Exception):
60*90c8c64dSAndroid Build Coastguard Worker  """Thrown to cleanly abort operation."""
61*90c8c64dSAndroid Build Coastguard Worker  def __init__(self,*args,**kwargs):
62*90c8c64dSAndroid Build Coastguard Worker    Exception.__init__(self,*args,**kwargs)
63*90c8c64dSAndroid Build Coastguard Worker
64*90c8c64dSAndroid Build Coastguard Worker
65*90c8c64dSAndroid Build Coastguard Workerclass Adb(object):
66*90c8c64dSAndroid Build Coastguard Worker  """Encapsulates adb functionality."""
67*90c8c64dSAndroid Build Coastguard Worker
68*90c8c64dSAndroid Build Coastguard Worker  def __init__(self):
69*90c8c64dSAndroid Build Coastguard Worker    """Initialize adb."""
70*90c8c64dSAndroid Build Coastguard Worker    self._command = ["adb"]
71*90c8c64dSAndroid Build Coastguard Worker
72*90c8c64dSAndroid Build Coastguard Worker
73*90c8c64dSAndroid Build Coastguard Worker  def Exec(self, cmd, stdout=None, stderr=None):
74*90c8c64dSAndroid Build Coastguard Worker    """Runs an adb command, and prints that command to stdout.
75*90c8c64dSAndroid Build Coastguard Worker
76*90c8c64dSAndroid Build Coastguard Worker      Raises:
77*90c8c64dSAndroid Build Coastguard Worker        ExecutionException: if the adb command returned an error.
78*90c8c64dSAndroid Build Coastguard Worker
79*90c8c64dSAndroid Build Coastguard Worker      Example:
80*90c8c64dSAndroid Build Coastguard Worker        adb.Exec("shell", "ls") will run "adb shell ls"
81*90c8c64dSAndroid Build Coastguard Worker    """
82*90c8c64dSAndroid Build Coastguard Worker    cmd = self._command + cmd
83*90c8c64dSAndroid Build Coastguard Worker    PrintCommand(cmd)
84*90c8c64dSAndroid Build Coastguard Worker    result = subprocess.call(cmd, stdout=stdout, stderr=stderr)
85*90c8c64dSAndroid Build Coastguard Worker    if result:
86*90c8c64dSAndroid Build Coastguard Worker      raise ExecutionException("adb: %s returned %s" % (cmd, result))
87*90c8c64dSAndroid Build Coastguard Worker
88*90c8c64dSAndroid Build Coastguard Worker
89*90c8c64dSAndroid Build Coastguard Worker  def WaitForDevice(self):
90*90c8c64dSAndroid Build Coastguard Worker    """Waits for the android device to be available on usb with adbd running."""
91*90c8c64dSAndroid Build Coastguard Worker    self.Exec(["wait-for-device"])
92*90c8c64dSAndroid Build Coastguard Worker
93*90c8c64dSAndroid Build Coastguard Worker
94*90c8c64dSAndroid Build Coastguard Worker  def Run(self, cmd, stdout=None, stderr=None):
95*90c8c64dSAndroid Build Coastguard Worker    """Waits for the device, and then runs a command.
96*90c8c64dSAndroid Build Coastguard Worker
97*90c8c64dSAndroid Build Coastguard Worker      Raises:
98*90c8c64dSAndroid Build Coastguard Worker        ExecutionException: if the adb command returned an error.
99*90c8c64dSAndroid Build Coastguard Worker
100*90c8c64dSAndroid Build Coastguard Worker      Example:
101*90c8c64dSAndroid Build Coastguard Worker        adb.Run("shell", "ls") will run "adb shell ls"
102*90c8c64dSAndroid Build Coastguard Worker    """
103*90c8c64dSAndroid Build Coastguard Worker    self.WaitForDevice()
104*90c8c64dSAndroid Build Coastguard Worker    self.Exec(cmd, stdout=stdout, stderr=stderr)
105*90c8c64dSAndroid Build Coastguard Worker
106*90c8c64dSAndroid Build Coastguard Worker
107*90c8c64dSAndroid Build Coastguard Worker  def Get(self, cmd):
108*90c8c64dSAndroid Build Coastguard Worker    """Waits for the device, and then runs a command, returning the output.
109*90c8c64dSAndroid Build Coastguard Worker
110*90c8c64dSAndroid Build Coastguard Worker      Raises:
111*90c8c64dSAndroid Build Coastguard Worker        ExecutionException: if the adb command returned an error.
112*90c8c64dSAndroid Build Coastguard Worker
113*90c8c64dSAndroid Build Coastguard Worker      Example:
114*90c8c64dSAndroid Build Coastguard Worker        adb.Get(["shell", "ls"]) will run "adb shell ls"
115*90c8c64dSAndroid Build Coastguard Worker    """
116*90c8c64dSAndroid Build Coastguard Worker    self.WaitForDevice()
117*90c8c64dSAndroid Build Coastguard Worker    cmd = self._command + cmd
118*90c8c64dSAndroid Build Coastguard Worker    PrintCommand(cmd)
119*90c8c64dSAndroid Build Coastguard Worker    try:
120*90c8c64dSAndroid Build Coastguard Worker      text = subprocess.check_output(cmd)
121*90c8c64dSAndroid Build Coastguard Worker      return text.strip()
122*90c8c64dSAndroid Build Coastguard Worker    except subprocess.CalledProcessError as ex:
123*90c8c64dSAndroid Build Coastguard Worker      raise ExecutionException("adb: %s returned %s" % (cmd, ex.returncode))
124*90c8c64dSAndroid Build Coastguard Worker
125*90c8c64dSAndroid Build Coastguard Worker
126*90c8c64dSAndroid Build Coastguard Worker  def Shell(self, cmd, stdout=None, stderr=None):
127*90c8c64dSAndroid Build Coastguard Worker    """Runs an adb shell command
128*90c8c64dSAndroid Build Coastguard Worker      Args:
129*90c8c64dSAndroid Build Coastguard Worker        cmd: The command to run.
130*90c8c64dSAndroid Build Coastguard Worker
131*90c8c64dSAndroid Build Coastguard Worker      Raises:
132*90c8c64dSAndroid Build Coastguard Worker        ExecutionException: if the adb command returned an error.
133*90c8c64dSAndroid Build Coastguard Worker
134*90c8c64dSAndroid Build Coastguard Worker      Example:
135*90c8c64dSAndroid Build Coastguard Worker        adb.Shell(["ls"]) will run "adb shell ls"
136*90c8c64dSAndroid Build Coastguard Worker    """
137*90c8c64dSAndroid Build Coastguard Worker    cmd = ["shell"] + cmd
138*90c8c64dSAndroid Build Coastguard Worker    self.Run(cmd, stdout=stdout, stderr=stderr)
139*90c8c64dSAndroid Build Coastguard Worker
140*90c8c64dSAndroid Build Coastguard Worker
141*90c8c64dSAndroid Build Coastguard Worker  def GetProp(self, name):
142*90c8c64dSAndroid Build Coastguard Worker    """Gets a system property from the device."""
143*90c8c64dSAndroid Build Coastguard Worker    return self.Get(["shell", "getprop", name])
144*90c8c64dSAndroid Build Coastguard Worker
145*90c8c64dSAndroid Build Coastguard Worker
146*90c8c64dSAndroid Build Coastguard Worker  def Reboot(self):
147*90c8c64dSAndroid Build Coastguard Worker    """Reboots the device, and waits for boot to complete."""
148*90c8c64dSAndroid Build Coastguard Worker    # Reboot
149*90c8c64dSAndroid Build Coastguard Worker    self.Run(["reboot"])
150*90c8c64dSAndroid Build Coastguard Worker    # Wait until it comes back on adb
151*90c8c64dSAndroid Build Coastguard Worker    self.WaitForDevice()
152*90c8c64dSAndroid Build Coastguard Worker    # Poll until the system says it's booted
153*90c8c64dSAndroid Build Coastguard Worker    while self.GetProp("sys.boot_completed") != "1":
154*90c8c64dSAndroid Build Coastguard Worker      time.sleep(2)
155*90c8c64dSAndroid Build Coastguard Worker    # Dismiss the keyguard
156*90c8c64dSAndroid Build Coastguard Worker    self.Shell(["wm", "dismiss-keyguard"]);
157*90c8c64dSAndroid Build Coastguard Worker
158*90c8c64dSAndroid Build Coastguard Worker  def GetBatteryProperties(self):
159*90c8c64dSAndroid Build Coastguard Worker    """A dict of the properties from adb shell dumpsys battery"""
160*90c8c64dSAndroid Build Coastguard Worker    def ConvertVal(s):
161*90c8c64dSAndroid Build Coastguard Worker      if s == "true":
162*90c8c64dSAndroid Build Coastguard Worker        return True
163*90c8c64dSAndroid Build Coastguard Worker      elif s == "false":
164*90c8c64dSAndroid Build Coastguard Worker        return False
165*90c8c64dSAndroid Build Coastguard Worker      else:
166*90c8c64dSAndroid Build Coastguard Worker        try:
167*90c8c64dSAndroid Build Coastguard Worker          return int(s)
168*90c8c64dSAndroid Build Coastguard Worker        except ValueError:
169*90c8c64dSAndroid Build Coastguard Worker          return s
170*90c8c64dSAndroid Build Coastguard Worker    text = self.Get(["shell", "dumpsys", "battery"])
171*90c8c64dSAndroid Build Coastguard Worker    lines = [line.strip() for line in text.split("\n")][1:]
172*90c8c64dSAndroid Build Coastguard Worker    lines = [[s.strip() for s in line.split(":", 1)] for line in lines]
173*90c8c64dSAndroid Build Coastguard Worker    lines = [(k,ConvertVal(v)) for k,v in lines]
174*90c8c64dSAndroid Build Coastguard Worker    return dict(lines)
175*90c8c64dSAndroid Build Coastguard Worker
176*90c8c64dSAndroid Build Coastguard Worker  def GetBatteryLevel(self):
177*90c8c64dSAndroid Build Coastguard Worker    """Returns the battery level"""
178*90c8c64dSAndroid Build Coastguard Worker    return self.GetBatteryProperties()["level"]
179*90c8c64dSAndroid Build Coastguard Worker
180*90c8c64dSAndroid Build Coastguard Worker
181*90c8c64dSAndroid Build Coastguard Worker
182*90c8c64dSAndroid Build Coastguard Workerdef CurrentTimestamp():
183*90c8c64dSAndroid Build Coastguard Worker  """Returns the current time in a format suitable for filenames."""
184*90c8c64dSAndroid Build Coastguard Worker  return datetime.datetime.now().strftime("%Y-%m-%d-%H-%M-%S")
185*90c8c64dSAndroid Build Coastguard Worker
186*90c8c64dSAndroid Build Coastguard Worker
187*90c8c64dSAndroid Build Coastguard Workerdef ParseOptions():
188*90c8c64dSAndroid Build Coastguard Worker  """Parse the command line options.
189*90c8c64dSAndroid Build Coastguard Worker
190*90c8c64dSAndroid Build Coastguard Worker    Returns an argparse options object.
191*90c8c64dSAndroid Build Coastguard Worker  """
192*90c8c64dSAndroid Build Coastguard Worker  parser = argparse.ArgumentParser(description="Run monkeys and collect the results.")
193*90c8c64dSAndroid Build Coastguard Worker  parser.add_argument("--dir", action="store",
194*90c8c64dSAndroid Build Coastguard Worker                      help="output directory for results of monkey runs")
195*90c8c64dSAndroid Build Coastguard Worker  parser.add_argument("--events", action="store", type=int, default=125000,
196*90c8c64dSAndroid Build Coastguard Worker                      help="number of events per monkey run")
197*90c8c64dSAndroid Build Coastguard Worker  parser.add_argument("-p", action="append", dest="packages",
198*90c8c64dSAndroid Build Coastguard Worker                      help="package to use (default is a set of system-wide packages")
199*90c8c64dSAndroid Build Coastguard Worker  parser.add_argument("--runs", action="store", type=int, default=10000000,
200*90c8c64dSAndroid Build Coastguard Worker                      help="number of monkey runs to perform")
201*90c8c64dSAndroid Build Coastguard Worker  parser.add_argument("--type", choices=["crash", "anr"],
202*90c8c64dSAndroid Build Coastguard Worker                      help="only stop on errors of the given type (crash or anr)")
203*90c8c64dSAndroid Build Coastguard Worker  parser.add_argument("--description", action="store",
204*90c8c64dSAndroid Build Coastguard Worker                      help="only stop if the error description contains DESCRIPTION")
205*90c8c64dSAndroid Build Coastguard Worker
206*90c8c64dSAndroid Build Coastguard Worker  options = parser.parse_args()
207*90c8c64dSAndroid Build Coastguard Worker
208*90c8c64dSAndroid Build Coastguard Worker  if not options.dir:
209*90c8c64dSAndroid Build Coastguard Worker    options.dir = "monkeys-%s" % CurrentTimestamp()
210*90c8c64dSAndroid Build Coastguard Worker
211*90c8c64dSAndroid Build Coastguard Worker  if not options.packages:
212*90c8c64dSAndroid Build Coastguard Worker    options.packages = [
213*90c8c64dSAndroid Build Coastguard Worker        "com.google.android.deskclock",
214*90c8c64dSAndroid Build Coastguard Worker        "com.android.calculator2",
215*90c8c64dSAndroid Build Coastguard Worker        "com.google.android.contacts",
216*90c8c64dSAndroid Build Coastguard Worker        "com.android.launcher",
217*90c8c64dSAndroid Build Coastguard Worker        "com.google.android.launcher",
218*90c8c64dSAndroid Build Coastguard Worker        "com.android.mms",
219*90c8c64dSAndroid Build Coastguard Worker        "com.google.android.apps.messaging",
220*90c8c64dSAndroid Build Coastguard Worker        "com.android.phone",
221*90c8c64dSAndroid Build Coastguard Worker        "com.google.android.dialer",
222*90c8c64dSAndroid Build Coastguard Worker        "com.android.providers.downloads.ui",
223*90c8c64dSAndroid Build Coastguard Worker        "com.android.settings",
224*90c8c64dSAndroid Build Coastguard Worker        "com.google.android.calendar",
225*90c8c64dSAndroid Build Coastguard Worker        "com.google.android.GoogleCamera",
226*90c8c64dSAndroid Build Coastguard Worker        "com.google.android.apps.photos",
227*90c8c64dSAndroid Build Coastguard Worker        "com.google.android.gms",
228*90c8c64dSAndroid Build Coastguard Worker        "com.google.android.setupwizard",
229*90c8c64dSAndroid Build Coastguard Worker        "com.google.android.googlequicksearchbox",
230*90c8c64dSAndroid Build Coastguard Worker        "com.google.android.packageinstaller",
231*90c8c64dSAndroid Build Coastguard Worker        "com.google.android.apps.nexuslauncher"
232*90c8c64dSAndroid Build Coastguard Worker      ]
233*90c8c64dSAndroid Build Coastguard Worker
234*90c8c64dSAndroid Build Coastguard Worker  return options
235*90c8c64dSAndroid Build Coastguard Worker
236*90c8c64dSAndroid Build Coastguard Worker
237*90c8c64dSAndroid Build Coastguard Workeradb = Adb()
238*90c8c64dSAndroid Build Coastguard Worker
239*90c8c64dSAndroid Build Coastguard Workerdef main():
240*90c8c64dSAndroid Build Coastguard Worker  """Main entry point."""
241*90c8c64dSAndroid Build Coastguard Worker
242*90c8c64dSAndroid Build Coastguard Worker  def LogcatThreadFunc():
243*90c8c64dSAndroid Build Coastguard Worker    logcatProcess.communicate()
244*90c8c64dSAndroid Build Coastguard Worker
245*90c8c64dSAndroid Build Coastguard Worker  options = ParseOptions()
246*90c8c64dSAndroid Build Coastguard Worker
247*90c8c64dSAndroid Build Coastguard Worker  # Set up the device a little bit
248*90c8c64dSAndroid Build Coastguard Worker  PrintStatus("Setting up the device")
249*90c8c64dSAndroid Build Coastguard Worker  adb.Run(["root"])
250*90c8c64dSAndroid Build Coastguard Worker  time.sleep(2)
251*90c8c64dSAndroid Build Coastguard Worker  adb.WaitForDevice()
252*90c8c64dSAndroid Build Coastguard Worker  adb.Run(["remount"])
253*90c8c64dSAndroid Build Coastguard Worker  time.sleep(2)
254*90c8c64dSAndroid Build Coastguard Worker  adb.WaitForDevice()
255*90c8c64dSAndroid Build Coastguard Worker  adb.Shell(["echo ro.audio.silent=1 > /data/local.prop"])
256*90c8c64dSAndroid Build Coastguard Worker  adb.Shell(["chmod 644 /data/local.prop"])
257*90c8c64dSAndroid Build Coastguard Worker
258*90c8c64dSAndroid Build Coastguard Worker  # Figure out how many leading zeroes we need.
259*90c8c64dSAndroid Build Coastguard Worker  pattern = "%%0%dd" % len(str(options.runs-1))
260*90c8c64dSAndroid Build Coastguard Worker
261*90c8c64dSAndroid Build Coastguard Worker  # Make the output directory
262*90c8c64dSAndroid Build Coastguard Worker  if os.path.exists(options.dir) and not os.path.isdir(options.dir):
263*90c8c64dSAndroid Build Coastguard Worker    sys.stderr.write("Output directory already exists and is not a directory: %s\n"
264*90c8c64dSAndroid Build Coastguard Worker        % options.dir)
265*90c8c64dSAndroid Build Coastguard Worker    sys.exit(1)
266*90c8c64dSAndroid Build Coastguard Worker  elif not os.path.exists(options.dir):
267*90c8c64dSAndroid Build Coastguard Worker    os.makedirs(options.dir)
268*90c8c64dSAndroid Build Coastguard Worker
269*90c8c64dSAndroid Build Coastguard Worker  # Run the tests
270*90c8c64dSAndroid Build Coastguard Worker  for run in range(1, options.runs+1):
271*90c8c64dSAndroid Build Coastguard Worker    PrintStatus("Run %d of %d: %s" % (run, options.runs,
272*90c8c64dSAndroid Build Coastguard Worker        datetime.datetime.now().strftime("%A, %B %d %Y %I:%M %p")))
273*90c8c64dSAndroid Build Coastguard Worker
274*90c8c64dSAndroid Build Coastguard Worker    # Reboot and wait for 30 seconds to let the system quiet down so the
275*90c8c64dSAndroid Build Coastguard Worker    # log isn't polluted with all the boot completed crap.
276*90c8c64dSAndroid Build Coastguard Worker    if True:
277*90c8c64dSAndroid Build Coastguard Worker      adb.Reboot()
278*90c8c64dSAndroid Build Coastguard Worker      PrintCommand(["sleep", "30"])
279*90c8c64dSAndroid Build Coastguard Worker      time.sleep(30)
280*90c8c64dSAndroid Build Coastguard Worker
281*90c8c64dSAndroid Build Coastguard Worker    # Monkeys can outrun the battery, so if it's getting low, pause to
282*90c8c64dSAndroid Build Coastguard Worker    # let it charge.
283*90c8c64dSAndroid Build Coastguard Worker    if True:
284*90c8c64dSAndroid Build Coastguard Worker      targetBatteryLevel = 20
285*90c8c64dSAndroid Build Coastguard Worker      while True:
286*90c8c64dSAndroid Build Coastguard Worker        level = adb.GetBatteryLevel()
287*90c8c64dSAndroid Build Coastguard Worker        if level > targetBatteryLevel:
288*90c8c64dSAndroid Build Coastguard Worker          break
289*90c8c64dSAndroid Build Coastguard Worker        print "Battery level is %d%%.  Pausing to let it charge above %d%%." % (
290*90c8c64dSAndroid Build Coastguard Worker            level, targetBatteryLevel)
291*90c8c64dSAndroid Build Coastguard Worker        time.sleep(60)
292*90c8c64dSAndroid Build Coastguard Worker
293*90c8c64dSAndroid Build Coastguard Worker    filebase = os.path.sep.join((options.dir, pattern % run))
294*90c8c64dSAndroid Build Coastguard Worker    bugreportFilename = filebase + "-bugreport.txt"
295*90c8c64dSAndroid Build Coastguard Worker    monkeyFilename = filebase + "-monkey.txt"
296*90c8c64dSAndroid Build Coastguard Worker    logcatFilename = filebase + "-logcat.txt"
297*90c8c64dSAndroid Build Coastguard Worker    htmlFilename = filebase + ".html"
298*90c8c64dSAndroid Build Coastguard Worker
299*90c8c64dSAndroid Build Coastguard Worker    monkeyFile = file(monkeyFilename, "w")
300*90c8c64dSAndroid Build Coastguard Worker    logcatFile = file(logcatFilename, "w")
301*90c8c64dSAndroid Build Coastguard Worker    bugreportFile = None
302*90c8c64dSAndroid Build Coastguard Worker
303*90c8c64dSAndroid Build Coastguard Worker    # Clear the log, then start logcat
304*90c8c64dSAndroid Build Coastguard Worker    adb.Shell(["logcat", "-c", "-b", "main,system,events,crash"])
305*90c8c64dSAndroid Build Coastguard Worker    cmd = ["adb", "logcat", "-b", "main,system,events,crash"]
306*90c8c64dSAndroid Build Coastguard Worker    PrintCommand(cmd)
307*90c8c64dSAndroid Build Coastguard Worker    logcatProcess = subprocess.Popen(cmd, stdout=logcatFile, stderr=None)
308*90c8c64dSAndroid Build Coastguard Worker    logcatThread = threading.Thread(target=LogcatThreadFunc)
309*90c8c64dSAndroid Build Coastguard Worker    logcatThread.start()
310*90c8c64dSAndroid Build Coastguard Worker
311*90c8c64dSAndroid Build Coastguard Worker    # Run monkeys
312*90c8c64dSAndroid Build Coastguard Worker    cmd = [
313*90c8c64dSAndroid Build Coastguard Worker        "monkey",
314*90c8c64dSAndroid Build Coastguard Worker        "-c", "android.intent.category.LAUNCHER",
315*90c8c64dSAndroid Build Coastguard Worker        "--ignore-security-exceptions",
316*90c8c64dSAndroid Build Coastguard Worker        "--monitor-native-crashes",
317*90c8c64dSAndroid Build Coastguard Worker        "-v", "-v", "-v"
318*90c8c64dSAndroid Build Coastguard Worker      ]
319*90c8c64dSAndroid Build Coastguard Worker    for pkg in options.packages:
320*90c8c64dSAndroid Build Coastguard Worker      cmd.append("-p")
321*90c8c64dSAndroid Build Coastguard Worker      cmd.append(pkg)
322*90c8c64dSAndroid Build Coastguard Worker    if options.type == "anr":
323*90c8c64dSAndroid Build Coastguard Worker      cmd.append("--ignore-crashes")
324*90c8c64dSAndroid Build Coastguard Worker      cmd.append("--ignore-native-crashes")
325*90c8c64dSAndroid Build Coastguard Worker    if options.type == "crash":
326*90c8c64dSAndroid Build Coastguard Worker      cmd.append("--ignore-timeouts")
327*90c8c64dSAndroid Build Coastguard Worker    if options.description:
328*90c8c64dSAndroid Build Coastguard Worker      cmd.append("--match-description")
329*90c8c64dSAndroid Build Coastguard Worker      cmd.append("'" + options.description + "'")
330*90c8c64dSAndroid Build Coastguard Worker    cmd.append(str(options.events))
331*90c8c64dSAndroid Build Coastguard Worker    try:
332*90c8c64dSAndroid Build Coastguard Worker      adb.Shell(cmd, stdout=monkeyFile, stderr=monkeyFile)
333*90c8c64dSAndroid Build Coastguard Worker      needReport = False
334*90c8c64dSAndroid Build Coastguard Worker    except ExecutionException:
335*90c8c64dSAndroid Build Coastguard Worker      # Monkeys failed, take a bugreport
336*90c8c64dSAndroid Build Coastguard Worker      bugreportFile = file(bugreportFilename, "w")
337*90c8c64dSAndroid Build Coastguard Worker      adb.Shell(["bugreport"], stdout=bugreportFile, stderr=None)
338*90c8c64dSAndroid Build Coastguard Worker      needReport = True
339*90c8c64dSAndroid Build Coastguard Worker    finally:
340*90c8c64dSAndroid Build Coastguard Worker      monkeyFile.close()
341*90c8c64dSAndroid Build Coastguard Worker      try:
342*90c8c64dSAndroid Build Coastguard Worker        logcatProcess.terminate()
343*90c8c64dSAndroid Build Coastguard Worker      except OSError:
344*90c8c64dSAndroid Build Coastguard Worker        pass # it must have died on its own
345*90c8c64dSAndroid Build Coastguard Worker      logcatThread.join()
346*90c8c64dSAndroid Build Coastguard Worker      logcatFile.close()
347*90c8c64dSAndroid Build Coastguard Worker      if bugreportFile:
348*90c8c64dSAndroid Build Coastguard Worker        bugreportFile.close()
349*90c8c64dSAndroid Build Coastguard Worker
350*90c8c64dSAndroid Build Coastguard Worker    if needReport:
351*90c8c64dSAndroid Build Coastguard Worker      # Generate the html
352*90c8c64dSAndroid Build Coastguard Worker      cmd = ["bugreport", "--monkey", monkeyFilename, "--html", htmlFilename,
353*90c8c64dSAndroid Build Coastguard Worker          "--logcat", logcatFilename, bugreportFilename]
354*90c8c64dSAndroid Build Coastguard Worker      PrintCommand(cmd)
355*90c8c64dSAndroid Build Coastguard Worker      result = subprocess.call(cmd)
356*90c8c64dSAndroid Build Coastguard Worker
357*90c8c64dSAndroid Build Coastguard Worker
358*90c8c64dSAndroid Build Coastguard Worker
359*90c8c64dSAndroid Build Coastguard Workerif __name__ == "__main__":
360*90c8c64dSAndroid Build Coastguard Worker  main()
361*90c8c64dSAndroid Build Coastguard Worker
362*90c8c64dSAndroid Build Coastguard Worker# vim: set ts=2 sw=2 sts=2 expandtab nocindent autoindent:
363