[Fuchsia] Allow the Fuchsia test-runner scripts to use AEMU
Adding an aemu_target.py that supports running headless AEMU with swiftshader. Adds AEMU checkout to the build (with aemu_checkout set to True). Add support for AEMU in layout tests. R=marshallk@google.com Bug: 1000906 Change-Id: Ie4a9e7957c5a33822dd44e8892c0820307ea5b02 Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1789849 Reviewed-by: Kevin Marshall <kmarshall@chromium.org> Reviewed-by: Nico Weber <thakis@chromium.org> Commit-Queue: Chong Gu <chonggu@google.com> Cr-Commit-Position: refs/heads/master@{#700484}
This commit is contained in:
27
DEPS
27
DEPS
@ -121,6 +121,11 @@ vars = {
|
||||
# Wildcards are supported (e.g. "qemu.*").
|
||||
'checkout_fuchsia_boot_images': "qemu.x64,qemu.arm64",
|
||||
|
||||
# By Default, do not checkout AEMU, as it is too big. This can be overridden
|
||||
# e.g. with custom_vars.
|
||||
# TODO(chonggu): Delete once AEMU package is small enough.
|
||||
'checkout_aemu': False,
|
||||
|
||||
# Default to the empty board. Desktop Chrome OS builds don't need cros SDK
|
||||
# dependencies. Other Chrome OS builds should always define this explicitly.
|
||||
'cros_board': '',
|
||||
@ -1327,6 +1332,28 @@ deps = {
|
||||
'dep_type': 'cipd',
|
||||
},
|
||||
|
||||
'src/third_party/aemu-linux-x64': {
|
||||
'packages': [
|
||||
{
|
||||
'package': 'fuchsia/third_party/aemu/linux-amd64',
|
||||
'version': 'IzRqaHDMNtw9FjGgpntL65P_3dvQRLIuzxBkSUpoG1UC'
|
||||
},
|
||||
],
|
||||
'condition': 'host_os == "linux" and checkout_aemu',
|
||||
'dep_type': 'cipd',
|
||||
},
|
||||
|
||||
'src/third_party/aemu-mac-x64': {
|
||||
'packages': [
|
||||
{
|
||||
'package': 'fuchsia/third_party/aemu/mac-amd64',
|
||||
'version': 'T9bWxf8aUC5TwCFgPxpuW29Mfy-7Z9xCfXB9QO8MfU0C'
|
||||
},
|
||||
],
|
||||
'condition': 'host_os == "mac" and checkout_aemu',
|
||||
'dep_type': 'cipd',
|
||||
},
|
||||
|
||||
'src/third_party/re2/src':
|
||||
Var('chromium_git') + '/external/github.com/google/re2.git' + '@' + '67bce690decdb507b13e14050661f8b9ebfcfe6c',
|
||||
|
||||
|
72
build/fuchsia/aemu_target.py
Normal file
72
build/fuchsia/aemu_target.py
Normal file
@ -0,0 +1,72 @@
|
||||
# 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.
|
||||
|
||||
"""Implements commands for running and interacting with Fuchsia on AEMU."""
|
||||
|
||||
import os
|
||||
import platform
|
||||
import qemu_target
|
||||
import logging
|
||||
|
||||
from common import GetEmuRootForPlatform
|
||||
|
||||
class AemuTarget(qemu_target.QemuTarget):
|
||||
def __init__(self, output_dir, target_cpu, system_log_file, emu_type,
|
||||
cpu_cores, require_kvm, ram_size_mb):
|
||||
super(AemuTarget, self).__init__(output_dir, target_cpu, system_log_file,
|
||||
emu_type, cpu_cores, require_kvm,
|
||||
ram_size_mb)
|
||||
|
||||
# TODO(crbug.com/1000907): Enable AEMU for arm64.
|
||||
if platform.machine() == 'aarch64':
|
||||
raise Exception('AEMU does not support arm64 hosts.')
|
||||
|
||||
# TODO(bugs.fuchsia.dev/p/fuchsia/issues/detail?id=37301): Remove
|
||||
# once aemu is part of default fuchsia build
|
||||
def _EnsureEmulatorExists(self, path):
|
||||
assert os.path.exists(path), \
|
||||
'This checkout is missing %s. To check out the files, add this\n' \
|
||||
'entry to the "custon_vars" section of your .gclient file:\n\n' \
|
||||
' "checkout_aemu": True\n\n' % (self._emu_type)
|
||||
|
||||
def _BuildCommand(self):
|
||||
aemu_exec = 'emulator-headless'
|
||||
|
||||
aemu_folder = GetEmuRootForPlatform(self._emu_type)
|
||||
|
||||
self._EnsureEmulatorExists(aemu_folder)
|
||||
aemu_path = os.path.join(aemu_folder, aemu_exec)
|
||||
|
||||
# `VirtioInput` is needed for touch input device support on Fuchsia.
|
||||
# `RefCountPipe` is needed for proper cleanup of resources when a process
|
||||
# that uses Vulkan dies inside the guest
|
||||
aemu_features = 'VirtioInput,RefCountPipe'
|
||||
|
||||
# Configure the CPU to emulate.
|
||||
# On Linux, we can enable lightweight virtualization (KVM) if the host and
|
||||
# guest architectures are the same.
|
||||
if self._IsKvmEnabled():
|
||||
aemu_features += ',KVM,GLDirectMem,Vulkan'
|
||||
else:
|
||||
if self._target_cpu != 'arm64':
|
||||
aemu_features += ',-GLDirectMem'
|
||||
|
||||
# All args after -fuchsia flag gets passed to QEMU
|
||||
aemu_command = [aemu_path,
|
||||
'-feature', aemu_features,
|
||||
'-window-size', '1024x600',
|
||||
'-gpu', 'swiftshader_indirect',
|
||||
'-fuchsia'
|
||||
]
|
||||
|
||||
aemu_command.extend(self._BuildQemuConfig())
|
||||
|
||||
aemu_command.extend([
|
||||
'-vga', 'none',
|
||||
'-device', 'isa-debug-exit,iobase=0xf4,iosize=0x04',
|
||||
'-device', 'virtio-keyboard-pci',
|
||||
'-device', 'virtio_input_multi_touch_pci_1',
|
||||
'-device', 'ich9-ahci,id=ahci'])
|
||||
logging.info(' '.join(aemu_command))
|
||||
return aemu_command
|
@ -40,9 +40,9 @@ def GetHostArchFromPlatform():
|
||||
return 'arm64'
|
||||
raise Exception('Unsupported host architecture: %s' % host_arch)
|
||||
|
||||
def GetQemuRootForPlatform():
|
||||
def GetEmuRootForPlatform(emulator):
|
||||
return os.path.join(DIR_SOURCE_ROOT, 'third_party',
|
||||
'qemu-' + GetHostOsFromPlatform() + '-' +
|
||||
emulator + '-' + GetHostOsFromPlatform() + '-' +
|
||||
GetHostArchFromPlatform())
|
||||
|
||||
def ConnectPortForwardingTask(target, local_port, remote_port = 0):
|
||||
|
@ -6,10 +6,10 @@ import logging
|
||||
import os
|
||||
import sys
|
||||
|
||||
from aemu_target import AemuTarget
|
||||
from device_target import DeviceTarget
|
||||
from qemu_target import QemuTarget
|
||||
|
||||
|
||||
def AddCommonArgs(arg_parser):
|
||||
"""Adds command line arguments to |arg_parser| for options which are shared
|
||||
across test and executable target types."""
|
||||
@ -34,8 +34,13 @@ def AddCommonArgs(arg_parser):
|
||||
common_args.add_argument('--target-staging-path',
|
||||
help='target path under which to stage packages '
|
||||
'during deployment.', default='/data')
|
||||
common_args.add_argument('--device', '-d', action='store_true', default=False,
|
||||
help='Run on hardware device instead of QEMU.')
|
||||
common_args.add_argument('--device', default=None,
|
||||
choices=['aemu','qemu','device'],
|
||||
help='Choose to run on aemu|qemu|device. ' +
|
||||
'By default, Fuchsia will run in QEMU.')
|
||||
common_args.add_argument('-d', action='store_const', dest='device',
|
||||
const='device',
|
||||
help='Run on device instead of emulator.')
|
||||
common_args.add_argument('--host', help='The IP of the target device. ' +
|
||||
'Optional.')
|
||||
common_args.add_argument('--node-name',
|
||||
@ -64,7 +69,11 @@ def AddCommonArgs(arg_parser):
|
||||
help='Enable debug-level logging.')
|
||||
common_args.add_argument('--qemu-cpu-cores', type=int, default=4,
|
||||
help='Sets the number of CPU cores to provide if '
|
||||
'launching in a VM with QEMU.'),
|
||||
'launching in a VM.'),
|
||||
common_args.add_argument('--memory', type=int, default=2048,
|
||||
help='Sets the RAM size (MB) if launching in a VM'),
|
||||
common_args.add_argument('--no-kvm', action='store_true', default=False,
|
||||
help='Disable KVM virtualization'),
|
||||
common_args.add_argument(
|
||||
'--os_check', choices=['check', 'update', 'ignore'],
|
||||
default='update',
|
||||
@ -94,7 +103,6 @@ def ConfigureLogging(args):
|
||||
def GetDeploymentTargetForArgs(args, require_kvm=False):
|
||||
"""Constructs a deployment target object using parameters taken from
|
||||
command line arguments."""
|
||||
|
||||
if args.system_log_file == '-':
|
||||
system_log_file = sys.stdout
|
||||
elif args.system_log_file:
|
||||
@ -102,19 +110,27 @@ def GetDeploymentTargetForArgs(args, require_kvm=False):
|
||||
else:
|
||||
system_log_file = None
|
||||
|
||||
# Allow fuchsia to run on qemu if device not explicitly chosen.
|
||||
if not args.device:
|
||||
return QemuTarget(output_dir=args.output_directory,
|
||||
target_cpu=args.target_cpu,
|
||||
cpu_cores=args.qemu_cpu_cores,
|
||||
system_log_file=system_log_file,
|
||||
require_kvm=require_kvm)
|
||||
args.device = 'qemu'
|
||||
|
||||
target_args = { 'output_dir':args.output_directory,
|
||||
'target_cpu':args.target_cpu,
|
||||
'system_log_file':system_log_file }
|
||||
if args.device == 'device':
|
||||
target_args.update({ 'host':args.host,
|
||||
'node_name':args.node_name,
|
||||
'port':args.port,
|
||||
'ssh_config':args.ssh_config,
|
||||
'fuchsia_out_dir':args.fuchsia_out_dir,
|
||||
'os_check':args.os_check })
|
||||
return DeviceTarget(**target_args)
|
||||
else:
|
||||
return DeviceTarget(output_dir=args.output_directory,
|
||||
target_cpu=args.target_cpu,
|
||||
host=args.host,
|
||||
node_name=args.node_name,
|
||||
port=args.port,
|
||||
ssh_config=args.ssh_config,
|
||||
fuchsia_out_dir=args.fuchsia_out_dir,
|
||||
system_log_file=system_log_file,
|
||||
os_check=args.os_check)
|
||||
target_args.update({ 'cpu_cores':args.qemu_cpu_cores,
|
||||
'require_kvm':not args.no_kvm,
|
||||
'emu_type':args.device,
|
||||
'ram_size_mb':args.memory })
|
||||
if args.device == 'qemu':
|
||||
return QemuTarget(**target_args)
|
||||
else:
|
||||
return AemuTarget(**target_args)
|
||||
|
92
build/fuchsia/emu_target.py
Normal file
92
build/fuchsia/emu_target.py
Normal file
@ -0,0 +1,92 @@
|
||||
# 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.
|
||||
|
||||
"""Implements commands for running/interacting with Fuchsia on an emulator."""
|
||||
|
||||
import boot_data
|
||||
import logging
|
||||
import os
|
||||
import subprocess
|
||||
import sys
|
||||
import target
|
||||
import tempfile
|
||||
|
||||
class EmuTarget(target.Target):
|
||||
def __init__(self, output_dir, target_cpu, system_log_file):
|
||||
"""output_dir: The directory which will contain the files that are
|
||||
generated to support the emulator deployment.
|
||||
target_cpu: The emulated target CPU architecture.
|
||||
Can be 'x64' or 'arm64'."""
|
||||
super(EmuTarget, self).__init__(output_dir, target_cpu)
|
||||
self._emu_process = None
|
||||
self._system_log_file = system_log_file
|
||||
|
||||
def __enter__(self):
|
||||
return self
|
||||
|
||||
def _GetEmulatorName(self):
|
||||
pass
|
||||
|
||||
def _BuildCommand(self):
|
||||
"""Build the command that will be run to start Fuchsia in the emulator."""
|
||||
pass
|
||||
|
||||
# Used by the context manager to ensure that the emulator is killed when
|
||||
# the Python process exits.
|
||||
def __exit__(self, exc_type, exc_val, exc_tb):
|
||||
self.Shutdown();
|
||||
|
||||
def Start(self):
|
||||
emu_command = self._BuildCommand()
|
||||
|
||||
# We pass a separate stdin stream. Sharing stdin across processes
|
||||
# leads to flakiness due to the OS prematurely killing the stream and the
|
||||
# Python script panicking and aborting.
|
||||
# The precise root cause is still nebulous, but this fix works.
|
||||
# See crbug.com/741194.
|
||||
logging.debug('Launching %s.' % (self._GetEmulatorName()))
|
||||
logging.debug(' '.join(emu_command))
|
||||
|
||||
# Zircon sends debug logs to serial port (see kernel.serial=legacy flag
|
||||
# above). Serial port is redirected to a file through emulator stdout.
|
||||
# Unless a |_system_log_file| is explicitly set, we output the kernel serial
|
||||
# log to a temporary file, and print that out if we are unable to connect to
|
||||
# the emulator guest, to make it easier to diagnose connectivity issues.
|
||||
temporary_system_log_file = None
|
||||
if self._system_log_file:
|
||||
stdout = self._system_log_file
|
||||
stderr = subprocess.STDOUT
|
||||
else:
|
||||
temporary_system_log_file = tempfile.NamedTemporaryFile('w')
|
||||
stdout = temporary_system_log_file
|
||||
stderr = sys.stderr
|
||||
|
||||
self._emu_process = subprocess.Popen(emu_command, stdin=open(os.devnull),
|
||||
stdout=stdout, stderr=stderr)
|
||||
|
||||
try:
|
||||
self._WaitUntilReady();
|
||||
except target.FuchsiaTargetException:
|
||||
if temporary_system_log_file:
|
||||
logging.info('Kernel logs:\n' +
|
||||
open(temporary_system_log_file.name, 'r').read())
|
||||
raise
|
||||
|
||||
def Shutdown(self):
|
||||
if self._IsEmuStillRunning():
|
||||
logging.info('Shutting down %s' % (self._GetEmulatorName()))
|
||||
self._emu_process.kill()
|
||||
|
||||
def _IsEmuStillRunning(self):
|
||||
if not self._emu_process:
|
||||
return False
|
||||
return os.waitpid(self._emu_process.pid, os.WNOHANG)[0] == 0
|
||||
|
||||
def _GetEndpoint(self):
|
||||
if not self._IsEmuStillRunning():
|
||||
raise Exception('%s quit unexpectedly.' % (self._GetEmulatorName()))
|
||||
return ('localhost', self._host_ssh_port)
|
||||
|
||||
def _GetSshConfigPath(self):
|
||||
return boot_data.GetSSHConfigPath(self._output_dir)
|
@ -6,19 +6,17 @@
|
||||
|
||||
import boot_data
|
||||
import common
|
||||
import emu_target
|
||||
import logging
|
||||
import md5
|
||||
import os
|
||||
import platform
|
||||
import shutil
|
||||
import socket
|
||||
import subprocess
|
||||
import sys
|
||||
import target
|
||||
import tempfile
|
||||
import time
|
||||
|
||||
from common import GetQemuRootForPlatform, EnsurePathExists
|
||||
from common import GetEmuRootForPlatform, EnsurePathExists
|
||||
|
||||
|
||||
# Virtual networking configuration data for QEMU.
|
||||
@ -31,46 +29,33 @@ GUEST_MAC_ADDRESS = '52:54:00:63:5e:7b'
|
||||
EXTENDED_BLOBSTORE_SIZE = 1073741824 # 1GB
|
||||
|
||||
|
||||
class QemuTarget(target.Target):
|
||||
def __init__(self, output_dir, target_cpu, cpu_cores, system_log_file,
|
||||
require_kvm, ram_size_mb=2048):
|
||||
"""output_dir: The directory which will contain the files that are
|
||||
generated to support the QEMU deployment.
|
||||
target_cpu: The emulated target CPU architecture.
|
||||
Can be 'x64' or 'arm64'."""
|
||||
super(QemuTarget, self).__init__(output_dir, target_cpu)
|
||||
self._qemu_process = None
|
||||
self._ram_size_mb = ram_size_mb
|
||||
self._system_log_file = system_log_file
|
||||
self._cpu_cores = cpu_cores
|
||||
self._require_kvm = require_kvm
|
||||
class QemuTarget(emu_target.EmuTarget):
|
||||
def __init__(self, output_dir, target_cpu, system_log_file,
|
||||
emu_type, cpu_cores, require_kvm, ram_size_mb):
|
||||
super(QemuTarget, self).__init__(output_dir, target_cpu,
|
||||
system_log_file)
|
||||
self._emu_type=emu_type
|
||||
self._cpu_cores=cpu_cores
|
||||
self._require_kvm=require_kvm
|
||||
self._ram_size_mb=ram_size_mb
|
||||
|
||||
def __enter__(self):
|
||||
return self
|
||||
def _GetEmulatorName(self):
|
||||
return self._emu_type
|
||||
|
||||
# Used by the context manager to ensure that QEMU is killed when the Python
|
||||
# process exits.
|
||||
def __exit__(self, exc_type, exc_val, exc_tb):
|
||||
self.Shutdown();
|
||||
def _IsKvmEnabled(self):
|
||||
if self._require_kvm:
|
||||
if (sys.platform.startswith('linux') and
|
||||
os.access('/dev/kvm', os.R_OK | os.W_OK)):
|
||||
if self._target_cpu == 'arm64' and platform.machine() == 'aarch64':
|
||||
return True
|
||||
if self._target_cpu == 'x64' and platform.machine() == 'x86_64':
|
||||
return True
|
||||
return False
|
||||
|
||||
def Start(self):
|
||||
def _BuildQemuConfig(self):
|
||||
boot_data.AssertBootImagesExist(self._GetTargetSdkArch(), 'qemu')
|
||||
|
||||
qemu_path = os.path.join(GetQemuRootForPlatform(), 'bin',
|
||||
'qemu-system-' + self._GetTargetSdkLegacyArch())
|
||||
kernel_args = boot_data.GetKernelArgs(self._output_dir)
|
||||
|
||||
# TERM=dumb tells the guest OS to not emit ANSI commands that trigger
|
||||
# noisy ANSI spew from the user's terminal emulator.
|
||||
kernel_args.append('TERM=dumb')
|
||||
|
||||
# Enable logging to the serial port. This is a temporary fix to investigate
|
||||
# the root cause for https://crbug.com/869753 .
|
||||
kernel_args.append('kernel.serial=legacy')
|
||||
|
||||
qemu_command = [qemu_path,
|
||||
'-m', str(self._ram_size_mb),
|
||||
'-nographic',
|
||||
emu_command = [
|
||||
'-kernel', EnsurePathExists(
|
||||
boot_data.GetTargetFile('qemu-kernel.kernel',
|
||||
self._GetTargetSdkArch(),
|
||||
@ -78,6 +63,7 @@ class QemuTarget(target.Target):
|
||||
'-initrd', EnsurePathExists(
|
||||
boot_data.GetBootImage(self._output_dir, self._GetTargetSdkArch(),
|
||||
boot_data.TARGET_TYPE_QEMU)),
|
||||
'-m', str(self._ram_size_mb),
|
||||
'-smp', str(self._cpu_cores),
|
||||
|
||||
# Attach the blobstore and data volumes. Use snapshot mode to discard
|
||||
@ -92,38 +78,20 @@ class QemuTarget(target.Target):
|
||||
# monitor.
|
||||
'-serial', 'stdio',
|
||||
'-monitor', 'none',
|
||||
|
||||
'-append', ' '.join(kernel_args)
|
||||
]
|
||||
|
||||
# Configure the machine to emulate, based on the target architecture.
|
||||
if self._target_cpu == 'arm64':
|
||||
qemu_command.extend([
|
||||
emu_command.extend([
|
||||
'-machine','virt',
|
||||
])
|
||||
netdev_type = 'virtio-net-pci'
|
||||
else:
|
||||
qemu_command.extend([
|
||||
emu_command.extend([
|
||||
'-machine', 'q35',
|
||||
])
|
||||
netdev_type = 'e1000'
|
||||
|
||||
# Configure the CPU to emulate.
|
||||
# On Linux, we can enable lightweight virtualization (KVM) if the host and
|
||||
# guest architectures are the same.
|
||||
enable_kvm = self._require_kvm or (sys.platform.startswith('linux') and (
|
||||
(self._target_cpu == 'arm64' and platform.machine() == 'aarch64') or
|
||||
(self._target_cpu == 'x64' and platform.machine() == 'x86_64')) and
|
||||
os.access('/dev/kvm', os.R_OK | os.W_OK))
|
||||
if enable_kvm:
|
||||
qemu_command.extend(['-enable-kvm', '-cpu', 'host,migratable=no'])
|
||||
else:
|
||||
logging.warning('Unable to launch QEMU with KVM acceleration.')
|
||||
if self._target_cpu == 'arm64':
|
||||
qemu_command.extend(['-cpu', 'cortex-a53'])
|
||||
else:
|
||||
qemu_command.extend(['-cpu', 'Haswell,+smap,-check,-fsgsbase'])
|
||||
|
||||
# Configure virtual network. It is used in the tests to connect to
|
||||
# testserver running on the host.
|
||||
netdev_config = 'user,id=net0,net=%s,dhcpstart=%s,host=%s' % \
|
||||
@ -131,61 +99,50 @@ class QemuTarget(target.Target):
|
||||
|
||||
self._host_ssh_port = common.GetAvailableTcpPort()
|
||||
netdev_config += ",hostfwd=tcp::%s-:22" % self._host_ssh_port
|
||||
qemu_command.extend([
|
||||
emu_command.extend([
|
||||
'-netdev', netdev_config,
|
||||
'-device', '%s,netdev=net0,mac=%s' % (netdev_type, GUEST_MAC_ADDRESS),
|
||||
])
|
||||
|
||||
# We pass a separate stdin stream to qemu. Sharing stdin across processes
|
||||
# leads to flakiness due to the OS prematurely killing the stream and the
|
||||
# Python script panicking and aborting.
|
||||
# The precise root cause is still nebulous, but this fix works.
|
||||
# See crbug.com/741194.
|
||||
logging.debug('Launching QEMU.')
|
||||
logging.debug(' '.join(qemu_command))
|
||||
|
||||
# Zircon sends debug logs to serial port (see kernel.serial=legacy flag
|
||||
# above). Serial port is redirected to a file through QEMU stdout.
|
||||
# Unless a |_system_log_file| is explicitly set, we output the kernel serial
|
||||
# log to a temporary file, and print that out if we are unable to connect to
|
||||
# the QEMU guest, to make it easier to diagnose connectivity issues.
|
||||
temporary_system_log_file = None
|
||||
if self._system_log_file:
|
||||
stdout = self._system_log_file
|
||||
stderr = subprocess.STDOUT
|
||||
# Configure the CPU to emulate.
|
||||
# On Linux, we can enable lightweight virtualization (KVM) if the host and
|
||||
# guest architectures are the same.
|
||||
if self._IsKvmEnabled():
|
||||
kvm_command = ['-enable-kvm', '-cpu', 'host,migratable=no']
|
||||
else:
|
||||
temporary_system_log_file = tempfile.NamedTemporaryFile('w')
|
||||
stdout = temporary_system_log_file
|
||||
stderr = sys.stderr
|
||||
logging.warning('Unable to launch %s with KVM acceleration.'
|
||||
% (self._emu_type) +
|
||||
'The guest VM will be slow.')
|
||||
if self._target_cpu == 'arm64':
|
||||
kvm_command = ['-cpu', 'cortex-a53']
|
||||
else:
|
||||
kvm_command = ['-cpu', 'Haswell,+smap,-check,-fsgsbase']
|
||||
|
||||
self._qemu_process = subprocess.Popen(qemu_command, stdin=open(os.devnull),
|
||||
stdout=stdout, stderr=stderr)
|
||||
try:
|
||||
self._WaitUntilReady();
|
||||
except target.FuchsiaTargetException:
|
||||
if temporary_system_log_file:
|
||||
logging.info("Kernel logs:\n" +
|
||||
open(temporary_system_log_file.name, 'r').read())
|
||||
raise
|
||||
emu_command.extend(kvm_command)
|
||||
|
||||
def Shutdown(self):
|
||||
if self._IsQemuStillRunning():
|
||||
logging.info('Shutting down QEMU.')
|
||||
self._qemu_process.kill()
|
||||
kernel_args = boot_data.GetKernelArgs(self._output_dir)
|
||||
|
||||
def _IsQemuStillRunning(self):
|
||||
if not self._qemu_process:
|
||||
return False
|
||||
return os.waitpid(self._qemu_process.pid, os.WNOHANG)[0] == 0
|
||||
# TERM=dumb tells the guest OS to not emit ANSI commands that trigger
|
||||
# noisy ANSI spew from the user's terminal emulator.
|
||||
kernel_args.append('TERM=dumb')
|
||||
|
||||
def _GetEndpoint(self):
|
||||
if not self._IsQemuStillRunning():
|
||||
raise Exception('QEMU quit unexpectedly.')
|
||||
return ('localhost', self._host_ssh_port)
|
||||
# Construct kernel cmd line
|
||||
kernel_args.append('kernel.serial=legacy')
|
||||
|
||||
def _GetSshConfigPath(self):
|
||||
return boot_data.GetSSHConfigPath(self._output_dir)
|
||||
# Don't 'reboot' the emulator if the kernel crashes
|
||||
kernel_args.append('kernel.halt-on-panic=true')
|
||||
|
||||
emu_command.extend(['-append', ' '.join(kernel_args)])
|
||||
|
||||
return emu_command
|
||||
|
||||
def _BuildCommand(self):
|
||||
qemu_exec = 'qemu-system-'+self._GetTargetSdkLegacyArch()
|
||||
qemu_command = [os.path.join(GetEmuRootForPlatform(self._emu_type), 'bin',
|
||||
qemu_exec)]
|
||||
qemu_command.extend(self._BuildQemuConfig())
|
||||
qemu_command.append('-nographic')
|
||||
return qemu_command
|
||||
|
||||
def _ComputeFileHash(filename):
|
||||
hasher = md5.new()
|
||||
@ -202,7 +159,8 @@ def _EnsureBlobstoreQcowAndReturnPath(output_dir, target_arch):
|
||||
"""Returns a file containing the Fuchsia blobstore in a QCOW format,
|
||||
with extra buffer space added for growth."""
|
||||
|
||||
qimg_tool = os.path.join(common.GetQemuRootForPlatform(), 'bin', 'qemu-img')
|
||||
qimg_tool = os.path.join(common.GetEmuRootForPlatform('qemu'),
|
||||
'bin', 'qemu-img')
|
||||
fvm_tool = os.path.join(common.SDK_ROOT, 'tools', 'fvm')
|
||||
blobstore_path = boot_data.GetTargetFile('storage-full.blk', target_arch,
|
||||
'qemu')
|
||||
|
@ -193,7 +193,7 @@ group.
|
||||
|
||||
### Running test suites
|
||||
|
||||
Building test suites generate a launcher script to run them on a QEMU instance
|
||||
Building test suites generate a launcher script to run them on an emulator
|
||||
or a physical device. These scripts are generated at `out/fuchsia/bin`. For
|
||||
instance,to run the `base_unittests` target, launch:
|
||||
|
||||
@ -204,6 +204,10 @@ $ out/fuchsia/bin/run_base_unittests
|
||||
Common gtest arguments such as `--gtest_filter=...` are supported by the run
|
||||
script. The launcher script also symbolizes backtraces.
|
||||
|
||||
The test suite, by default, will run on QEMU. AEMU can be used for running
|
||||
tests that interact with Fuchsia's window manager, Scenic. To change the device
|
||||
that Fuchsia will run on, use `--device={aemu|qemu|device}`.
|
||||
|
||||
To run a test suite on an *unprovisioned device* in a zedboot state, simply add
|
||||
`-d` to the test runner script arguments. Subsequent runs of the test runner
|
||||
script will be able to pick up the same device.
|
||||
|
@ -60,6 +60,8 @@ def _import_fuchsia_runner():
|
||||
# pylint: disable=import-error
|
||||
# pylint: disable=invalid-name
|
||||
# pylint: disable=redefined-outer-name
|
||||
global aemu_target
|
||||
import aemu_target
|
||||
global fuchsia_target
|
||||
import target as fuchsia_target
|
||||
global qemu_target
|
||||
@ -123,12 +125,20 @@ class SubprocessOutputLogger(object):
|
||||
self._process.kill()
|
||||
|
||||
class _TargetHost(object):
|
||||
def __init__(self, build_path, ports_to_forward):
|
||||
def __init__(self, build_path, ports_to_forward, target_device):
|
||||
try:
|
||||
self._target = None
|
||||
self._target = qemu_target.QemuTarget(
|
||||
build_path, 'x64', cpu_cores=CPU_CORES, system_log_file=None,
|
||||
require_kvm=True, ram_size_mb=8192)
|
||||
target_args = { 'output_dir':build_path,
|
||||
'target_cpu':'x64',
|
||||
'system_log_file':None,
|
||||
'cpu_cores':CPU_CORES,
|
||||
'require_kvm':True,
|
||||
'emu_type':target_device,
|
||||
'ram_size_mb':8192}
|
||||
if target_device == 'qemu':
|
||||
self._target = qemu_target.QemuTarget(**target_args)
|
||||
else:
|
||||
self._target = aemu_target.AemuTarget(**target_args)
|
||||
self._target.Start()
|
||||
self._setup_target(build_path, ports_to_forward)
|
||||
except:
|
||||
@ -185,6 +195,7 @@ class FuchsiaPort(base.Port):
|
||||
|
||||
self._operating_system = 'fuchsia'
|
||||
self._version = 'fuchsia'
|
||||
self._target_device = self.get_option('device')
|
||||
|
||||
# TODO(sergeyu): Add support for arm64.
|
||||
self._architecture = 'x86_64'
|
||||
@ -212,7 +223,7 @@ class FuchsiaPort(base.Port):
|
||||
super(FuchsiaPort, self).setup_test_run()
|
||||
try:
|
||||
self._target_host = _TargetHost(
|
||||
self._build_path(), self.SERVER_PORTS)
|
||||
self._build_path(), self.SERVER_PORTS, self._target_device)
|
||||
|
||||
if self.get_option('zircon_logging'):
|
||||
self._zircon_logger = SubprocessOutputLogger(
|
||||
|
@ -143,6 +143,11 @@ def parse_args(args):
|
||||
action='store_false',
|
||||
default=True,
|
||||
help=('Do not log Zircon debug messages.')),
|
||||
optparse.make_option(
|
||||
'--device',
|
||||
choices=['aemu','qemu'],
|
||||
default='qemu',
|
||||
help=('Choose device to launch Fuchsia with.')),
|
||||
]))
|
||||
|
||||
option_group_definitions.append(
|
||||
|
Reference in New Issue
Block a user