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