| #! /usr/bin/env vpython3 |
| # Copyright 2019 The Chromium Authors |
| # Use of this source code is governed by a BSD-style license that can be |
| # found in the LICENSE file. |
| |
| import argparse |
| import os |
| import logging |
| import pathlib |
| import sys |
| |
| _SRC_ROOT = os.path.abspath( |
| os.path.join(os.path.dirname(__file__), '..', '..', '..')) |
| |
| sys.path.append( |
| os.path.join(_SRC_ROOT, 'third_party', 'catapult', 'devil')) |
| from devil.android.tools import script_common |
| from devil.utils import logging_common |
| |
| sys.path.append( |
| os.path.join(_SRC_ROOT, 'build', 'android')) |
| import devil_chromium |
| from pylib.local.emulator import avd |
| |
| |
| def _add_avd_config_argument(parser): |
| parser.add_argument('--avd-config', |
| type=os.path.realpath, |
| metavar='PATH', |
| required=True, |
| help='Path to an AVD config text protobuf.') |
| |
| |
| def _add_common_arguments(parser): |
| logging_common.AddLoggingArguments(parser) |
| script_common.AddEnvironmentArguments(parser) |
| |
| |
| def main(raw_args): |
| |
| parser = argparse.ArgumentParser() |
| |
| subparsers = parser.add_subparsers() |
| subparser = subparsers.add_parser( |
| 'install', |
| help='Install the CIPD packages specified in the given config.') |
| _add_common_arguments(subparser) |
| _add_avd_config_argument(subparser) |
| |
| def install_cmd(args): |
| avd.AvdConfig(args.avd_config).Install() |
| return 0 |
| |
| subparser.set_defaults(func=install_cmd) |
| |
| subparser = subparsers.add_parser( |
| 'uninstall', |
| help='Uninstall all the artifacts associated with the given config.') |
| _add_common_arguments(subparser) |
| _add_avd_config_argument(subparser) |
| |
| def uninstall_cmd(args): |
| avd.AvdConfig(args.avd_config).Uninstall() |
| return 0 |
| |
| subparser.set_defaults(func=uninstall_cmd) |
| |
| subparser = subparsers.add_parser( |
| 'create', |
| help='Create an AVD CIPD package according to the given config.') |
| _add_common_arguments(subparser) |
| _add_avd_config_argument(subparser) |
| subparser.add_argument( |
| '--snapshot', |
| action='store_true', |
| help='Snapshot the AVD before creating the CIPD package.') |
| subparser.add_argument('--force', |
| action='store_true', |
| help='Pass --force to AVD creation.') |
| subparser.add_argument('--keep', |
| action='store_true', |
| help='Keep the AVD after creating the CIPD package.') |
| subparser.add_argument( |
| '--privileged-apk', |
| action='append', |
| default=[], |
| dest='privileged_apk_pairs', |
| nargs=2, |
| metavar=('APK_PATH', 'DEVICE_PARTITION'), |
| help='Privileged apks to be installed during AVD launching. Expecting ' |
| 'two strings where the first element being the path to the APK, and the ' |
| 'second element being the system image partition on device where the APK ' |
| 'will be pushed to. Example: --privileged-apk path/to/some.apk /system') |
| subparser.add_argument( |
| '--additional-apk', |
| action='append', |
| default=[], |
| dest='additional_apks', |
| metavar='APK_PATH', |
| type=os.path.realpath, |
| help='Additional apk to be installed during AVD launching') |
| subparser.add_argument( |
| '--cipd-json-output', |
| type=os.path.realpath, |
| metavar='PATH', |
| help='Path to which `cipd create` should dump json output ' |
| 'via -json-output.') |
| subparser.add_argument( |
| '--dry-run', |
| action='store_true', |
| help='Skip the CIPD package creation after creating the AVD.') |
| |
| def create_cmd(args): |
| avd.AvdConfig(args.avd_config).Create( |
| force=args.force, |
| snapshot=args.snapshot, |
| keep=args.keep, |
| additional_apks=args.additional_apks, |
| privileged_apk_tuples=[tuple(p) for p in args.privileged_apk_pairs], |
| cipd_json_output=args.cipd_json_output, |
| dry_run=args.dry_run) |
| return 0 |
| |
| subparser.set_defaults(func=create_cmd) |
| |
| subparser = subparsers.add_parser( |
| 'start', |
| help='Start an AVD instance with the given config.', |
| formatter_class=argparse.ArgumentDefaultsHelpFormatter) |
| _add_common_arguments(subparser) |
| _add_avd_config_argument(subparser) |
| subparser.add_argument( |
| '--wipe-data', |
| action='store_true', |
| default=False, |
| help='Reset user data image for this emulator. Note that when set, all ' |
| 'the customization, e.g. wifi, additional apks, privileged apks will be ' |
| 'gone') |
| subparser.add_argument( |
| '--read-only', |
| action='store_true', |
| help='Allowing running multiple instances of emulators on the same AVD, ' |
| 'but cannot save snapshot. This will be forced to False if emulator ' |
| 'has a system snapshot.') |
| subparser.add_argument('--no-read-only', |
| action='store_false', |
| dest='read_only') |
| # TODO(crbug.com/1278096): Default to False when AVDs with sideloaded |
| # system apks are rolled. |
| subparser.set_defaults(read_only=True) |
| subparser.add_argument( |
| '--writable-system', |
| action='store_true', |
| default=False, |
| help='Makes system & vendor image writable after adb remount. This will ' |
| 'be forced to True, if emulator has a system snapshot.') |
| subparser.add_argument( |
| '--emulator-window', |
| action='store_true', |
| default=False, |
| help='Enable graphical window display on the emulator.') |
| subparser.add_argument( |
| '--gpu-mode', |
| help='Override the mode of hardware OpenGL ES emulation indicated by the ' |
| 'AVD. See "emulator -help-gpu" for a full list of modes. Note when set ' |
| 'to "host", it needs a valid DISPLAY env, even if "--emulator-window" is ' |
| 'false, and it will not work under remote sessions like chrome remote ' |
| 'desktop.') |
| subparser.add_argument( |
| '--debug-tags', |
| help='Comma-separated list of debug tags. This can be used to enable or ' |
| 'disable debug messages from specific parts of the emulator, e.g. ' |
| 'init,snapshot. See "emulator -help-debug-tags" ' |
| 'for a full list of tags.') |
| subparser.add_argument( |
| '--disk-size', |
| help='Override the default disk size for the emulator instance.') |
| subparser.add_argument( |
| '--enable-network', |
| action='store_true', |
| help='Enable the network (WiFi and mobile data) on the emulator.') |
| subparser.add_argument( |
| '--require-fast-start', |
| action='store_true', |
| help='Shortens the start-up timeout. Used by bots to avoid startup ' |
| 'regressions.') |
| |
| def start_cmd(args): |
| avd_config = avd.AvdConfig(args.avd_config) |
| if not avd_config.IsAvailable(): |
| logging.warning('Emulator not up-to-date, installing (takes a minute)...') |
| avd_config.Install() |
| logging.warning('Starting emulator...') |
| |
| debug_tags = args.debug_tags |
| if not debug_tags and args.verbose: |
| debug_tags = 'time,init' |
| |
| inst = avd_config.CreateInstance() |
| inst.Start(read_only=args.read_only, |
| window=args.emulator_window, |
| writable_system=args.writable_system, |
| gpu_mode=args.gpu_mode, |
| wipe_data=args.wipe_data, |
| debug_tags=debug_tags, |
| disk_size=args.disk_size, |
| enable_network=args.enable_network, |
| require_fast_start=args.require_fast_start) |
| print('%s started (pid: %d)' % (str(inst), inst._emulator_proc.pid)) |
| return 0 |
| |
| subparser.set_defaults(func=start_cmd) |
| |
| subparser = subparsers.add_parser( |
| 'list', |
| help='Shows possible values for --avd-config.', |
| formatter_class=argparse.ArgumentDefaultsHelpFormatter) |
| _add_common_arguments(subparser) |
| |
| def list_cmd(args): |
| files = pathlib.Path(__file__).parent.glob('proto/*.textpb') |
| avd_configs = [avd.AvdConfig(os.path.relpath(f)) for f in files] |
| avd_configs.sort(key=lambda c: c.avd_proto_path) |
| fmt_string = '{:70} {:40} {}' |
| print( |
| fmt_string.format('Possible values for --avd-config:', 'Name', |
| 'Active & Up-to-date')) |
| for avd_config in avd_configs: |
| print( |
| fmt_string.format(avd_config.avd_proto_path, avd_config.avd_name, |
| avd_config.IsAvailable())) |
| print() |
| print('Warning: playstore images currently require --wipe-data. ' |
| 'See: https://crbug.com/1116196') |
| return 0 |
| |
| subparser.set_defaults(func=list_cmd) |
| |
| if len(sys.argv) == 1: |
| parser.print_help() |
| return 1 |
| |
| args = parser.parse_args(raw_args) |
| |
| logging_common.InitializeLogging(args) |
| devil_chromium.Initialize(adb_path=args.adb_path) |
| return args.func(args) |
| |
| |
| if __name__ == '__main__': |
| sys.exit(main(sys.argv[1:])) |