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