blob: c8dc65d4974aaf2556e207ebceeb39d5eed54a4b [file] [log] [blame]
# Copyright 2012 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.
from __future__ import print_function
import atexit
import copy
import logging
import optparse
import os
import shlex
import socket
import sys
from py_utils import cloud_storage # pylint: disable=import-error
from telemetry import compat_mode_options
from telemetry.core import platform
from telemetry.core import util
from telemetry.internal.browser import browser_finder
from telemetry.internal.browser import browser_finder_exceptions
from telemetry.internal.browser import profile_types
from telemetry.internal.platform import android_device
from telemetry.internal.platform import device_finder
from telemetry.internal.platform import remote_platform_options
from telemetry.internal.util import binary_manager
from telemetry.util import wpr_modes
def _IsWin():
return sys.platform == 'win32'
class BrowserFinderOptions(optparse.Values):
"""Options to be used for discovering a browser."""
emulator_environment = None
def __init__(self, browser_type=None):
optparse.Values.__init__(self)
self.browser_type = browser_type
self.browser_executable = None
# The set of possible platforms the browser should run on.
self.target_platforms = None
self.chrome_root = None # Path to src/
self.chromium_output_dir = None # E.g.: out/Debug
self.device = None
self.cros_ssh_identity = None
self.cros_remote = None
self.cros_remote_ssh_port = None
self.verbosity = 0
self.browser_options = BrowserOptions()
self.output_file = None
self.remote_platform_options = None
self.performance_mode = None
# TODO(crbug.com/798703): remove this
self.no_performance_mode = False
self.interval_profiling_target = ''
self.interval_profiling_periods = []
self.interval_profiling_frequency = 1000
self.interval_profiler_options = ''
self.capture_screen_video = False
self.experimental_system_tracing = False
self.experimental_system_data_sources = False
self.force_sideload_perfetto = False
def __repr__(self):
return str(sorted(self.__dict__.items()))
def Copy(self):
return copy.deepcopy(self)
def CreateParser(self, *args, **kwargs):
parser = optparse.OptionParser(*args, **kwargs)
# Options to interact with a potential external results processor.
parser.set_defaults(
external_results_processor=False,
intermediate_dir=None,
# TODO(crbug.com/928275): Remove these when Telemetry is no longer
# involved in any results processing.
output_dir=None,
output_formats=[],
legacy_output_formats=[],
reset_results=True,
results_label='telemetry_run',
upload_results=False,
upload_bucket=None)
# Selection group
group = optparse.OptionGroup(parser, 'Which browser to use')
group.add_option(
'--browser',
dest='browser_type',
default=None,
help='Browser type to run, '
'in order of priority. Supported values: list,%s' %
', '.join(browser_finder.FindAllBrowserTypes()))
group.add_option(
'--browser-executable',
dest='browser_executable',
help='The exact browser to run.')
group.add_option(
'--chrome-root',
dest='chrome_root',
help='Where to look for chrome builds. '
'Defaults to searching parent dirs by default.')
group.add_option(
'--chromium-output-directory',
dest='chromium_output_dir',
help='Where to look for build artifacts. '
'Can also be specified by setting environment variable '
'CHROMIUM_OUTPUT_DIR.')
group.add_option(
'--remote',
dest='cros_remote',
help='The hostname of a remote ChromeOS device to use.')
group.add_option(
'--remote-ssh-port',
type=int,
# This is set in ParseArgs if necessary.
default=-1,
dest='cros_remote_ssh_port',
help='The SSH port of the remote ChromeOS device (requires --remote).')
compat_mode_options_list = [
compat_mode_options.NO_FIELD_TRIALS,
compat_mode_options.IGNORE_CERTIFICATE_ERROR,
compat_mode_options.LEGACY_COMMAND_LINE_PATH,
compat_mode_options.GPU_BENCHMARKING_FALLBACKS,
compat_mode_options.DONT_REQUIRE_ROOTED_DEVICE]
parser.add_option(
'--compatibility-mode',
action='append',
dest='compatibility_mode',
choices=compat_mode_options_list,
default=[],
help='Select the compatibility change that you want to enforce when '
'running benchmarks. The options are: %s' % ', '.join(
compat_mode_options_list))
parser.add_option(
'--legacy-json-trace-format',
action='store_true',
help='Request traces from Chrome in legacy JSON format.')
parser.add_option(
'--experimental-system-tracing',
action='store_true',
help='Use system tracing from Perfetto to trace Chrome.')
parser.add_option(
'--experimental-system-data-sources',
action='store_true',
help='Use Perfetto tracing to collect power and CPU usage data.')
parser.add_option(
'--force-sideload-perfetto',
action='store_true',
help='Sideload perfetto binaries from the cloud even if the device '
'already has Perfetto installed.')
identity = None
testing_rsa = os.path.join(
util.GetTelemetryThirdPartyDir(), 'chromite', 'ssh_keys', 'testing_rsa')
if os.path.exists(testing_rsa):
identity = testing_rsa
group.add_option(
'--identity',
dest='cros_ssh_identity',
default=identity,
help='The identity file to use when ssh\'ing into the ChromeOS device')
parser.add_option_group(group)
# Debugging options
group = optparse.OptionGroup(parser, 'When things go wrong')
group.add_option('--print-bootstrap-deps',
action='store_true',
help='Output bootstrap deps list.')
group.add_option(
'--extra-chrome-categories', dest='extra_chrome_categories', type=str,
help='Filter string to enable additional chrome tracing categories. See'
' documentation here: https://cs.chromium.org/chromium/src/base/'
'trace_event/trace_config.h?rcl='
'c8db6c6371ca047c24d41f3972d5819bc83d83ae&l=125')
group.add_option(
'--extra-atrace-categories', dest='extra_atrace_categories', type=str,
help='Comma-separated list of extra atrace categories. Use atrace'
' --list_categories to get full list.')
group.add_option(
'--enable-systrace', dest='enable_systrace', action='store_true',
help='Enable collection of systrace. (Useful on ChromeOS where'
' atrace is not supported; collects scheduling information.)')
group.add_option(
'--capture-screen-video',
dest='capture_screen_video', action='store_true',
help='Capture the screen during the test and save it to a video file '
'(note that it is supported only on some platforms)')
group.add_option(
'--periodic-screenshot-frequency-ms',
dest='periodic_screenshot_frequency_ms', type=int,
help='During each story, capture a screenshot every x ms and save it to a file.')
parser.add_option_group(group)
# Platform options
group = optparse.OptionGroup(parser, 'Platform options')
group.add_option(
'--performance-mode',
choices=[android_device.HIGH_PERFORMANCE_MODE,
android_device.NORMAL_PERFORMANCE_MODE,
android_device.LITTLE_ONLY_PERFORMANCE_MODE,
android_device.KEEP_PERFORMANCE_MODE],
default=android_device.HIGH_PERFORMANCE_MODE,
help='Some platforms run on "full performance mode" where the '
'test is executed at maximum CPU speed in order to minimize noise '
'(specially important for dashboards / continuous builds). '
'This option allows to choose performance mode. '
'Available choices: '
'high (default): high performance mode; '
'normal: normal performance mode; '
'little-only: execute the benchmark on little cores only; '
'keep: don\'t touch the device performance settings.')
# TODO(crbug.com/1025207): Rename this to --support-apk
group.add_option(
'--webview-embedder-apk',
action="append",
default=[],
help='When running tests on android webview, more than one apk needs to'
' be installed. The apk running the test is said to embed webview. More'
' than one apk may be specified if needed.')
parser.add_option_group(group)
# Remote platform options
group = optparse.OptionGroup(parser, 'Remote platform options')
group.add_option('--android-denylist-file',
help='Device denylist JSON file.')
group.add_option(
'--device',
help='The device ID to use. '
'If not specified, only 0 or 1 connected devices are supported. '
'If specified as "android", all available Android devices are '
'used.')
group.add_option(
'--install-bundle-module',
dest='modules_to_install',
action='append',
default=[],
help='Specify Android App Bundle modules to install in addition to the '
'base module. Ignored on Non-Android platforms.')
group.add_option(
'--compile-apk',
help='Compiles the APK under test using dex2oat in the specified mode. '
'Ignored on non-Android platforms.')
group.add_option(
'--avd-config',
default=None,
help='A path to an AVD configuration to use for starting an Android '
'emulator.'
)
parser.add_option_group(group)
group = optparse.OptionGroup(parser, 'Fuchsia platform options')
group.add_option(
'--fuchsia-ssh-config',
default='out/Release',
help='Specify the ssh_config file used to connect to the Fuchsia OS.')
group.add_option(
'--fuchsia-device-address',
help='The IP of the target Fuchsia device. Optional.')
group.add_option(
'--fuchsia-ssh-port',
type=int,
help='The port on the host to which the ssh service running on the '
'Fuchsia device was forwarded. Will skip using the device-finder tool '
'if specified.')
group.add_option(
'--fuchsia-system-log-file',
help='The file where Fuchsia system logs will be stored.')
group.add_option(
'--fuchsia-repo',
default="fuchsia.com",
help='The name of the Fuchsia repo used to serve required packages.')
parser.add_option_group(group)
# CPU profiling on Android/Linux/ChromeOS.
group = optparse.OptionGroup(parser, (
'CPU profiling over intervals of interest, '
'Android, Linux, and ChromeOS only'))
group.add_option(
'--interval-profiling-target', dest='interval_profiling_target',
default='renderer:main',
metavar='PROCESS_NAME[:THREAD_NAME]|"system_wide"',
help='Run the CPU profiler on this process/thread (default=%default), '
'which is supported only on Linux and Android, or system-wide, which '
'is supported only on ChromeOS.')
group.add_option(
'--interval-profiling-period', dest='interval_profiling_periods',
type='choice',
choices=('navigation', 'interactions', 'story_run'),
action='append', default=[], metavar='PERIOD',
help='Run the CPU profiler during this test period. '
'May be specified multiple times except when the story_run period is '
'used; available choices are ["navigation", "interactions", '
'"story_run"]. Profile data will be written to '
'artifacts/*.perf.data (Android/ChromeOS) or '
'artifacts/*.profile.pb (Linux) files in the output directory. See '
'https://developer.android.com/ndk/guides/simpleperf for more info on '
'Android profiling via simpleperf.')
group.add_option(
'--interval-profiling-frequency', default=1000, metavar='FREQUENCY',
type=int,
help='Frequency of CPU profiling samples, in samples per second '
'(default=%default). This flag is used only on Android')
group.add_option(
'--interval-profiler-options',
dest='interval_profiler_options', type=str,
metavar='"--flag <options> ..."',
help='Addtional arguments to pass to the CPU profiler. This is used '
'only on ChromeOS. On ChromeOS, pass the linux perf\'s subcommand name '
'followed by the options to pass to the perf tool. Supported perf '
'subcommands are "record" and "stat". '
'Eg: "record -e cycles -c 4000000 -g". Note: "-a" flag is added to the '
'perf command by default. Do not pass options that are incompatible '
'with the system-wide profile collection.')
parser.add_option_group(group)
# Browser options.
self.browser_options.AddCommandLineArgs(parser)
real_parse = parser.parse_args
def ParseArgs(args=None):
defaults = parser.get_default_values()
for k, v in defaults.__dict__.items():
if k in self.__dict__ and self.__dict__[k] != None:
continue
self.__dict__[k] = v
ret = real_parse(args, self) # pylint: disable=E1121
if self.chromium_output_dir:
os.environ['CHROMIUM_OUTPUT_DIR'] = self.chromium_output_dir
# Set up Android emulator if necessary.
self.ParseAndroidEmulatorOptions()
# Parse remote platform options.
self.BuildRemotePlatformOptions()
if self.remote_platform_options.device == 'list':
if binary_manager.NeedsInit():
binary_manager.InitDependencyManager([])
devices = device_finder.GetDevicesMatchingOptions(self)
print('Available devices:')
for device in devices:
print(' ', device.name)
sys.exit(0)
if self.browser_executable and not self.browser_type:
self.browser_type = 'exact'
if self.browser_type == 'list':
if binary_manager.NeedsInit():
binary_manager.InitDependencyManager([])
devices = device_finder.GetDevicesMatchingOptions(self)
if not devices:
sys.exit(0)
browser_types = {}
for device in devices:
try:
possible_browsers = browser_finder.GetAllAvailableBrowsers(self,
device)
browser_types[device.name] = sorted(
[browser.browser_type for browser in possible_browsers])
except browser_finder_exceptions.BrowserFinderException as ex:
print('ERROR: ', ex, file=sys.stderr)
sys.exit(1)
print('Available browsers:')
if len(browser_types) == 0:
print(' No devices were found.')
for device_name in sorted(browser_types.keys()):
print(' ', device_name)
for browser_type in browser_types[device_name]:
print(' ', browser_type)
if len(browser_types[device_name]) == 0:
print(' No browsers found for this device')
sys.exit(0)
if ((self.browser_type == 'cros-chrome' or
self.browser_type == 'lacros-chrome') and
self.cros_remote and (self.cros_remote_ssh_port < 0)):
try:
self.cros_remote_ssh_port = socket.getservbyname('ssh')
except OSError as e:
raise RuntimeError(
'Running a CrOS test in remote mode, but failed to retrieve port '
'used by SSH service. This likely means SSH is not installed on '
'the system. Original error: %s' % e)
# Profiling other periods along with the story_run period leads to running
# multiple profiling processes at the same time. The effects of performing
# muliple CPU profiling at the same time is unclear and may generate
# incorrect profiles so this will not be supported.
if (len(self.interval_profiling_periods) > 1
and 'story_run' in self.interval_profiling_periods):
print('Cannot specify other periods along with the story_run period.')
sys.exit(1)
self.interval_profiler_options = shlex.split(
self.interval_profiler_options, posix=(not _IsWin()))
# Parse browser options.
self.browser_options.UpdateFromParseResults(self)
return ret
parser.parse_args = ParseArgs
return parser
def IsBrowserTypeRelevant(self, browser_type):
"""Determines if the browser_type is worth initializing.
This check is used to sidestep any unnecessary work involved with searching
for a browser that might not actually be needed. For example, this check
could be used to prevent Telemetry from searching for a Clank browser if
browser_type is android-weblayer.
"""
return (browser_type == self.browser_type or
self.browser_type in ('list', 'any',))
def IsBrowserTypeReference(self):
"""Determines if the browser_type is a reference browser_type."""
return self.browser_type and self.browser_type.startswith('reference-')
def IsBrowserTypeBundle(self):
"""Determines if the browser_type is a bundle browser_type."""
return self.browser_type and self.browser_type.endswith('-bundle')
def _NoOpFunctionForTesting(self):
"""No-op function that can be overridden for unittests."""
pass
def ParseAndroidEmulatorOptions(self):
"""Parses Android emulator args, and if necessary, starts an emulator.
No-ops if --avd-config is not specified or if an emulator is already
started.
Performing this setup during argument parsing isn't ideal, but we need to
set up the emulator sometime between arg parsing and browser finding.
"""
if not self.avd_config:
return
if BrowserFinderOptions.emulator_environment:
return
build_android_dir = os.path.join(
util.GetChromiumSrcDir(), 'build', 'android')
if not os.path.exists(build_android_dir):
raise RuntimeError(
'--avd-config specified, but Chromium //build/android directory not '
'available')
# Everything after this point only works if //build/android is actually
# available, which we can't rely on, so use this to exit early in unittests.
self._NoOpFunctionForTesting()
sys.path.append(build_android_dir)
# pylint: disable=import-error
from pylib import constants as pylib_constants
from pylib.local.emulator import local_emulator_environment
# pylint: enable=import-error
# We need to call this so that the Chromium output directory is set if it
# is not explicitly specified via the command line argument/environment
# variable.
pylib_constants.CheckOutputDirectory()
class AvdArgs(object):
"""A class to stand in for the AVD argparse.ArgumentParser object.
Chromium's Android emulator code expects quite a few arguments from
//build/android/test_runner.py, but the only one we actually care about
here is avd_config. So, use a stand-in class with some sane defaults.
"""
def __init__(self, avd_config):
self.avd_config = avd_config
self.emulator_count = 1
self.emulator_window = False
self.use_webview_provider = False
self.replace_system_package = False
self.denylist_file = None
self.test_devices = []
self.enable_concurrent_adb = False
self.logcat_output_dir = None
self.logcat_output_file = None
self.num_retries = 1
self.recover_devices = False
self.skip_clear_data = True
self.tool = None
self.adb_path = None
self.enable_device_cache = True
avd_args = AvdArgs(self.avd_config)
BrowserFinderOptions.emulator_environment =\
local_emulator_environment.LocalEmulatorEnvironment(
avd_args, None, None)
BrowserFinderOptions.emulator_environment.SetUp()
atexit.register(BrowserFinderOptions.emulator_environment.TearDown)
# TODO(eakuefner): Factor this out into OptionBuilder pattern
def BuildRemotePlatformOptions(self):
if self.device or self.android_denylist_file:
self.remote_platform_options = (
remote_platform_options.AndroidPlatformOptions(
self.device, self.android_denylist_file))
# We delete these options because they should live solely in the
# AndroidPlatformOptions instance belonging to this class.
if self.device:
del self.device
if self.android_denylist_file:
del self.android_denylist_file
else:
self.remote_platform_options = (
remote_platform_options.AndroidPlatformOptions())
def AppendExtraBrowserArgs(self, args):
self.browser_options.AppendExtraBrowserArgs(args)
def MergeDefaultValues(self, defaults):
for k, v in defaults.__dict__.items():
self.ensure_value(k, v)
class BrowserOptions(object):
"""Options to be used for launching a browser."""
# Allows clients to check whether they are dealing with a browser_options
# object, without having to import this module. This may be needed in some
# cases to avoid cyclic-imports.
IS_BROWSER_OPTIONS = True
# Levels of browser logging.
NO_LOGGING = 'none'
NON_VERBOSE_LOGGING = 'non-verbose'
VERBOSE_LOGGING = 'verbose'
SUPER_VERBOSE_LOGGING = 'super-verbose'
_LOGGING_LEVELS = (NO_LOGGING, NON_VERBOSE_LOGGING, VERBOSE_LOGGING,
SUPER_VERBOSE_LOGGING)
_DEFAULT_LOGGING_LEVEL = NO_LOGGING
def __init__(self):
self.browser_type = None
self.show_stdout = False
self.extensions_to_load = []
# When set to True, the browser will use the default profile. Telemetry
# will not provide an alternate profile directory.
self.dont_override_profile = False
self.profile_dir = None
self.profile_type = None
self.assert_gpu_compositing = False
self._extra_browser_args = set()
self.extra_wpr_args = []
self.wpr_mode = wpr_modes.WPR_OFF
# The amount of time Telemetry should wait for the browser to start.
# This property is not exposed as a command line option.
self._browser_startup_timeout = 60
self.disable_background_networking = True
self.browser_user_agent_type = None
# Some benchmarks (startup, loading, and memory related) need this to get
# more representative measurements. Only has an effect for page sets based
# on SharedPageState. New clients should probably define their own shared
# state and make cache clearing decisions on their own.
self.flush_os_page_caches_on_start = False
# Background pages of built-in component extensions can interfere with
# performance measurements.
# pylint: disable=invalid-name
self.disable_component_extensions_with_background_pages = True
# Disable default apps.
self.disable_default_apps = True
self.logging_verbosity = self._DEFAULT_LOGGING_LEVEL
# Whether to log verbose browser details like the full commandline used to
# start the browser. This variable can be changed from one run to another
# in order to cut back on log sizes. See crbug.com/943650.
self.trim_logs = False
# The cloud storage bucket & path for uploading logs data produced by the
# browser to.
# If logs_cloud_remote_path is None, a random remote path is generated every
# time the logs data is uploaded.
self.logs_cloud_bucket = cloud_storage.TELEMETRY_OUTPUT
self.logs_cloud_remote_path = None
# Whether to take screen shot for failed page & put them in telemetry's
# profiling results.
self.take_screenshot_for_failed_page = False
# A list of tuples where the first element is path to an existing file,
# and the second argument is a path (relative to the user-data-dir) to copy
# the file to. Uses recursive directory creation if directories do not
# already exist.
self.profile_files_to_copy = []
# The list of compatibility change that you want to enforce, mainly for
# earlier versions of Chrome
self.compatibility_mode = []
# If not None, a ProjectConfig object with information about the benchmark
# runtime environment.
self.environment = None
def __repr__(self):
return str(sorted(self.__dict__.items()))
def Copy(self):
return copy.deepcopy(self)
def IsCrosBrowserOptions(self):
return False
@classmethod
def AddCommandLineArgs(cls, parser):
############################################################################
# Please do not add any more options here without first discussing with #
# a telemetry owner. This is not the right place for platform-specific #
# options. #
############################################################################
group = optparse.OptionGroup(parser, 'Browser options')
profile_choices = profile_types.GetProfileTypes()
group.add_option(
'--profile-type',
dest='profile_type',
type='choice',
default='clean',
choices=profile_choices,
help=('The user profile to use. A clean profile is used by default. '
'Supported values: ' + ', '.join(profile_choices)))
group.add_option(
'--profile-dir',
dest='profile_dir',
help='Profile directory to launch the browser with. '
'A clean profile is used by default')
group.add_option(
'--extra-browser-args',
dest='extra_browser_args_as_string',
help='Additional arguments to pass to the browser when it starts')
group.add_option(
'--extra-wpr-args',
dest='extra_wpr_args_as_string',
help=('Additional arguments to pass to Web Page Replay. '
'See third_party/web-page-replay/replay.py for usage.'))
group.add_option(
'--show-stdout',
action='store_true',
help='When possible, will display the stdout of the process')
group.add_option(
'--browser-logging-verbosity',
dest='logging_verbosity',
type='choice',
choices=cls._LOGGING_LEVELS,
help=('Browser logging verbosity. The log file is saved in temp '
"directory. Note that logging affects the browser's "
'performance. Supported values: %s. Defaults to %s.' % (
', '.join(cls._LOGGING_LEVELS), cls._DEFAULT_LOGGING_LEVEL)))
group.add_option(
'--assert-gpu-compositing',
dest='assert_gpu_compositing', action='store_true',
help='Assert the browser uses gpu compositing and not software path.')
parser.add_option_group(group)
group = optparse.OptionGroup(parser, 'Compatibility options')
group.add_option(
'--gtest_output',
help='Ignored argument for compatibility with runtest.py harness')
parser.add_option_group(group)
def UpdateFromParseResults(self, finder_options):
"""Copies our options from finder_options."""
browser_options_list = [
'extra_browser_args_as_string',
'extra_wpr_args_as_string',
'profile_dir',
'profile_type',
'show_stdout',
'compatibility_mode'
]
for o in browser_options_list:
a = getattr(finder_options, o, None)
if a is not None:
setattr(self, o, a)
delattr(finder_options, o)
self.browser_type = finder_options.browser_type
if hasattr(self, 'extra_browser_args_as_string'):
tmp = shlex.split(self.extra_browser_args_as_string, posix=(not _IsWin()))
self.AppendExtraBrowserArgs(tmp)
delattr(self, 'extra_browser_args_as_string')
if hasattr(self, 'extra_wpr_args_as_string'):
tmp = shlex.split(self.extra_wpr_args_as_string, posix=(not _IsWin()))
self.extra_wpr_args.extend(tmp)
delattr(self, 'extra_wpr_args_as_string')
if self.profile_type == 'default':
self.dont_override_profile = True
if self.profile_dir:
if self.profile_type != 'clean':
logging.critical(
"It's illegal to specify both --profile-type and --profile-dir.\n"
"For more information see: http://goo.gl/ngdGD5")
sys.exit(1)
self.profile_dir = os.path.abspath(self.profile_dir)
if self.profile_dir and not os.path.isdir(self.profile_dir):
logging.critical(
"Directory specified by --profile-dir (%s) doesn't exist "
"or isn't a directory.\n"
"For more information see: http://goo.gl/ngdGD5" % self.profile_dir)
sys.exit(1)
if not self.profile_dir:
self.profile_dir = profile_types.GetProfileDir(self.profile_type)
if getattr(finder_options, 'logging_verbosity'):
self.logging_verbosity = finder_options.logging_verbosity
delattr(finder_options, 'logging_verbosity')
# This deferred import is necessary because browser_options is imported in
# telemetry/telemetry/__init__.py.
finder_options.browser_options = CreateChromeBrowserOptions(self)
@property
def extra_browser_args(self):
return self._extra_browser_args
@property
def browser_startup_timeout(self):
return self._browser_startup_timeout
@browser_startup_timeout.setter
def browser_startup_timeout(self, value):
self._browser_startup_timeout = value
def AppendExtraBrowserArgs(self, args):
if isinstance(args, list):
self._extra_browser_args.update(args)
else:
self._extra_browser_args.add(args)
def CreateChromeBrowserOptions(br_options):
browser_type = br_options.browser_type
if (platform.GetHostPlatform().GetOSName() == 'chromeos' or
(browser_type and 'cros' in browser_type)):
return CrosBrowserOptions(br_options)
return br_options
class ChromeBrowserOptions(BrowserOptions):
"""Chrome-specific browser options."""
def __init__(self, br_options):
super(ChromeBrowserOptions, self).__init__()
# Copy to self.
self.__dict__.update(br_options.__dict__)
class CrosBrowserOptions(ChromeBrowserOptions):
"""ChromeOS-specific browser options."""
def __init__(self, br_options):
super(CrosBrowserOptions, self).__init__(br_options)
# Create a browser with oobe property.
self.create_browser_with_oobe = False
# Clear enterprise policy before logging in.
self.clear_enterprise_policy = True
# By default, allow policy fetches to fail. A side effect is that the user
# profile may become initialized before policy is available.
# When this is set to True, chrome will not allow policy fetches to fail and
# block user profile initialization on policy initialization.
self.expect_policy_fetch = False
# Disable GAIA/enterprise services.
self.disable_gaia_services = True
# Mute audio.
self.mute_audio = True
# TODO(cywang): crbug.com/760414
# Add login delay for ARC container boot time measurement for now.
# Should actually simulate username/password typing in the login
# screen instead or make the wait time fixed for cros login.
self.login_delay = 0
self.auto_login = True
self.gaia_login = False
self.username = 'test@test.test'
self.password = ''
self.gaia_id = '12345'
# For non-accelerated QEMU VMs.
self.browser_startup_timeout = 240
def IsCrosBrowserOptions(self):
return True