Commit 6c5ebb18 authored by John Budorick's avatar John Budorick Committed by Commit Bot

android: add support for spinning up multiple instances of the emulator.

Bug: 922145
Change-Id: Iabea0d27059ad64d76a72f80b4a3d88e97e6f6f0
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1836598Reviewed-by: default avatarBen Pastene <bpastene@chromium.org>
Reviewed-by: default avatarAndrew Luo <aluo@chromium.org>
Commit-Queue: John Budorick <jbudorick@chromium.org>
Cr-Commit-Position: refs/heads/master@{#702646}
parent 42e5f477
......@@ -2,8 +2,10 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
import logging
import os
from devil.utils import parallelizer
from pylib.constants import host_paths
from pylib.local.device import local_device_environment
......@@ -13,19 +15,55 @@ with host_paths.SysPath(AVD_DIR_PATH):
import avd # pylint: disable=import-error
# Mirroring https://bit.ly/2OjuxcS#23
_MAX_ANDROID_EMULATORS = 16
class LocalEmulatorEnvironment(local_device_environment.LocalDeviceEnvironment):
def __init__(self, args, output_manager, error_func):
super(LocalEmulatorEnvironment, self).__init__(args, output_manager,
error_func)
self._avd_config = avd.AvdConfig(args.avd_config)
self._emulator_instance = None
if args.emulator_count < 1:
error_func('--emulator-count must be >= 1')
elif args.emulator_count >= _MAX_ANDROID_EMULATORS:
logging.warning('--emulator-count capped at 16.')
self._emulator_count = min(_MAX_ANDROID_EMULATORS, args.emulator_count)
self._emulator_instances = []
self._device_serials = []
#override
def SetUp(self):
self._avd_config.Install()
self._emulator_instance = self._avd_config.StartInstance()
self._device_serials = [self._emulator_instance.serial]
emulator_instances = [
self._avd_config.CreateInstance() for _ in range(self._emulator_count)
]
def start_emulator_instance(e):
try:
e.Start()
return e
except avd.AvdException:
logging.exception('Failed to start emulator instance.')
return None
parallel_emulators = parallelizer.SyncParallelizer(emulator_instances)
self._emulator_instances = [
emu
for emu in parallel_emulators.pMap(start_emulator_instance).pGet(None)
if emu is not None
]
self._device_serials = [e.serial for e in self._emulator_instances]
if not self._emulator_instances:
raise Exception('Failed to start any instances of the emulator.')
elif len(self._emulator_instances) < self._emulator_count:
logging.warning(
'Running with fewer emulator instances than requested (%d vs %d)',
len(self._emulator_instances), self._emulator_count)
super(LocalEmulatorEnvironment, self).SetUp()
#override
......@@ -33,5 +71,4 @@ class LocalEmulatorEnvironment(local_device_environment.LocalDeviceEnvironment):
try:
super(LocalEmulatorEnvironment, self).TearDown()
finally:
if self._emulator_instance:
self._emulator_instance.Stop()
parallelizer.SyncParallelizer(self._emulator_instances).Stop()
......@@ -315,6 +315,11 @@ def AddEmulatorOptions(parser):
help='Path to the avd config textpb. '
'(See //tools/android/avd/proto/ for message definition'
' and existing textpb files.)')
parser.add_argument(
'--emulator-count',
type=int,
default=1,
help='Number of emulators to use.')
def AddGTestOptions(parser):
......
......@@ -365,15 +365,23 @@ class AvdConfig(object):
if not os.path.exists(d):
os.makedirs(d)
def StartInstance(self):
"""Starts an AVD instance.
def CreateInstance(self):
"""Creates an AVD instance without starting it.
Returns:
An _AvdInstance.
"""
self._Initialize()
instance = _AvdInstance(
return _AvdInstance(
self._emulator_path, self._config.avd_name, self._emulator_home)
def StartInstance(self):
"""Starts an AVD instance.
Returns:
An _AvdInstance.
"""
instance = self.CreateInstance()
instance.Start()
return instance
......@@ -400,6 +408,9 @@ class _AvdInstance(object):
self._emulator_serial = None
self._sink = None
def __str__(self):
return '%s|%s' % (self._avd_name, (self._emulator_serial or id(self)))
def Start(self, read_only=True):
"""Starts the emulator running an instance of the given AVD."""
with tempfile_ext.TemporaryFileName() as socket_path, (contextlib.closing(
......@@ -445,9 +456,9 @@ class _AvdInstance(object):
self._emulator_serial = timeout_retry.Run(
listen_for_serial, timeout=30, retries=0, args=[sock])
logging.info('%s started', self._emulator_serial)
except Exception:
except Exception as e:
self.Stop()
raise
raise AvdException('Emulator failed to start: %s' % str(e))
def Stop(self):
"""Stops the emulator process."""
......
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