Commit 94c302a8 authored by John Budorick's avatar John Budorick Committed by Commit Bot

android: configure sdcard at runtime.

Also adds .ini file reading & writing logic.

Bug: 922145
Change-Id: I6abd19f70dc610f2b8b0e0bb5068ef0d64bf659a
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1973194Reviewed-by: default avatarYun Liu <yliuyliu@google.com>
Commit-Queue: John Budorick <jbudorick@chromium.org>
Cr-Commit-Position: refs/heads/master@{#726182}
parent ebf569b8
...@@ -9,7 +9,6 @@ import os ...@@ -9,7 +9,6 @@ import os
import socket import socket
import stat import stat
import subprocess import subprocess
import textwrap
import threading import threading
from google.protobuf import text_format # pylint: disable=import-error from google.protobuf import text_format # pylint: disable=import-error
...@@ -20,15 +19,10 @@ from devil.utils import cmd_helper ...@@ -20,15 +19,10 @@ from devil.utils import cmd_helper
from devil.utils import timeout_retry from devil.utils import timeout_retry
from py_utils import tempfile_ext from py_utils import tempfile_ext
from pylib import constants from pylib import constants
from pylib.local.emulator import ini
from pylib.local.emulator.proto import avd_pb2 from pylib.local.emulator.proto import avd_pb2
_ALL_PACKAGES = object() _ALL_PACKAGES = object()
_CONFIG_INI_CONTENTS = textwrap.dedent("""\
disk.dataPartition.size=4G
hw.lcd.density={density}
hw.lcd.height={height}
hw.lcd.width={width}
""")
_DEFAULT_AVDMANAGER_PATH = os.path.join(constants.ANDROID_SDK_ROOT, 'tools', _DEFAULT_AVDMANAGER_PATH = os.path.join(constants.ANDROID_SDK_ROOT, 'tools',
'bin', 'avdmanager') 'bin', 'avdmanager')
# Default to a 480dp mdpi screen (a relatively large phone). # Default to a 480dp mdpi screen (a relatively large phone).
...@@ -98,7 +92,7 @@ class _AvdManagerAgent(object): ...@@ -98,7 +92,7 @@ class _AvdManagerAgent(object):
'-Dcom.android.sdkmanager.toolsdir=%s' % fake_tools_dir, '-Dcom.android.sdkmanager.toolsdir=%s' % fake_tools_dir,
}) })
def Create(self, avd_name, system_image, force=False, sdcard=None): def Create(self, avd_name, system_image, force=False):
"""Call `avdmanager create`. """Call `avdmanager create`.
Args: Args:
...@@ -119,8 +113,6 @@ class _AvdManagerAgent(object): ...@@ -119,8 +113,6 @@ class _AvdManagerAgent(object):
] ]
if force: if force:
create_cmd += ['--force'] create_cmd += ['--force']
if sdcard:
create_cmd += ['--sdcard', sdcard]
create_proc = cmd_helper.Popen( create_proc = cmd_helper.Popen(
create_cmd, create_cmd,
...@@ -228,8 +220,7 @@ class AvdConfig(object): ...@@ -228,8 +220,7 @@ class AvdConfig(object):
avd_manager.Create( avd_manager.Create(
avd_name=self._config.avd_name, avd_name=self._config.avd_name,
system_image=self._config.system_image_name, system_image=self._config.system_image_name,
force=force, force=force)
sdcard=self._config.avd_settings.sdcard.size)
try: try:
logging.info('Modifying AVD configuration.') logging.info('Modifying AVD configuration.')
...@@ -249,15 +240,18 @@ class AvdConfig(object): ...@@ -249,15 +240,18 @@ class AvdConfig(object):
density = (self._config.avd_settings.screen.density density = (self._config.avd_settings.screen.density
or _DEFAULT_SCREEN_DENSITY) or _DEFAULT_SCREEN_DENSITY)
config_ini_contents = {
'hw.lcd.density': density,
'hw.lcd.height': height,
'hw.lcd.width': width,
}
with open(config_ini, 'a') as config_ini_file: with open(config_ini, 'a') as config_ini_file:
config_ini_contents = _CONFIG_INI_CONTENTS.format( ini.dump(config_ini_contents, config_ini_file)
density=density, height=height, width=width)
config_ini_file.write(config_ini_contents)
# Start & stop the AVD. # Start & stop the AVD.
self._Initialize() self._Initialize()
instance = _AvdInstance(self._emulator_path, self._config.avd_name, instance = _AvdInstance(self._emulator_path, self._emulator_home,
self._emulator_home) self._config)
instance.Start(read_only=False, snapshot_save=snapshot) instance.Start(read_only=False, snapshot_save=snapshot)
device_utils.DeviceUtils(instance.serial).WaitUntilFullyBooted( device_utils.DeviceUtils(instance.serial).WaitUntilFullyBooted(
timeout=180, retries=0) timeout=180, retries=0)
...@@ -407,8 +401,7 @@ class AvdConfig(object): ...@@ -407,8 +401,7 @@ class AvdConfig(object):
An _AvdInstance. An _AvdInstance.
""" """
self._Initialize() self._Initialize()
return _AvdInstance(self._emulator_path, self._config.avd_name, return _AvdInstance(self._emulator_path, self._emulator_home, self._config)
self._emulator_home)
def StartInstance(self): def StartInstance(self):
"""Starts an AVD instance. """Starts an AVD instance.
...@@ -428,15 +421,16 @@ class _AvdInstance(object): ...@@ -428,15 +421,16 @@ class _AvdInstance(object):
but its other methods can be freely called. but its other methods can be freely called.
""" """
def __init__(self, emulator_path, avd_name, emulator_home): def __init__(self, emulator_path, emulator_home, avd_config):
"""Create an _AvdInstance object. """Create an _AvdInstance object.
Args: Args:
emulator_path: path to the emulator binary. emulator_path: path to the emulator binary.
avd_name: name of the AVD to run.
emulator_home: path to the emulator home directory. emulator_home: path to the emulator home directory.
avd_config: AVD config proto.
""" """
self._avd_name = avd_name self._avd_config = avd_config
self._avd_name = avd_config.avd_name
self._emulator_home = emulator_home self._emulator_home = emulator_home
self._emulator_path = emulator_path self._emulator_path = emulator_path
self._emulator_proc = None self._emulator_proc = None
...@@ -448,6 +442,7 @@ class _AvdInstance(object): ...@@ -448,6 +442,7 @@ class _AvdInstance(object):
def Start(self, read_only=True, snapshot_save=False, window=False): def Start(self, read_only=True, snapshot_save=False, window=False):
"""Starts the emulator running an instance of the given AVD.""" """Starts the emulator running an instance of the given AVD."""
with tempfile_ext.TemporaryFileName() as socket_path, (contextlib.closing( with tempfile_ext.TemporaryFileName() as socket_path, (contextlib.closing(
socket.socket(socket.AF_UNIX))) as sock: socket.socket(socket.AF_UNIX))) as sock:
sock.bind(socket_path) sock.bind(socket_path)
...@@ -457,7 +452,19 @@ class _AvdInstance(object): ...@@ -457,7 +452,19 @@ class _AvdInstance(object):
self._avd_name, self._avd_name,
'-report-console', '-report-console',
'unix:%s' % socket_path, 'unix:%s' % socket_path,
'-no-boot-anim',
] ]
android_avd_home = os.path.join(self._emulator_home, 'avd')
avd_dir = os.path.join(android_avd_home, '%s.avd' % self._avd_name)
hardware_qemu_path = os.path.join(avd_dir, 'hardware-qemu.ini')
if os.path.exists(hardware_qemu_path):
with open(hardware_qemu_path) as hardware_qemu_file:
hardware_qemu_contents = ini.load(hardware_qemu_file)
else:
hardware_qemu_contents = {}
if read_only: if read_only:
emulator_cmd.append('-read-only') emulator_cmd.append('-read-only')
if not snapshot_save: if not snapshot_save:
...@@ -472,6 +479,27 @@ class _AvdInstance(object): ...@@ -472,6 +479,27 @@ class _AvdInstance(object):
raise AvdException('Emulator failed to start: DISPLAY not defined') raise AvdException('Emulator failed to start: DISPLAY not defined')
else: else:
emulator_cmd.append('-no-window') emulator_cmd.append('-no-window')
hardware_qemu_contents['hw.sdCard'] = 'true'
if self._avd_config.avd_settings.sdcard.size:
sdcard_path = os.path.join(self._emulator_home, 'avd',
'%s.avd' % self._avd_name, 'cr-sdcard.img')
if not os.path.exists(sdcard_path):
mksdcard_path = os.path.join(
os.path.dirname(self._emulator_path), 'mksdcard')
mksdcard_cmd = [
mksdcard_path,
self._avd_config.avd_settings.sdcard.size,
sdcard_path,
]
cmd_helper.RunCmd(mksdcard_cmd)
emulator_cmd.extend(['-sdcard', sdcard_path])
hardware_qemu_contents['hw.sdCard.path'] = sdcard_path
with open(hardware_qemu_path, 'w') as hardware_qemu_file:
ini.dump(hardware_qemu_contents, hardware_qemu_file)
sock.listen(1) sock.listen(1)
logging.info('Starting emulator.') logging.info('Starting emulator.')
......
# Copyright 2019 The Chromium Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
"""Basic .ini encoding and decoding."""
def loads(ini_str, strict=True):
ret = {}
for line in ini_str.splitlines():
key, val = line.split('=', 1)
if strict and key in ret:
raise ValueError('Multiple entries present for key "%s"' % key)
ret[key] = val
return ret
def load(fp):
return loads(fp.read())
def dumps(obj):
ret = ''
for k, v in obj.iteritems():
ret += '%s=%s\n' % (k, str(v))
return ret
def dump(obj, fp):
fp.write(dumps(obj))
...@@ -4,7 +4,11 @@ ...@@ -4,7 +4,11 @@
import logging import logging
from devil import base_error
from devil.android import device_errors
from devil.android import device_utils
from devil.utils import parallelizer from devil.utils import parallelizer
from devil.utils import timeout_retry
from pylib.local.device import local_device_environment from pylib.local.device import local_device_environment
from pylib.local.emulator import avd from pylib.local.emulator import avd
...@@ -36,12 +40,27 @@ class LocalEmulatorEnvironment(local_device_environment.LocalDeviceEnvironment): ...@@ -36,12 +40,27 @@ class LocalEmulatorEnvironment(local_device_environment.LocalDeviceEnvironment):
] ]
def start_emulator_instance(e): def start_emulator_instance(e):
try:
e.Start(window=self._emulator_window) def impl(e):
try:
e.Start(window=self._emulator_window)
except avd.AvdException:
logging.exception('Failed to start emulator instance.')
return None
try:
device_utils.DeviceUtils(e.serial).WaitUntilFullyBooted()
except base_error.BaseError:
e.Stop()
raise
return e return e
except avd.AvdException:
logging.exception('Failed to start emulator instance.') return timeout_retry.Run(
return None impl,
timeout=30,
retries=2,
args=[e],
retry_if_func=
lambda exc: isinstance(exc, device_errors.CommandTimeoutError))
parallel_emulators = parallelizer.SyncParallelizer(emulator_instances) parallel_emulators = parallelizer.SyncParallelizer(emulator_instances)
self._emulator_instances = [ self._emulator_instances = [
......
...@@ -173,6 +173,7 @@ pylib/local/device/local_device_monkey_test_run.py ...@@ -173,6 +173,7 @@ pylib/local/device/local_device_monkey_test_run.py
pylib/local/device/local_device_test_run.py pylib/local/device/local_device_test_run.py
pylib/local/emulator/__init__.py pylib/local/emulator/__init__.py
pylib/local/emulator/avd.py pylib/local/emulator/avd.py
pylib/local/emulator/ini.py
pylib/local/emulator/local_emulator_environment.py pylib/local/emulator/local_emulator_environment.py
pylib/local/emulator/proto/__init__.py pylib/local/emulator/proto/__init__.py
pylib/local/emulator/proto/avd_pb2.py pylib/local/emulator/proto/avd_pb2.py
......
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