def _GetAttachedDevices(blacklist_file, test_device): """Get all attached devices. Args: test_device: Name of a specific device to use. Returns: A list of attached devices. """ blacklist = (device_blacklist.Blacklist(blacklist_file) if blacklist_file else None) attached_devices = device_utils.DeviceUtils.HealthyDevices(blacklist) if test_device: test_device = [d for d in attached_devices if d == test_device] if not test_device: raise device_errors.DeviceUnreachableError( 'Did not find device %s among attached device. Attached devices: %s' % (test_device, ', '.join(attached_devices))) return test_device else: if not attached_devices: raise device_errors.NoDevicesError() return sorted(attached_devices)
def _GetAttachedDevices(blacklist_file, test_device, enable_cache, num_retries): """Get all attached devices. Args: blacklist_file: Path to device blacklist. test_device: Name of a specific device to use. enable_cache: Whether to enable checksum caching. Returns: A list of attached devices. """ blacklist = (device_blacklist.Blacklist(blacklist_file) if blacklist_file else None) attached_devices = device_utils.DeviceUtils.HealthyDevices( blacklist, enable_device_files_cache=enable_cache, default_retries=num_retries) if test_device: test_device = [d for d in attached_devices if d == test_device] if not test_device: raise device_errors.DeviceUnreachableError( 'Did not find device %s among attached device. Attached devices: %s' % (test_device, ', '.join(attached_devices))) return test_device else: if not attached_devices: raise device_errors.NoDevicesError() return sorted(attached_devices)
def InitShell(self, device=None): ''' Runs adb as root, and installs the apk as needed. |device| is the target device to run on, if multiple devices are connected. Returns 0 on success or a non-zero exit code on a terminal failure. ''' try: devices = device_utils.DeviceUtils.HealthyDevices() if device: self.device = next((d for d in devices if d == device), None) if not self.device: raise device_errors.DeviceUnreachableError(device) elif devices: self.device = devices[0] else: raise device_errors.NoDevicesError() logging.getLogger().debug('Using device: %s', self.device) # Clean the logs on the device to avoid displaying prior activity. subprocess.check_call(self._CreateADBCommand(['logcat', '-c'])) self.device.EnableRoot() self.device.Install(self.paths.apk_path) except base_error.BaseError as e: # Report 'device not found' as infra failures. See http://crbug.com/493900 print 'Exception in AndroidShell.InitShell:\n%s' % str(e) if e.is_infra_error or 'error: device not found' in str(e): return constants.INFRA_EXIT_CODE return constants.ERROR_EXIT_CODE return 0
def main(argv): parser = optparse.OptionParser(usage='Usage: %prog [options] device_port ' 'host_port [device_port_2 host_port_2] ...', description=__doc__) parser.add_option('-v', '--verbose', dest='verbose_count', default=0, action='count', help='Verbose level (multiple times for more)') parser.add_option('--device', help='Serial number of device we should use.') parser.add_option('--blacklist-file', help='Device blacklist JSON file.') parser.add_option('--debug', action='store_const', const='Debug', dest='build_type', default='Release', help='Use Debug build of host tools instead of Release.') options, args = parser.parse_args(argv) run_tests_helper.SetLogLevel(options.verbose_count) devil_chromium.Initialize() if len(args) < 2 or not len(args) % 2: parser.error('Need even number of port pairs') sys.exit(1) try: port_pairs = [int(a) for a in args[1:]] port_pairs = zip(port_pairs[::2], port_pairs[1::2]) except ValueError: parser.error('Bad port number') sys.exit(1) blacklist = (device_blacklist.Blacklist(options.blacklist_file) if options.blacklist_file else None) devices = device_utils.DeviceUtils.HealthyDevices(blacklist) if options.device: device = next((d for d in devices if d == options.device), None) if not device: raise device_errors.DeviceUnreachableError(options.device) elif devices: device = devices[0] logging.info('No device specified. Defaulting to %s', devices[0]) else: raise device_errors.NoDevicesError() constants.SetBuildType(options.build_type) try: forwarder.Forwarder.Map(port_pairs, device) while True: time.sleep(60) except KeyboardInterrupt: sys.exit(0) finally: forwarder.Forwarder.UnmapAllDevicePorts(device)
def devices(self): # Initialize lazily so that host-only tests do not fail when no devices are # attached. if self._devices is None: self._InitDevices() if not self._devices: raise device_errors.NoDevicesError() return self._devices
def testDetermineDeviceToUse_emptyListWithNoAttachedDevices(self): user_specified_devices = [] device_utils.DeviceUtils.HealthyDevices = mock.MagicMock( side_effect=device_errors.NoDevicesError()) with self.assertRaises(device_errors.NoDevicesError) as _: list_verification.DetermineDeviceToUse(user_specified_devices) device_utils.DeviceUtils.HealthyDevices.assert_called_with( device_arg=None)
def main(): parser = argparse.ArgumentParser( description="Script to do semi-automated upgrade testing.") parser.add_argument('-v', '--verbose', action='count', help='Print verbose log information.') parser.add_argument('--blacklist-file', dest='denylist_file', help=argparse.SUPPRESS) parser.add_argument('--denylist-file', help='Device denylist JSON file.') command_parsers = parser.add_subparsers(dest='command') subparser = command_parsers.add_parser('create_app_data') subparser.add_argument('--old-apk', required=True, help='Path to apk to update from.') subparser.add_argument('--app-data', required=True, help='Path to where the app data backup should be ' 'saved to.') subparser.add_argument('--package-name', help='Chrome apk package name.') subparser = command_parsers.add_parser('test_update') subparser.add_argument('--old-apk', required=True, help='Path to apk to update from.') subparser.add_argument('--new-apk', required=True, help='Path to apk to update to.') subparser.add_argument('--app-data', required=True, help='Path to where the app data backup is saved.') subparser.add_argument('--package-name', help='Chrome apk package name.') args = parser.parse_args() run_tests_helper.SetLogLevel(args.verbose) devil_chromium.Initialize() denylist = (device_denylist.Denylist(args.denylist_file) if args.denylist_file else None) devices = device_utils.DeviceUtils.HealthyDevices(denylist) if not devices: raise device_errors.NoDevicesError() device = devices[0] logging.info('Using device %s for testing.', str(device)) package_name = (args.package_name if args.package_name else apk_helper.GetPackageName(args.old_apk)) if args.command == 'create_app_data': CreateAppData(device, args.old_apk, args.app_data, package_name) elif args.command == 'test_update': TestUpdate(device, args.old_apk, args.new_apk, args.app_data, package_name) else: raise Exception('Unknown test command: %s' % args.command)
def main(): # Parse options. parser = optparse.OptionParser(description=__doc__, usage='screenshot.py [options] [filename]') parser.add_option('-d', '--device', metavar='ANDROID_DEVICE', help='Serial ' 'number of Android device to use.', default=None) parser.add_option('--blacklist-file', help='Device blacklist JSON file.') parser.add_option('-f', '--file', help='Save result to file instead of ' 'generating a timestamped file name.', metavar='FILE') parser.add_option('-v', '--verbose', help='Verbose logging.', action='store_true') video_options = optparse.OptionGroup(parser, 'Video capture') video_options.add_option('--video', help='Enable video capturing. Requires ' 'Android KitKat or later', action='store_true') video_options.add_option('-b', '--bitrate', help='Bitrate in megabits/s, ' 'from 0.1 to 100 mbps, %default mbps by default.', default=4, type='float') video_options.add_option('-r', '--rotate', help='Rotate video by 90 degrees.', default=False, action='store_true') video_options.add_option('-s', '--size', metavar='WIDTHxHEIGHT', help='Frame size to use instead of the device ' 'screen size.', default=None) parser.add_option_group(video_options) (options, args) = parser.parse_args() if len(args) > 1: parser.error('Too many positional arguments.') host_file = args[0] if args else options.file if options.verbose: logging.getLogger().setLevel(logging.DEBUG) blacklist = (device_blacklist.Blacklist(options.blacklist_file) if options.blacklist_file else None) devices = device_utils.DeviceUtils.HealthyDevices(blacklist) if options.device: device = next((d for d in devices if d == options.device), None) if not device: raise device_errors.DeviceUnreachableError(options.device) else: if len(devices) > 1: parser.error('Multiple devices are attached. ' 'Please specify device serial number with --device.') elif len(devices) == 1: device = devices[0] else: raise device_errors.NoDevicesError() if options.video: _CaptureVideo(device, host_file, options) else: _CaptureScreenshot(device, host_file) return 0
def BlacklistDevice(self, device, reason='local_device_failure'): device_serial = device.adb.GetDeviceSerial() if self._blacklist: self._blacklist.Extend([device_serial], reason=reason) with self._devices_lock: self._devices = [d for d in self._devices if str(d) != device_serial] logging.error('Device %s blacklisted: %s', device_serial, reason) if not self._devices: raise device_errors.NoDevicesError( 'All devices were blacklisted due to errors')
def GlobalSetUp(self): os.putenv('TEST_HTTP_PORT', str(ANDROID_TEST_HTTP_PORT)) os.putenv('TEST_HTTPS_PORT', str(ANDROID_TEST_HTTPS_PORT)) devices = device_utils.DeviceUtils.HealthyDevices() if not devices: raise device_errors.NoDevicesError() elif len(devices) > 1: logging.warning('Multiple devices attached. Using %s.' % devices[0]) self._device = devices[0] forwarder.Forwarder.Map( [(ANDROID_TEST_HTTP_PORT, ANDROID_TEST_HTTP_PORT), (ANDROID_TEST_HTTPS_PORT, ANDROID_TEST_HTTPS_PORT)], self._device)
def _InitDevices(self): device_arg = 'default' if self._target_devices_file: device_arg = device_list.GetPersistentDeviceList( self._target_devices_file) if not device_arg: logging.warning('No target devices specified. Falling back to ' 'running on all available devices.') device_arg = 'default' else: logging.info('Read device list %s from target devices file.', str(device_arg)) elif self._device_serials: device_arg = self._device_serials self._devices = device_utils.DeviceUtils.HealthyDevices( self._blacklist, enable_device_files_cache=self._enable_device_cache, default_retries=self._max_tries - 1, device_arg=device_arg) if not self._devices: raise device_errors.NoDevicesError('No devices were available') if self._logcat_output_file: self._logcat_output_dir = tempfile.mkdtemp() @handle_shard_failures_with(on_failure=self.BlacklistDevice) def prepare_device(d): d.WaitUntilFullyBooted() if self._enable_device_cache: cache_path = _DeviceCachePath(d) if os.path.exists(cache_path): logging.info('Using device cache: %s', cache_path) with open(cache_path) as f: d.LoadCacheData(f.read()) # Delete cached file so that any exceptions cause it to be cleared. os.unlink(cache_path) if self._logcat_output_dir: logcat_file = os.path.join( self._logcat_output_dir, '%s_%s' % (d.adb.GetDeviceSerial(), datetime.datetime.utcnow().strftime('%Y%m%dT%H%M%S'))) monitor = logcat_monitor.LogcatMonitor(d.adb, clear=True, output_file=logcat_file) self._logcat_monitors.append(monitor) monitor.Start() self.parallel_devices.pMap(prepare_device)
def GetDevices(requested_devices, blacklist_file): blacklist = (device_blacklist.Blacklist(blacklist_file) if blacklist_file else None) devices = device_utils.DeviceUtils.HealthyDevices(blacklist) if not devices: raise device_errors.NoDevicesError() elif requested_devices: requested = set(requested_devices) available = set(str(d) for d in devices) missing = requested.difference(available) if missing: raise device_errors.DeviceUnreachableError(next(iter(missing))) return sorted( device_utils.DeviceUtils(d) for d in available.intersection(requested)) else: return devices
def GetDevices(requested_devices, denylist_file): """Gets a list of healthy devices matching the given parameters.""" if not isinstance(denylist_file, device_denylist.Denylist): denylist_file = (device_denylist.Denylist(denylist_file) if denylist_file else None) devices = device_utils.DeviceUtils.HealthyDevices(denylist_file) if not devices: raise device_errors.NoDevicesError() elif requested_devices: requested = set(requested_devices) available = set(str(d) for d in devices) missing = requested.difference(available) if missing: raise device_errors.DeviceUnreachableError(next(iter(missing))) return sorted( device_utils.DeviceUtils(d) for d in available.intersection(requested)) else: return devices
option_parser.print_help() sys.exit(1) if not options.browser in constants.PACKAGE_INFO.keys(): option_parser.error('Unknown browser option ' + options.browser) devil_chromium.Initialize() package_info = constants.PACKAGE_INFO[options.browser] package = package_info.package activity = package_info.activity devices = device_utils.DeviceUtils.HealthyDevices() if not devices: raise device_errors.NoDevicesError() elif len(devices) > 1: logging.warning('Multiple devices attached. Using %s.', str(devices[0])) device = devices[0] try: device.EnableRoot() except device_errors.CommandFailedError as e: # Try to change the flags and start the activity anyway. # TODO(jbudorick) Handle this exception appropriately after interface # conversions are finished. logging.error(str(e)) flags = flag_changer.FlagChanger(device, package_info.cmdline_file) flags.AddFlags([ENABLE_TEST_INTENTS_FLAG]) device.StartActivity(intent.Intent(package=package, activity=activity,
def main(): parser = argparse.ArgumentParser() parser.add_argument('apk_path', help='The path to the APK to install.') parser.add_argument('--split', action='append', dest='splits', help='A glob matching the apk splits. ' 'Can be specified multiple times.') parser.add_argument('--native_lib', dest='native_libs', help='Path to native library (repeatable)', action='append', default=[]) parser.add_argument('--dex-file', dest='dex_files', help='Path to dex files (repeatable)', action='append', default=[]) parser.add_argument('-d', '--device', dest='device', help='Target device for apk to install on.') parser.add_argument('--uninstall', action='store_true', default=False, help='Remove the app and all side-loaded files.') parser.add_argument('--output-directory', help='Path to the root build directory.') parser.add_argument('--no-threading', action='store_false', default=True, dest='threading', help='Do not install and push concurrently') parser.add_argument( '--no-cache', action='store_false', default=True, dest='cache', help='Do not use cached information about what files are ' 'currently on the target device.') parser.add_argument('--show-proguard-warning', action='store_true', default=False, help='Print a warning about proguard being disabled') parser.add_argument('-v', '--verbose', dest='verbose_count', default=0, action='count', help='Verbose level (multiple times for more)') args = parser.parse_args() run_tests_helper.SetLogLevel(args.verbose_count) constants.SetBuildType('Debug') if args.output_directory: constants.SetOutputDirectory(args.output_directory) if args.device: # Retries are annoying when commands fail for legitimate reasons. Might want # to enable them if this is ever used on bots though. device = device_utils.DeviceUtils(args.device, default_retries=0, enable_device_files_cache=True) else: devices = device_utils.DeviceUtils.HealthyDevices( default_retries=0, enable_device_files_cache=True) if not devices: raise device_errors.NoDevicesError() elif len(devices) == 1: device = devices[0] else: all_devices = device_utils.DeviceUtils.parallel(devices) msg = ('More than one device available.\n' 'Use --device=SERIAL to select a device.\n' 'Available devices:\n') descriptions = all_devices.pMap( lambda d: d.build_description).pGet(None) for d, desc in zip(devices, descriptions): msg += ' %s (%s)\n' % (d, desc) raise Exception(msg) apk = apk_helper.ToHelper(args.apk_path) if args.uninstall: Uninstall(device, apk.GetPackageName()) else: Install(device, apk, split_globs=args.splits, native_libs=args.native_libs, dex_files=args.dex_files, enable_device_cache=args.cache, use_concurrency=args.threading, show_proguard_warning=args.show_proguard_warning)
def main(argv): option_parser = optparse.OptionParser() option_parser.add_option('-l', '--low', help='Simulate Activity#onLowMemory()', action='store_true') option_parser.add_option( '-t', '--trim', help=('Simulate Activity#onTrimMemory(...) with ' + ', '.join(ACTION_TRIM.keys())), type='string') option_parser.add_option('-b', '--browser', default=DEFAULT_BROWSER, help=('Which browser to use. One of ' + ', '.join(constants.PACKAGE_INFO.keys()) + ' [default: %default]'), type='string') (options, args) = option_parser.parse_args(argv) if len(args) > 1: print 'Unknown argument: ', args[1:] option_parser.print_help() sys.exit(1) if options.low and options.trim: option_parser.error('options --low and --trim are mutually exclusive') if not options.low and not options.trim: option_parser.print_help() sys.exit(1) action = None if options.low: action = ACTION_LOW elif options.trim in ACTION_TRIM.keys(): action = ACTION_TRIM[options.trim] if action is None: option_parser.print_help() sys.exit(1) if not options.browser in constants.PACKAGE_INFO.keys(): option_parser.error('Unknown browser option ' + options.browser) devil_chromium.Initialize() package_info = constants.PACKAGE_INFO[options.browser] package = package_info.package activity = package_info.activity devices = device_utils.DeviceUtils.HealthyDevices() if not devices: raise device_errors.NoDevicesError() elif len(devices) > 1: logging.warning('Multiple devices attached. Using %s.', str(devices[0])) device = devices[0] try: device.EnableRoot() except device_errors.CommandFailedError as e: # Try to change the flags and start the activity anyway. # TODO(jbudorick) Handle this exception appropriately after interface # conversions are finished. logging.error(str(e)) flags = flag_changer.FlagChanger(device, package_info.cmdline_file) flags.AddFlags([ENABLE_TEST_INTENTS_FLAG]) device.StartActivity( intent.Intent(package=package, activity=activity, action=action))
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', help='Target device for apk to install on. Enter multiple' ' times for multiple devices.') parser.add_argument('--adb-path', help='Absolute path to the adb binary to use.') parser.add_argument('--blacklist-file', help='Device blacklist JSON file.') parser.add_argument('-v', '--verbose', action='count', help='Enable verbose logging.') parser.add_argument('--downgrade', action='store_true', help='If set, allows downgrading of apk.') args = parser.parse_args() run_tests_helper.SetLogLevel(args.verbose) constants.SetBuildType(args.build_type) devil_custom_deps = None if args.adb_path: devil_custom_deps = { 'adb': { devil_env.GetPlatform(): [args.adb_path], }, } devil_chromium.Initialize(output_directory=constants.GetOutDirectory(), custom_deps=devil_custom_deps) 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) blacklist = (device_blacklist.Blacklist(args.blacklist_file) if args.blacklist_file else None) devices = device_utils.DeviceUtils.HealthyDevices(blacklist) if args.devices: devices = [d for d in devices if d in args.devices] if not devices: raise device_errors.DeviceUnreachableError(args.devices) elif not devices: raise device_errors.NoDevicesError() def blacklisting_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) except device_errors.CommandFailedError: logging.exception('Failed to install %s', args.apk_name) if blacklist: blacklist.Extend([str(device)], reason='install_failure') logging.warning('Blacklisting %s', str(device)) except device_errors.CommandTimeoutError: logging.exception('Timed out while installing %s', args.apk_name) if blacklist: blacklist.Extend([str(device)], reason='install_timeout') logging.warning('Blacklisting %s', str(device)) device_utils.DeviceUtils.parallel(devices).pMap(blacklisting_install)
def testPicklable_NoDevicesError(self): original = device_errors.NoDevicesError() self.assertIsPicklable(original)
def devices(self): if not self._devices: raise device_errors.NoDevicesError() return self._devices
def main(): parser = argparse.ArgumentParser(description=__doc__) parser.usage = '''%(prog)s --device-path PATH [--device SERIAL] [flags...] No flags: Prints existing command-line file. Empty string: Deletes command-line file. Otherwise: Writes command-line file. ''' parser.add_argument('-d', '--device', dest='device', help='Target device for apk to install on.') parser.add_argument('--device-path', required=True, help='Remote path to flags file.') parser.add_argument('-e', '--executable', dest='executable', default='chrome', help='Name of the executable.') args, remote_args = parser.parse_known_args() devil_chromium.Initialize() as_root = not args.device_path.startswith('/data/local/tmp/') if args.device: devices = [device_utils.DeviceUtils(args.device, default_retries=0)] else: devices = device_utils.DeviceUtils.HealthyDevices(default_retries=0) if not devices: raise device_errors.NoDevicesError() all_devices = device_utils.DeviceUtils.parallel(devices) def print_args(): def read_flags(device): try: return device.ReadFile(args.device_path, as_root=as_root).rstrip() except device_errors.AdbCommandFailedError: return '' # File might not exist. descriptions = all_devices.pMap(lambda d: d.build_description).pGet(None) flags = all_devices.pMap(read_flags).pGet(None) for d, desc, flags in zip(devices, descriptions, flags): print ' %s (%s): %r' % (d, desc, flags) # No args == print flags. if not remote_args: print 'Existing flags (in %s):' % args.device_path print_args() return 0 # Empty string arg == delete flags file. if len(remote_args) == 1 and not remote_args[0]: def delete_flags(device): device.RunShellCommand(['rm', '-f', args.device_path], as_root=as_root) all_devices.pMap(delete_flags).pGet(None) print 'Deleted %s' % args.device_path return 0 # Set flags. quoted_args = ' '.join(cmd_helper.SingleQuote(x) for x in remote_args) flags_str = ' '.join([args.executable, quoted_args]) def write_flags(device): device.WriteFile(args.device_path, flags_str, as_root=as_root) device.RunShellCommand(['chmod', '0664', args.device_path], as_root=as_root) all_devices.pMap(write_flags).pGet(None) print 'Wrote flags to %s' % args.device_path print_args() return 0
def main(): parser = argparse.ArgumentParser() parser.add_argument('apk_path', help='The path to the APK to install.') parser.add_argument('--split', action='append', dest='splits', help='A glob matching the apk splits. ' 'Can be specified multiple times.') parser.add_argument('--lib-dir', help='Path to native libraries directory.') parser.add_argument('--dex-files', help='List of dex files to push.', action='append', default=[]) parser.add_argument('-d', '--device', dest='device', help='Target device for apk to install on.') parser.add_argument('--uninstall', action='store_true', default=False, help='Remove the app and all side-loaded files.') parser.add_argument('--output-directory', help='Path to the root build directory.') parser.add_argument('--no-threading', action='store_true', default=False, help='Do not install and push concurrently') parser.add_argument('-v', '--verbose', dest='verbose_count', default=0, action='count', help='Verbose level (multiple times for more)') args = parser.parse_args() run_tests_helper.SetLogLevel(args.verbose_count) constants.SetBuildType('Debug') if args.output_directory: constants.SetOutputDirectory(args.output_directory) main_timer = time_profile.TimeProfile() install_timer = time_profile.TimeProfile() push_native_timer = time_profile.TimeProfile() push_dex_timer = time_profile.TimeProfile() if args.device: # Retries are annoying when commands fail for legitimate reasons. Might want # to enable them if this is ever used on bots though. device = device_utils.DeviceUtils(args.device, default_retries=0) else: devices = device_utils.DeviceUtils.HealthyDevices(default_retries=0) if not devices: raise device_errors.NoDevicesError() elif len(devices) == 1: device = devices[0] else: all_devices = device_utils.DeviceUtils.parallel(devices) msg = ('More than one device available.\n' 'Use --device=SERIAL to select a device.\n' 'Available devices:\n') descriptions = all_devices.pMap(lambda d: d.build_description).pGet(None) for d, desc in zip(devices, descriptions): msg += ' %s (%s)\n' % (d, desc) raise Exception(msg) apk_help = apk_helper.ApkHelper(args.apk_path) apk_package = apk_help.GetPackageName() device_incremental_dir = '/data/local/tmp/incremental-app-%s' % apk_package if args.uninstall: device.Uninstall(apk_package) device.RunShellCommand(['rm', '-rf', device_incremental_dir], check_return=True) logging.info('Uninstall took %s seconds.', main_timer.GetDelta()) return if device.build_version_sdk >= version_codes.MARSHMALLOW: if apk_help.HasIsolatedProcesses(): raise Exception('Cannot use perform incremental installs on Android M+ ' 'without first disabling isolated processes. Use GN arg: ' 'disable_incremental_isolated_processes=true to do so.') # Install .apk(s) if any of them have changed. def do_install(): install_timer.Start() if args.splits: splits = [] for split_glob in args.splits: splits.extend((f for f in glob.glob(split_glob))) device.InstallSplitApk(args.apk_path, splits, reinstall=True, allow_cached_props=True, permissions=()) else: device.Install(args.apk_path, reinstall=True, permissions=()) install_timer.Stop(log=False) # Push .so and .dex files to the device (if they have changed). def do_push_files(): if args.lib_dir: push_native_timer.Start() device_lib_dir = posixpath.join(device_incremental_dir, 'lib') device.PushChangedFiles([(args.lib_dir, device_lib_dir)], delete_device_stale=True) push_native_timer.Stop(log=False) if args.dex_files: push_dex_timer.Start() # Put all .dex files to be pushed into a temporary directory so that we # can use delete_device_stale=True. with build_utils.TempDir() as temp_dir: device_dex_dir = posixpath.join(device_incremental_dir, 'dex') # Ensure no two files have the same name. transformed_names = _TransformDexPaths(args.dex_files) for src_path, dest_name in zip(args.dex_files, transformed_names): shutil.copyfile(src_path, os.path.join(temp_dir, dest_name)) device.PushChangedFiles([(temp_dir, device_dex_dir)], delete_device_stale=True) push_dex_timer.Stop(log=False) # Create 2 lock files: # * install.lock tells the app to pause on start-up (until we release it). # * firstrun.lock is used by the app to pause all secondary processes until # the primary process finishes loading the .dex / .so files. def create_lock_files(): # Creates or zeros out lock files. cmd = ('D="%s";' 'mkdir -p $D &&' 'echo -n >$D/install.lock 2>$D/firstrun.lock') device.RunShellCommand(cmd % device_incremental_dir, check_return=True) # The firstrun.lock is released by the app itself. def release_installer_lock(): device.RunShellCommand('echo > %s/install.lock' % device_incremental_dir, check_return=True) create_lock_files() # Concurrency here speeds things up quite a bit, but DeviceUtils hasn't # been designed for multi-threading. Enabling only because this is a # developer-only tool. if args.no_threading: do_install() do_push_files() else: reraiser_thread.RunAsync((do_install, do_push_files)) release_installer_lock() logging.info('Took %s seconds (install=%s, libs=%s, dex=%s)', main_timer.GetDelta(), install_timer.GetDelta(), push_native_timer.GetDelta(), push_dex_timer.GetDelta())