Commit 54d52de2 authored by jrg@google.com's avatar jrg@google.com

Android buildbot reliability fixes.

More changes to help make the chromium android buildbot more reliable.
Unlikely to be comprehensive but in the right direction.

BUG=None
TEST=

Review URL: http://codereview.chromium.org/8787010

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@113004 0039d316-1c4b-4281-b951-d872f2087c98
parent a92b5f30
...@@ -13,8 +13,10 @@ Assumes system environment ANDROID_NDK_ROOT has been set. ...@@ -13,8 +13,10 @@ Assumes system environment ANDROID_NDK_ROOT has been set.
import logging import logging
import os import os
import signal
import subprocess import subprocess
import sys import sys
import time
import android_commands import android_commands
...@@ -22,7 +24,31 @@ import android_commands ...@@ -22,7 +24,31 @@ import android_commands
sys.path.append(os.path.join(os.path.abspath(os.path.dirname(__file__)), '..', sys.path.append(os.path.join(os.path.abspath(os.path.dirname(__file__)), '..',
'..', 'third_party', 'android', 'testrunner')) '..', 'third_party', 'android', 'testrunner'))
import adb_interface import adb_interface
import cmd_helper
import errors
import run_command
class EmulatorLaunchException(Exception):
"""Emulator failed to launch."""
pass
def _KillAllEmulators():
"""Kill all running emulators that look like ones we started.
There are odd 'sticky' cases where there can be no emulator process
running but a device slot is taken. A little bot trouble and and
we're out of room forever.
"""
emulators = android_commands.GetEmulators()
if not emulators:
return
for emu_name in emulators:
cmd_helper.GetCmdOutput(['adb', '-s', emu_name, 'emu', 'kill'])
logging.info('Emulator killing is async; give a few seconds for all to die.')
for i in range(5):
if not android_commands.GetEmulators():
return
time.sleep(1)
def _GetAvailablePort(): def _GetAvailablePort():
"""Returns an available TCP port for the console.""" """Returns an available TCP port for the console."""
...@@ -52,6 +78,16 @@ class Emulator(object): ...@@ -52,6 +78,16 @@ class Emulator(object):
device: Device name of this emulator. device: Device name of this emulator.
""" """
# Signals we listen for to kill the emulator on
_SIGNALS = (signal.SIGINT, signal.SIGHUP)
# Time to wait for an emulator launch, in seconds.
_EMULATOR_LAUNCH_TIMEOUT = 120
# Timeout interval of wait-for-device command before bouncing to a a
# process life check.
_EMULATOR_WFD_TIMEOUT = 5
def __init__(self): def __init__(self):
try: try:
android_sdk_root = os.environ['ANDROID_SDK_ROOT'] android_sdk_root = os.environ['ANDROID_SDK_ROOT']
...@@ -63,22 +99,18 @@ class Emulator(object): ...@@ -63,22 +99,18 @@ class Emulator(object):
self.popen = None self.popen = None
self.device = None self.device = None
def Reset(self): def _DeviceName(self):
"""Kill a running emulator. """Return our device name."""
port = _GetAvailablePort()
May be needed if the test scripts stopped abnormally and an return ('emulator-%d' % port, port)
emulator is left around."""
adb = adb_interface.AdbInterface()
logging.info('Killing any existing emulator.')
adb.SendCommand('emu kill')
def Launch(self): def Launch(self):
"""Launches the emulator and waits for package manager to startup. """Launches the emulator and waits for package manager to startup.
If fails, an exception will be raised. If fails, an exception will be raised.
""" """
port = _GetAvailablePort() _KillAllEmulators() # just to be sure
self.device = "emulator-%d" % port (self.device, port) = self._DeviceName()
self.popen = subprocess.Popen(args=[ self.popen = subprocess.Popen(args=[
self.emulator, self.emulator,
# Speed up emulator launch by 40%. Really. # Speed up emulator launch by 40%. Really.
...@@ -88,15 +120,63 @@ class Emulator(object): ...@@ -88,15 +120,63 @@ class Emulator(object):
'-partition-size', '256', '-partition-size', '256',
# Use a familiar name and port. # Use a familiar name and port.
'-avd', 'buildbot', '-avd', 'buildbot',
'-port', str(port)]) '-port', str(port)],
# This will not return until device's package manager starts up or an stderr=subprocess.STDOUT)
# exception is raised. self._InstallKillHandler()
android_commands.AndroidCommands(self.device, True) self._ConfirmLaunch()
def _ConfirmLaunch(self):
"""Confirm the emulator launched properly.
Loop on a wait-for-device with a very small timeout. On each
timeout, check the emulator process is still alive.
After confirming a wait-for-device can be successful, make sure
it returns the right answer.
"""
a = android_commands.AndroidCommands(self.device, False)
seconds_waited = 0
number_of_waits = 2 # Make sure we can wfd twice
adb_cmd = "adb -s %s %s" % (self.device, 'wait-for-device')
while seconds_waited < self._EMULATOR_LAUNCH_TIMEOUT:
try:
run_command.RunCommand(adb_cmd, timeout_time=self._EMULATOR_WFD_TIMEOUT,
retry_count=1)
number_of_waits -= 1
if not number_of_waits:
break
except errors.WaitForResponseTimedOutError as e:
seconds_waited += self._EMULATOR_WFD_TIMEOUT
adb_cmd = "adb -s %s %s" % (self.device, 'kill-server')
run_command.RunCommand(adb_cmd)
self.popen.poll()
if self.popen.returncode != None:
raise EmulatorLaunchException('EMULATOR DIED')
if seconds_waited >= self._EMULATOR_LAUNCH_TIMEOUT:
raise EmulatorLaunchException('TIMEOUT with wait-for-device')
logging.info('Seconds waited on wait-for-device: %d', seconds_waited)
# Now that we checked for obvious problems, wait for a boot complete.
# Waiting for the package manager has been problematic.
a.Adb().WaitForBootComplete()
def Shutdown(self): def Shutdown(self):
"""Shuts down the process started by launch.""" """Shuts down the process started by launch."""
self.popen.terminate() if self.popen:
self.popen.poll()
if self.popen.returncode == None:
self.popen.kill()
self.popen = None
def _ShutdownOnSignal(self, signum, frame):
logging.critical('emulator _ShutdownOnSignal')
for sig in self._SIGNALS:
signal.signal(sig, signal.SIG_DFL)
self.Shutdown()
raise KeyboardInterrupt # print a stack
def _InstallKillHandler(self):
"""Install a handler to kill the emulator when we exit unexpectedly."""
for sig in self._SIGNALS:
signal.signal(sig, self._ShutdownOnSignal)
def main(argv): def main(argv):
Emulator().launch() Emulator().launch()
......
...@@ -215,7 +215,6 @@ def Dispatch(options): ...@@ -215,7 +215,6 @@ def Dispatch(options):
if options.use_emulator: if options.use_emulator:
t = TimeProfile('Emulator launch') t = TimeProfile('Emulator launch')
buildbot_emulator = emulator.Emulator() buildbot_emulator = emulator.Emulator()
buildbot_emulator.Reset()
buildbot_emulator.Launch() buildbot_emulator.Launch()
t.Stop() t.Stop()
attached_devices.append(buildbot_emulator.device) attached_devices.append(buildbot_emulator.device)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment