#!/usr/bin/env vpython3 # # Copyright (c) 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. """Utility script to install APKs from the command line quickly.""" import argparse import glob import logging import os import sys import devil_chromium from devil.android import apk_helper from devil.android import device_denylist from devil.android import device_errors from devil.android import device_utils from devil.utils import run_tests_helper from pylib import constants def main(): parser = argparse.ArgumentParser() apk_group = parser.add_mutually_exclusive_group(required=True) apk_group.add_argument('--apk', dest='apk_name', help='DEPRECATED The name of the apk containing the' ' application (with the .apk extension).') apk_group.add_argument('apk_path', nargs='?', help='The path to the APK to install.') # TODO(jbudorick): Remove once no clients pass --apk_package parser.add_argument('--apk_package', help='DEPRECATED unused') parser.add_argument('--split', action='append', dest='splits', help='A glob matching the apk splits. ' 'Can be specified multiple times.') parser.add_argument('--keep_data', action='store_true', default=False, help='Keep the package data when installing ' 'the application.') parser.add_argument('--debug', action='store_const', const='Debug', dest='build_type', default=os.environ.get('BUILDTYPE', 'Debug'), help='If set, run test suites under out/Debug. ' 'Default is env var BUILDTYPE or Debug') parser.add_argument('--release', action='store_const', const='Release', dest='build_type', help='If set, run test suites under out/Release. ' 'Default is env var BUILDTYPE or Debug.') parser.add_argument('-d', '--device', dest='devices', action='append', default=[], help='Target device for apk to install on. Enter multiple' ' times for multiple devices.') parser.add_argument('--adb-path', type=os.path.abspath, help='Absolute path to the adb binary to use.') parser.add_argument('--denylist-file', help='Device denylist JSON file.') parser.add_argument('-v', '--verbose', action='count', help='Enable verbose logging.', default=0) parser.add_argument('--downgrade', action='store_true', help='If set, allows downgrading of apk.') parser.add_argument('--timeout', type=int, default=device_utils.DeviceUtils.INSTALL_DEFAULT_TIMEOUT, help='Seconds to wait for APK installation. ' '(default: %(default)s)') args = parser.parse_args() run_tests_helper.SetLogLevel(args.verbose) constants.SetBuildType(args.build_type) devil_chromium.Initialize( output_directory=constants.GetOutDirectory(), adb_path=args.adb_path) apk = args.apk_path or args.apk_name if not apk.endswith('.apk'): apk += '.apk' if not os.path.exists(apk): apk = os.path.join(constants.GetOutDirectory(), 'apks', apk) if not os.path.exists(apk): parser.error('%s not found.' % apk) if args.splits: splits = [] base_apk_package = apk_helper.ApkHelper(apk).GetPackageName() for split_glob in args.splits: apks = [f for f in glob.glob(split_glob) if f.endswith('.apk')] if not apks: logging.warning('No apks matched for %s.', split_glob) for f in apks: helper = apk_helper.ApkHelper(f) if (helper.GetPackageName() == base_apk_package and helper.GetSplitName()): splits.append(f) denylist = (device_denylist.Denylist(args.denylist_file) if args.denylist_file else None) devices = device_utils.DeviceUtils.HealthyDevices(denylist=denylist, device_arg=args.devices) def denylisting_install(device): try: if args.splits: device.InstallSplitApk(apk, splits, reinstall=args.keep_data, allow_downgrade=args.downgrade) else: device.Install(apk, reinstall=args.keep_data, allow_downgrade=args.downgrade, timeout=args.timeout) except (device_errors.CommandFailedError, device_errors.DeviceUnreachableError): logging.exception('Failed to install %s', apk) if denylist: denylist.Extend([str(device)], reason='install_failure') logging.warning('Denylisting %s', str(device)) except device_errors.CommandTimeoutError: logging.exception('Timed out while installing %s', apk) if denylist: denylist.Extend([str(device)], reason='install_timeout') logging.warning('Denylisting %s', str(device)) device_utils.DeviceUtils.parallel(devices).pMap(denylisting_install) if __name__ == '__main__': sys.exit(main())