1#!/usr/bin/env vpython3 2# 3# Copyright 2012 The Chromium Authors 4# Use of this source code is governed by a BSD-style license that can be 5# found in the LICENSE file. 6 7"""Utility script to install APKs from the command line quickly.""" 8 9import argparse 10import glob 11import logging 12import os 13import sys 14 15import devil_chromium 16from devil.android import apk_helper 17from devil.android import device_denylist 18from devil.android import device_errors 19from devil.android import device_utils 20from devil.utils import run_tests_helper 21from pylib import constants 22 23 24def main(): 25 parser = argparse.ArgumentParser() 26 27 apk_group = parser.add_mutually_exclusive_group(required=True) 28 apk_group.add_argument('--apk', dest='apk_name', 29 help='DEPRECATED The name of the apk containing the' 30 ' application (with the .apk extension).') 31 apk_group.add_argument('apk_path', nargs='?', 32 help='The path to the APK to install.') 33 34 # TODO(jbudorick): Remove once no clients pass --apk_package 35 parser.add_argument('--apk_package', help='DEPRECATED unused') 36 parser.add_argument('--split', 37 action='append', 38 dest='splits', 39 help='A glob matching the apk splits. ' 40 'Can be specified multiple times.') 41 parser.add_argument('--keep_data', 42 action='store_true', 43 default=False, 44 help='Keep the package data when installing ' 45 'the application.') 46 parser.add_argument('--debug', action='store_const', const='Debug', 47 dest='build_type', 48 default=os.environ.get('BUILDTYPE', 'Debug'), 49 help='If set, run test suites under out/Debug. ' 50 'Default is env var BUILDTYPE or Debug') 51 parser.add_argument('--release', action='store_const', const='Release', 52 dest='build_type', 53 help='If set, run test suites under out/Release. ' 54 'Default is env var BUILDTYPE or Debug.') 55 parser.add_argument('-d', '--device', dest='devices', action='append', 56 default=[], 57 help='Target device for apk to install on. Enter multiple' 58 ' times for multiple devices.') 59 parser.add_argument('--adb-path', type=os.path.abspath, 60 help='Absolute path to the adb binary to use.') 61 parser.add_argument('--denylist-file', help='Device denylist JSON file.') 62 parser.add_argument('-v', 63 '--verbose', 64 action='count', 65 help='Enable verbose logging.', 66 default=0) 67 parser.add_argument('--downgrade', action='store_true', 68 help='If set, allows downgrading of apk.') 69 parser.add_argument('--timeout', type=int, 70 default=device_utils.DeviceUtils.INSTALL_DEFAULT_TIMEOUT, 71 help='Seconds to wait for APK installation. ' 72 '(default: %(default)s)') 73 74 args = parser.parse_args() 75 76 run_tests_helper.SetLogLevel(args.verbose) 77 constants.SetBuildType(args.build_type) 78 79 devil_chromium.Initialize( 80 output_directory=constants.GetOutDirectory(), 81 adb_path=args.adb_path) 82 83 apk = args.apk_path or args.apk_name 84 if not apk.endswith('.apk'): 85 apk += '.apk' 86 if not os.path.exists(apk): 87 apk = os.path.join(constants.GetOutDirectory(), 'apks', apk) 88 if not os.path.exists(apk): 89 parser.error('%s not found.' % apk) 90 91 if args.splits: 92 splits = [] 93 base_apk_package = apk_helper.ApkHelper(apk).GetPackageName() 94 for split_glob in args.splits: 95 apks = [f for f in glob.glob(split_glob) if f.endswith('.apk')] 96 if not apks: 97 logging.warning('No apks matched for %s.', split_glob) 98 for f in apks: 99 helper = apk_helper.ApkHelper(f) 100 if (helper.GetPackageName() == base_apk_package 101 and helper.GetSplitName()): 102 splits.append(f) 103 104 denylist = (device_denylist.Denylist(args.denylist_file) 105 if args.denylist_file else None) 106 devices = device_utils.DeviceUtils.HealthyDevices(denylist=denylist, 107 device_arg=args.devices) 108 109 def denylisting_install(device): 110 try: 111 if args.splits: 112 device.InstallSplitApk(apk, splits, reinstall=args.keep_data, 113 allow_downgrade=args.downgrade) 114 else: 115 device.Install(apk, reinstall=args.keep_data, 116 allow_downgrade=args.downgrade, 117 timeout=args.timeout) 118 except (device_errors.CommandFailedError, 119 device_errors.DeviceUnreachableError): 120 logging.exception('Failed to install %s', apk) 121 if denylist: 122 denylist.Extend([str(device)], reason='install_failure') 123 logging.warning('Denylisting %s', str(device)) 124 except device_errors.CommandTimeoutError: 125 logging.exception('Timed out while installing %s', apk) 126 if denylist: 127 denylist.Extend([str(device)], reason='install_timeout') 128 logging.warning('Denylisting %s', str(device)) 129 130 device_utils.DeviceUtils.parallel(devices).pMap(denylisting_install) 131 132 133if __name__ == '__main__': 134 sys.exit(main()) 135